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
51 changes: 51 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Release

on:
push:
branches:
- main
- dev

permissions:
contents: write
issues: write
pull-requests: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
name: Release
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: yarn
cache-dependency-path: frontend/yarn.lock

- name: Install dependencies
run: yarn install --frozen-lockfile

# Gate the release: a push to main/dev with failing unit tests must not
# cut a version. (E2E is omitted here — it needs Playwright browsers and
# a live backend; PRs already run the full suite via test.yml.)
- name: Unit tests
run: yarn test

- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn release
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ This repo uses **semantic versioning**, and commit titles follow **Conventional

Don't dress a real feature as `refactor`/`chore` (it would skip a release) or inflate a refactor into `feat` (it over-bumps). If you squash-merge a PR, the **PR title** becomes the commit message, so it must follow the same convention.

> Release automation is **not** wired up in this repo yet (no `semantic-release`, no tags, `server/package.json` is `0.0.0`) — the convention currently records the *intended* bump. The sibling **subturtle-extension-apps** repo enforces the identical mapping automatically via `semantic-release`.
**Link the ClickUp task:** when the work has a task id, append it as `#<taskId>` to the commit subject — and to the **PR title** so it survives a squash-merge — e.g. `feat: show dashboard version in a global footer #86exqazkq`. Use the bare id (not the `CU-` branch prefix). The type prefix still drives the version bump; the `#<taskId>` just keeps `git log` greppable and linkable back to ClickUp.

> Release automation is wired up for the **frontend** via `semantic-release` ([frontend/release.config.cjs](frontend/release.config.cjs), [.github/workflows/release.yml](.github/workflows/release.yml)) — it owns the version in [frontend/package.json](frontend/package.json) and cuts a tagged release on pushes to `dev`/`main` that contain releasable commits. The **server** has no release pipeline yet (`server/package.json` stays `0.0.0`). The sibling **subturtle-extension-apps** repo enforces the identical mapping via its own `semantic-release` setup.

## Gotchas

Expand Down
14 changes: 14 additions & 0 deletions frontend/components/partial/AppVersionFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<div v-if="version" class="px-4 py-3 text-center text-xs text-gray-400 dark:text-gray-500">
{{ t('app.version', { version }) }}
</div>
</template>

<script setup lang="ts">
const { t } = useI18n();
const config = useRuntimeConfig();

// Baked in at build time from package.json (see nuxt.config.ts). Owned by
// semantic-release, so it reflects the latest released dashboard version.
const version = computed(() => config.public.APP_VERSION as string);
</script>
4 changes: 4 additions & 0 deletions frontend/layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<NuxtPage />
</div>
</template>

<template #footer>
<PartialAppVersionFooter />
</template>
</DashboardShell>

<!-- Single global "plan limit reached" modal. The modular-rest interceptor
Expand Down
3 changes: 3 additions & 0 deletions frontend/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"app": {
"version": "Version {version}"
},
"bundle": {
"nav": "Phrase Bundles",
"list": "Bundle List",
Expand Down
4 changes: 4 additions & 0 deletions frontend/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { version as APP_VERSION } from './package.json';

export default defineNuxtConfig({
compatibilityDate: '2024-10-13',
devtools: { enabled: true },
Expand All @@ -17,6 +19,8 @@ export default defineNuxtConfig({
MIXPANEL_API_HOST: process.env.NUXT_PUBLIC_MIXPANEL_API_HOST,
chromeWebStoreUrl: process.env.NUXT_PUBLIC_CHROME_WEB_STORE_URL || 'https://chromewebstore.google.com/detail/PLACEHOLDER',
STRIPE_PUBLISHABLE_KEY: process.env.NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
// Baked in at build time from package.json (owned by semantic-release).
APP_VERSION,
},
},

Expand Down
9 changes: 8 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"private": true,
"name": "subturtle-dashboard",
"version": "0.0.0",
"type": "module",
"scripts": {
"build": "nuxt build",
Expand All @@ -18,7 +20,9 @@
"test:coverage:watch": "vitest --coverage",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui",
"test:ui:run": "vitest --ui --run"
"test:ui:run": "vitest --ui --run",
"release": "semantic-release",
"release:dry": "semantic-release --dry-run --no-ci"
},
"devDependencies": {
"@cssninja/nuxt-toaster": "^0.3.12",
Expand All @@ -29,6 +33,8 @@
"@pinia/testing": "^1.0.2",
"@playwright/test": "^1.54.1",
"@rollup/plugin-alias": "^3.1.9",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/typography": "^0.5.7",
"@testing-library/vue": "^8.1.0",
Expand All @@ -43,6 +49,7 @@
"prettier": "^2.8.0",
"prettier-plugin-tailwindcss": "^0.2.0",
"sass-embedded": "^1.83.4",
"semantic-release": "^25.0.3",
"tailwindcss": "^3.4.1",
"typescript": "^4.6.4",
"vitest": "^1.0.0",
Expand Down
35 changes: 35 additions & 0 deletions frontend/release.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const { execSync } = require('node:child_process');

function detectBranch() {
if (process.env.GITHUB_REF_NAME) return process.env.GITHUB_REF_NAME;
try {
return execSync('git rev-parse --abbrev-ref HEAD', {
stdio: ['ignore', 'pipe', 'ignore'],
})
.toString()
.trim();
} catch {
return 'main';
}
}

const isDev = detectBranch() === 'dev';
const changelogFile = isDev ? 'CHANGELOG-DEV.md' : 'CHANGELOG.md';

module.exports = {
branches: ['main', { name: 'dev', prerelease: true }],
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
['@semantic-release/changelog', { changelogFile }],
['@semantic-release/npm', { npmPublish: false }],
[
'@semantic-release/git',
{
assets: ['package.json', changelogFile],
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
},
],
'@semantic-release/github',
],
};
Loading
Loading