Skip to content

Release Obsidian plugin #99

Release Obsidian plugin

Release Obsidian plugin #99

Workflow file for this run

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