Merge pull request #20 from ciphera-net/staging
[PULSE-28] Changelog / release process
This commit is contained in:
21
CHANGELOG.md
Normal file
21
CHANGELOG.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to Pulse (frontend and product) are documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and Pulse uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) with a **0.x.y** version scheme while in initial development. The leading `0` indicates that the public API and behaviour may change until we release **1.0.0**.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- No unreleased changes yet; add items here as you work toward the next release.
|
||||
|
||||
## [0.1.0] - 2026-02-09
|
||||
|
||||
### Added
|
||||
|
||||
- Initial changelog and release process (PULSE-28).
|
||||
- Release documentation in `docs/releasing.md` and optional changelog check script.
|
||||
|
||||
---
|
||||
|
||||
[Unreleased]: https://github.com/ciphera-net/pulse/compare/v0.1.0...HEAD
|
||||
[0.1.0]: https://github.com/ciphera-net/pulse/releases/tag/v0.1.0
|
||||
@@ -60,6 +60,10 @@ npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
## Releasing
|
||||
|
||||
Changelog and release process (who updates it, when, how to tag, deploy) are documented in [docs/releasing.md](docs/releasing.md). Versions use **0.x.y** while in initial development; the single product changelog is [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
## Design System
|
||||
|
||||
The frontend follows the Ciphera design language:
|
||||
|
||||
46
app/changelog/page.tsx
Normal file
46
app/changelog/page.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Changelog - Pulse',
|
||||
description: 'Release history and notable changes for Pulse, privacy-first web analytics.',
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads CHANGELOG.md from the project root and renders it on the /changelog page.
|
||||
* Content is loaded at build time; redeploy to show new releases.
|
||||
*/
|
||||
export default function ChangelogPage() {
|
||||
const changelogPath = path.join(process.cwd(), 'CHANGELOG.md')
|
||||
const content = fs.readFileSync(changelogPath, 'utf-8')
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-3xl px-4 sm:px-6 py-8">
|
||||
<h1 className="text-3xl font-bold text-neutral-900 dark:text-white mb-2">
|
||||
Changelog
|
||||
</h1>
|
||||
<p className="text-neutral-600 dark:text-neutral-400 mb-8 text-sm">
|
||||
Release history and notable changes. We use{' '}
|
||||
<a
|
||||
href="https://keepachangelog.com/en/1.1.0/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-brand-orange hover:underline"
|
||||
>
|
||||
Keep a Changelog
|
||||
</a>{' '}
|
||||
and <strong>0.x.y</strong> versioning while in initial development.
|
||||
</p>
|
||||
<article
|
||||
className="prose prose-neutral dark:prose-invert max-w-none
|
||||
prose-headings:font-semibold prose-headings:tracking-tight
|
||||
prose-a:text-brand-orange prose-a:no-underline hover:prose-a:underline
|
||||
prose-ul:my-4 prose-li:my-0.5"
|
||||
>
|
||||
<ReactMarkdown>{content}</ReactMarkdown>
|
||||
</article>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -26,6 +26,7 @@ const footerLinks = {
|
||||
{ name: 'Contact', href: 'https://ciphera.net/contact', external: true },
|
||||
],
|
||||
resources: [
|
||||
{ name: 'Changelog', href: '/changelog', external: false },
|
||||
{ name: 'Installation', href: '/installation', external: false },
|
||||
{ name: 'Integrations', href: '/integrations', external: false },
|
||||
{ name: 'Documentation', href: 'https://docs.ciphera.net', external: true },
|
||||
@@ -55,6 +56,9 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
<Component href="/about" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
|
||||
Why {appName}
|
||||
</Component>
|
||||
<Component href="/changelog" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
|
||||
Changelog
|
||||
</Component>
|
||||
<Component href="/pricing" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
|
||||
Pricing
|
||||
</Component>
|
||||
|
||||
54
docs/releasing.md
Normal file
54
docs/releasing.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Releasing Pulse
|
||||
|
||||
This document describes how to cut a release for Pulse (changelog, tagging, and deploy). It applies to the **pulse-frontend** repo (GitHub: [ciphera-net/pulse](https://github.com/ciphera-net/pulse)). The backend (pulse-backend) can be tagged separately if you version it; the single product changelog lives here.
|
||||
|
||||
## Who updates the changelog
|
||||
|
||||
The person cutting the release (or the PR author merging the release PR) is responsible for updating `CHANGELOG.md` before the tag is created. No release tag should be pushed without a corresponding changelog entry.
|
||||
|
||||
## When to update
|
||||
|
||||
- **Before** creating the git tag for the release.
|
||||
- Move items from the `[Unreleased]` section into a new version section (e.g. `[0.2.0] - YYYY-MM-DD`), then clear or repopulate `[Unreleased]` as needed.
|
||||
- Update the comparison links at the bottom of `CHANGELOG.md` (e.g. add `[0.2.0]: ...` and set `[Unreleased]` to `compare/v0.2.0...HEAD`).
|
||||
|
||||
## Version numbering (0.x.y)
|
||||
|
||||
While Pulse is in initial development we use **0.x.y**:
|
||||
|
||||
- **0** = initial development; we may change behaviour or “API” without a new major version.
|
||||
- **x** (minor) = new features or small breaking changes; bump for a release that adds functionality.
|
||||
- **y** (patch) = bug fixes only; bump for a release that only fixes bugs.
|
||||
|
||||
When we are ready to commit to stability we release **1.0.0** and then follow strict [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## How to tag a release
|
||||
|
||||
1. Ensure `CHANGELOG.md` has an entry for the new version (see **When to update** above).
|
||||
2. (Optional) Run the changelog check so the version in the tag matches an entry in the changelog:
|
||||
```bash
|
||||
./scripts/check-changelog.sh 0.2.0
|
||||
```
|
||||
3. Commit any changelog (and link) updates, merge to the target branch (usually `main` for production).
|
||||
4. Create an annotated tag (use the same version as in the changelog, with a `v` prefix):
|
||||
```bash
|
||||
git tag -a v0.2.0 -m "Release 0.2.0"
|
||||
git push origin v0.2.0
|
||||
```
|
||||
|
||||
Use the same version number in the tag as in the changelog (e.g. `v0.2.0` ↔ `[0.2.0]`).
|
||||
|
||||
## Deploy (staging and production)
|
||||
|
||||
- **Staging:** Push to the `staging` branch; Coolify deploys from `staging` to the staging environment.
|
||||
- **Production:** Only the `main` branch is deployed to production. Merge `staging` → `main` when ready, then push. Tagging (e.g. `v0.2.0`) is done from `main` after the release commit is merged; Coolify auto-deploys on push to `main`.
|
||||
|
||||
So the usual flow is: merge release work (including changelog) to `main`, then create and push the tag from `main`.
|
||||
|
||||
## Checklist for each release
|
||||
|
||||
- [ ] Changelog updated: new version section with date, and `[Unreleased]` updated.
|
||||
- [ ] Bottom-of-file comparison links updated in `CHANGELOG.md`.
|
||||
- [ ] (Optional) `./scripts/check-changelog.sh <version>` passes.
|
||||
- [ ] Changes merged to `main`.
|
||||
- [ ] Tag created and pushed: `git tag -a vX.Y.Z -m "Release X.Y.Z"` then `git push origin vX.Y.Z`.
|
||||
1177
package-lock.json
generated
1177
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pulse-frontend",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -24,6 +24,7 @@
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-simple-maps": "^3.0.0",
|
||||
"recharts": "^2.15.0",
|
||||
"sonner": "^2.0.7",
|
||||
|
||||
31
scripts/check-changelog.sh
Executable file
31
scripts/check-changelog.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# * Verifies that CHANGELOG.md has an entry for the given version (e.g. 0.1.0 or v0.1.0).
|
||||
# * Use before tagging a release; can be wired into CI.
|
||||
# * Usage: ./scripts/check-changelog.sh <version>
|
||||
|
||||
set -e
|
||||
|
||||
VERSION="${1:-}"
|
||||
CHANGELOG="${CHANGELOG:-CHANGELOG.md}"
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Usage: $0 <version> (e.g. 0.1.0 or v0.1.0)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Strip leading 'v' if present for consistent matching
|
||||
NORMALIZED="${VERSION#v}"
|
||||
|
||||
if [ ! -f "$CHANGELOG" ]; then
|
||||
echo "Error: $CHANGELOG not found (run from repo root)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Keep a Changelog style: ## [1.0.0] or ## [1.0.0] - 2026-02-09
|
||||
if grep -qE "^## \[${NORMALIZED}\]" "$CHANGELOG"; then
|
||||
echo "OK: CHANGELOG has an entry for version $NORMALIZED"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Error: CHANGELOG.md has no entry for version $NORMALIZED (expected a line like '## [$NORMALIZED] - YYYY-MM-DD')" >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user