Merge branch 'localApps' into renovate/ghcr.io-utensils-nxv-0.x

This commit is contained in:
okxlin
2026-08-07 17:10:29 +08:00
committed by GitHub
265 changed files with 150 additions and 78 deletions
+23
View File
@@ -378,3 +378,26 @@ wakapi
# Reviewed single-service Renovate candidates (2026-08-01).
codex2api
opencode
# Reviewed digest-only Renovate candidates (2026-08-07).
podfetch
isrvd
chromium-kasm
filezilla-kasm
firefox-kasm
insomnia-kasm
only-office-kasm
postman-kasm
signal-kasm
slack-kasm
vlc-kasm
audacity-kasm
blender-kasm
brave-kasm
gimp-kasm
inkscape-kasm
obsidian-kasm
pinta-kasm
remmina-kasm
sublime-text-kasm
vivaldi-kasm
@@ -811,6 +811,33 @@ class RenovateAppVersionTests(unittest.TestCase):
self.assertIn("headRefName,headRepositoryOwner,isCrossRepository", reconcile)
self.assertIn('.headRefName | startswith("selfhosted-renovate/")', reconcile)
def test_automerge_allows_exact_digest_only_updates_without_version_marker(self):
workflow = (
REPO_ROOT / ".github" / "workflows" / "renovate-automerge.yml"
).read_text(encoding="utf-8")
self.assertIn("def digest_reference(image):", workflow)
self.assertIn(
're.fullmatch(r"([^@\\s]+)@sha256:([0-9a-fA-F]{64})", image)',
workflow,
)
self.assertIn("old_digest[0] != new_digest[0]", workflow)
self.assertIn("old_digest[1] == new_digest[1]", workflow)
self.assertIn("filename_is_compose != previous_is_compose", workflow)
self.assertIn("digest_only=true", workflow)
self.assertIn("steps.shape.outputs.digest_only", workflow)
self.assertIn("Digest-only image update; app-version marker is not required", workflow)
self.assertIn("Update app version [skip ci]", workflow)
def test_reconcile_delegates_all_whitelisted_open_prs_to_automerge_gate(self):
workflow = (
REPO_ROOT / ".github" / "workflows" / "renovate-automerge-reconcile.yml"
).read_text(encoding="utf-8")
self.assertNotIn('index("renovate-auto")', workflow)
self.assertNotIn("Update app version [skip ci]", workflow)
self.assertIn("gh workflow run renovate-automerge.yml", workflow)
def test_semantic_entrypoint_blocks_external_host_abort(self):
entrypoint = REPO_ROOT / ".github" / "scripts" / "renovate-entrypoint.sh"
with tempfile.TemporaryDirectory(prefix="renovate-entrypoint-test-") as tmp:
@@ -21,7 +21,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Find eligible Renovate PRs missing automerge label
- name: Find eligible Renovate PRs
id: scan
env:
GH_TOKEN: ${{ github.token }}
@@ -36,7 +36,7 @@ jobs:
mapfile -t pr_numbers < <(
gh pr list --repo "$REPO" --state open --limit 100 \
--json number,author,labels,isDraft,baseRefName,headRefName,headRepositoryOwner,isCrossRepository \
--json number,author,isDraft,baseRefName,headRefName,headRepositoryOwner,isCrossRepository \
--jq '.[]
| select(
.author.login == "app/renovate" or
@@ -51,7 +51,6 @@ jobs:
)
| select(.isDraft | not)
| select(.baseRefName == "localApps")
| select(([.labels[].name] | index("renovate-auto")) | not)
| .number'
)
@@ -89,19 +88,6 @@ jobs:
continue
fi
pull_commits=$(gh api "repos/$REPO/pulls/$pr_number/commits" --paginate --jq '.[].commit.message' || true)
base_sha=$(gh pr view "$pr_number" --repo "$REPO" --json baseRefOid --jq '.baseRefOid' || true)
head_sha=$(gh pr view "$pr_number" --repo "$REPO" --json headRefOid --jq '.headRefOid' || true)
compare_commits=''
if [ -n "$base_sha" ] && [ -n "$head_sha" ]; then
compare_commits=$(gh api "repos/$REPO/compare/$base_sha...$head_sha" --jq '.commits[].commit.message' || true)
fi
all_commits="$(printf '%s\n%s\n' "$pull_commits" "$compare_commits")"
if ! echo "$all_commits" | grep -Fq 'Update app version [skip ci]'; then
continue
fi
eligible+=("$pr_number")
done
+37 -1
View File
@@ -159,12 +159,21 @@ jobs:
reject(f"compose must contain exactly one service: {path}")
return data, services
def digest_reference(image):
if not isinstance(image, str):
return None
match = re.fullmatch(r"([^@\s]+)@sha256:([0-9a-fA-F]{64})", image)
if match is None:
return None
return match.group(1), match.group(2).lower()
try:
with open("/tmp/renovate-pr-files.json", encoding="utf-8") as fh:
files = json.load(fh)
apps = set()
compose_files = []
digest_only = True
for file_info in files:
filename = file_info["filename"]
@@ -178,8 +187,14 @@ jobs:
reject(f"changed file outside apps/: {path}")
apps.add(match.group(1))
if filename.endswith("/docker-compose.yml") or (previous and previous.endswith("/docker-compose.yml")):
filename_is_compose = filename.endswith("/docker-compose.yml")
previous_is_compose = bool(previous and previous.endswith("/docker-compose.yml"))
if filename_is_compose or previous_is_compose:
compose_files.append((previous or filename, filename))
if previous and filename_is_compose != previous_is_compose:
digest_only = False
else:
digest_only = False
if len(apps) != 1:
reject(f"PR must affect exactly one app, got {', '.join(sorted(apps))}")
@@ -205,6 +220,16 @@ jobs:
if not old_image or not new_image or old_image == new_image:
reject(f"compose service image must change: {new_resolved_path}")
old_digest = digest_reference(old_image)
new_digest = digest_reference(new_image)
if (
old_digest is None
or new_digest is None
or old_digest[0] != new_digest[0]
or old_digest[1] == new_digest[1]
):
digest_only = False
old_data.pop("version", None)
new_data.pop("version", None)
for service in old_services.values():
@@ -221,6 +246,11 @@ jobs:
checked += 1
print(f"single-service image-only update verified for {app_name} across {checked} compose file(s)")
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
if digest_only:
output.write("digest_only=true\n")
else:
output.write("digest_only=false\n")
except GateReject as exc:
print(str(exc), file=sys.stderr)
sys.exit(42)
@@ -260,6 +290,12 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ steps.shape.outputs.digest_only }}" = "true" ]; then
echo "Digest-only image update; app-version marker is not required"
echo "found=true" >> "$GITHUB_OUTPUT"
exit 0
fi
PR_NUMBER="${{ github.event.pull_request.number || inputs.pr_number }}"
REPO="${{ github.repository }}"
@@ -1,6 +1,6 @@
services:
atvloadly:
image: "bitxeno/atvloadly:v0.4.6"
image: "bitxeno/atvloadly:v0.4.7"
container_name: ${CONTAINER_NAME}
restart: always
networks:
@@ -1,6 +1,6 @@
services:
audacity-kasm:
image: "kasmweb/audacity:1.19.0-rolling-weekly@sha256:f2707362ce735267332cc434c78d23d34090c5d7a97d03d5ea4ca053bc268bb1"
image: "kasmweb/audacity:1.19.0-rolling-weekly@sha256:64957edcd3516dfc01a0e9bf602ec735d2e07de111a8d0358e9738195927cade"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -3,7 +3,7 @@ networks:
external: true
services:
babybuddy:
image: "linuxserver/babybuddy:2.9.2"
image: "linuxserver/babybuddy:2.10.0"
container_name: ${CONTAINER_NAME}
restart: always
networks:
@@ -3,7 +3,7 @@ networks:
external: true
services:
blade-of-agony:
image: "linuxserver/blade-of-agony:3.1.20260730"
image: "linuxserver/blade-of-agony:3.1.20260807"
container_name: ${CONTAINER_NAME}
restart: always
networks:
@@ -1,6 +1,6 @@
services:
blender-kasm:
image: "kasmweb/blender:1.19.0-rolling-weekly@sha256:c92e7e4ee6074c5aeb8096862d0d2910bfcbceec87038c9d70c3a63b9fdb89d8"
image: "kasmweb/blender:1.19.0-rolling-weekly@sha256:a80430080504eacd1092842ea5fc4627b945406bbdab1f85c3e098ef4a048b0d"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -1,6 +1,6 @@
services:
brave-kasm:
image: "kasmweb/brave:1.19.0-rolling-weekly@sha256:a6683fba210f11b2bb293ccf9c1531e8a52a4070c728b4c31c14db527b1b6beb"
image: "kasmweb/brave:1.19.0-rolling-weekly@sha256:646e7849a56109990faa742b91595c2eda970d9b9c8472c08432c0036ae7029a"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -3,7 +3,7 @@ networks:
external: true
services:
brave:
image: "linuxserver/brave:1.93.129"
image: "linuxserver/brave:1.93.132"
container_name: ${CONTAINER_NAME}
restart: always
networks:
@@ -3,7 +3,7 @@ networks:
external: true
services:
calibre:
image: "linuxserver/calibre:9.12.0"
image: "linuxserver/calibre:9.13.0"
container_name: ${CONTAINER_NAME}
restart: always
networks:
@@ -1,6 +1,6 @@
services:
chromium-kasm:
image: "kasmweb/chromium:1.19.0-rolling-weekly@sha256:cda6f157fa4309443f728b42c905533ca4d55b5747302258aace2e06db071f72"
image: "kasmweb/chromium:1.19.0-rolling-weekly@sha256:60f34130c6b6485755a3ad37f4e2ac110723c55c090df78cbc60814b6f6c2b45"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -1,6 +1,6 @@
services:
claper:
image: "ghcr.io/claperco/claper:2.5.1"
image: "ghcr.io/claperco/claper:3.0.0@sha256:ebdd932616623d3dba6dcf5ea5d967380db88d507a719eb8c00dbf5d29a6d9c8"
container_name: ${CONTAINER_NAME}
restart: always
networks:
@@ -1,6 +1,6 @@
services:
codex2api:
image: "ghcr.io/james-6-23/codex2api:2.7.0@sha256:68e220e9dd981b5dc680cc3ba059cfb3697e2a3a5626b6a6306afb11e6fd6b43"
image: "ghcr.io/james-6-23/codex2api:2.7.1@sha256:cc16f8af03e96d146b09950e0fb3e43e0afbc66dcb7c329cbbbec02e95edc582"
container_name: ${CONTAINER_NAME}
restart: always
security_opt:
@@ -1,6 +1,6 @@
services:
cpa-manager-plus:
image: "seakee/cpa-manager-plus:v1.11.11"
image: "seakee/cpa-manager-plus:v1.11.12"
container_name: ${CONTAINER_NAME}
ports:
- "${PANEL_APP_PORT_HTTP}:18317"
@@ -1,6 +1,6 @@
services:
cpa-usage-keeper:
image: ghcr.io/willxup/cpa-usage-keeper:v1.14.2
image: ghcr.io/willxup/cpa-usage-keeper:v1.14.3
container_name: ${CONTAINER_NAME}
ports:
- ${PANEL_APP_PORT_HTTP}:8080
@@ -19,7 +19,7 @@ services:
timeout: 10s
retries: 3
start_period: 40s
image: lissy93/dashy:4.5.5
image: lissy93/dashy:4.5.6
labels:
createdBy: "Apps"
@@ -1,6 +1,6 @@
services:
dbx:
image: "t8y2/dbx:0.5.75"
image: "t8y2/dbx:0.5.77"
container_name: ${CONTAINER_NAME}
ports:
- "${PANEL_APP_PORT_HTTP}:4224"
@@ -7,7 +7,7 @@ services:
ports:
- "${PANEL_APP_PORT_HTTP}:1188"
command: ["/app/deeplx", "-token", "${TOKEN_VAULE}"]
image: missuo/deeplx:v1.2.3
image: missuo/deeplx:v1.2.4
labels:
createdBy: "Apps"
@@ -1,6 +1,6 @@
services:
dragonfly:
image: "docker.dragonflydb.io/dragonflydb/dragonfly:v1.40.0"
image: "docker.dragonflydb.io/dragonflydb/dragonfly:v1.40.1"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -6,7 +6,7 @@ services:
- 1panel-network
ports:
- "${PANEL_APP_PORT_HTTP}:80"
image: vectorim/element-web:v1.12.24
image: vectorim/element-web:v1.12.25
labels:
createdBy: "Apps"
@@ -1,6 +1,6 @@
services:
filerise:
image: "error311/filerise-docker:v3.25.0"
image: "error311/filerise-docker:v3.26.1"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -1,6 +1,6 @@
services:
filezilla-kasm:
image: "kasmweb/filezilla:1.19.0-rolling-weekly@sha256:3a4831da8d510417ca7606942d8ae9f6fb48a74d010c6f6107c5798d7976acb8"
image: "kasmweb/filezilla:1.19.0-rolling-weekly@sha256:a8a62b7728984357baf9af1d197032c496753175df1e94491ff0e7316b143ae7"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -1,6 +1,6 @@
services:
firefox-kasm:
image: "kasmweb/firefox:1.19.0-rolling-weekly@sha256:1f6c0d62afee626780134044cbaad6b6442562f0bc3c3f759cb5d3f8437962b2"
image: "kasmweb/firefox:1.19.0-rolling-weekly@sha256:a0d12f54ab2a51f2aa70adbe14b68ad8cefdbbb2d71fb41bbc0cbfdfa1e902e4"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
networks:
@@ -3,7 +3,7 @@ networks:
external: true
services:
flexget:
image: "linuxserver/flexget:3.20.0"
image: "linuxserver/flexget:3.20.1"
container_name: ${CONTAINER_NAME}
restart: always
networks:

Some files were not shown because too many files have changed in this diff Show More