diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcb4f57..71600bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Release on: push: tags: - - "v*" + - "v[0-9]+.[0-9]+.[0-9]+" permissions: contents: read @@ -217,7 +217,15 @@ jobs: exit 0 fi git commit -m "chore: vendor installer scripts ${TAG} from ${SOURCE_REPO}" - git push origin "$branch" + # Fetch first so --force-with-lease has a remote-tracking ref to + # compare against when a previous run already pushed this branch; + # the explicit refspec is needed because the clone is single-branch. + git fetch origin "+refs/heads/$branch:refs/remotes/origin/$branch" 2>/dev/null || true + git push --force-with-lease origin "$branch" + if [ -n "$(gh pr list --repo "$TARGET_REPO" --head "$branch" --json number --jq '.[].number')" ]; then + echo "vendoring PR for $branch already exists; skipping creation" + exit 0 + fi gh pr create \ --repo "$TARGET_REPO" \ --title "chore: vendor installer scripts ${TAG}" \ diff --git a/CHANGELOG.md b/CHANGELOG.md index ae9f001..3514e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.0] - 2026-07-16 + ### Added - Cross-platform `install.sh` and `install.ps1` installers for the standalone diff --git a/install.sh b/install.sh index 4fb9ed1..5404e76 100755 --- a/install.sh +++ b/install.sh @@ -217,15 +217,18 @@ prepare_destination() { BIN_DIR="$FINAL_PARENT/cloudsmith" case "$TARGET" in windows-*) BIN="$BIN_DIR/cloudsmith.exe" ;; *) BIN="$BIN_DIR/cloudsmith" ;; esac METADATA_FILE="$BIN_DIR/.cloudsmith-installation" - LOCK_DIR="$FINAL_PARENT/.install.lock" + lock_dir="$FINAL_PARENT/.install.lock" mkdir -p "$FINAL_PARENT" waited=0 - until mkdir "$LOCK_DIR" 2>/dev/null; do - [ "$waited" -lt 120 ] || die "timed out waiting for installation lock: $LOCK_DIR" + until mkdir "$lock_dir" 2>/dev/null; do + [ "$waited" -lt 120 ] || die "timed out waiting for installation lock: $lock_dir" sleep 1 waited=$((waited + 1)) done + # Track the lock for cleanup only once this process owns it, so a waiter + # that dies never releases another installer's lock. + LOCK_DIR="$lock_dir" } reuse_existing_install() { diff --git a/tests/install.bats b/tests/install.bats index 7e96000..f2f935e 100644 --- a/tests/install.bats +++ b/tests/install.bats @@ -604,6 +604,29 @@ executable=$bin_dir/cloudsmith" [ -x "$final_parent/cloudsmith/cloudsmith" ] } +@test "a waiter that dies does not remove another installer's lock" { + build_fixture "$FIXTURE_DIR" "1.19.0" "$TEST_TARGET" + local final_parent="$INSTALL_ROOT/1.19.0/$TEST_TARGET" + mkdir -p "$final_parent/.install.lock" + + "$INSTALL_SH" \ + --version 1.19.0 \ + --target "$TEST_TARGET" \ + --install-root "$INSTALL_ROOT" \ + --manifest-url "$FIXTURE_URL/manifest.txt" \ + >"$BATS_TEST_TMPDIR/bg.out" 2>"$BATS_TEST_TMPDIR/bg.err" & + local bg_pid=$! + + sleep 2 + kill -TERM "$bg_pid" + + local bg_status=0 + wait "$bg_pid" || bg_status=$? + + [ "$bg_status" -ne 0 ] + [ -d "$final_parent/.install.lock" ] +} + @test "concurrent installs of the same version both succeed" { build_fixture "$FIXTURE_DIR" "1.19.0" "$TEST_TARGET"