diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 1ab7d44..8f4c0a5 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -2,10 +2,9 @@ name: Build and Release PS3Dec on: push: - branches: [main, dev] tags: ['v*'] pull_request: - branches: [main, dev] + branches: [main] workflow_dispatch: permissions: @@ -16,8 +15,64 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + checks: + name: Rust and Python checks + runs-on: ubuntu-24.04 + timeout-minutes: 15 + env: + CARGO_TERM_COLOR: always + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Verify release tag and versions + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + run: | + if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "Release tags must point to a commit on main." >&2 + exit 1 + fi + python3 - <<'PY' + import os + import tomllib + from pathlib import Path + + package = tomllib.loads(Path("Cargo.toml").read_text())["package"] + version = package["version"] + tag = os.environ["GITHUB_REF_NAME"] + if tag != f"v{version}": + raise SystemExit(f"Tag {tag} does not match Cargo.toml; expected v{version}.") + lock = tomllib.loads(Path("Cargo.lock").read_text()) + locked = next((p for p in lock["package"] if p["name"] == package["name"] and "source" not in p), None) + if locked is None or locked["version"] != version: + raise SystemExit("Cargo.lock version does not match Cargo.toml; run cargo check and commit both files.") + print(f"Release version verified: {tag}") + PY + + - name: Load the repository's pinned Rust toolchain + run: rustup show active-toolchain + + - name: Cache Rust dependencies + uses: swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 + with: + key: checks + save-if: ${{ github.event_name != 'pull_request' }} + + - name: Check Rust formatting + run: cargo fmt --all -- --check + + - name: Check Python syntax + run: python3 -m compileall -q tests + + - name: Check Rust code with Clippy + run: cargo clippy --locked --all-targets -- -D warnings + build: name: Build ${{ matrix.target }} + needs: checks runs-on: ${{ matrix.os }} timeout-minutes: 45 strategy: @@ -98,7 +153,8 @@ jobs: - name: End-to-end decryption checks if: runner.os == 'Linux' run: | - cargo build --locked --bin ps3dec + mkdir -p target/debug + cp "target/$TARGET/release/$BINARY" "target/debug/$BINARY" python3 -B tests/e2e.py - name: Prepare package @@ -132,8 +188,7 @@ jobs: name: Publish release needs: build if: >- - github.event_name == 'push' && - (github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v')) + github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: @@ -142,15 +197,38 @@ jobs: run: shell: bash steps: - - name: Checkout full history for branch validation - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Checkout release history + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: fetch-depth: 0 persist-credentials: false - - name: Verify stable release comes from main - if: startsWith(github.ref, 'refs/tags/') - run: git merge-base --is-ancestor "$GITHUB_SHA" origin/main + - name: Include commits in release notes + run: | + python3 - <<'PY' + import os + import subprocess + from pathlib import Path + + sha = os.environ["GITHUB_SHA"] + previous = subprocess.run( + ["git", "--no-pager", "describe", "--tags", "--match", "v[0-9]*", "--match", "[0-9]*", "--abbrev=0", f"{sha}^"], + capture_output=True, text=True, + ) + commit_range = f"{previous.stdout.strip()}..{sha}" if previous.returncode == 0 else sha + commits = subprocess.run( + ["git", "--no-pager", "log", "--no-merges", "--format=- %s (%h)", commit_range], + capture_output=True, text=True, check=True, + ).stdout + repo_url = f"{os.environ['GITHUB_SERVER_URL']}/{os.environ['GITHUB_REPOSITORY']}" + run_url = f"{repo_url}/actions/runs/{os.environ['GITHUB_RUN_ID']}" + Path("RELEASE_NOTES.md").write_text( + f"Built from commit [{sha}]({repo_url}/commit/{sha}).\n\n" + f"[Build run]({run_url}).\n\n" + "Verify downloads with SHA256SUMS.\n\n" + "## Commits\n\n" + commits, + ) + PY - name: Download all platform archives uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -166,15 +244,12 @@ jobs: - name: Publish release with generated notes uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1 with: - tag: ${{ github.ref == 'refs/heads/dev' && format('dev-{0}', github.run_number) || github.ref_name }} + tag: ${{ github.ref_name }} commit: ${{ github.sha }} - prerelease: ${{ github.ref == 'refs/heads/dev' }} - makeLatest: ${{ github.ref != 'refs/heads/dev' }} + prerelease: false + makeLatest: true generateReleaseNotes: true - body: | - Built from commit [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}). - [Build run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}). - Verify downloads with SHA256SUMS. + bodyFile: RELEASE_NOTES.md artifacts: artifacts/*.tar.gz,artifacts/*.zip,artifacts/SHA256SUMS artifactErrorsFailBuild: true immutableCreate: true diff --git a/Cargo.lock b/Cargo.lock index 16810e8..f4ebb6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -982,7 +982,7 @@ dependencies = [ [[package]] name = "ps3decrs" -version = "2.0.1" +version = "3.0.0" dependencies = [ "aes", "atomicwrites", diff --git a/Cargo.toml b/Cargo.toml index 3a97609..b60ab7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ps3decrs" -version = "2.0.1" +version = "3.0.0" edition = "2024" description = "PS3 ISO decryption tool." repository = "https://github.com/Redrrx/ps3dec" diff --git a/README.md b/README.md index f60f7d9..767d980 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,29 @@ If you visit the releases page you might find two types * Stable == ready to use, reliable enough. * Preview == trying out requests, and toying around before stable. +### creating a release + +You choose the version; nothing bumps it for you. + +| Event | What happens | +|-------|--------------| +| Push to `dev` or merge into `main` | No extra build | +| Open or update a PR into `main` | Rust formatting, Clippy, Python syntax, all six platform builds, and Linux decryption tests | +| Push a `v*` tag | Check the version, build and test, then publish if everything passes | +| Manual run | Full checks and builds, without publishing | + +1. Set your version in `Cargo.toml`, then run `cargo check` to update `Cargo.lock`. +2. Commit both files, open a PR into `main`, and wait for the checks to pass. Require **Rust and Python checks** and all six **Build** checks before merging. +3. Merge the PR, then tag your chosen version from the updated `main`: + +```sh +git switch main +git pull --ff-only origin main +git tag v3.0.0 +git push origin v3.0.0 +``` + +`3.0.0` is an example; use your chosen version and an unused tag. The tag must match `Cargo.toml` and `Cargo.lock`, and point to a commit on `main`. Release notes include commits since the previous version tag and GitHub's generated notes. Linux tests use the release executable already built, so there's no second debug build. ## Acknowledgements diff --git a/src/queue.rs b/src/queue.rs index 3ea43b8..1873ba9 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -349,7 +349,7 @@ pub fn run( return run_tui(args, &pool, logs); } let interactive = io::stderr().is_terminal() && logs.is_none(); - let style = progress_style(); + let style = progress_style(); let _header = interactive.then(|| { let header = ProgressBar::hidden(); header.set_prefix(" # ISO");