2.8.0 #68
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "app-v*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Release tag to build, for example app-v0.1.0" | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| env: | |
| RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} | |
| jobs: | |
| release: | |
| name: Build ${{ matrix.label }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - label: macOS Intel | |
| os: macos-latest | |
| target: x86_64-apple-darwin | |
| args: --target x86_64-apple-darwin | |
| stableAsset: codex-usage-desktop-macos-x64.dmg | |
| updaterAsset: codex-usage-desktop-macos-x64.app.tar.gz | |
| - label: macOS Apple Silicon | |
| os: macos-latest | |
| target: aarch64-apple-darwin | |
| args: --target aarch64-apple-darwin | |
| stableAsset: codex-usage-desktop-macos-arm64.dmg | |
| updaterAsset: codex-usage-desktop-macos-arm64.app.tar.gz | |
| - label: Windows x64 | |
| os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| args: --target x86_64-pc-windows-msvc | |
| stableAsset: codex-usage-desktop-windows-x64-setup.exe | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ env.RELEASE_TAG }} | |
| fetch-depth: 0 | |
| - name: Validate release tag | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="$(node -p "require('./src-tauri/tauri.conf.json').version")" | |
| expected="app-v${version}" | |
| if [[ "${RELEASE_TAG}" != "${expected}" ]]; then | |
| echo "Release tag ${RELEASE_TAG} does not match src-tauri/tauri.conf.json version ${version}." | |
| echo "Expected tag: ${expected}" | |
| exit 1 | |
| fi | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: 10 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Cache Rust | |
| uses: swatinem/rust-cache@v2 | |
| with: | |
| workspaces: src-tauri -> target | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Test frontend | |
| run: pnpm test | |
| - name: Typecheck frontend | |
| run: pnpm typecheck | |
| - name: Test Rust backend | |
| run: cargo test --manifest-path src-tauri/Cargo.toml | |
| - name: Generate release notes | |
| id: release_notes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| previous_tag="$(git describe --tags --match 'app-v*' --abbrev=0 "${RELEASE_TAG}^" 2>/dev/null || true)" | |
| if [[ -n "${previous_tag}" ]]; then | |
| range="${previous_tag}..${RELEASE_TAG}" | |
| else | |
| range="${RELEASE_TAG}" | |
| fi | |
| { | |
| echo "## What's Changed" | |
| echo | |
| has_changes=false | |
| version_bump_regex='^chore(\([^)]*\))?:[[:space:]]*[0-9]+\.[0-9]+\.[0-9]+$' | |
| while IFS= read -r subject; do | |
| [[ -z "${subject}" ]] && continue | |
| if [[ "${subject}" =~ ${version_bump_regex} ]]; then | |
| continue | |
| fi | |
| has_changes=true | |
| echo "- ${subject}" | |
| done < <(git log --format=%s --reverse "${range}") | |
| if [[ "${has_changes}" == "false" ]]; then | |
| echo "- No notable commit changes." | |
| fi | |
| echo | |
| if [[ -n "${previous_tag}" ]]; then | |
| echo "**Full Changelog**: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/${previous_tag}...${RELEASE_TAG}" | |
| else | |
| echo "**Full Changelog**: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commits/${RELEASE_TAG}" | |
| fi | |
| } > release-notes.md | |
| { | |
| echo "body<<EOF" | |
| cat release-notes.md | |
| echo "EOF" | |
| } >> "${GITHUB_OUTPUT}" | |
| - name: Build and publish Tauri app | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| with: | |
| tagName: ${{ env.RELEASE_TAG }} | |
| releaseName: Codex Usage Desktop ${{ env.RELEASE_TAG }} | |
| releaseBody: ${{ steps.release_notes.outputs.body }} | |
| releaseDraft: true | |
| prerelease: false | |
| args: ${{ matrix.args }} | |
| - name: Prepare stable DMG asset | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| search_dirs=() | |
| for dir in \ | |
| "src-tauri/target/${{ matrix.target }}/release/bundle/dmg" \ | |
| "src-tauri/target/release/bundle/dmg" | |
| do | |
| if [[ -d "${dir}" ]]; then | |
| search_dirs+=("${dir}") | |
| fi | |
| done | |
| if [[ "${#search_dirs[@]}" -eq 0 ]]; then | |
| echo "No Tauri DMG bundle directories were found." | |
| exit 1 | |
| fi | |
| dmg="$(find "${search_dirs[@]}" -maxdepth 1 -type f -name '*.dmg' | head -n 1)" | |
| updater="$(find "src-tauri/target/${{ matrix.target }}/release/bundle/macos" -maxdepth 1 -type f -name '*.app.tar.gz' | head -n 1)" | |
| signature="$(find "src-tauri/target/${{ matrix.target }}/release/bundle/macos" -maxdepth 1 -type f -name '*.app.tar.gz.sig' | head -n 1)" | |
| if [[ -z "${dmg}" || -z "${updater}" || -z "${signature}" ]]; then | |
| echo "The DMG, updater archive, or updater signature is missing." | |
| exit 1 | |
| fi | |
| mkdir -p release-assets | |
| cp "${dmg}" "release-assets/${{ matrix.stableAsset }}" | |
| cp "${updater}" "release-assets/${{ matrix.updaterAsset }}" | |
| cp "${signature}" "release-assets/${{ matrix.updaterAsset }}.sig" | |
| - name: Upload stable macOS assets | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| for asset in release-assets/*; do | |
| for attempt in 1 2 3; do | |
| if gh release upload "${RELEASE_TAG}" "${asset}" \ | |
| --repo "${GITHUB_REPOSITORY}" \ | |
| --clobber | |
| then | |
| break | |
| fi | |
| if [[ "${attempt}" -eq 3 ]]; then | |
| echo "Failed to upload ${asset} after ${attempt} attempts." | |
| exit 1 | |
| fi | |
| delay=$((attempt * 15)) | |
| echo "Upload failed for ${asset}; retrying in ${delay} seconds." | |
| sleep "${delay}" | |
| done | |
| done | |
| - name: Prepare and validate Windows assets | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| search_dirs=() | |
| for dir in \ | |
| "src-tauri/target/${{ matrix.target }}/release/bundle/nsis" \ | |
| "src-tauri/target/release/bundle/nsis" | |
| do | |
| if [[ -d "${dir}" ]]; then | |
| search_dirs+=("${dir}") | |
| fi | |
| done | |
| if [[ "${#search_dirs[@]}" -eq 0 ]]; then | |
| echo "No Tauri NSIS bundle directories were found." | |
| exit 1 | |
| fi | |
| setup="$(find "${search_dirs[@]}" -maxdepth 1 -type f -name '*-setup.exe' | head -n 1)" | |
| if [[ -z "${setup}" ]]; then | |
| echo "The setup executable is missing." | |
| exit 1 | |
| fi | |
| signature="${setup}.sig" | |
| if [[ ! -f "${signature}" ]]; then | |
| echo "The setup executable signature is missing: ${signature}" | |
| exit 1 | |
| fi | |
| mkdir -p release-assets | |
| cp "${setup}" "release-assets/${{ matrix.stableAsset }}" | |
| cp "${signature}" "release-assets/${{ matrix.stableAsset }}.sig" | |
| - name: Upload Windows assets | |
| if: runner.os == 'Windows' | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: ${{ env.RELEASE_TAG }} | |
| draft: true | |
| files: release-assets/* | |
| updater-manifest: | |
| name: Publish updater manifest | |
| needs: release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download stable updater assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| mkdir updater-assets | |
| gh release download "${RELEASE_TAG}" \ | |
| --repo "${GITHUB_REPOSITORY}" \ | |
| --dir updater-assets \ | |
| --pattern 'codex-usage-desktop-macos-*.app.tar.gz' \ | |
| --pattern 'codex-usage-desktop-macos-*.app.tar.gz.sig' \ | |
| --pattern 'codex-usage-desktop-windows-x64-setup.exe' \ | |
| --pattern 'codex-usage-desktop-windows-x64-setup.exe.sig' | |
| - name: Generate complete updater manifest | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="${RELEASE_TAG#app-v}" | |
| base_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${RELEASE_TAG}" | |
| published_at="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" | |
| mac_x64_sig="$(cat updater-assets/codex-usage-desktop-macos-x64.app.tar.gz.sig)" | |
| mac_arm64_sig="$(cat updater-assets/codex-usage-desktop-macos-arm64.app.tar.gz.sig)" | |
| windows_x64_sig="$(cat updater-assets/codex-usage-desktop-windows-x64-setup.exe.sig)" | |
| jq -n \ | |
| --arg version "${version}" \ | |
| --arg notes "See the GitHub release for changes in ${RELEASE_TAG}." \ | |
| --arg pub_date "${published_at}" \ | |
| --arg mac_x64_sig "${mac_x64_sig}" \ | |
| --arg mac_arm64_sig "${mac_arm64_sig}" \ | |
| --arg windows_x64_sig "${windows_x64_sig}" \ | |
| --arg mac_x64_url "${base_url}/codex-usage-desktop-macos-x64.app.tar.gz" \ | |
| --arg mac_arm64_url "${base_url}/codex-usage-desktop-macos-arm64.app.tar.gz" \ | |
| --arg windows_x64_url "${base_url}/codex-usage-desktop-windows-x64-setup.exe" \ | |
| '{ | |
| version: $version, | |
| notes: $notes, | |
| pub_date: $pub_date, | |
| platforms: { | |
| "darwin-x86_64": {signature: $mac_x64_sig, url: $mac_x64_url}, | |
| "darwin-aarch64": {signature: $mac_arm64_sig, url: $mac_arm64_url}, | |
| "windows-x86_64": {signature: $windows_x64_sig, url: $windows_x64_url} | |
| } | |
| }' > latest.json | |
| - name: Upload complete updater manifest | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: ${{ env.RELEASE_TAG }} | |
| draft: true | |
| files: latest.json | |
| - name: Publish completed release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: gh release edit "${RELEASE_TAG}" --repo "${GITHUB_REPOSITORY}" --draft=false --latest |