From 632e2838dc45c74f6cc47e2f6648b93bf65db668 Mon Sep 17 00:00:00 2001 From: mroczect Date: Fri, 21 Aug 2026 21:02:38 +0700 Subject: [PATCH 1/2] ci(workflow): improve publish validation and add fmt/clippy checks --- .github/workflows/publish.yml | 46 +++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6ce164da..86f4ffec 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,18 +20,43 @@ jobs: - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable with: - components: clippy + toolchain: 1.96.0 + components: clippy, rustfmt - - name: Validate release.json and tags + - name: Install jq + run: sudo apt-get update && sudo apt-get install -y jq + + - name: Validate release.json, versions, and tags env: GH_TOKEN: ${{ github.token }} run: | + set -euo pipefail + if ! jq -e '.crates | type == "array" and length > 0' release.json >/dev/null; then echo "::error::release.json invalid: crates must be a non-empty array" exit 1 fi - while read -r name version; do + while IFS=' ' read -r name version; do + echo "Validating $name v$version" + + # Crate must exist in workspace + if ! cargo metadata --no-deps --format-version 1 \ + | jq -e --arg name "$name" '.packages[] | select(.name == $name)' >/dev/null; then + echo "::error::Crate $name not found in workspace" + exit 1 + fi + + # Version must match Cargo.toml + actual=$(cargo metadata --no-deps --format-version 1 \ + | jq -r --arg name "$name" '.packages[] | select(.name == $name) | .version') + + if [ "$actual" != "$version" ]; then + echo "::error::Version mismatch for $name: release.json=$version, Cargo.toml=$actual" + exit 1 + fi + + # Tag must exist on remote tag="${name}@${version}" echo "Checking tag $tag" if ! git ls-remote --tags origin "refs/tags/${tag}" | grep -q "refs/tags/${tag}"; then @@ -40,29 +65,34 @@ jobs: fi done < <(jq -r '.crates[] | "\(.name) \(.version)"' release.json) - - name: Test and publish each crate in order + - name: Check workspace formatting + run: cargo fmt --all -- --check + + - name: Test, lint, and publish each crate in order env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: | - while read -r name version; do + set -euo pipefail + + while IFS=' ' read -r name version; do echo "==========================================" echo "Processing $name v$version" echo "==========================================" - # Build & test + # Test cargo test -p "$name" --all-targets || { echo "::error::Tests failed for $name" exit 1 } - # Clippy with warnings denied + # Clippy cargo clippy -p "$name" --all-targets -- -D warnings || { echo "::error::Clippy failed for $name" exit 1 } # Publish - cargo publish -p "$name" || { + cargo publish -p "$name" --locked || { echo "::error::Publish failed for $name" exit 1 } From 526d9a449116004959f29f22f8ed5382211dde63 Mon Sep 17 00:00:00 2001 From: mroczect Date: Fri, 21 Aug 2026 21:02:38 +0700 Subject: [PATCH 2/2] ci(scripts): refactor prepare-release for version validation --- scripts/prepare-release.sh | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/scripts/prepare-release.sh b/scripts/prepare-release.sh index 58b51cd0..79fef93e 100644 --- a/scripts/prepare-release.sh +++ b/scripts/prepare-release.sh @@ -10,6 +10,16 @@ readonly GREEN='\033[0;32m' readonly YELLOW='\033[0;33m' readonly NC='\033[0m' +# Urutan publish: dependency-first +readonly CRATE_ORDER=( + "libvctrl_sha512" + "libvctrl_handler" + "libvctrl_core" + "libvctrl" + "libvctrl_plumbing" + "libvctrl_porcelain" +) + log() { local level="$1"; shift local msg="$*" @@ -40,6 +50,7 @@ ensure_clean_workspace() { if ! git diff-index --quiet HEAD --; then error_exit "Uncommitted changes found. Commit or stash them first." fi + local branch branch=$(git rev-parse --abbrev-ref HEAD) if [ "$branch" != "master" ] && [ "$branch" != "main" ]; then @@ -47,6 +58,7 @@ ensure_clean_workspace() { read -r -p "Continue? (y/n) " confirm [ "$confirm" = "y" ] || exit 0 fi + git fetch origin local local_commit remote_commit local_commit=$(git rev-parse HEAD) @@ -58,22 +70,10 @@ ensure_clean_workspace() { fi } -# Urutan publish yang benar -readonly CRATE_ORDER=( - "libvctrl_sha512" - "libvctrl_handler" - "libvctrl_core" - "libvctrl" - "libvctrl_plumbing" - "libvctrl_porcelain" -) - get_version() { local crate="$1" - if [ ! -d "$crate" ]; then - error_exit "Directory '$crate' does not exist" - fi - (cd "$crate" && cargo pkgid | cut -d'#' -f2 | cut -d: -f1) + cargo metadata --no-deps --format-version 1 \ + | jq -r --arg name "$crate" '.packages[] | select(.name == $name) | .version' } generate_release_json() { @@ -103,13 +103,11 @@ push_tags() { version=$(get_version "$crate") local tag="${crate}@${version}" - # Cek remote dulu if git ls-remote --tags origin "refs/tags/${tag}" | grep -q "refs/tags/${tag}"; then log WARN "Tag $tag already exists on remote, skipping push" continue fi - # Buat tag lokal jika belum ada if ! git rev-parse "$tag" >/dev/null 2>&1; then log INFO "Creating tag $tag" git tag -a "$tag" -m "Release $crate v$version" @@ -120,30 +118,19 @@ push_tags() { done } -main() { - log INFO "Release preparation started" - check_prerequisites - ensure_clean_workspace - - # 1. Generate release.json - generate_release_json - - # 2. Create new branch +create_release_pr() { local branch_name branch_name="release/$(date +%Y%m%d%H%M%S)" log INFO "Creating branch $branch_name" git checkout -b "$branch_name" - # 3. Commit release.json - log INFO "Committing $RELEASE_JSON (force add)" + log INFO "Committing $RELEASE_JSON" git add -f "$RELEASE_JSON" git commit -m "chore(release): add $RELEASE_JSON for ordered publishing" - # 4. Push branch log INFO "Pushing branch $branch_name" git push -u origin "$branch_name" - # 5. Create PR log INFO "Creating pull request" cat > /tmp/pr_body.md <