Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Automated releases, driven by conventional commits.
#
# Every push to main, release-please recomputes the next version from the
# commits since the last tag (`fix:` → patch, `feat:` → minor, `!`/BREAKING →
# major, all within the prerelease line configured in release-please-config.json)
# and keeps a "chore(main): release <version>" PR open with the bumped
# package.json / manifest.json / manifest-beta.json and a generated CHANGELOG.md.
# Merging that PR is the release: release-please tags it and publishes the
# GitHub release, then the jobs below attach the built plugin files and record
# the version in versions.json.
#
# Nothing is released by merging an ordinary PR — only by merging the release
# PR — so a docs-only merge cannot mint a version.
#
# The tag release-please creates does NOT fire .github/workflows/release.yml:
# GitHub does not re-trigger workflows for refs pushed with GITHUB_TOKEN. That
# file remains the manual escape hatch for a hand-pushed tag; this one is the
# automated path. Keep the two in sync if the build or the asset list changes.
name: Release Please

on:
push:
branches: ["main"]

permissions:
contents: write
pull-requests: write

jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
version: ${{ steps.release.outputs.version }}
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{ secrets.GITHUB_TOKEN }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

# The release exists but is empty until this runs: Obsidian installs a plugin
# from these three files, so a release without them is unusable.
publish-assets:
needs: release-please
if: needs.release-please.outputs.release_created == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: ${{ needs.release-please.outputs.tag_name }}

- name: Use Node.js 20.x
uses: actions/setup-node@v5
with:
node-version: "20.x"
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Build plugin
run: npm run build

# Same assertion release.yml makes: manifest.json ships inside the release
# and Obsidian trusts its version field, so a drift between it and the tag
# would install as the wrong version.
- name: Verify manifest version matches tag
run: |
tag="${{ needs.release-please.outputs.tag_name }}"
manifest_version=$(node -p "require('./manifest.json').version")
if [ "$tag" != "$manifest_version" ]; then
echo "::error::Tag '$tag' does not match manifest.json version '$manifest_version'."
exit 1
fi

- name: Attach plugin files to the release
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
gh release upload "${{ needs.release-please.outputs.tag_name }}" \
main.js manifest.json styles.css --clobber

# versions.json maps every published plugin version to the minimum Obsidian
# version it needs. release-please cannot write it — the key is the version
# itself, not a fixed path — so version-bump.mjs (the same script the manual
# `npm version` flow uses) appends the entry afterwards. Obsidian reads this
# file from the default branch, not from the release, so landing it one commit
# after the tag is fine.
record-version:
needs: [release-please, publish-assets]
if: needs.release-please.outputs.release_created == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: main

- name: Use Node.js 20.x
uses: actions/setup-node@v5
with:
node-version: "20.x"

- name: Record the release in versions.json
env:
npm_package_version: ${{ needs.release-please.outputs.version }}
run: node version-bump.mjs

- name: Commit if anything changed
run: |
if git diff --quiet; then
echo "versions.json already records ${{ needs.release-please.outputs.version }}."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add manifest.json manifest-beta.json versions.json
git commit -m "chore: record ${{ needs.release-please.outputs.version }} in versions.json"
git push origin main
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# The manual release path: publishes whatever tag you push by hand, after
# `npm version <x.y.z>`. The automated path is .github/workflows/release-please.yml,
# which tags and publishes when its release PR is merged — a tag it creates does
# not reach this workflow (GitHub does not re-trigger on GITHUB_TOKEN pushes), so
# the two cannot both publish one release. Keep the build and asset list here in
# step with that file.
name: Release

on:
Expand Down
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "2.4.0-beta.3"
}
26 changes: 20 additions & 6 deletions MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,26 @@ and skips entirely when no bundle is installed.

- Beta channel: install via [BRAT](https://github.com/TfTHacker/obsidian42-brat) against this repo;
BRAT reads `manifest-beta.json`.
- Cut a release: `npm version <x.y.z[-beta.N]>` → `version-bump.mjs` syncs `manifest.json` +
`versions.json` (and `manifest-beta.json`) → push the tag. `.github/workflows/release.yml` verifies
the tag equals the manifest version and publishes `main.js`, `manifest.json`, `styles.css`. A `-`
in the tag marks it a GitHub prerelease.
- Keep `manifest.json`, `manifest-beta.json`, and `package.json` versions in sync — the release
workflow fails the build if the tag and `manifest.json` disagree.
- **Normal path — merge the release PR.** Every push to `main`,
`.github/workflows/release-please.yml` recomputes the next version from the conventional commits
since the last tag and keeps a `chore(main): release <version>` PR open, containing the bumped
`package.json` / `manifest.json` / `manifest-beta.json` and a generated `CHANGELOG.md`. Merging
that PR *is* the release: it tags, publishes the GitHub release, attaches `main.js`,
`manifest.json`, `styles.css`, and appends the `versions.json` entry. Merging any other PR never
cuts a version.
- **Write commit subjects release-please can read.** `fix:` → patch, `feat:` → minor, `!` or a
`BREAKING CHANGE:` footer → major — all within the prerelease line configured in
`release-please-config.json` (currently `2.4.0-beta.N`). To pin a version by hand, put
`Release-As: 2.5.0` in a commit body. To graduate the beta line to a stable `2.4.0`, drop
`"prerelease": true` (and `"versioning": "prerelease"`) from that config in the same PR.
- **Manual path — push a tag.** `npm version <x.y.z[-beta.N]>` → `version-bump.mjs` syncs
`manifest.json` + `versions.json` (and `manifest-beta.json`) → push the tag.
`.github/workflows/release.yml` verifies the tag equals the manifest version and publishes the
same three files. A `-` in the tag marks it a GitHub prerelease. Use this only when you need a
release the commit history would not produce; afterwards set `.release-please-manifest.json` to
the version you published, or release-please will keep proposing it.
- Keep `manifest.json`, `manifest-beta.json`, and `package.json` versions in sync — both release
workflows fail the build if the tag and `manifest.json` disagree.

## Localization (i18n)

Expand Down
31 changes: 31 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"release-type": "node",
"packages": {
".": {
"package-name": "paperout-to-authors",
"extra-files": [
{ "type": "json", "path": "manifest.json", "jsonpath": "$.version" },
{ "type": "json", "path": "manifest-beta.json", "jsonpath": "$.version" }
]
}
},
"include-v-in-tag": false,
"include-component-in-tag": false,
"versioning": "prerelease",
"prerelease": true,
"prerelease-type": "beta",
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance" },
{ "type": "refactor", "section": "Refactoring" },
{ "type": "docs", "section": "Documentation" },
{ "type": "revert", "section": "Reverts" },
{ "type": "build", "section": "Build & Tooling" },
{ "type": "ci", "section": "Build & Tooling" },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "style", "section": "Styling", "hidden": true },
{ "type": "chore", "section": "Chores", "hidden": true }
]
}