Skip to content

Merge pull request #114 from ecmwf/chore/release-0.9.1 #14

Merge pull request #114 from ecmwf/chore/release-0.9.1

Merge pull request #114 from ecmwf/chore/release-0.9.1 #14

Workflow file for this run

name: Publish Crate
on:
push:
tags:
- '*'
workflow_dispatch:
inputs:
dry_run:
description: "Dry-run only (no actual publish)"
required: false
type: boolean
default: true
jobs:
verify-tag:
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
outputs:
should_publish: ${{ steps.check.outputs.should_publish }}
steps:
- uses: actions/checkout@v4
- name: Verify tag matches crate versions
id: check
run: |
set -euo pipefail
server_version=$(grep '^version\s*=' Cargo.toml | head -1 | cut -d'"' -f2)
validators_version=$(grep '^version\s*=' aviso-validators/Cargo.toml | head -1 | cut -d'"' -f2)
ecpds_version=$(grep '^version\s*=' aviso-ecpds/Cargo.toml | head -1 | cut -d'"' -f2)
if [ -z "${server_version}" ] || [ -z "${validators_version}" ] || [ -z "${ecpds_version}" ]; then
echo "::error::Could not extract crate versions from Cargo manifests"
exit 1
fi
# All three crates must move in lockstep. A divergent version is
# almost always an accidental partial bump in a PR rather than an
# intentional independent release; failing loud here catches it
# at tag-push time rather than after a half-finished publish.
if [ "${server_version}" != "${validators_version}" ] || [ "${server_version}" != "${ecpds_version}" ]; then
echo "::error::Crate versions are not in lockstep: server=${server_version}, validators=${validators_version}, ecpds=${ecpds_version}"
echo "should_publish=false" >> "$GITHUB_OUTPUT"
exit 1
fi
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" != "true" ]; then
echo "::error::Manual non-dry-run publishing is disabled. Create and push a matching release tag to publish."
echo "should_publish=false" >> "$GITHUB_OUTPUT"
exit 1
fi
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
echo "should_publish=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# Accept both `0.4.1` and `v0.4.1` git tags; strip leading `v`
# before comparing to the Cargo manifest versions.
pushed_tag="${{ github.ref_name }}"
normalized_tag="${pushed_tag#v}"
if [ "${normalized_tag}" = "${server_version}" ]; then
echo "should_publish=true" >> "$GITHUB_OUTPUT"
else
echo "Tag ${pushed_tag} (normalized: ${normalized_tag}) does not match crate version ${server_version}, skipping."
echo "should_publish=false" >> "$GITHUB_OUTPUT"
fi
publish-validators:
needs: verify-tag
if: ${{ needs.verify-tag.outputs.should_publish == 'true' }}
runs-on: ubuntu-latest
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Publish aviso-validators
run: |
set -euo pipefail
ERR_FILE="${RUNNER_TEMP}/publish-validators.err"
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
cargo publish --manifest-path aviso-validators/Cargo.toml --dry-run
else
if cargo publish --manifest-path aviso-validators/Cargo.toml 2>"${ERR_FILE}"; then
exit 0
fi
if grep -q 'already exists on crates.io index' "${ERR_FILE}"; then
echo "aviso-validators is already published for this version; continuing."
exit 0
fi
cat "${ERR_FILE}" >&2
exit 1
fi
publish-ecpds:
needs: verify-tag
if: ${{ needs.verify-tag.outputs.should_publish == 'true' }}
runs-on: ubuntu-latest
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Publish aviso-ecpds
run: |
set -euo pipefail
ERR_FILE="${RUNNER_TEMP}/publish-ecpds.err"
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
cargo publish --manifest-path aviso-ecpds/Cargo.toml --dry-run
else
if cargo publish --manifest-path aviso-ecpds/Cargo.toml 2>"${ERR_FILE}"; then
exit 0
fi
if grep -q 'already exists on crates.io index' "${ERR_FILE}"; then
echo "aviso-ecpds is already published for this version; continuing."
exit 0
fi
cat "${ERR_FILE}" >&2
exit 1
fi
publish-server:
needs: [publish-validators, publish-ecpds]
if: ${{ needs.publish-validators.result == 'success' && needs.publish-ecpds.result == 'success' }}
runs-on: ubuntu-latest
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Publish aviso-server
run: |
set -euo pipefail
ERR_FILE="${RUNNER_TEMP}/publish-server.err"
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
cargo publish --manifest-path Cargo.toml --dry-run
exit 0
fi
for attempt in 1 2 3 4 5 6 7 8 9 10; do
if cargo publish --manifest-path Cargo.toml 2>"${ERR_FILE}"; then
exit 0
fi
# crates.io index propagation can lag in two shapes, and
# every alternative below MUST be scoped to the aviso
# leaf crates so an unrelated dependency-resolution error
# (e.g. a real bug in a serde or tokio version pin) does
# not get mistaken for index lag and silently retried for
# 5 minutes:
#
# shape A (first publish only): the leaf crate does not
# exist on the registry at all yet -- "no matching
# package named `aviso-X` found" / "failed to get
# `aviso-X` as a dependency".
#
# shape B (every subsequent release): the leaf crate
# exists, but the specific new version just pushed by
# the previous job has not propagated to the index --
# "failed to select a version for the requirement
# `aviso-X = ...`". Cargo also emits a "candidate
# versions found which didn't match" continuation
# line for shape B, but that line is NOT scoped to a
# crate name and fires for any version-selection
# failure, so it is intentionally NOT in the regex.
# The "failed to select a version" line above always
# co-emits, so shape B coverage is preserved.
#
# Each crate-name alternative uses `.?` to match an
# optional opening quote/backtick/space character rather
# than encoding cargo's current backtick style, so the
# regex survives a future cargo output tweak.
if grep -Eq '(no matching package named|failed to get|failed to select a version for the requirement) .?aviso-(validators|ecpds)|download of config\.json failed|spurious network error|Could not resolve host: index\.crates\.io' "${ERR_FILE}"; then
echo "Dependency/index not ready yet (attempt ${attempt}/10); retrying in 30s..."
sleep 30
continue
fi
cat "${ERR_FILE}" >&2
exit 1
done
cat "${ERR_FILE}" >&2
echo "Timed out waiting for aviso-validators / aviso-ecpds to become available on crates.io." >&2
exit 1