diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 20189f8..e669188 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,12 +90,113 @@ jobs: exit 1 fi + - name: Check version against crates.io + id: version_check + shell: bash + run: | + set -euo pipefail + TAG="${GITHUB_REF#refs/tags/}" + LOCAL_VER="${TAG#v}" + CRATE_NAME="masterror" + + echo "Local version: ${LOCAL_VER}" + + # Fetch current version from crates.io + CRATESIO_VER=$(curl -s "https://crates.io/api/v1/crates/${CRATE_NAME}" | jq -r '.crate.max_version // empty') + + if [ -z "${CRATESIO_VER}" ]; then + echo "Crate not found on crates.io, proceeding with first publish" + echo "should_publish=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "crates.io version: ${CRATESIO_VER}" + + # Equal versions check + if [ "${LOCAL_VER}" = "${CRATESIO_VER}" ]; then + echo "Version ${LOCAL_VER} already published on crates.io" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Semver comparison using inline Rust script + TMPDIR=$(mktemp -d) + mkdir -p "${TMPDIR}/src" + cat > "${TMPDIR}/src/main.rs" << 'RUST_EOF' + use std::env; + + fn main() { + let args: Vec = env::args().collect(); + if args.len() != 3 { + eprintln!("Usage: compare "); + std::process::exit(1); + } + + let v1 = match semver::Version::parse(&args[1]) { + Ok(v) => v, + Err(e) => { + eprintln!("Failed to parse version1: {}", e); + std::process::exit(1); + } + }; + + let v2 = match semver::Version::parse(&args[2]) { + Ok(v) => v, + Err(e) => { + eprintln!("Failed to parse version2: {}", e); + std::process::exit(1); + } + }; + + if v1 > v2 { + println!("greater"); + } else if v1 < v2 { + println!("less"); + } else { + println!("equal"); + } + } + RUST_EOF + + cat > "${TMPDIR}/Cargo.toml" << 'TOML_EOF' + [package] + name = "semver-compare" + version = "0.1.0" + edition = "2024" + + [dependencies] + semver = "1.0" + TOML_EOF + + # Build and run comparison + COMPARISON=$(cd "${TMPDIR}" && cargo run --quiet -- "${LOCAL_VER}" "${CRATESIO_VER}" 2>/dev/null || echo "unknown") + rm -rf "${TMPDIR}" + + if [ "${COMPARISON}" = "greater" ]; then + echo "Local version ${LOCAL_VER} > crates.io version ${CRATESIO_VER}, proceeding" + echo "should_publish=true" >> "$GITHUB_OUTPUT" + elif [ "${COMPARISON}" = "less" ]; then + echo "Local version ${LOCAL_VER} < crates.io version ${CRATESIO_VER}" + echo "Cannot publish older version" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + exit 1 + elif [ "${COMPARISON}" = "equal" ]; then + echo "Version ${LOCAL_VER} already published on crates.io" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + else + echo "Could not determine version ordering, manual check required" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + exit 1 + fi + - name: Install Rust (${{ steps.msrv.outputs.msrv }}) + if: steps.version_check.outputs.should_publish == 'true' uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ steps.msrv.outputs.msrv }} - name: Maybe publish masterror-template + if: steps.version_check.outputs.should_publish == 'true' env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} shell: bash @@ -120,9 +221,11 @@ jobs: fi - name: Wait for crates.io index sync (after template) + if: steps.version_check.outputs.should_publish == 'true' run: sleep 15 - name: Maybe publish masterror-derive + if: steps.version_check.outputs.should_publish == 'true' env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} shell: bash @@ -147,9 +250,11 @@ jobs: fi - name: Wait for crates.io index sync + if: steps.version_check.outputs.should_publish == 'true' run: sleep 15 - name: Publish masterror + if: steps.version_check.outputs.should_publish == 'true' env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} shell: bash