publish #649
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: "publish" | |
| # change this when ready to release if you want CI/CD | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| interactionId: | |
| description: "Discord Interaction ID" | |
| required: false | |
| type: string | |
| env: | |
| CN_APPLICATION: cap/cap | |
| APP_CARGO_TOML: apps/desktop/src-tauri/Cargo.toml | |
| SENTRY_ORG: cap-s2 | |
| SENTRY_PROJECT: cap-desktop | |
| jobs: | |
| draft: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.read_version.outputs.value }} | |
| tag_name: ${{ steps.create_tag.outputs.tag_name }} | |
| needs_release: ${{ steps.create_tag.outputs.release_published != 'true' }} | |
| cn_release_stdout: ${{ steps.create_cn_release.outputs.stdout }} | |
| gh_release_url: ${{ steps.create_gh_release.outputs.url || steps.create_tag.outputs.release_url }} | |
| permissions: | |
| contents: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Read version number | |
| uses: SebRollen/toml-action@v1.0.2 | |
| id: read_version | |
| with: | |
| file: ${{ env.APP_CARGO_TOML }} | |
| field: "package.version" | |
| - name: Prepare release | |
| id: create_tag | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const tag = "cap-v${{ steps.read_version.outputs.value }}"; | |
| const tagRef = `tags/${tag}`; | |
| const TAG_EXISTED = "tag_existed"; | |
| const TAG_NAME = "tag_name"; | |
| const RELEASE_PUBLISHED = "release_published"; | |
| const RELEASE_URL = "release_url"; | |
| core.setOutput(TAG_NAME, tag); | |
| async function main() { | |
| let tagExisted = true; | |
| let tagSha = ""; | |
| let releasePublished = false; | |
| let releaseUrl = ""; | |
| try { | |
| const tagRefResponse = await github.rest.git.getRef({ | |
| ref: tagRef, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| tagExisted = true; | |
| tagSha = tagRefResponse.data.object.sha; | |
| core.notice(`Tag '${tag}' already exists. Reusing it for this release run.`); | |
| } catch (error) { | |
| if ("status" in error && error.status === 404) tagExisted = false; | |
| else throw error; | |
| } | |
| if (!tagExisted) | |
| await github.rest.git.createRef({ | |
| ref: `refs/${tagRef}`, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.sha, | |
| }); | |
| const releases = await github.paginate(github.rest.repos.listReleases, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| per_page: 100, | |
| }); | |
| const release = releases.find((release) => release.tag_name === tag); | |
| if (release) { | |
| releaseUrl = release.html_url; | |
| releasePublished = !release.draft; | |
| if (releasePublished) | |
| throw new Error(`Release '${tag}' is already published: ${releaseUrl}. Bump apps/desktop/src-tauri/Cargo.toml before publishing a new build.`); | |
| else | |
| core.notice(`Draft release '${tag}' already exists. Continuing build and upload.`); | |
| } | |
| if (tagExisted && !releasePublished && tagSha !== context.sha) { | |
| await github.rest.git.updateRef({ | |
| ref: tagRef, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.sha, | |
| force: true, | |
| }); | |
| core.notice(`Updated unpublished tag '${tag}' to ${context.sha}.`); | |
| } | |
| core.setOutput(TAG_EXISTED, tagExisted); | |
| core.setOutput(RELEASE_PUBLISHED, releasePublished); | |
| core.setOutput(RELEASE_URL, releaseUrl); | |
| } | |
| await main(); | |
| - name: Create draft CN release | |
| id: create_cn_release | |
| if: ${{ steps.create_tag.outputs.release_published != 'true' }} | |
| uses: crabnebula-dev/cloud-release@v0 | |
| with: | |
| command: release draft ${{ env.CN_APPLICATION }} ${{ steps.read_version.outputs.value }} --framework tauri | |
| api-key: ${{ secrets.CN_API_KEY }} | |
| - name: Create draft GH release | |
| id: create_gh_release | |
| if: ${{ steps.create_tag.outputs.release_published != 'true' }} | |
| # TODO: Change to stable version when available | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: ${{ steps.read_version.outputs.value }} | |
| tag_name: ${{ steps.create_tag.outputs.tag_name }} | |
| draft: true | |
| generate_release_notes: true | |
| - name: Update Discord interaction | |
| if: ${{ inputs.interactionId != '' && steps.create_tag.outputs.release_published != 'true' }} | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| async function main() { | |
| const token = await core.getIDToken("cap-discord-bot"); | |
| const cnReleaseId = JSON.parse(`${{ steps.create_cn_release.outputs.stdout }}`).id; | |
| const resp = await fetch("https://cap-discord-bot.brendonovich.workers.dev/github-workflow", { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| type: "release-ready", | |
| tag: "${{ steps.create_tag.outputs.tag_name }}", | |
| version: "${{ steps.read_version.outputs.value }}", | |
| releaseUrl: "${{ steps.create_gh_release.outputs.url }}", | |
| interactionId: "${{ inputs.interactionId }}", | |
| cnReleaseId | |
| }), | |
| headers: { | |
| "Content-Type": "application/json", | |
| Authorization: `Bearer ${token}`, | |
| } | |
| }); | |
| if(resp.status !== 200) throw new Error(await resp.text()); | |
| } | |
| main(); | |
| build: | |
| needs: draft | |
| if: ${{ needs.draft.outputs.needs_release == 'true' }} | |
| permissions: | |
| contents: write | |
| actions: read | |
| id-token: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| settings: | |
| - target: x86_64-apple-darwin | |
| runner: macos-latest-xlarge | |
| - target: aarch64-apple-darwin | |
| runner: macos-latest-xlarge | |
| - target: x86_64-pc-windows-msvc | |
| runner: windows-2022 | |
| - target: x86_64-unknown-linux-gnu | |
| runner: ubuntu-24.04 | |
| env: | |
| TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} | |
| TURBO_TEAM: ${{ secrets.TURBO_TEAM }} | |
| runs-on: ${{ matrix.settings.runner }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.draft.outputs.tag_name }} | |
| - name: Install Linux desktop dependencies | |
| if: ${{ runner.os == 'Linux' }} | |
| uses: ./.github/actions/install-desktop-deps | |
| - name: Create API Key File | |
| if: ${{ runner.os == 'macOS' }} | |
| run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8 | |
| - uses: apple-actions/import-codesign-certs@8f3fb608891dd2244cdab3d69cd68c0d37a7fe93 # v2 | |
| if: ${{ runner.os == 'macOS' }} | |
| with: | |
| p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} | |
| p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| - name: Verify certificate | |
| if: ${{ runner.os == 'macOS' }} | |
| run: security find-identity -v -p codesigning ${{ runner.temp }}/build.keychain | |
| - name: Rust setup | |
| uses: dtolnay/rust-toolchain@1.88.0 | |
| with: | |
| targets: ${{ matrix.settings.target }} | |
| - name: Verify Rust toolchain | |
| shell: bash | |
| run: | | |
| rustc -Vv | |
| cargo -V | |
| rustup show active-toolchain | |
| - uses: ./.github/actions/setup-rust-cache | |
| with: | |
| target: ${{ matrix.settings.target }} | |
| - uses: ./.github/actions/setup-js | |
| - name: Create .env file in root | |
| shell: bash | |
| run: | | |
| { | |
| echo "appVersion=${{ needs.draft.outputs.version }}" | |
| echo "VITE_ENVIRONMENT=production" | |
| echo "CAP_DESKTOP_SENTRY_URL=https://6a3b6a09e6ae976c2ad6fff710e88748@o4506859771527168.ingest.us.sentry.io/4508330917101568" | |
| echo "NEXT_PUBLIC_WEB_URL=${{ secrets.NEXT_PUBLIC_WEB_URL }}" | |
| echo 'NEXTAUTH_URL=${{ secrets.NEXT_PUBLIC_WEB_URL }}' | |
| echo 'VITE_POSTHOG_KEY=${{ secrets.VITE_POSTHOG_KEY }}' | |
| echo 'VITE_POSTHOG_HOST=${{ secrets.VITE_POSTHOG_HOST }}' | |
| echo 'VITE_SERVER_URL=${{ secrets.NEXT_PUBLIC_WEB_URL }}' | |
| echo 'RUST_TARGET_TRIPLE=${{ matrix.settings.target }}' | |
| } >> .env | |
| - name: Run cap-setup | |
| shell: bash | |
| run: pnpm -w cap-setup | |
| env: | |
| RUST_TARGET_TRIPLE: ${{ matrix.settings.target }} | |
| APPLE_SIGNING_IDENTITY: ${{ runner.os == 'macOS' && secrets.APPLE_SIGNING_IDENTITY || '' }} | |
| APPLE_KEYCHAIN: ${{ runner.os == 'macOS' && format('{0}/build.keychain', runner.temp) || '' }} | |
| - name: Build desktop binaries | |
| shell: bash | |
| run: | | |
| if [[ "$RUNNER_OS" == "Linux" ]]; then | |
| export CARGO_PROFILE_RELEASE_DEBUG=0 | |
| fi | |
| ./scripts/build-desktop-binaries.sh ${{ matrix.settings.target }} | |
| # The release profile uses fat LTO + full debuginfo, so the final link | |
| # peaks well above the 16GB stock Linux runner and gets OOM-killed | |
| # ("runner received a shutdown signal"). The runner already ships an | |
| # active /swapfile (resizing it fails with "Text file busy"), so add a | |
| # large swapfile on the roomy /mnt disk on top of the existing swap. | |
| # Linux-only; macOS/Windows are unaffected. | |
| - name: Increase swap space (Linux) | |
| if: ${{ runner.os == 'Linux' }} | |
| shell: bash | |
| run: | | |
| sudo swapoff /mnt/swapfile 2>/dev/null || true | |
| sudo rm -f /mnt/swapfile | |
| sudo fallocate -l 16G /mnt/swapfile | |
| sudo chmod 600 /mnt/swapfile | |
| sudo mkswap /mnt/swapfile | |
| sudo swapon /mnt/swapfile | |
| swapon --show | |
| free -h | |
| - name: Build app | |
| working-directory: apps/desktop | |
| run: ${{ runner.os == 'Linux' && 'CARGO_PROFILE_RELEASE_DEBUG=0 ' || '' }}pnpm build:tauri --target ${{ matrix.settings.target }} --config src-tauri/tauri.prod.conf.json ${{ runner.os == 'Windows' && '--bundles nsis' || runner.os == 'Linux' && '--bundles deb --verbose' || '' }} | |
| env: | |
| # https://github.com/tauri-apps/tauri-action/issues/740 | |
| CI: false | |
| LD_LIBRARY_PATH: ${{ runner.os == 'Linux' && format('{0}/target/{1}/release:{0}/target/native-deps/lib', github.workspace, matrix.settings.target) || '' }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # codesigning | |
| APPLE_CERTIFICATE: ${{ runner.os == 'macOS' && secrets.APPLE_CERTIFICATE || '' }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ runner.os == 'macOS' && secrets.APPLE_CERTIFICATE_PASSWORD || '' }} | |
| APPLE_SIGNING_IDENTITY: ${{ runner.os == 'macOS' && secrets.APPLE_SIGNING_IDENTITY || '' }} | |
| # notarization | |
| APPLE_API_ISSUER: ${{ runner.os == 'macOS' && secrets.APPLE_API_ISSUER || '' }} | |
| APPLE_API_KEY: ${{ runner.os == 'macOS' && secrets.APPLE_API_KEY || '' }} | |
| APPLE_API_KEY_PATH: ${{ runner.os == 'macOS' && format('{0}/api.p8', github.workspace) || '' }} | |
| APPLE_KEYCHAIN: ${{ runner.os == 'macOS' && format('{0}/build.keychain', runner.temp) || '' }} | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| RUST_TARGET_TRIPLE: ${{ matrix.settings.target }} | |
| # Guards against the Linux packaging regressions: | |
| # 1. Frontend missing: vinxi must produce apps/desktop/.output/public, | |
| # which Tauri EMBEDS into the binary (it is NOT shipped as a loose | |
| # /usr/lib/Cap/index.html file). A blank webview ships if turbo's cache | |
| # restores an empty .output/public (see @cap/desktop#build outputs in | |
| # turbo.json), so we assert the build output exists and is non-empty. | |
| # 2. FFmpeg soname mismatch: every libav*/libsw* the main binary lists as | |
| # NEEDED must be bundled under /usr/lib/cap/ with the exact same soname. | |
| # The bundled libs come from native-deps (FFmpeg 7); if the binary | |
| # linked system FFmpeg 6 the loader fails at launch. | |
| # 3. Undeclared runtime dependency: a system lib the binary NEEDs that is | |
| # neither bundled nor part of the declared GTK/webkit stack must appear | |
| # in the .deb Depends, or the loader aborts at launch. This is the | |
| # libpipewire-0.3.so.0 crash that shipped in 0.5.2. | |
| - name: Verify Linux deb contents | |
| if: ${{ runner.os == 'Linux' }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # (1) frontend was actually built. Tauri embeds .output/public into the | |
| # binary at build time, so an empty/missing dir => blank webview. | |
| FE="apps/desktop/.output/public/index.html" | |
| if [[ ! -s "$FE" ]]; then | |
| echo "::error::Frontend build output missing/empty ($FE) - webview would be blank." | |
| ls -la apps/desktop/.output/public 2>/dev/null || echo "(no .output/public dir)" | |
| exit 1 | |
| fi | |
| echo "Frontend build output OK ($FE, $(wc -c < "$FE") bytes)" | |
| UNSUPPORTED_ARTIFACT="$(find target/${{ matrix.settings.target }}/release/bundle -type f \( -name '*.AppImage' -o -name '*.rpm' \) -print -quit)" | |
| if [[ -n "$UNSUPPORTED_ARTIFACT" ]]; then | |
| echo "::error::Unexpected Linux non-deb artifact produced: $UNSUPPORTED_ARTIFACT" | |
| exit 1 | |
| fi | |
| DEB="$(find target/${{ matrix.settings.target }}/release/bundle/deb -name '*.deb' | head -n1)" | |
| if [[ -z "$DEB" ]]; then echo "::error::No .deb produced"; exit 1; fi | |
| if [[ ! -s "$DEB.sig" ]]; then echo "::error::No .deb updater signature produced next to $DEB"; exit 1; fi | |
| echo "Inspecting $DEB" | |
| WORK="$(mktemp -d)" | |
| dpkg-deb -x "$DEB" "$WORK" | |
| # Best-effort confirmation that the SPA actually got embedded into the | |
| # binary (Tauri stores asset path keys as plaintext). Informational only. | |
| if strings "$WORK/usr/bin/Cap" 2>/dev/null | grep -q "index.html"; then | |
| echo "Binary appears to embed the frontend (index.html key present)" | |
| else | |
| echo "::warning::Could not confirm embedded frontend key in binary (asset format may differ)" | |
| fi | |
| # (2) every FFmpeg soname the binary NEEDs is bundled | |
| BIN="$WORK/usr/bin/Cap" | |
| NEEDED="$(objdump -p "$BIN" | awk '/NEEDED/{print $2}' | grep -E '^lib(av|sw|postproc)' || true)" | |
| echo "Binary NEEDs FFmpeg sonames:"; echo "${NEEDED:-(none)}" | |
| echo "Bundled FFmpeg libs:"; ls -1 "$WORK/usr/lib/cap" 2>/dev/null || true | |
| MISSING=0 | |
| for so in $NEEDED; do | |
| if [[ ! -f "$WORK/usr/lib/cap/$so" ]]; then | |
| echo "::error::Binary NEEDs $so but it is not bundled under /usr/lib/cap/" | |
| MISSING=1 | |
| fi | |
| done | |
| if [[ "$MISSING" -ne 0 ]]; then | |
| echo "::error::FFmpeg soname mismatch between binary and bundled libs." | |
| exit 1 | |
| fi | |
| echo "FFmpeg soname bundle OK" | |
| # (3) runtime libs that are NOT bundled and NOT pulled in by the | |
| # declared GTK/webkit stack must be declared in the .deb Depends, or | |
| # the dynamic loader aborts at launch (the libpipewire-0.3.so.0 crash | |
| # in 0.5.2). Assert the curated set of such sonames the binary links. | |
| DEPENDS="$(dpkg-deb -f "$DEB" Depends || true)" | |
| echo "Declared Depends: ${DEPENDS:-(none)}" | |
| NEEDED_ALL="$(objdump -p "$BIN" | awk '/NEEDED/{print $2}')" | |
| # soname -> a Depends token that satisfies it. The alsa token is a | |
| # substring so it matches both libasound2 and libasound2t64. | |
| declare -A SONAME_DEP=( | |
| [libpipewire-0.3.so.0]="libpipewire-0.3-0" | |
| [libasound.so.2]="libasound2" | |
| ) | |
| DEP_MISSING=0 | |
| for so in "${!SONAME_DEP[@]}"; do | |
| if echo "$NEEDED_ALL" | grep -qx "$so"; then | |
| tok="${SONAME_DEP[$so]}" | |
| if ! echo "$DEPENDS" | grep -q "$tok"; then | |
| echo "::error::Binary NEEDs $so but '$tok' is not declared in .deb Depends (add it to tauri.conf.json bundle.linux.deb.depends)." | |
| DEP_MISSING=1 | |
| else | |
| echo "Runtime dep OK: $so -> $tok" | |
| fi | |
| fi | |
| done | |
| if [[ "$DEP_MISSING" -ne 0 ]]; then | |
| echo "::error::Undeclared runtime dependency in .deb Depends." | |
| exit 1 | |
| fi | |
| echo "Runtime dependency declarations OK" | |
| - name: Upload unsigned Windows installer | |
| if: ${{ runner.os == 'Windows' }} | |
| id: upload_unsigned_windows_installer | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: unsigned-windows-installer | |
| path: target/${{ matrix.settings.target }}/release/bundle/nsis/*.exe | |
| if-no-files-found: error | |
| - name: Submit SignPath signing request | |
| if: ${{ runner.os == 'Windows' }} | |
| id: submit_signpath_signing_request | |
| uses: signpath/github-action-submit-signing-request@v1 | |
| with: | |
| api-token: ${{ secrets.SIGNPATH_API_TOKEN }} | |
| organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }} | |
| project-slug: ${{ secrets.SIGNPATH_PROJECT_SLUG }} | |
| signing-policy-slug: ${{ secrets.SIGNPATH_SIGNING_POLICY_SLUG }} | |
| artifact-configuration-slug: ${{ secrets.SIGNPATH_ARTIFACT_CONFIGURATION_SLUG }} | |
| github-artifact-id: ${{ steps.upload_unsigned_windows_installer.outputs.artifact-id }} | |
| wait-for-completion: true | |
| output-artifact-directory: signed-windows-installer | |
| - name: Restore signed Windows installer | |
| if: ${{ runner.os == 'Windows' }} | |
| shell: pwsh | |
| run: | | |
| $signedDir = "signed-windows-installer" | |
| $bundleDir = "target/${{ matrix.settings.target }}/release/bundle/nsis" | |
| if (-not (Test-Path $signedDir)) { | |
| throw "Signed artifact directory '$signedDir' not found." | |
| } | |
| $executables = Get-ChildItem -Path $signedDir -Filter *.exe -Recurse | |
| if (-not $executables) { | |
| throw "No signed executables found in '$signedDir'." | |
| } | |
| Write-Host "Copying signed executables to: $bundleDir" | |
| Copy-Item -Path (Join-Path $signedDir '*.exe') -Destination $bundleDir -Force | |
| Write-Host "Files in bundle directory after signing:" | |
| Get-ChildItem -Path $bundleDir -Filter *.exe | ForEach-Object { Write-Host " - $($_.Name)" } | |
| - name: Re-sign Windows installer for Tauri updater | |
| if: ${{ runner.os == 'Windows' }} | |
| shell: bash | |
| working-directory: apps/desktop | |
| run: | | |
| BUNDLE_DIR="../../target/${{ matrix.settings.target }}/release/bundle/nsis" | |
| for exe in "$BUNDLE_DIR"/*.exe; do | |
| echo "Re-signing $(basename "$exe") for Tauri updater..." | |
| rm -f "${exe}.sig" | |
| pnpm tauri signer sign -k "$TAURI_SIGNING_PRIVATE_KEY" -p "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" "$exe" | |
| done | |
| echo "Signature files after re-signing:" | |
| ls -la "$BUNDLE_DIR"/*.sig | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| - name: Upload assets | |
| if: ${{ runner.os != 'Linux' }} | |
| uses: crabnebula-dev/cloud-release@v0 | |
| with: | |
| working-directory: apps/desktop | |
| command: release upload ${{ env.CN_APPLICATION }} "${{ needs.draft.outputs.version }}" --framework tauri | |
| api-key: ${{ secrets.CN_API_KEY }} | |
| env: | |
| TAURI_BUNDLE_PATH: ../.. | |
| - name: Upload Linux deb asset | |
| if: ${{ runner.os == 'Linux' }} | |
| uses: crabnebula-dev/cloud-release@v0 | |
| with: | |
| working-directory: apps/desktop | |
| command: release upload ${{ env.CN_APPLICATION }} "${{ needs.draft.outputs.version }}" --file "../../target/${{ matrix.settings.target }}/release/bundle/deb/Cap_${{ needs.draft.outputs.version }}_amd64.deb" --signature "../../target/${{ matrix.settings.target }}/release/bundle/deb/Cap_${{ needs.draft.outputs.version }}_amd64.deb.sig" --public-platform deb-x86_64 --update-platform linux-x86_64-deb | |
| api-key: ${{ secrets.CN_API_KEY }} | |
| - uses: matbour/setup-sentry-cli@8ef22a4ff03bcd1ebbcaa3a36a81482ca8e3872e | |
| - name: Upload debug symbols to Sentry | |
| if: ${{ runner.os == 'macOS' }} | |
| shell: bash | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| run: | | |
| sentry-cli debug-files upload -o ${{ env.SENTRY_ORG }} -p ${{ env.SENTRY_PROJECT }} target/Cap.dSYM | |
| - name: Upload debug symbols to Sentry | |
| if: ${{ runner.os == 'Windows' }} | |
| shell: bash | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| run: | | |
| sentry-cli debug-files upload -o ${{ env.SENTRY_ORG }} -p ${{ env.SENTRY_PROJECT }} target/${{ matrix.settings.target }}/release/cap_desktop.pdb | |
| done: | |
| needs: [draft, build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| steps: | |
| - name: Send Discord notification | |
| if: ${{ inputs.interactionId != '' }} | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| async function main() { | |
| const token = await core.getIDToken("cap-discord-bot"); | |
| const cnReleaseId = JSON.parse(`${{ needs.draft.outputs.cn_release_stdout }}`).id; | |
| const resp = await fetch("https://cap-discord-bot.brendonovich.workers.dev/github-workflow", { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| type: "release-done", | |
| interactionId: "${{ inputs.interactionId }}", | |
| version: "${{ needs.draft.outputs.version }}", | |
| releaseUrl: "${{ needs.draft.outputs.gh_release_url }}", | |
| cnReleaseId | |
| }), | |
| headers: { | |
| "Content-Type": "application/json", | |
| Authorization: `Bearer ${token}`, | |
| } | |
| }); | |
| if(resp.status !== 200) throw new Error(await resp.text()); | |
| } | |
| main(); |