Skip to content

Watch Upstream Docker Images #7

Watch Upstream Docker Images

Watch Upstream Docker Images #7

name: Watch Upstream Docker Images
on:
schedule:
- cron: "17 */6 * * *"
workflow_dispatch:
permissions:
actions: write
contents: write
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
sync-upstream:
name: Sync Watched Upstream Versions
runs-on: ubuntu-latest
env:
WATCH_MATRIX: |
[
{
"package_name": "nitro-cli",
"repo": "library/amazonlinux",
"filter": "^(2023[.][0-9]+[.][0-9]+[.][0-9]+)$",
"second_filter": "",
"version_file": "packages/nitro-cli/.current-version",
"publish_input": "deploy-nitro-cli"
},
{
"package_name": "walrus-upload-relay",
"repo": "mysten/walrus-upload-relay",
"filter": "^main-v([0-9]+[.][0-9]+[.][0-9]+)$",
"second_filter": "^main-arm64-v{{version}}$",
"version_file": "packages/walrus-upload-relay/.current-version",
"publish_input": "deploy-walrus-upload-relay"
}
]
steps:
- name: Checkout main
uses: actions/checkout@v6
with:
ref: main
- name: Fetch latest upstream tags
id: watch
shell: bash
run: |
set -euo pipefail
fetch_latest_tag() {
local repo="$1"
local filter="$2"
local max_pages="$3"
local page=1
while (( page <= max_pages )); do
response="$(
curl -fsSL "https://hub.docker.com/v2/repositories/${repo}/tags?page=${page}&page_size=100"
)"
tag="$(
jq -r --arg filter "${filter}" '
.results[]?.name
| match($filter)?
| select(. != null)
| (.captures[0].string // .string)
' <<< "${response}" | head -n1
)"
if [[ -n "${tag}" ]]; then
printf '%s\n' "${tag}"
return 0
fi
page=$((page + 1))
done
echo "No tag matched ${filter} in ${repo}" >&2
return 1
}
packages="$(jq -cn '{}')"
while read -r package; do
package_name="$(jq -r '.package_name' <<< "${package}")"
repo="$(jq -r '.repo' <<< "${package}")"
filter="$(jq -r '.filter' <<< "${package}")"
second_filter="$(jq -r '.second_filter' <<< "${package}")"
latest_version="$(fetch_latest_tag "${repo}" "${filter}" 3)"
if [[ -n "${second_filter}" ]]; then
resolved_second_filter="${second_filter//\{\{version\}\}/${latest_version}}"
fetch_latest_tag "${repo}" "${resolved_second_filter}" 3 > /dev/null
fi
packages="$(
jq -c \
--arg package_name "${package_name}" \
--arg latest_version "${latest_version}" \
--argjson package "${package}" \
'. + {($package_name): ($package + {latest_version: $latest_version})}' \
<<< "${packages}"
)"
done < <(jq -c '.[]' <<< "${WATCH_MATRIX}")
{
echo "packages<<EOF"
jq -c . <<< "${packages}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: Patch and commit latest versions
id: sync
env:
WATCHED_PACKAGES: ${{ steps.watch.outputs.packages }}
shell: bash
run: |
set -euo pipefail
update_readme_version() {
local package_name="$1"
local current_version="$2"
local latest_version="$3"
sed -i "/\[\`cmdoss\/${package_name}\`\]/s/\`${current_version}\` 👁️/\`${latest_version}\` 👁️/" README.md
if ! grep -F "[\`cmdoss/${package_name}\`]" README.md | grep -Fq "\`${latest_version}\` 👁️"; then
echo "Failed to update ${package_name} version in README.md" >&2
exit 1
fi
}
updated=false
deploy_inputs="$(
jq -c '
map({(.publish_input): "false"})
| add
| . + {"deploy-auth-proxy": "false"}
' <<< "${WATCH_MATRIX}"
)"
summary_file="$(mktemp)"
while read -r package; do
package_name="$(jq -r '.package_name' <<< "${package}")"
version_file="$(jq -r '.version_file' <<< "${package}")"
publish_input="$(jq -r '.publish_input' <<< "${package}")"
latest_version="$(jq -r '.latest_version' <<< "${package}")"
current_version="$(tr -d '[:space:]' < "${version_file}")"
if [[ -z "${current_version}" ]]; then
echo "No version found in ${version_file}" >&2
exit 1
fi
if [[ "${current_version}" == "${latest_version}" ]]; then
echo "${package_name} is already at ${latest_version}"
continue
fi
printf '%s\n' "${latest_version}" > "${version_file}"
update_readme_version "${package_name}" "${current_version}" "${latest_version}"
deploy_inputs="$(jq -c --arg publish_input "${publish_input}" '.[$publish_input] = "true"' <<< "${deploy_inputs}")"
updated=true
printf '%s\n' "- ${package_name}: ${current_version} -> ${latest_version}" >> "${summary_file}"
done < <(jq -c '.[]' <<< "${WATCHED_PACKAGES}")
if [[ "${updated}" != "true" ]]; then
{
echo "updated=false"
echo "deploy-inputs<<EOF"
jq -c . <<< "${deploy_inputs}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
echo "No watched upstream image updates found."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
mapfile -d '' changed_paths < <(git diff --name-only -z)
git add -- "${changed_paths[@]}"
summary="$(cat "${summary_file}")"
git commit -m "chore: update watched upstream image versions" -m "${summary}"
git push origin HEAD:main
{
echo "updated=true"
echo "deploy-inputs<<EOF"
jq -c . <<< "${deploy_inputs}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: Dispatch publish
if: steps.sync.outputs.updated == 'true'
env:
GH_TOKEN: ${{ github.token }}
DEPLOY_INPUTS: ${{ steps.sync.outputs['deploy-inputs'] }}
shell: bash
run: |
set -euo pipefail
payload="$(
jq -cn \
--argjson inputs "${DEPLOY_INPUTS}" \
'{
ref: "main",
inputs: $inputs
}'
)"
curl -fsSL \
-X POST \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/workflows/publish.yaml/dispatches" \
-d "${payload}"