fix(release): mirror TCR images asynchronously
This commit is contained in:
1 parent
bc6fdfdcd4
commit
95e0f3eb97
6 files changed
+198
-106
No files matched your search
@@ -54,7 +54,6 @@ permissions:
|
||||
|
||||
env:
|
||||
GHCR_IMAGE_NAME: ghcr.io/tianma-if/edgeever
|
||||
TCR_IMAGE_NAME: ccr.ccs.tencentyun.com/edgeever/edgeever
|
||||
|
||||
jobs:
|
||||
container-test:
|
||||
@@ -144,11 +143,6 @@ jobs:
|
||||
echo "${GHCR_IMAGE_NAME}:${version}"
|
||||
echo "${GHCR_IMAGE_NAME}:latest"
|
||||
echo "EOF"
|
||||
echo "mirror_tags<<EOF"
|
||||
echo "${RELEASE_TAG}"
|
||||
echo "${version}"
|
||||
echo "latest"
|
||||
echo "EOF"
|
||||
echo "version=${version}"
|
||||
echo "audit_tag=${RELEASE_TAG}"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
@@ -159,10 +153,6 @@ jobs:
|
||||
echo "${GHCR_IMAGE_NAME}:main"
|
||||
echo "${GHCR_IMAGE_NAME}:sha-${short_sha}"
|
||||
echo "EOF"
|
||||
echo "mirror_tags<<EOF"
|
||||
echo "main"
|
||||
echo "sha-${short_sha}"
|
||||
echo "EOF"
|
||||
echo "version=main"
|
||||
echo "audit_tag=main"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
@@ -181,18 +171,6 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Sign in to Tencent Cloud Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ccr.ccs.tencentyun.com
|
||||
username: ${{ secrets.TENCENT_TCR_USERNAME }}
|
||||
password: ${{ secrets.TENCENT_TCR_PASSWORD }}
|
||||
|
||||
- name: Install registry copy tool
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes skopeo
|
||||
|
||||
- name: Build and publish image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
@@ -207,44 +185,12 @@ jobs:
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Mirror image to Tencent Cloud Container Registry
|
||||
env:
|
||||
MIRROR_TAGS: ${{ steps.image.outputs.mirror_tags }}
|
||||
run: |
|
||||
while IFS= read -r image_tag; do
|
||||
[[ -n "${image_tag}" ]] || continue
|
||||
for attempt in 1 2 3; do
|
||||
if skopeo copy \
|
||||
--all \
|
||||
--preserve-digests \
|
||||
--authfile "${HOME}/.docker/config.json" \
|
||||
"docker://${GHCR_IMAGE_NAME}:${image_tag}" \
|
||||
"docker://${TCR_IMAGE_NAME}:${image_tag}"; then
|
||||
break
|
||||
fi
|
||||
if [[ "${attempt}" -eq 3 ]]; then
|
||||
echo "Failed to mirror ${image_tag} after ${attempt} attempts" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Mirror attempt ${attempt} failed for ${image_tag}; retrying" >&2
|
||||
sleep "$((attempt * 15))"
|
||||
done
|
||||
done <<< "${MIRROR_TAGS}"
|
||||
|
||||
- name: Verify mirrored anonymous image access
|
||||
- name: Verify anonymous GHCR image access
|
||||
run: |
|
||||
docker logout ghcr.io
|
||||
docker logout ccr.ccs.tencentyun.com
|
||||
ghcr_inspect="$(docker buildx imagetools inspect "${GHCR_IMAGE_NAME}:${{ steps.image.outputs.audit_tag }}")"
|
||||
tcr_inspect="$(docker buildx imagetools inspect "${TCR_IMAGE_NAME}:${{ steps.image.outputs.audit_tag }}")"
|
||||
ghcr_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${ghcr_inspect}" | head -n 1)"
|
||||
tcr_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${tcr_inspect}" | head -n 1)"
|
||||
test -n "${ghcr_digest}"
|
||||
test "${ghcr_digest}" = "${tcr_digest}"
|
||||
for image in "${GHCR_IMAGE_NAME}" "${TCR_IMAGE_NAME}"; do
|
||||
docker buildx imagetools inspect --raw "${image}:${{ steps.image.outputs.audit_tag }}" |
|
||||
jq -e '([.manifests[].platform.architecture] | index("amd64") != null) and ([.manifests[].platform.architecture] | index("arm64") != null)'
|
||||
done
|
||||
docker buildx imagetools inspect "${GHCR_IMAGE_NAME}:${{ steps.image.outputs.audit_tag }}"
|
||||
docker buildx imagetools inspect --raw "${GHCR_IMAGE_NAME}:${{ steps.image.outputs.audit_tag }}" |
|
||||
jq -e '([.manifests[].platform.architecture] | index("amd64") != null) and ([.manifests[].platform.architecture] | index("arm64") != null)'
|
||||
|
||||
release-audit:
|
||||
if: github.repository == 'tianma-if/edgeever' && github.event_name == 'release'
|
||||
@@ -256,19 +202,11 @@ jobs:
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
expected_digest=""
|
||||
for image in "${GHCR_IMAGE_NAME}" "${TCR_IMAGE_NAME}"; do
|
||||
release_inspect="$(docker buildx imagetools inspect "${image}:${RELEASE_TAG}")"
|
||||
latest_inspect="$(docker buildx imagetools inspect "${image}:latest")"
|
||||
release_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${release_inspect}" | head -n 1)"
|
||||
latest_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${latest_inspect}" | head -n 1)"
|
||||
test -n "${release_digest}"
|
||||
test "${release_digest}" = "${latest_digest}"
|
||||
if [[ -z "${expected_digest}" ]]; then
|
||||
expected_digest="${release_digest}"
|
||||
else
|
||||
test "${release_digest}" = "${expected_digest}"
|
||||
fi
|
||||
docker buildx imagetools inspect --raw "${image}:${RELEASE_TAG}" |
|
||||
jq -e '([.manifests[].platform.architecture] | index("amd64") != null) and ([.manifests[].platform.architecture] | index("arm64") != null)'
|
||||
done
|
||||
release_inspect="$(docker buildx imagetools inspect "${GHCR_IMAGE_NAME}:${RELEASE_TAG}")"
|
||||
latest_inspect="$(docker buildx imagetools inspect "${GHCR_IMAGE_NAME}:latest")"
|
||||
release_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${release_inspect}" | head -n 1)"
|
||||
latest_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${latest_inspect}" | head -n 1)"
|
||||
test -n "${release_digest}"
|
||||
test "${release_digest}" = "${latest_digest}"
|
||||
docker buildx imagetools inspect --raw "${GHCR_IMAGE_NAME}:${RELEASE_TAG}" |
|
||||
jq -e '([.manifests[].platform.architecture] | index("amd64") != null) and ([.manifests[].platform.architecture] | index("arm64") != null)'
|
||||
@@ -0,0 +1,144 @@
|
||||
name: Mirror Docker image to Tencent TCR
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Build and publish Docker image
|
||||
types:
|
||||
- completed
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_tag:
|
||||
description: "Immutable GHCR tag to mirror"
|
||||
required: true
|
||||
type: string
|
||||
destination_tags:
|
||||
description: "Comma-separated TCR tags"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
|
||||
env:
|
||||
GHCR_IMAGE_NAME: ghcr.io/tianma-if/edgeever
|
||||
TCR_IMAGE_NAME: ccr.ccs.tencentyun.com/edgeever/edgeever
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
if: >-
|
||||
github.repository == 'tianma-if/edgeever' &&
|
||||
(
|
||||
github.event_name == 'release' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(
|
||||
github.event_name == 'workflow_run' &&
|
||||
github.event.workflow_run.conclusion == 'success' &&
|
||||
github.event.workflow_run.event == 'push'
|
||||
)
|
||||
)
|
||||
name: Mirror public image without blocking releases
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Resolve immutable source and destination tags
|
||||
id: image
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
SOURCE_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
INPUT_SOURCE_TAG: ${{ inputs.source_tag }}
|
||||
INPUT_DESTINATION_TAGS: ${{ inputs.destination_tags }}
|
||||
run: |
|
||||
if [[ "${EVENT_NAME}" == "release" ]]; then
|
||||
source_tag="${RELEASE_TAG}"
|
||||
destination_tags="${RELEASE_TAG},${RELEASE_TAG#v},latest"
|
||||
elif [[ "${EVENT_NAME}" == "workflow_run" ]]; then
|
||||
source_tag="sha-${SOURCE_SHA:0:12}"
|
||||
destination_tags="main,${source_tag}"
|
||||
else
|
||||
source_tag="${INPUT_SOURCE_TAG}"
|
||||
destination_tags="${INPUT_DESTINATION_TAGS}"
|
||||
fi
|
||||
if [[ ! "${source_tag}" =~ ^[A-Za-z0-9._-]+$ ]]; then
|
||||
echo "Invalid source tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
IFS=',' read -ra tags <<< "${destination_tags}"
|
||||
for image_tag in "${tags[@]}"; do
|
||||
if [[ ! "${image_tag}" =~ ^[A-Za-z0-9._-]+$ ]]; then
|
||||
echo "Invalid destination tag: ${image_tag}" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
{
|
||||
echo "source_tag=${source_tag}"
|
||||
echo "destination_tags=${destination_tags}"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Sign in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Sign in to Tencent Cloud Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ccr.ccs.tencentyun.com
|
||||
username: ${{ secrets.TENCENT_TCR_USERNAME }}
|
||||
password: ${{ secrets.TENCENT_TCR_PASSWORD }}
|
||||
|
||||
- name: Install registry copy tool
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes skopeo
|
||||
|
||||
- name: Mirror image tags
|
||||
env:
|
||||
SOURCE_TAG: ${{ steps.image.outputs.source_tag }}
|
||||
DESTINATION_TAGS: ${{ steps.image.outputs.destination_tags }}
|
||||
run: |
|
||||
IFS=',' read -ra tags <<< "${DESTINATION_TAGS}"
|
||||
for image_tag in "${tags[@]}"; do
|
||||
for attempt in 1 2 3; do
|
||||
if skopeo copy \
|
||||
--all \
|
||||
--preserve-digests \
|
||||
--authfile "${HOME}/.docker/config.json" \
|
||||
"docker://${GHCR_IMAGE_NAME}:${SOURCE_TAG}" \
|
||||
"docker://${TCR_IMAGE_NAME}:${image_tag}"; then
|
||||
break
|
||||
fi
|
||||
if [[ "${attempt}" -eq 3 ]]; then
|
||||
echo "Failed to mirror ${image_tag} after ${attempt} attempts" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Mirror attempt ${attempt} failed for ${image_tag}; retrying" >&2
|
||||
sleep "$((attempt * 15))"
|
||||
done
|
||||
done
|
||||
|
||||
- name: Verify mirrored anonymous image access
|
||||
env:
|
||||
SOURCE_TAG: ${{ steps.image.outputs.source_tag }}
|
||||
DESTINATION_TAGS: ${{ steps.image.outputs.destination_tags }}
|
||||
run: |
|
||||
docker logout ghcr.io
|
||||
docker logout ccr.ccs.tencentyun.com
|
||||
source_inspect="$(docker buildx imagetools inspect "${GHCR_IMAGE_NAME}:${SOURCE_TAG}")"
|
||||
source_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${source_inspect}" | head -n 1)"
|
||||
test -n "${source_digest}"
|
||||
IFS=',' read -ra tags <<< "${DESTINATION_TAGS}"
|
||||
for image_tag in "${tags[@]}"; do
|
||||
mirror_inspect="$(docker buildx imagetools inspect "${TCR_IMAGE_NAME}:${image_tag}")"
|
||||
mirror_digest="$(sed -n 's/^Digest:[[:space:]]*//p' <<<"${mirror_inspect}" | head -n 1)"
|
||||
test "${source_digest}" = "${mirror_digest}"
|
||||
docker buildx imagetools inspect --raw "${TCR_IMAGE_NAME}:${image_tag}" |
|
||||
jq -e '([.manifests[].platform.architecture] | index("amd64") != null) and ([.manifests[].platform.architecture] | index("arm64") != null)'
|
||||
done
|
||||
@@ -20,7 +20,7 @@
|
||||
7. **Draft 内准备资产**:通过带 `release_tag` 的 `workflow_dispatch` 在 Draft 中准备并验证资产;Android 重建时须在 Draft 阶段完成 Google Play 交付、用 Play 签名 APK 替换临时资产并通过独立签名门禁;`published` 事件只审计,禁止重新构建或上传,签名不符时恢复 Draft。
|
||||
8. **桌面验证职责**:桌面 Release 工作流负责测试、包结构检查、签名与公证;代理不再重复下载 Draft 或执行本地首次启动验收,除非用户明确要求。
|
||||
9. **发布后更新**:正式发布后,发布流程默认不得下载、覆盖安装或启动 `/Applications/EdgeEver.app`;已安装的桌面端通过应用内自动更新机制获取新版。仅在用户明确要求时使用 `--install-desktop` 执行原有安装验收,功能体验由用户在实际使用中验证。
|
||||
10. **失败处理**:工作流或资产审计失败时保持或恢复 Draft,修复后重跑;不得公开已知损坏的 Release。
|
||||
10. **失败处理**:Release 阻塞工作流或资产审计失败时保持或恢复 Draft,修复后重跑;不得公开已知损坏的 Release。GHCR 镜像属于阻塞门禁;腾讯云 TCR 公共镜像由独立工作流在正式发布后异步同步和审计,其耗时或失败不得阻塞 GitHub Release 或将已发布版本恢复为 Draft。
|
||||
11. **Release 说明结构**:使用中英文双语格式(正文禁止包含字面量 `\n`),只写用户可感知的变化、影响以及必要的升级或迁移提醒。类型检查、构建命令、签名、公证、资产复用等技术验证细节保留在 Actions 和关联 Issue 中,不写入公开 Release 正文。功能/修复关联对应 Issue 并标记 Label,发布后回链并关闭 Issue。正文结构:
|
||||
|
||||
```md
|
||||
|
||||
+12
-7
@@ -53,11 +53,14 @@ previous installation check is actually needed.
|
||||
Release asset rather than the overall GitHub tag. This prevents a Web-only or
|
||||
API-only Release from prompting an unnecessary native update.
|
||||
- The script creates the tracking Issue and Draft Release, validates or reuses
|
||||
native assets, prepares the multi-platform Docker image in both GHCR and the
|
||||
public Tencent TCR mirror, publishes, and closes the Issue without installing
|
||||
native assets, prepares and audits the multi-platform GHCR image, publishes,
|
||||
and closes the Issue without installing
|
||||
the desktop application by default; installation remains available as an
|
||||
explicit option.
|
||||
Demo deployment continues independently after its Actions URL is printed.
|
||||
- A separate workflow mirrors and audits the public Tencent TCR image
|
||||
asynchronously after the formal Release is published. Its duration or failure
|
||||
does not block the GitHub Release or return a published version to Draft.
|
||||
- This command does not authorize or run mobile store delivery itself. After
|
||||
Draft native assets are prepared, publication is blocked unless the Android
|
||||
APK uses the Google Play app-signing certificate. If that gate fails, the
|
||||
@@ -71,16 +74,18 @@ previous installation check is actually needed.
|
||||
The official repository must define `TENCENT_TCR_USERNAME` and
|
||||
`TENCENT_TCR_PASSWORD` Actions secrets. For the TCR Personal Edition registry,
|
||||
the username is the Tencent Cloud account ID and the password is the fixed
|
||||
registry password initialized in the TCR console. Draft preparation publishes
|
||||
the same tags to GHCR and TCR; both registries are checked anonymously before
|
||||
the Release can be published.
|
||||
registry password initialized in the TCR console. GHCR is the blocking Release
|
||||
gate. TCR receives the same tags asynchronously after publication and performs
|
||||
its own anonymous-access, digest, and architecture checks.
|
||||
|
||||
## Failure and Resume
|
||||
|
||||
- Validation, Draft asset, or Docker image failures leave the Release unpublished.
|
||||
- Validation, Draft asset, or GHCR image failures leave the Release unpublished.
|
||||
- An asynchronous TCR mirror failure leaves the formal Release intact and is
|
||||
repaired or rerun in its independent Actions workflow.
|
||||
- Rerunning the same command resumes a matching Draft created by an interrupted
|
||||
run instead of creating another Issue, commit, or Release.
|
||||
- A failed post-publication native or Docker audit attempts to return the Release to
|
||||
- A failed post-publication native or GHCR audit attempts to return the Release to
|
||||
Draft and leaves the Issue open.
|
||||
- If an explicit application installation fails, the script restores the previous
|
||||
app from its macOS Trash backup when possible.
|
||||
@@ -45,10 +45,12 @@ bun run release -- \
|
||||
Android arm64 APK。未变化的原生资产沿用原文件名、版本和校验和。
|
||||
- 桌面端和 Android 更新检查使用对应 Release 资产中记录的版本,而不是整体
|
||||
GitHub Tag,避免仅涉及 Web 或 API 的 Release 触发无效原生更新。
|
||||
- 脚本负责创建跟踪 Issue 和 Draft Release、验证或复用原生资产、准备多架构
|
||||
Docker 镜像并同时写入 GHCR 与腾讯云 TCR 公共镜像、正式发布、关闭 Issue,
|
||||
- 脚本负责创建跟踪 Issue 和 Draft Release、验证或复用原生资产、准备并审计
|
||||
GHCR 多架构 Docker 镜像、正式发布、关闭 Issue,
|
||||
默认不安装桌面端应用;安装能力作为显式选项保留。
|
||||
输出 Actions 链接后,Demo 部署会独立继续执行。
|
||||
- 腾讯云 TCR 公共镜像由独立工作流在正式 Release 发布后异步同步和审计;其
|
||||
耗时或失败不会阻塞 GitHub Release,也不会把已发布版本恢复为 Draft。
|
||||
- 此命令不会自行授权或执行移动端商店交付。Draft 原生资产准备完成后,发布
|
||||
命令会强制核验 Android APK 是否使用 Google Play 应用签名证书;未通过时
|
||||
保持 Draft 并停止。此时先针对同一 Draft 执行
|
||||
@@ -60,14 +62,15 @@ bun run release -- \
|
||||
|
||||
官方仓库必须配置 `TENCENT_TCR_USERNAME` 和 `TENCENT_TCR_PASSWORD` 两个
|
||||
Actions Secret。对于 TCR 个人版,用户名是腾讯云账号 ID,密码是在 TCR 控制台
|
||||
初始化的固定登录密码。Draft 准备阶段会向 GHCR 与 TCR 写入相同标签;正式发布
|
||||
前会以匿名方式检查两个仓库。
|
||||
初始化的固定登录密码。GHCR 是正式发布的阻塞门禁;TCR 在发布后异步写入相同
|
||||
标签并独立执行匿名访问、Digest 和架构检查。
|
||||
|
||||
## 失败与续跑
|
||||
|
||||
- 本地验证、Draft 资产或 Docker 镜像失败时,Release 保持未发布状态。
|
||||
- 本地验证、Draft 资产或 GHCR 镜像失败时,Release 保持未发布状态。
|
||||
- TCR 异步镜像失败时保留正式 Release,并在独立 Actions 工作流中修复、重跑。
|
||||
- 中断后重新执行相同命令,会续跑匹配的 Draft,不会重复创建 Issue、提交或
|
||||
Release。
|
||||
- 发布后的原生资产或 Docker 镜像审计失败时,脚本会尝试将 Release 恢复为
|
||||
- 发布后的原生资产或 GHCR 镜像审计失败时,脚本会尝试将 Release 恢复为
|
||||
Draft,并保留 Issue。
|
||||
- 显式安装时若替换应用失败,脚本会尽可能从 macOS 废纸篓备份恢复上一版应用。
|
||||
@@ -75,6 +75,7 @@ describe("Docker release contract", () => {
|
||||
|
||||
test("gates official image publishing and release auditing", () => {
|
||||
const workflow = readProjectFile(".github/workflows/docker-image.yml");
|
||||
const mirrorWorkflow = readProjectFile(".github/workflows/docker-tcr-mirror.yml");
|
||||
expect(workflow.match(/github\.repository == 'tianma-if\/edgeever'/g)?.length).toBeGreaterThanOrEqual(2);
|
||||
expect(workflow).toContain("release_tag");
|
||||
expect(workflow).toContain("contents: write\n packages: write");
|
||||
@@ -82,24 +83,25 @@ describe("Docker release contract", () => {
|
||||
expect(workflow).toContain('gh release view "${RELEASE_TAG}"');
|
||||
expect(workflow).not.toContain('releases/tags/${RELEASE_TAG}');
|
||||
expect(workflow).toContain("docker logout ghcr.io");
|
||||
expect(workflow).toContain("TCR_IMAGE_NAME: ccr.ccs.tencentyun.com/edgeever/edgeever");
|
||||
expect(workflow).toContain("secrets.TENCENT_TCR_USERNAME");
|
||||
expect(workflow).toContain("secrets.TENCENT_TCR_PASSWORD");
|
||||
expect(workflow).toContain("sudo apt-get install --yes skopeo");
|
||||
expect(workflow).toContain("name: Mirror image to Tencent Cloud Container Registry");
|
||||
expect(workflow).toContain('skopeo copy \\');
|
||||
expect(workflow).toContain("--all");
|
||||
expect(workflow).toContain("--preserve-digests");
|
||||
expect(workflow).toContain('--authfile "${HOME}/.docker/config.json"');
|
||||
expect(workflow).toContain('"docker://${GHCR_IMAGE_NAME}:${image_tag}"');
|
||||
expect(workflow).toContain('"docker://${TCR_IMAGE_NAME}:${image_tag}"');
|
||||
expect(workflow).toContain("for attempt in 1 2 3; do");
|
||||
expect(workflow).toContain('Failed to mirror ${image_tag} after ${attempt} attempts');
|
||||
expect(workflow).toContain('sleep "$((attempt * 15))"');
|
||||
expect(workflow).not.toContain('echo "${TCR_IMAGE_NAME}:${RELEASE_TAG}"');
|
||||
expect(workflow).toContain('docker logout ccr.ccs.tencentyun.com');
|
||||
expect(workflow).toContain('test "${ghcr_digest}" = "${tcr_digest}"');
|
||||
expect(workflow).toContain('for image in "${GHCR_IMAGE_NAME}" "${TCR_IMAGE_NAME}"');
|
||||
expect(workflow).toContain("docker buildx imagetools inspect");
|
||||
expect(workflow).not.toContain("TCR_IMAGE_NAME");
|
||||
expect(workflow).not.toContain("TENCENT_TCR_USERNAME");
|
||||
|
||||
expect(mirrorWorkflow).toContain("name: Mirror Docker image to Tencent TCR");
|
||||
expect(mirrorWorkflow).toContain("workflow_run:");
|
||||
expect(mirrorWorkflow).toContain("release:");
|
||||
expect(mirrorWorkflow).toContain("github.event.workflow_run.event == 'push'");
|
||||
expect(mirrorWorkflow).toContain("TCR_IMAGE_NAME: ccr.ccs.tencentyun.com/edgeever/edgeever");
|
||||
expect(mirrorWorkflow).toContain("secrets.TENCENT_TCR_USERNAME");
|
||||
expect(mirrorWorkflow).toContain("secrets.TENCENT_TCR_PASSWORD");
|
||||
expect(mirrorWorkflow).toContain("sudo apt-get install --yes skopeo");
|
||||
expect(mirrorWorkflow).toContain('skopeo copy \\');
|
||||
expect(mirrorWorkflow).toContain("--all");
|
||||
expect(mirrorWorkflow).toContain("--preserve-digests");
|
||||
expect(mirrorWorkflow).toContain('"docker://${GHCR_IMAGE_NAME}:${SOURCE_TAG}"');
|
||||
expect(mirrorWorkflow).toContain('"docker://${TCR_IMAGE_NAME}:${image_tag}"');
|
||||
expect(mirrorWorkflow).toContain("for attempt in 1 2 3; do");
|
||||
expect(mirrorWorkflow).toContain('Failed to mirror ${image_tag} after ${attempt} attempts');
|
||||
expect(mirrorWorkflow).toContain('test "${source_digest}" = "${mirror_digest}"');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user