diff --git a/.gitea/workflows/poll-upstream.yml b/.gitea/workflows/poll-upstream.yml new file mode 100644 index 0000000..25476ea --- /dev/null +++ b/.gitea/workflows/poll-upstream.yml @@ -0,0 +1,103 @@ +name: poll-upstream + +on: + schedule: + - cron: "0 */6 * * *" + workflow_dispatch: {} + +concurrency: + group: poll-upstream + cancel-in-progress: true + +env: + APT_BASE: https://downloads.claude.ai/claude-desktop/apt/stable + +jobs: + check: + runs-on: fedora-43 + steps: + - name: Get upstream latest version + id: upstream + run: | + packages_url="${APT_BASE}/dists/stable/main/binary-amd64/Packages" + version=$(curl --silent --show-error --fail --location "${packages_url}" \ + | awk '/^Version:/{print $2}' | sort --version-sort | tail -1) + if [ -z "${version}" ]; then echo "no version found in ${packages_url}"; exit 1; fi + echo "version=${version}" >> "$GITHUB_OUTPUT" + echo "Upstream latest: ${version}" + + - name: Check if all packages are published + id: published + run: | + version="${UPSTREAM_VERSION}" + needs_build=false + for fedora_version in 43 44; do + base_url="https://rpm.lair.cafe/fedora/${fedora_version}/x86_64" + rpm_name="claude-desktop-${version}-1.fc${fedora_version}.x86_64.rpm" + + # check that the rpm file exists + http_code=$(curl \ + --silent \ + --write-out "%{http_code}" \ + --output /dev/null \ + --head \ + --url "${base_url}/${rpm_name}") + if [ "${http_code}" = "404" ]; then + echo "missing: ${base_url}/${rpm_name}" + needs_build=true + continue + elif [ "${http_code}" != "200" ]; then + echo "unexpected HTTP ${http_code} for ${base_url}/${rpm_name}" + exit 1 + fi + echo "found: ${base_url}/${rpm_name}" + + # check that the repo index references this package + if ! curl --silent --fail "${base_url}/repodata/repomd.xml" \ + | grep --quiet 'primary'; then + echo "missing or invalid repomd.xml at ${base_url}/repodata/" + needs_build=true + continue + fi + if ! dnf repoquery \ + --repofrompath=check,"${base_url}" \ + --repo=check \ + --quiet \ + "claude-desktop-${version}" 2>&1 \ + | grep --quiet "claude-desktop"; then + echo "repo index missing: claude-desktop-${version} not in ${base_url}/repodata/" + needs_build=true + continue + fi + echo "indexed: claude-desktop-${version} in ${base_url}/repodata/" + done + echo "already_built=$( [ "${needs_build}" = "true" ] && echo false || echo true )" >> "$GITHUB_OUTPUT" + env: + UPSTREAM_VERSION: ${{ steps.upstream.outputs.version }} + + # In-flight guard: a dispatch while a build-release run is queued or + # executing would cancel it (concurrency cancel-in-progress) and restart + # identical work. Skip dispatching and let the running build complete; + # the next poll re-checks the published RPMs. Note: the runs API reports + # path as "@", hence the startswith match. + - name: Check for in-flight release build + id: inflight + run: | + count=$(curl --fail --silent --show-error --location \ + --header "Authorization: token ${{ secrets.DISPATCH_TOKEN }}" \ + --url "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/actions/runs?limit=50" \ + | jq '[.workflow_runs[] + | select((.path // "") | startswith("build-release.yml@")) + | select(.status != "completed")] | length') + echo "count=${count}" >> "$GITHUB_OUTPUT" + echo "in-flight build-release runs: ${count}" + + - name: Trigger build workflow + if: steps.published.outputs.already_built == 'false' && steps.inflight.outputs.count == '0' + run: | + curl --fail --silent --show-error --location \ + --request POST \ + --header "Authorization: token ${{ secrets.DISPATCH_TOKEN }}" \ + --header 'Content-Type: application/json' \ + --url "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/actions/workflows/build-release.yml/dispatches" \ + --data "{\"ref\":\"refs/heads/main\",\"inputs\":{\"version\":\"${{ steps.upstream.outputs.version }}\"}}"