Skip to content

sync-upstream-version #29

sync-upstream-version

sync-upstream-version #29

name: sync-upstream-version
on:
workflow_dispatch:
schedule:
- cron: "0 12 * * 1"
permissions:
contents: write
pull-requests: write
jobs:
sync:
# Runs by default. Set the repository variable DISABLE_UPSTREAM_VERSION_SYNC
# to 'true' to stop it.
if: vars.DISABLE_UPSTREAM_VERSION_SYNC != 'true'
runs-on: ubuntu-latest
env:
# Only whether the webhook is configured belongs at job scope: a step
# `if:` cannot read the `secrets` context, but the secret itself has no
# business in the environment of steps that install and run upstream
# code. The notification steps map the secret in themselves.
DISCORD_CONFIGURED: ${{ secrets.DISCORD_WEBHOOK != '' }}
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Fetch latest upstream release
id: upstream
run: |
set -euo pipefail
api="https://api.github.com/repos/caronc/apprise/releases/latest"
tag="$(curl -sSL "$api" | jq -r '.tag_name')"
if [ -z "$tag" ] || [ "$tag" = "null" ]; then
echo "Failed to read latest upstream release tag." >&2
exit 1
fi
version="${tag#v}"
pinned="$(sed -n 's/^var UpstreamVersion = "\([^"]*\)"/\1/p' internal/version/version.go)"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "pinned=$pinned" >> "$GITHUB_OUTPUT"
if [ "$version" = "$pinned" ]; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Already pinned to $pinned." >> "$GITHUB_STEP_SUMMARY"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Update UpstreamVersion
if: steps.upstream.outputs.changed == 'true'
env:
UPSTREAM_VERSION: ${{ steps.upstream.outputs.version }}
run: |
python - <<'PY'
import os
import re
from pathlib import Path
path = Path("internal/version/version.go")
data = path.read_text()
version = os.environ["UPSTREAM_VERSION"]
pattern = r'(var\s+UpstreamVersion\s*=\s*")([^"]+)(")'
updated, count = re.subn(pattern, r'\g<1>' + version + r'\g<3>', data)
if count == 0:
raise SystemExit("UpstreamVersion not found in version.go")
if updated != data:
path.write_text(updated)
PY
# The bump alone only moves a constant. Measuring the gap it opens is the
# point: without this the PR looks trivial and the work stays invisible
# until someone reads a red parity run.
- name: Check out the new upstream release
if: steps.upstream.outputs.changed == 'true'
env:
UPSTREAM_TAG: ${{ steps.upstream.outputs.tag }}
run: |
set -euo pipefail
git -C .. clone --depth 1 --branch "$UPSTREAM_TAG" https://github.com/caronc/apprise apprise
- name: Set up Go
if: steps.upstream.outputs.changed == 'true'
uses: actions/setup-go@v7
with:
go-version-file: go.mod
- name: Set up Python
if: steps.upstream.outputs.changed == 'true'
uses: actions/setup-python@v7
with:
python-version: "3.14"
- name: Install parity dependencies
if: steps.upstream.outputs.changed == 'true'
run: bash scripts/ci/setup_parity_env.sh
# The report is written whether or not the suite passes, so a red run
# still names the providers and schemas that need porting.
- name: Measure the gap the new release opens
if: steps.upstream.outputs.changed == 'true'
continue-on-error: true
run: bash scripts/ci/run_parity_tests.sh
- name: Publish gap summary
if: steps.upstream.outputs.changed == 'true'
run: cat reports/parity_report.md >> "$GITHUB_STEP_SUMMARY"
- name: Compose pull request body
if: steps.upstream.outputs.changed == 'true'
env:
UPSTREAM_TAG: ${{ steps.upstream.outputs.tag }}
PINNED: ${{ steps.upstream.outputs.pinned }}
run: |
{
echo "Syncs \`internal/version.UpstreamVersion\` from \`$PINNED\` to upstream \`$UPSTREAM_TAG\`."
echo
echo "Moving the pin does not port anything: it points the parity suite at the new"
echo "release so the work becomes visible. The gap measured against this release is"
echo "below. Parity CI on this PR will be red until every row is closed."
echo
sed -n '/## Summary/,$p' reports/parity_report.md
} > reports/pr_body.md
- name: Create pull request
id: pr
if: steps.upstream.outputs.changed == 'true'
uses: peter-evans/create-pull-request@v8
with:
branch: chore/sync-upstream-version
delete-branch: true
commit-message: "chore: sync upstream apprise version to ${{ steps.upstream.outputs.tag }}"
title: "chore: sync upstream apprise version to ${{ steps.upstream.outputs.tag }}"
body-path: reports/pr_body.md
add-paths: internal/version/version.go
# A sync PR nobody looks at is the same as no sync at all, so the release
# and the gap it opens get announced rather than left in the PR list. The
# payload is built with jq because the report text is not ours to trust
# as JSON.
- name: Announce the new upstream release
if: steps.upstream.outputs.changed == 'true' && env.DISCORD_CONFIGURED == 'true'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
UPSTREAM_TAG: ${{ steps.upstream.outputs.tag }}
PINNED: ${{ steps.upstream.outputs.pinned }}
PR_URL: ${{ steps.pr.outputs.pull-request-url }}
run: |
set -euo pipefail
summary=""
if [ -f reports/parity_report.md ]; then
summary="$(sed -n '/## Summary/,$p' reports/parity_report.md | head -c 1200)"
fi
if [ -z "$summary" ]; then
summary="Parity report not generated; see the run log."
fi
content="$(printf 'upstream apprise %s is out (pinned: %s).\n%s\n\n%s' \
"$UPSTREAM_TAG" "$PINNED" "${PR_URL:-no sync PR was opened}" "$summary")"
jq -n --arg content "$content" '{content: $content}' \
| curl -sS -X POST -H "Content-Type: application/json" -d @- "$DISCORD_WEBHOOK"
# Without this the checker can break silently and the pin just quietly
# stops moving, which is the failure the checker exists to prevent.
- name: Notify Discord on sync failure
if: failure() && env.DISCORD_CONFIGURED == 'true'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
run: |
run_url="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
payload=$(printf '{"content":"upstream version sync failed for %s: %s"}' "$GITHUB_REPOSITORY" "$run_url")
curl -sS -X POST -H "Content-Type: application/json" -d "$payload" "$DISCORD_WEBHOOK"