Skip to content

upstream-watch

upstream-watch #37

name: upstream-watch
# Keeps the repo "alive": daily check for a newer upstream Quantum ESPRESSO
# release. Opens an issue when one appears — a human still cuts the release tag.
#
# The job FAILS (red run) when it cannot perform the check at all — an
# unreachable GitLab API must not look like "nothing new".
on:
schedule:
- cron: '23 6 * * *' # daily 06:23 UTC
workflow_dispatch:
permissions:
contents: read
issues: write
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for newer Quantum ESPRESSO release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MAINTAINER: krabiswabbie
run: |
set -euo pipefail
fetch() {
for _ in 1 2 3; do
curl -fsSL --max-time 60 "$1" && return 0
sleep 20
done
return 1
}
current="$(grep -m1 -oE 'QE_VERSION=[0-9.]+' Dockerfile | cut -d= -f2)"
echo "Pinned QE: $current"
# QE source lives on GitLab (QEF/q-e). Stable releases are tags of the
# form qe-X.Y or qe-X.Y.Z — exclude RCs (-rc.N), -devel, and variant
# tags (e.g. qe-7.5CN, qe-7.2-omp5) by matching pure version tags only.
if ! tags="$(fetch 'https://gitlab.com/api/v4/projects/QEF%2Fq-e/repository/tags?per_page=100')"; then
echo "::error::GitLab API unreachable after 3 attempts — could not check for updates."
exit 1
fi
latest="$(printf '%s' "$tags" \
| grep -oE '"name":"qe-[0-9]+\.[0-9]+(\.[0-9]+)?"' \
| grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' \
| sort -V | tail -1 || true)"
if [ -z "$latest" ]; then
echo "::error::No stable qe-X.Y tag in the GitLab response — API shape probably changed; this watcher needs fixing."
exit 1
fi
echo "Latest upstream stable: $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 archive tarball our Dockerfile downloads actually exists.
# A 404 means the tag exists but the archive does not yet — quiet skip.
# A dead connection is not an answer and must not look like one.
# (Capturing curl's output instead of `|| echo 000`: curl already
# prints 000 on a connection failure and the two would concatenate.)
if out="$(curl -sSL --max-time 60 -o /dev/null -w '%{http_code}' \
"https://gitlab.com/QEF/q-e/-/archive/qe-${latest}/q-e-qe-${latest}.tar.gz" 2>/dev/null)"; then
code="$out"
else
code="000"
fi
if [ "$code" = "000" ]; then
echo "::error::gitlab.com unreachable — could not confirm the ${latest} archive."
exit 1
fi
if [ "$code" != "200" ]; then
echo "Upstream has $latest but archive tarball returns HTTP $code; skipping."
exit 0
fi
title="Upstream Quantum ESPRESSO ${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' \
"Quantum ESPRESSO **${latest}** is available upstream (GitLab archive tarball verified). This repo is pinned to **${current}**." \
"" \
"To release (per README \"Bumping the QE version\"):" \
"1. Edit \`ARG QE_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/qe-base:${latest}\`." \
"" \
"Review the upstream release notes before releasing — a minor-version bump can shuffle CMake flags or build targets (this image builds only the \`pw pp\` targets)." \
"" \
"Publishing the image is only half of it. Nothing consumes the new tag until \`material/core\` moves its pins: \`QE_VERSION\` in \`.gitlab-ci.yml\` (the source of truth, it feeds the runner build-args) plus the \`ARG\` default in \`Dockerfile.qerunner\`, which governs local builds and must not drift from it. Adopt only after a runner smoke — a green image build says nothing about whether pw.x still converges the way the runner expects." \
"" \
"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"