From 9d177a15e867816ad27df7c89b27dff74d747a11 Mon Sep 17 00:00:00 2001 From: sepehr-safari Date: Sun, 12 Jul 2026 21:00:52 +0300 Subject: [PATCH] chore(release): macOS + Linux packaging and release workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Package Studio via `native package` and automate a GitHub release on tag push — the packaging foundation for the 0.5.0 launch. - .github/workflows/release.yml: on a v* tag, a matrix builds the macOS package (.app → ad-hoc-signed .dmg) and the Linux package (.tar.gz) via `native build` + `native package --archive`, gated by `native doctor` (strict on macOS); a publish job downloads both and cuts the GitHub release with generated notes. Least-privilege token (contents: write only on the publish job); the tag/repo reach `gh` through the environment, not interpolated into the script, so a crafted tag can't inject shell. - RELEASING.md: the release runbook (bump version, changelog, tag, verify) plus the macOS ad-hoc "right-click → Open" note and the local packaging command; notarization + the menu-bar monitor are called out as post-0.5. Verified locally: `native package --target macos --signing adhoc --archive` produces a launchable studio.app + .dmg (arm64, adhoc codesign), and the packaged binary runs both its GUI and `ci` faces. release.yml is valid YAML. Ad-hoc signing per the 0.5.0 scope decision; notarization is deferred. Closes #70. --- .github/workflows/release.yml | 91 +++++++++++++++++++++++++++++++++++ CURRENT_STATE.md | 10 +++- RELEASING.md | 53 ++++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 RELEASING.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5f5291e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: Release + +# Cut a release when a v* tag is pushed: build the macOS (.dmg, ad-hoc signed) +# and Linux (.tar.gz) packages via `native package`, then publish a GitHub +# release with both artifacts attached. See RELEASING.md for the runbook. + +on: + push: + tags: + - "v*" + +permissions: + contents: read + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +jobs: + package: + name: package (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + target: macos + build_flags: "" + package_flags: "--signing adhoc" + artifact: "zig-out/package/*.dmg" + - os: ubuntu-latest + target: linux + build_flags: "-Dplatform=linux" + package_flags: "" + artifact: "zig-out/package/*.tar.gz" + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: 22 + - uses: mlugg/setup-zig@v2 + with: + version: 0.16.0 + - name: Install GTK (Linux) + if: runner.os == 'Linux' + run: sudo apt-get update && sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev + - name: Install Native SDK CLI + run: npm install -g @native-sdk/cli@0.4.1 + - name: Doctor (strict, macOS) + if: runner.os == 'macOS' + run: native doctor --strict + - name: Doctor (Linux) + if: runner.os == 'Linux' + run: native doctor + - name: Build release binary + run: native build ${{ matrix.build_flags }} + - name: Package + run: native package --target ${{ matrix.target }} ${{ matrix.package_flags }} --archive + - name: Upload package artifact + uses: actions/upload-artifact@v4 + with: + name: studio-${{ matrix.target }} + path: ${{ matrix.artifact }} + if-no-files-found: error + + publish: + name: publish release + needs: package + runs-on: ubuntu-latest + permissions: + contents: write # create the release and upload assets + steps: + - name: Download packages + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + - name: Publish GitHub release + # ref_name / repository come in through the environment, never + # interpolated into the script body, so a crafted tag can't inject shell. + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + REPO: ${{ github.repository }} + run: | + gh release create "$TAG" dist/* \ + --repo "$REPO" \ + --title "$TAG" \ + --generate-notes \ + --verify-tag diff --git a/CURRENT_STATE.md b/CURRENT_STATE.md index 866a088..0846865 100644 --- a/CURRENT_STATE.md +++ b/CURRENT_STATE.md @@ -16,7 +16,13 @@ inspector through the effects channel (#58, ADR-0009), and explicit-fault criticals raise OS notifications live (#60, ADR-0011) — all **in-runner** (`update_fx` + `fx.spawn` + the effects-bound platform services), no runner-eject. -Next is **S6 — public release & launch (0.5.0)**; see [ROADMAP.md](ROADMAP.md). +**S6 — public release & launch (0.5.0): in progress.** Packaging is wired +(#70) — `native package` builds a macOS `.app` (ad-hoc `.dmg`) and a Linux +`.tar.gz`, and a tag-triggered [release workflow](.github/workflows/release.yml) +publishes both to a GitHub release (see [RELEASING.md](RELEASING.md)). Remaining: +GUI test suite (#71), the frozen conformance contract (#72), release-ready docs +(#73), and the v0.5.0 cut (#74). The menu-bar monitor and notarization are +post-0.5; see [ROADMAP.md](ROADMAP.md). ## What's done @@ -179,7 +185,7 @@ live inspector surface with notifications (#54–#60) — is landed. | Area | Status | | --- | --- | -| `repo` (tooling, CI) | ✅ done for S0 | +| `repo` (tooling, CI) | ✅ S0 CI; 🔨 S6 packaging + release workflow (#70) | | `docs` (docs, ADRs) | ✅ done for S0 | | `ocpp` (engine) | ✅ S2 + ingestion (#29) + reports (#41) + anonymize (#42) + diff (#43) + replay core (#44); O(n) detection pending (#36) | | `ui` (native views) | ✅ S3 inspector (#27–#32) + replay transport (#44) + live-capture view (#59) + live notifications (#60) | diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..5e31e90 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,53 @@ +# Releasing OCPP DebugKit Studio + +Studio ships as a native binary per OS, cut from `main` via a tag. Releases are +pre-1.0 (0.x) while Zig, the Native SDK, and the toolkit conformance reference +are all pre-1.0 — see the [ROADMAP](ROADMAP.md) versioning note. + +## What a release produces + +A push of a `vX.Y.Z` tag triggers [`.github/workflows/release.yml`](.github/workflows/release.yml), +which builds and publishes a GitHub release with two artifacts: + +| Platform | Artifact | Notes | +| --- | --- | --- | +| macOS | `studio-X.Y.Z-macos-ReleaseFast.dmg` | A `.app` bundle, **ad-hoc signed** | +| Linux | `studio-X.Y.Z-linux-ReleaseFast.tar.gz` | The `studio` binary + resources | + +**macOS Gatekeeper:** the ad-hoc build is not notarized, so first launch needs +**right-click → Open** (or *System Settings → Privacy & Security → Open Anyway*). +Notarization — which removes that prompt — is a post-0.5 follow-up; it needs an +Apple Developer identity and signing credentials wired into CI as secrets. + +## Cutting a release + +1. **Green `main`.** CI must be green on the commit you are releasing. +2. **Bump the version** in [`app.zon`](app.zon) (`.version = "X.Y.Z"`). +3. **Finalize the changelog** — move the `Unreleased` section of + [`CHANGELOG.md`](CHANGELOG.md) under a dated `X.Y.Z` heading. +4. **Update the living docs** — `CURRENT_STATE.md` / `ROADMAP.md` as needed. +5. Land 2–4 through a normal PR and merge to `main`. +6. **Tag and push** from the merged commit: + ```sh + git tag vX.Y.Z + git push origin vX.Y.Z + ``` +7. The release workflow builds both packages and publishes the GitHub release + (`--generate-notes` for the auto notes; swap to `--notes-file` from the + changelog section if you prefer curated notes). + +The tag and the published release are **outward-facing and hard to reverse** — +push the tag only when the release commit is final. + +## Verifying packaging locally + +Build a package without cutting a release (macOS): + +```sh +native build +native package --target macos --signing adhoc --archive +# → zig-out/package/studio.app and zig-out/package/studio--macos-ReleaseFast.dmg +open zig-out/package/studio.app # smoke-launch it +``` + +`native doctor --strict` gates the manifest; the release workflow runs it too.