From af15e6e8ebbcd6ca937bd8a5d903a78bc8d71662 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:17:06 +0000 Subject: [PATCH 1/3] Initial plan From f907c4d388d6d32a3af8d5a1c81a1d3e2373e1b7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:20:01 +0000 Subject: [PATCH 2/3] ci: update workflows and add release automation Co-authored-by: SeokminHong <11614766+SeokminHong@users.noreply.github.com> Agent-Logs-Url: https://github.com/SeokminHong/builder-pattern/sessions/9b2ce6b3-8ee2-4548-8273-2ebf33fd156d --- .github/workflows/build_macos.yml | 8 ++--- .github/workflows/build_ubuntu.yml | 40 +++++++-------------- .github/workflows/build_wasm.yml | 8 ++--- .github/workflows/build_windows.yml | 8 ++--- .github/workflows/release.yml | 56 +++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 43 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index c901bde..6b04ec5 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -10,13 +10,11 @@ jobs: name: Check Examples runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true profile: minimal - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run all examples run: | diff --git a/.github/workflows/build_ubuntu.yml b/.github/workflows/build_ubuntu.yml index 8fdca1d..12ac6b8 100644 --- a/.github/workflows/build_ubuntu.yml +++ b/.github/workflows/build_ubuntu.yml @@ -11,39 +11,28 @@ jobs: name: Format & Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true - profile: minimal components: rustfmt, clippy - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + run: cargo fmt --all -- --check - name: Run clippy if: always() - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -D warnings + run: cargo clippy -- -D warnings check_examples: name: Check Examples runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true profile: minimal - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run all examples run: | @@ -58,16 +47,11 @@ jobs: name: Documentation Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true profile: minimal - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run doctest - uses: actions-rs/cargo@v1 - with: - command: test - args: --doc + run: cargo test --doc diff --git a/.github/workflows/build_wasm.yml b/.github/workflows/build_wasm.yml index 723fddd..34e468d 100644 --- a/.github/workflows/build_wasm.yml +++ b/.github/workflows/build_wasm.yml @@ -10,14 +10,12 @@ jobs: name: Check Examples runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true profile: minimal target: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run all examples run: | diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 0b0ee7a..a83ed79 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -10,13 +10,11 @@ jobs: name: Check Examples runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true profile: minimal - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run all examples run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..37f91b9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,56 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version: + description: 'New release version (e.g. 0.4.3)' + required: true + type: string + +permissions: + contents: write + +env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Update crate versions + run: | + VERSION="${{ github.event.inputs.version }}" + + if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid version: $VERSION" + exit 1 + fi + + sed -i "s/^version = \".*\"$/version = \"$VERSION\"/" builder-pattern/Cargo.toml + sed -i "s/^version = \".*\"$/version = \"$VERSION\"/" builder-pattern-macro/Cargo.toml + sed -i "s/^version = \".*\"$/version = \"$VERSION\"/" test-no-future/Cargo.toml + sed -i "s/builder-pattern-macro = { version = \".*\", path = \"\.\.\/builder-pattern-macro\" }/builder-pattern-macro = { version = \"$VERSION\", path = \"..\/builder-pattern-macro\" }/" builder-pattern/Cargo.toml + sed -i "s/builder-pattern = { version = \".*\", path = \"\.\.\/builder-pattern\", default-features = false }/builder-pattern = { version = \"$VERSION\", path = \"..\/builder-pattern\", default-features = false }/" test-no-future/Cargo.toml + + - name: Run tests + run: cargo test --doc + + - name: Commit and tag release + run: | + VERSION="${{ github.event.inputs.version }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add builder-pattern/Cargo.toml builder-pattern-macro/Cargo.toml test-no-future/Cargo.toml + git commit -m "chore: release v$VERSION" + git tag "v$VERSION" + git push + git push origin "v$VERSION" + + - name: Publish crates + run: ./scripts/publish.sh From 6cd57aa686dc6e086c5edc88be69b09f56a6fd9a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:25:43 +0000 Subject: [PATCH 3/3] ci: harden release workflow safeguards Co-authored-by: SeokminHong <11614766+SeokminHong@users.noreply.github.com> Agent-Logs-Url: https://github.com/SeokminHong/builder-pattern/sessions/9b2ce6b3-8ee2-4548-8273-2ebf33fd156d --- .github/workflows/release.yml | 86 +++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37f91b9..4d31841 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,10 @@ on: required: true type: string +concurrency: + group: release + cancel-in-progress: false + permissions: contents: write @@ -23,34 +27,96 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - name: Validate release tag + run: | + VERSION="${{ github.event.inputs.version }}" + if git ls-remote --exit-code --tags origin "refs/tags/v$VERSION" >/dev/null 2>&1; then + echo "Tag v$VERSION already exists on origin" + exit 1 + fi + - name: Update crate versions run: | VERSION="${{ github.event.inputs.version }}" + export VERSION if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Invalid version: $VERSION" exit 1 fi - sed -i "s/^version = \".*\"$/version = \"$VERSION\"/" builder-pattern/Cargo.toml - sed -i "s/^version = \".*\"$/version = \"$VERSION\"/" builder-pattern-macro/Cargo.toml - sed -i "s/^version = \".*\"$/version = \"$VERSION\"/" test-no-future/Cargo.toml - sed -i "s/builder-pattern-macro = { version = \".*\", path = \"\.\.\/builder-pattern-macro\" }/builder-pattern-macro = { version = \"$VERSION\", path = \"..\/builder-pattern-macro\" }/" builder-pattern/Cargo.toml - sed -i "s/builder-pattern = { version = \".*\", path = \"\.\.\/builder-pattern\", default-features = false }/builder-pattern = { version = \"$VERSION\", path = \"..\/builder-pattern\", default-features = false }/" test-no-future/Cargo.toml + python - <<'PY' + from pathlib import Path + import os + import re + + version = os.environ["VERSION"] + + def update_package_version(path: str): + p = Path(path) + lines = p.read_text().splitlines() + in_package = False + updated = False + for i, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith("[") and stripped.endswith("]"): + in_package = stripped == "[package]" + continue + if in_package and stripped.startswith("version = "): + lines[i] = f'version = "{version}"' + updated = True + break + if not updated: + raise RuntimeError(f"Could not update [package] version in {path}") + p.write_text("\n".join(lines) + "\n") + + def update_dependency_version(path: str, dep_name: str): + p = Path(path) + content = p.read_text() + pattern = rf'({re.escape(dep_name)}\s*=\s*\{{[^}]*\bversion\s*=\s*")[^"]+(")' + new_content, count = re.subn(pattern, rf"\g<1>{version}\2", content, count=1) + if count != 1: + raise RuntimeError( + f"Expected 1 version field for dependency '{dep_name}' in {path}, found {count}" + ) + p.write_text(new_content) + + update_package_version("builder-pattern/Cargo.toml") + update_package_version("builder-pattern-macro/Cargo.toml") + update_package_version("test-no-future/Cargo.toml") + update_dependency_version("builder-pattern/Cargo.toml", "builder-pattern-macro") + update_dependency_version("test-no-future/Cargo.toml", "builder-pattern") + PY - name: Run tests - run: cargo test --doc + run: cargo test - - name: Commit and tag release + - name: Commit release changes run: | VERSION="${{ github.event.inputs.version }}" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add builder-pattern/Cargo.toml builder-pattern-macro/Cargo.toml test-no-future/Cargo.toml + if git diff --cached --quiet; then + echo "No release changes detected for version $VERSION" + exit 1 + fi git commit -m "chore: release v$VERSION" + + - name: Publish crates + run: | + test -x ./scripts/publish.sh || { + echo "Expected executable publish script at ./scripts/publish.sh" + exit 1 + } + ./scripts/publish.sh || { + echo "Publishing to crates.io failed. Check cargo publish output in this step for details." + exit 1 + } + + - name: Push commit and tag + run: | + VERSION="${{ github.event.inputs.version }}" git tag "v$VERSION" git push git push origin "v$VERSION" - - - name: Publish crates - run: ./scripts/publish.sh