diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69c59d1f3..6837f1526 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,15 +1,20 @@ name: Release on: - workflow_dispatch: push: - branches: [main] - paths: - - '.changeset/**' - - 'packages/**' - - 'apps/**' - - 'package.json' - - 'pnpm-lock.yaml' + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to release (e.g. v0.1.0). Must start with "v"' + required: true + type: string + draft: + description: 'Create as draft release' + required: false + type: boolean + default: true concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -20,17 +25,125 @@ permissions: id-token: write jobs: - release: - name: Version PR + # ------------------------------------------------------------------ + # Gate: lint / typecheck / test on ubuntu only (fast, cheap). + # Full matrix is already covered by ci.yml on PRs; we just need a + # quick sanity pass before we spend runner-minutes on packaging. + # ------------------------------------------------------------------ + gate: + name: Gate (lint · typecheck · test) + runs-on: ubuntu-latest + if: github.repository == 'OpenCoworkAI/open-codesign' + env: + RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.RELEASE_REF }} + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: pnpm + + - name: Install + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Typecheck + run: pnpm typecheck + + - name: Test + run: pnpm -r test + + # ------------------------------------------------------------------ + # Changelog: build release notes from conventional commits. + # Runs in parallel with the gate; the build matrix waits for both. + # ------------------------------------------------------------------ + changelog: + name: Build changelog runs-on: ubuntu-latest if: github.repository == 'OpenCoworkAI/open-codesign' + env: + RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }} + outputs: + changelog: ${{ steps.build.outputs.changelog }} steps: - uses: actions/checkout@v4 with: + ref: ${{ env.RELEASE_REF }} + fetch-depth: 0 + + - name: Build changelog + id: build + uses: mikepenz/release-changelog-builder-action@c9dc8369bccbc41e0ac887f8fd674f5925d315f7 # v5 + with: + configurationJson: | + { + "categories": [ + { + "title": "### Features", + "labels": ["feat"], + "rules": [{ "pattern": "^feat", "on_property": "title" }] + }, + { + "title": "### Bug Fixes", + "labels": ["fix"], + "rules": [{ "pattern": "^fix", "on_property": "title" }] + }, + { + "title": "### Documentation", + "labels": ["docs"], + "rules": [{ "pattern": "^docs", "on_property": "title" }] + }, + { + "title": "### Other Changes", + "rules": [{ "pattern": "^(chore|refactor|perf|test|ci)", "on_property": "title" }] + } + ], + "ignore_labels": ["skip-changelog"], + "sort": { "order": "DESC", "on_property": "mergedAt" }, + "template": "#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}" + } + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # ------------------------------------------------------------------ + # Build: native packaging per platform. + # electron-builder reads publish config from electron-builder.yml. + # We do NOT sign in v0.1 — notarization deferred to Stage 2. + # ------------------------------------------------------------------ + build: + name: Build (${{ matrix.os }}) + needs: [gate, changelog] + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + artifact_glob: 'apps/desktop/release/*.dmg' + - os: windows-latest + artifact_glob: 'apps/desktop/release/*.exe' + - os: ubuntu-latest + artifact_glob: 'apps/desktop/release/*.AppImage' + runs-on: ${{ matrix.os }} + env: + RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.RELEASE_REF }} fetch-depth: 0 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - name: Setup Node uses: actions/setup-node@v4 @@ -41,14 +154,70 @@ jobs: - name: Install run: pnpm install --frozen-lockfile - # Versioning only. Publishing (npm + GitHub release artifacts) is - # intentionally NOT wired up yet — packaging needs code-signing - # (Mac notarization, Windows Authenticode) which we do not have. - - name: Create Version Pull Request - uses: changesets/action@v1 + # Build all workspace packages (turborepo respects dep graph) + - name: Build workspace + run: pnpm -r build --filter '!@open-codesign/desktop' + + # Package the Electron app. + # CSC_IDENTITY_AUTO_DISCOVERY=false: skip ad-hoc Mac signing prompt. + # WIN_CSC_LINK / WIN_CSC_KEY_PASSWORD: intentionally unset (no cert in v0.1). + - name: Package desktop + env: + CSC_IDENTITY_AUTO_DISCOVERY: 'false' + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: pnpm --filter @open-codesign/desktop release + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: installer-${{ matrix.os }} + path: ${{ matrix.artifact_glob }} + if-no-files-found: error + retention-days: 7 + + # ------------------------------------------------------------------ + # Publish: create (or update draft) GitHub Release and attach files. + # ------------------------------------------------------------------ + publish: + name: Publish GitHub Release + needs: [build, changelog] + runs-on: ubuntu-latest + env: + RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.RELEASE_REF }} + fetch-depth: 0 + + - name: Validate tag input on dispatch + if: github.event_name == 'workflow_dispatch' + run: | + if [[ ! "${{ inputs.tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then + echo "::error::tag must be semver-like (e.g. v1.2.3 or v1.2.3-rc.1)" + exit 1 + fi + # Verify the tag exists on the remote before proceeding + if ! git ls-remote --tags origin "refs/tags/${{ inputs.tag }}" | grep -q "${{ inputs.tag }}"; then + echo "::error::tag '${{ inputs.tag }}' does not exist on origin" + exit 1 + fi + + - name: Download all installers + uses: actions/download-artifact@v4 + with: + path: dist/ + merge-multiple: true + + - name: Create GitHub Release + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 with: - version: pnpm version-packages - commit: 'chore(release): version packages' - title: 'chore(release): version packages' + tag_name: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }} + name: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }} + body: ${{ needs.changelog.outputs.changelog }} + draft: ${{ github.event_name == 'push' && false || inputs.draft }} + prerelease: ${{ contains(github.event_name == 'push' && github.ref_name || inputs.tag, '-') }} + files: dist/** + fail_on_unmatched_files: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index a9e69ed56..5b43308b4 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,42 @@ open-codesign is an open-source desktop app that turns natural-language prompts - **Lean**: Target install size ≤ 80 MB. No bundled runtimes, no telemetry by default. - **Ecosystem-friendly**: Designed to handoff to [open-cowork](https://github.com/OpenCoworkAI/open-cowork) for engineering, and to interoperate with Claude Artifacts. +## Install + +Download the latest installer from the [GitHub Releases](https://github.com/OpenCoworkAI/open-codesign/releases) page. + +| Platform | File | Notes | +|---|---|---| +| macOS (Apple Silicon) | `open-codesign-*-arm64.dmg` | See Gatekeeper note below | +| macOS (Intel) | `open-codesign-*-x64.dmg` | See Gatekeeper note below | +| Windows | `open-codesign-*-Setup.exe` | See SmartScreen note below | +| Linux | `open-codesign-*.AppImage` | See AppImage note below | + +**macOS — Gatekeeper warning (v0.1 is unsigned)** + +Because v0.1 installers are not notarized, macOS will block the double-click open. To run anyway: + +1. Right-click (or Control-click) the `.dmg` and choose **Open**. +2. In the dialog that appears, click **Open** again. + +You only need to do this once per install. + +**Windows — SmartScreen warning (v0.1 is unsigned)** + +Windows may show "Windows protected your PC". To proceed: + +1. Click **More info**. +2. Click **Run anyway**. + +**Linux — AppImage** + +```bash +chmod +x open-codesign-*.AppImage +./open-codesign-*.AppImage +``` + +> **Security note:** v0.1 binaries carry no code-signing certificate. Users who prefer a verified build can compile from source — see [CONTRIBUTING.md](./CONTRIBUTING.md). Code signing (Apple Developer ID + Windows Authenticode) is planned for Stage 2. + ## Status & Roadmap See [`docs/ROADMAP.md`](./docs/ROADMAP.md). MVP success criterion: replicate every public Claude Design demo. diff --git a/apps/desktop/electron-builder.yml b/apps/desktop/electron-builder.yml index 06ac316f2..6e148d249 100644 --- a/apps/desktop/electron-builder.yml +++ b/apps/desktop/electron-builder.yml @@ -24,7 +24,3 @@ linux: - target: AppImage arch: [x64] category: Graphics -publish: - provider: github - owner: OpenCoworkAI - repo: open-codesign diff --git a/apps/desktop/package.json b/apps/desktop/package.json index ea1a37299..865e88693 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -8,6 +8,7 @@ "dev": "electron-vite dev", "build": "electron-vite build && electron-builder", "build:dir": "electron-vite build && electron-builder --dir", + "release": "electron-vite build && electron-builder --publish never", "typecheck": "tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p tsconfig.web.json", "test": "vitest run --passWithNoTests" },