Skip to content
Closed
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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ jobs:
# The top CHANGELOG.md heading must be exactly `## <package.json version>` (publish.yml takes
# the GitHub Release notes from that line). Into release/** a `## <x.y.z> (unreleased)`
# heading is accepted too. The target is the PR's base branch, or the pushed branch (main)
# when publish.yml calls this.
# when publish.yml calls this. Dependabot PRs (identified by the PR author, which only
# Dependabot can be, not the branch name) skip the version bump and ship with the next release.
- name: Check the CHANGELOG.md heading
env:
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || '' }}
PR_AUTHOR: ${{ github.event_name == 'pull_request' && github.event.pull_request.user.login || '' }}
run: node scripts/check-changelog-heading.mjs
# pnpm-workspace.yaml enforces the build allowlist and the 7-day release-age cooldown.
- run: pnpm install --frozen-lockfile
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to `glassnode-terminal` are documented here. The project fol
[semver](https://semver.org/); see [CONTRIBUTING.md](./CONTRIBUTING.md) for how versions and this
file are updated.

## 0.2.5

- CI no longer requires a version bump on Dependabot PRs: their dependency updates merge without
publishing and ship with the next release.
- Raise the transitive dev dependency `source-map-js` to 1.2.2 (GHSA-68fv-2mgg-jv7q), which
Dependabot could not update in the pnpm lockfile.

## 0.2.4

- Add repository owners in `CODEOWNERS` so GitHub can request ownership reviews automatically.
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Interactive TUI (Terminal User Interface) for Glassnode on-chain crypto data, bu

Follow [semver](https://semver.org/) (major: breaking for users — removed flags/env vars, changed defaults, higher Node floor; minor: new features; patch: fixes, docs, dependency bumps, refactors).

**Every change** (except PRs into `release/**` branches, which still add a CHANGELOG entry) MUST:
**Every change** (except PRs into `release/**` branches, which still add a CHANGELOG entry, and Dependabot PRs, which ship with the next release) MUST:

1. Bump `version` in `package.json`
2. Add a `## <version>` entry at the top of `CHANGELOG.md`
Expand All @@ -76,7 +76,7 @@ The `version` in `package.json` is exactly what gets published: CI never bumps i

## CI

- `.github/workflows/ci.yml` runs on PRs into `main` and `release/**`, and `publish.yml` calls it (`workflow_call`) as its `verify` job: the CHANGELOG heading check (`scripts/check-changelog-heading.mjs`: the top heading must be exactly `## <package.json version>`; into `release/**`, `## <x.y.z> (unreleased)` is also accepted), install, build, tests and a CLI smoke test, on Node 22 and 24 (`test (22)`, `test (24)` are the required checks). PRs into `main` additionally require a version greater than the base commit (`BASE_SHA`) and nonempty release notes.
- `.github/workflows/ci.yml` runs on PRs into `main` and `release/**`, and `publish.yml` calls it (`workflow_call`) as its `verify` job: the CHANGELOG heading check (`scripts/check-changelog-heading.mjs`: the top heading must be exactly `## <package.json version>`; into `release/**`, `## <x.y.z> (unreleased)` is also accepted), install, build, tests and a CLI smoke test, on Node 22 and 24 (`test (22)`, `test (24)` are the required checks). PRs into `main` additionally require a version greater than the base commit (`BASE_SHA`) and nonempty release notes, except PRs authored by `dependabot[bot]` (`PR_AUTHOR`).
- Every action is pinned by full commit SHA with a `# vX.Y.Z` comment, never a movable tag. To bump one, resolve the tag with `gh api repos/<owner>/<repo>/git/ref/tags/<tag>` (dereference an annotated tag with `gh api repos/<owner>/<repo>/git/tags/<sha>`), update SHA and comment together, and read the release notes. Dependabot proposes these updates.

## Publishing
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ For PRs into `main`, CI also compares the version with the exact PR base commit:
greater, and its changelog section must contain release notes. Locally, set `BASE_SHA` to a base
commit to run the same comparison.

**Dependabot PRs.** Dependabot cannot bump the version or write release notes, so CI skips the
version comparison for PRs opened by `dependabot[bot]` (the heading check still runs). Merging one
publishes nothing; the update ships with the next release, whose `CHANGELOG.md` entry should
mention it. For an urgent security fix, open a release PR right after merging.

**Release branches.** A large release can be prepared on a `release/**` branch. PRs into it carry
no version bump but still add their `CHANGELOG.md` entry under a single
`## <x.y.z> (unreleased)` heading; the last PR bumps the version and renames the heading to
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "glassnode-terminal",
"version": "0.2.4",
"version": "0.2.5",
"description": "Interactive TUI for exploring Glassnode on-chain and market crypto data",
"type": "module",
"main": "dist/cli.js",
Expand Down
9 changes: 5 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ minimumReleaseAgeExclude:
# glassnode-api's x402 needs ^2.18.0 to complete x402Version-2 payments.
- '@x402/*'

# Security floors for transitive dev deps (vitest > vite > postcss > nanoid).
# Security floors for transitive dev deps (vitest > vite > postcss > nanoid, source-map-js).
overrides:
postcss: ^8.5.23
nanoid@3: ^3.3.18
source-map-js: ^1.2.2
9 changes: 7 additions & 2 deletions scripts/check-changelog-heading.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
// Usage: node scripts/check-changelog-heading.mjs [target-branch]
// The target defaults to $TARGET_BRANCH, then `main`. Env CHANGELOG and PACKAGE_JSON override
// the file paths (for tests). Exits 1 with a GitHub `::error::` annotation on failure.
// BASE_SHA enables PR version/notes checks against that commit's package.json.
// BASE_SHA enables PR version/notes checks against that commit's package.json. PR_AUTHOR
// `dependabot[bot]` skips them: Dependabot cannot bump the version or write release notes, so its
// dependency updates merge without publishing and ship with the next release.
/* global process, console */
import { readFileSync } from 'node:fs';
import { execFileSync } from 'node:child_process';
Expand Down Expand Up @@ -46,7 +48,10 @@ console.log(`CHANGELOG.md heading "${heading}" is valid for a PR into ${target}.

// PR CI supplies the exact base commit. Push/release runs and local heading checks omit it.
// Release-branch PRs accumulate changes under an unreleased heading without a version bump.
if (process.env.BASE_SHA && !/^release\//.test(target)) {
const dependabot = process.env.PR_AUTHOR === 'dependabot[bot]';
if (process.env.BASE_SHA && dependabot) {
console.log('Dependabot PR: version bump not required; the update ships with the next release.');
} else if (process.env.BASE_SHA && !/^release\//.test(target)) {
const base = JSON.parse(execFileSync('git', ['show', `${process.env.BASE_SHA}:package.json`], { encoding: 'utf8' }));
if (!parseSemver(version) || !parseSemver(base.version) || compareSemver(version, base.version) <= 0) {
console.error(`::error file=package.json::Version ${version} must be greater than base version ${base.version} for a PR into ${target}.`);
Expand Down
21 changes: 20 additions & 1 deletion test/release-scripts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ describe('release-state.sh (fake npm)', () => {
});

describe('check-changelog-heading.mjs', () => {
function check(changelog: string, version: string, target: string, baseVersion?: string) {
function check(changelog: string, version: string, target: string, baseVersion?: string, prAuthor = '') {
const dir = tempDir();
let baseSha = '';
if (baseVersion !== undefined) {
Expand All @@ -360,6 +360,7 @@ describe('check-changelog-heading.mjs', () => {
env: {
...process.env,
BASE_SHA: baseSha,
PR_AUTHOR: prAuthor,
CHANGELOG: join(dir, 'CHANGELOG.md'),
PACKAGE_JSON: join(dir, 'package.json'),
},
Expand All @@ -382,6 +383,24 @@ describe('check-changelog-heading.mjs', () => {
expect(r.status, r.stderr).toBe(0);
});

it('lets Dependabot PRs keep the base version', () => {
const r = check(log('## 0.30.1'), '0.30.1', 'main', '0.30.1', 'dependabot[bot]');
expect(r.status, r.stderr).toBe(0);
expect(r.stdout).toContain('version bump not required');
});

it.each(['someone', 'dependabot'])('still requires a bump from PR author %s', (author) => {
const r = check(log('## 0.30.1'), '0.30.1', 'main', '0.30.1', author);
expect(r.status).toBe(1);
expect(r.stderr).toContain('must be greater than base version');
});

it('still checks the changelog heading on Dependabot PRs', () => {
const r = check(log('## 0.30.2'), '0.30.1', 'main', '0.30.1', 'dependabot[bot]');
expect(r.status).toBe(1);
expect(r.stderr).toMatch(/must be "## 0.30.1"/);
});

it('rejects a bumped PR version with an empty release section', () => {
const r = check('## 0.30.2\n\n## 0.30.1\n\n- old notes\n', '0.30.2', 'main', '0.30.1');
expect(r.status).toBe(1);
Expand Down
Loading