upstream-watch #29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: upstream-watch | |
| # Keeps the repo "alive": daily check for a newer upstream ABINIT release. | |
| # Opens an issue when one appears — a human still cuts the release tag. | |
| # | |
| # Daily, not weekly: 10.8.3 landed on a Friday and a Monday-only schedule sat | |
| # blind on it for three days. | |
| # | |
| # The job FAILS (red run) when it cannot perform the check at all — an | |
| # unreachable or reshaped abinit.org must not look like "nothing new". | |
| on: | |
| schedule: | |
| - cron: '17 6 * * *' # daily 06:17 UTC | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| issues: write | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Check for newer ABINIT release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| MAINTAINER: krabiswabbie | |
| run: | | |
| set -euo pipefail | |
| # abinit.org has a history of transient TLS/DNS failures, so retry | |
| # before concluding anything. | |
| fetch() { | |
| for _ in 1 2 3; do | |
| curl -fsSL --max-time 60 "$1" && return 0 | |
| sleep 20 | |
| done | |
| return 1 | |
| } | |
| current="$(grep -m1 -oE 'ABINIT_VERSION=[0-9.]+' Dockerfile | cut -d= -f2)" | |
| echo "Pinned ABINIT: $current" | |
| # Latest stable is announced on the ABINIT homepage as "Abinit X.Y.Z". | |
| if ! page="$(fetch https://www.abinit.org/)"; then | |
| echo "::error::abinit.org unreachable after 3 attempts — could not check for updates." | |
| exit 1 | |
| fi | |
| latest="$(printf '%s' "$page" \ | |
| | grep -oiE 'Abinit [0-9]+\.[0-9]+\.[0-9]+' \ | |
| | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" | |
| if [ -z "$latest" ]; then | |
| echo "::error::No version string on abinit.org — the page layout probably changed; this watcher needs fixing." | |
| exit 1 | |
| fi | |
| echo "Latest upstream: $latest" | |
| if [ "$current" = "$latest" ]; then | |
| echo "Up to date."; exit 0 | |
| fi | |
| newest="$(printf '%s\n%s\n' "$current" "$latest" | sort -V | tail -1)" | |
| if [ "$newest" != "$latest" ]; then | |
| echo "Pinned ($current) is newer than/equal to upstream ($latest); nothing to do."; exit 0 | |
| fi | |
| # Confirm the forge tarball our Dockerfile downloads actually exists. | |
| # A 404 is a real "announced but not published yet" and is worth | |
| # staying quiet about; a dead connection is not an answer at all and | |
| # must not be reported as one. Capturing curl's output instead of | |
| # `|| echo 000` matters — curl already prints 000 itself on a | |
| # connection failure, so the two concatenate into a code that matches | |
| # nothing. | |
| if out="$(curl -sSL --max-time 60 -o /dev/null -w '%{http_code}' \ | |
| "https://forge.abinit.org/abinit-${latest}.tar.gz" 2>/dev/null)"; then | |
| code="$out" | |
| else | |
| code="000" | |
| fi | |
| if [ "$code" = "000" ]; then | |
| echo "::error::forge.abinit.org unreachable — could not confirm the ${latest} tarball." | |
| exit 1 | |
| fi | |
| if [ "$code" != "200" ]; then | |
| echo "Upstream announces $latest but forge tarball returns HTTP $code; not published yet, skipping." | |
| exit 0 | |
| fi | |
| title="Upstream ABINIT ${latest} available (pinned: ${current})" | |
| if gh issue list --state open --search "in:title \"${title}\"" \ | |
| --json title --jq '.[].title' | grep -Fxq "$title"; then | |
| echo "Issue already open: $title"; exit 0 | |
| fi | |
| body="$(printf '%s\n' \ | |
| "ABINIT **${latest}** is available upstream (forge tarball verified). This repo is pinned to **${current}**." \ | |
| "" \ | |
| "To release (per README \"Bumping the ABINIT version\"):" \ | |
| "1. Edit \`ARG ABINIT_VERSION\` default in \`Dockerfile\` (both stages) to \`${latest}\`." \ | |
| "2. Update the version examples in \`README.md\`." \ | |
| "3. Commit to \`main\`." \ | |
| "4. Cut the tag: \`git tag v${latest} && git push --tags\` — GHA publishes \`ghcr.io/material-codes/abinit-base:${latest}\`." \ | |
| "" \ | |
| "Review the upstream changelog before releasing — a human should eyeball ABINIT/LibXC/toolchain changes before publishing a new base image." \ | |
| "" \ | |
| "Publishing the image is only half of it. Nothing consumes the new tag until \`material/core\` moves its pins: \`ABINIT_VERSION\` in \`.gitlab-ci.yml\` (the source of truth, it feeds the runner build-args), the \`ARG\` default in \`Dockerfile.abinitrunner\`, and the ABINIT smoke version in the \`Makefile\` — the last two govern local builds and must not drift from the first. Adopt only after a live G0W0 run: the input-variable set and the stdout parser in core were derived by iterating against one ABINIT branch, so a minor-version move can leave the runner reading output it no longer understands." \ | |
| "" \ | |
| "cc @${MAINTAINER}" \ | |
| "" \ | |
| "_Opened automatically by the upstream-watch workflow._")" | |
| # Assign + @mention deliberately: an issue opened by github-actions[bot] | |
| # generates NO notification unless you watch the repo, while assignment | |
| # and mentions land in the "Participating" class, which is emailed by | |
| # default. If the assignment ever stops working the run goes red, which | |
| # is itself the signal. | |
| gh issue create --title "$title" --body "$body" --assignee "$MAINTAINER" |