Release Obsidian plugin #99
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 Obsidian plugin | |
| on: | |
| push: | |
| tags: | |
| - '*' | |
| jobs: | |
| build: | |
| # Publishing a draft from the GitHub UI while it still carries the | |
| # placeholder name creates a real `untagged-<hash>` tag, which would | |
| # re-trigger this workflow and fail on "tag_name already exists" | |
| # (2.1.1). Those pushes are never a release; skip them outright. | |
| if: ${{ !startsWith(github.ref_name, 'untagged-') }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| # Required by attest-build-provenance to mint the signing certificate. | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | |
| with: | |
| bun-version-file: .bun-version | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build plugin | |
| run: bun run build | |
| # Signed provenance for the two built artifacts, so users can verify | |
| # they came from this repo and workflow rather than a hand-built | |
| # bundle: gh attestation verify main.js --repo s2b-dev/smart-second-brain | |
| # manifest.json is committed source, not a build output, so it is | |
| # not attested — git history is already its provenance. | |
| - name: Attest build provenance | |
| uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4 | |
| with: | |
| subject-path: | | |
| build/prod/main.js | |
| build/prod/styles.css | |
| # The release is created as a draft so the maintainer can attach | |
| # release notes and publish it by hand. If a DRAFT for the tag | |
| # already exists (a re-run, or a tag re-pointed before publishing), | |
| # replace its assets in place: `gh release create` would either fail | |
| # on the existing tag or silently mint a second draft that only shows | |
| # up via the API. A PUBLISHED release is never touched — users may | |
| # already have installed its bundle — so that case fails loudly, and | |
| # a draft that gets published mid-upload is detected afterwards. | |
| # Only a 404 from the lookup means "no release yet"; any other lookup | |
| # failure (auth, rate limit, outage) also fails rather than creating. | |
| - name: Create or update draft release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| tag="${GITHUB_REF#refs/tags/}" | |
| assets=(build/prod/main.js manifest.json build/prod/styles.css) | |
| if lookup=$(gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${tag}" 2>&1); then | |
| if [ "$(jq -r .draft <<<"$lookup")" != "true" ]; then | |
| echo "::error::Release $tag is already published; refusing to replace its assets." | |
| exit 1 | |
| fi | |
| echo "Draft release $tag exists; replacing its assets." | |
| gh release upload "$tag" "${assets[@]}" --clobber | |
| # GitHub has no conditional upload, so a maintainer publishing | |
| # the draft during the seconds between the check above and the | |
| # upload cannot be prevented — only detected. Re-check and fail | |
| # loudly so a published release with swapped assets is never a | |
| # silent green run. | |
| if [ "$(gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${tag}" --jq .draft)" != "true" ]; then | |
| echo "::error::Release $tag was published while its assets were being replaced; verify the published bundle." | |
| exit 1 | |
| fi | |
| elif grep -q "HTTP 404" <<<"$lookup"; then | |
| gh release create "$tag" \ | |
| --title="$tag" \ | |
| --draft \ | |
| "${assets[@]}" | |
| else | |
| echo "::error::Could not look up release $tag: $lookup" | |
| exit 1 | |
| fi |