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
19 changes: 3 additions & 16 deletions .claude/skills/qa-suggest/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@ Suggest new test cases for the current QA cycle by diffing the CHANGELOG against

## Step 1: Discovery

Read the extension package.json to get the version context:
Read the extension package.json to get the published version:

```text
Read packages/rangelink-vscode-extension/package.json
```

Extract:

- `nextTargetVersion` — the upcoming release version (`"Unreleased"` during trunk-based development, or a SemVer like `"1.1.0"` once locked in)
- `version` — the last published version (e.g., `1.0.0`)

**If `nextTargetVersion` is not set**, STOP: "Set `nextTargetVersion` in `packages/rangelink-vscode-extension/package.json` (e.g., `"Unreleased"`) before running `/qa-suggest`."
During trunk-based development the QA artifacts use the "Unreleased" placeholder (e.g., `qa-test-cases-unreleased.yaml`) — this convention is embedded in the QA tooling, not read from a config field. The `version` field in package.json always holds the last published SemVer.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Step 2: Locate QA YAMLs

Expand Down Expand Up @@ -144,30 +143,18 @@ Create a scratchpad file for the report. Use the `/scratchpad` conventions:

1. Determine the issue context from the current git branch (e.g., `issues/382` → issue ID `382`)
2. Find the next available sequence number in `.claude-work/issues/<ID>/scratchpads/`
3. Write the scratchpad. Choose the filename based on `nextTargetVersion`:
- If `nextTargetVersion` is `"Unreleased"`: `.claude-work/issues/<ID>/scratchpads/NNNN-qa-suggest.txt`
- If `nextTargetVersion` is a locked SemVer (e.g., `"2.0.0"`): `.claude-work/issues/<ID>/scratchpads/NNNN-qa-suggest-v<nextTargetVersion>.txt`
3. Write the scratchpad to `.claude-work/issues/<ID>/scratchpads/NNNN-qa-suggest.txt`

If no issue context can be determined, use `.claude-work/scratchpads/` instead.

The scratchpad should contain these sections in order:

### Header

If `nextTargetVersion` is `"Unreleased"`, use this header:

```text
# QA Suggest — v<version> → Unreleased
```

If `nextTargetVersion` is a locked SemVer (e.g., `"2.0.0"`), use this header instead:

```text
# QA Suggest — v<version> → v<nextTargetVersion>
```

Then continue with the shared body:

## What to do next

1. Review the suggested TCs below — edit descriptions, remove irrelevant ones
Expand Down
119 changes: 37 additions & 82 deletions docs/RELEASE-STRATEGY.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,6 @@ When documenting a feature that hasn't been released yet, add `<sup>Unreleased</

Skip marking cosmetic renames or rewording of existing features — only mark genuinely new functionality.

### Stripping Markers at Release Time

During the **Prepare** phase of a release:

1. Remove the top-of-README banner (the `> [!IMPORTANT]` admonition about unreleased features)
2. Strip all `<sup>Unreleased</sup>` markers from the README
3. Verify no markers remain: `grep -r '<sup>Unreleased</sup>' packages/`

The publishing script (`generate-publishing-instructions.sh`) also checks for leftover markers and blocks publishing if any are found. This serves as a safety net in case manual stripping is forgotten.

---

## Release Workflow
Expand All @@ -143,11 +133,15 @@ The publishing script (`generate-publishing-instructions.sh`) also checks for le

Releasing a package involves these phases:

1. **Prepare** - Bump version, update CHANGELOG, strip unreleased markers, commit changes
1. **Prepare**
1. `pnpm lock-version:vscode-extension X.Y.Z` — soft-lock the version for QA
2. Run QA pass (manual + automated TCs)
3. `pnpm finalize-release:vscode-extension` — hard-finalize: updates CHANGELOG, strips README markers, generates publishing instructions
2. **Build & Test** - Package and validate locally
3. **Publish** - Deploy to marketplace(s) and create GitHub release
4. **Tag** - Create annotated git tag following [tagging convention](#tagging-convention)
5. **Verify** - Confirm publication and test installation
6. **Next cycle** — `pnpm start-release:vscode-extension` to begin the next development cycle

### Package-Specific Instructions

Expand Down Expand Up @@ -326,44 +320,41 @@ git push origin vscode-extension-v0.1.0
### Example 2: Second Release (v0.1.1)

```bash
# 1. Update version in package.json to 0.1.1
# 2. Update CHANGELOG.md
git add packages/rangelink-vscode-extension/package.json
git add packages/rangelink-vscode-extension/CHANGELOG.md
git commit -m "chore(vscode-ext): bump version to 0.1.1"

# 3. Build, test, package
pnpm clean && pnpm install && pnpm -r compile && pnpm -r test
cd packages/rangelink-vscode-extension
pnpm package

# 4. Test locally
pnpm install-local:vscode

# 5. Publish to marketplace
pnpm publish

# 6. Tag and push
git tag -a vscode-extension-v0.1.1 -m "Release vscode-extension v0.1.1

Changes:
- Documentation improvements
- ESLint configuration fixes
"
# 1. Prepare: lock version, run QA, then finalize
pnpm lock-version:vscode-extension 0.1.1
# ... QA pass ...
pnpm finalize-release:vscode-extension

# 2. Build, test, package locally
pnpm package:vscode-extension
pnpm install-local:vscode-extension:both

# 3. Publish to marketplace
pnpm publish:vscode-extension:vsix

# 4. Tag and push
git tag -a vscode-extension-v0.1.1 -m "Release vscode-extension v0.1.1"
git push origin vscode-extension-v0.1.1

# 7. Create GitHub release with CHANGELOG content
# 5. Start next development cycle
pnpm start-release:vscode-extension

# 6. Create GitHub release with CHANGELOG content
```

### Example 3: Major Version Bump (v1.0.0)

```bash
# When ready for 1.0.0 (stable API, feature-complete)
# Same process, but version becomes 1.0.0
git tag -a vscode-extension-v1.0.0 -m "Release vscode-extension v1.0.0

First stable release with complete feature set and stable API.
"
# Same process as Example 2, with the new version number.
pnpm lock-version:vscode-extension 1.0.0
# ... QA pass ...
pnpm finalize-release:vscode-extension
pnpm package:vscode-extension
pnpm install-local:vscode-extension:both
pnpm publish:vscode-extension:vsix
git tag -a vscode-extension-v1.0.0 -m "Release vscode-extension v1.0.0"
git push origin vscode-extension-v1.0.0
pnpm start-release:vscode-extension
```

### Example 4: Multiple Package Release
Expand Down Expand Up @@ -427,15 +418,8 @@ These items are planned but not yet implemented:
- Automated CHANGELOG generation
- Better monorepo version coordination

- [ ] **Pre-commit hooks**
- Enforce clean working tree before tagging
- Validate version numbers match across package.json and CHANGELOG
- Prevent accidental dirty releases

- [ ] **Release verification scripts**
- Automated checks before publishing
- Version number validation
- CHANGELOG completeness check
- [x] **Pre-commit hooks** — working tree cleanliness enforced by the release scripts; remaining hook work: prevent commits that introduce version/CHANGELOG mismatches.
- [x] **Release verification scripts** — `pnpm lock-version:vscode-extension`, `pnpm finalize-release:vscode-extension`, and `pnpm generate:publish-instructions:vscode-extension` validate the working tree, version numbers, CHANGELOG, and unreleased markers before allowing each phase to proceed.

---

Expand All @@ -457,36 +441,7 @@ git tag -a vscode-extension-v0.1.0 ff52f9a -m "Release vscode-extension v0.1.0"
git push origin vscode-extension-v0.1.0
```

### Release v0.1.1 (Full Process)

```bash
# 1. Version bump
cd packages/rangelink-vscode-extension
# Edit package.json: "version": "0.1.1"
# Edit CHANGELOG.md
git add package.json CHANGELOG.md
git commit -m "chore(vscode-ext): bump version to 0.1.1"

# 2. Build and test
cd ../..
pnpm clean && pnpm install && pnpm -r compile && pnpm -r test

# 3. Package and test locally
cd packages/rangelink-vscode-extension
pnpm package
pnpm install-local:vscode

# 4. Publish
pnpm publish

# 5. Tag and release
cd ../..
git tag -a vscode-extension-v0.1.1 -m "Release vscode-extension v0.1.1"
git push origin vscode-extension-v0.1.1
# Then create GitHub release
```

---

**Last Updated:** 2025-11-02
**Status:** Active - Manual release process in use
**Last Updated:** 2026-05-26
**Status:** Active — automated via `pnpm lock-version:vscode-extension` → `pnpm finalize-release:vscode-extension` → `pnpm start-release:vscode-extension`
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"clean:all": "pnpm -r clean:all",
"compile": "pnpm clean && find . -name '*.tsbuildinfo' -delete && pnpm -r --workspace-concurrency=1 compile",
"enable-pnpm": "corepack enable",
"finalize-release:vscode-extension": "pnpm --filter rangelink-vscode-extension run finalize-release",
"fix": "pnpm lint:fix && pnpm format:fix",
"format": "prettier --check .",
"format:fix": "prettier --write .",
Expand All @@ -25,10 +26,12 @@
"install-local:vscode-extension:vscode": "pnpm --filter rangelink-vscode-extension install-local:vscode",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lock-version:vscode-extension": "pnpm --filter rangelink-vscode-extension run lock-version",
"package:prepare": "pnpm clean:all && pnpm install",
"package:vscode-extension": "pnpm --filter rangelink-vscode-extension clean && pnpm --filter rangelink-vscode-extension compile && pnpm --filter rangelink-vscode-extension test && pnpm --filter rangelink-vscode-extension package",
"package:vscode-extension:withInstall:both": "pnpm package:vscode-extension && pnpm install-local:vscode-extension:both",
"publish:vscode-extension:vsix": "pnpm --filter rangelink-vscode-extension publish:vsix",
"start-release:vscode-extension": "pnpm --filter rangelink-vscode-extension run start-release",
"test": "pnpm -r test",
"test:bats": "bats tests/shell/",
"test:release": "pnpm --filter rangelink-vscode-extension test:release",
Expand Down
35 changes: 17 additions & 18 deletions packages/rangelink-vscode-extension/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,23 @@ All `test:release*` commands accept `--label <tag>` (include TCs with QA YAML la

### Release QA Cycle (once per release)

| Script | When | Re-runnable? | What it does |
| ------------------------------------------ | ---------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------- |
| `pnpm lock-version:vscode-extension X.Y.Z` | Ready to start QA | Yes (idempotent) | Renames QA YAML → versioned, bumps `.version`, regenerates instructions |
| `pnpm finalize-release:vscode-extension` | QA passed, ready to ship | No (one-way door) | Finalizes CHANGELOG, strips README markers/banner, generates publishing instructions |
| `pnpm start-release:vscode-extension` | After publish, starting next cycle | Yes (idempotent) | Copies versioned YAML → unreleased, adds `[Unreleased]` CHANGELOG header, re-adds README banner |

```mermaid
flowchart TD
Z[generate:release-testing-instructions] -.->|generates guide| A
A[nextTargetVersion: Unreleased] --> B[generate:qa-test-plan]
B --> C[/qa-suggest in Claude Code/]
C --> D[Review + append new TCs]
D --> E[Commit YAML]
E --> F[generate:qa-issue]
F --> G[Single GitHub issue with grep commands per section]
G --> H[package:vscode-extension:withInstall:both]
H --> I[Manual QA pass — launch editor with fixture workspace]
I --> I1[Ready-now TCs — no setup needed]
I1 --> I2[Open terminals + bind]
I2 --> I3[Terminal-dependent TCs]
I4 --> J{All TCs pass?}
J -- No --> K[Fix + re-run affected TCs]
K --> J
J -- Yes --> L[Tag release + publish]
A[Version: Unreleased (deferred)] --> B[lock-version.sh X.Y.Z]
B --> C[QA pass — manual + automated TCs]
C --> D{All TCs pass?}
D -- No --> E[Fix bugs]
E --> C
D -- Yes --> F[finalize-release.sh]
F --> G[build VSIX + publish]
G --> H[start-release.sh]
H --> A
```

---
Expand Down Expand Up @@ -278,9 +277,9 @@ The QA test plan is a version-scoped YAML file that tracks both automated and ma
qa/qa-test-cases-unreleased.yaml
```

During trunk-based development the file is `qa/qa-test-cases-unreleased.yaml`. At release time `finalize-release` renames it to `qa/qa-test-cases-v<version>.yaml`.
During trunk-based development the file is `qa/qa-test-cases-unreleased.yaml`. At release time `pnpm lock-version:vscode-extension` renames it to `qa/qa-test-cases-v<version>.yaml`.

The filename mirrors `nextTargetVersion` from `package.json` (`"Unreleased"` during development). It is parsed automatically by the `generate-qa-issue` script — no extra flags needed. One file per release — Git tracks history across versions.
The filename is always `qa-test-cases-unreleased.yaml` during trunk-based development — the version is deferred until `pnpm lock-version:vscode-extension` locks it in at QA time. It is parsed automatically by the `generate-qa-issue` script — no extra flags needed. One file per release — Git tracks history across versions.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

New QA YAML files are created by `pnpm generate:qa-test-plan`. The script carries forward all TCs from the most recent YAML, resets `status:` fields to `pending`, and preserves `automated:` flags.

Expand Down
4 changes: 3 additions & 1 deletion packages/rangelink-vscode-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"clean:all": "pnpm clean && rm -rf node_modules .eslintcache *.log .vscode-test",
"compile": "pnpm compile:deps && pnpm generate-version:all && node esbuild.config.js",
"compile:deps": "cd ../barebone-logger && pnpm clean && pnpm compile && cd ../barebone-logger-testing && pnpm clean && pnpm compile && cd ../rangelink-core-ts && pnpm clean && pnpm compile",
"finalize-release": "./scripts/finalize-release.sh",
"generate-version": "node scripts/generate-version.js --copy-to out",
"generate-version:all": "node scripts/generate-version.js --copy-to out,dist",
"generate:publish-instructions": "./scripts/generate-publishing-instructions.sh",
Expand All @@ -45,8 +46,10 @@
"install-local": "./scripts/install-local.sh",
"install-local:cursor": "./scripts/install-local.sh cursor",
"install-local:vscode": "./scripts/install-local.sh vscode",
"lock-version": "./scripts/lock-version.sh",
"package": "rm -rf *.vsix && ../../scripts/sync-assets.sh && rm -f rangelink-vscode-extension-*.vsix && vsce package --no-dependencies",
"publish:vsix": "./scripts/publish-from-vsix.sh",
"start-release": "./scripts/start-release.sh",
"test": "jest --coverage",
"test:coverage": "jest --coverage --coverageReporters=text --coverageReporters=text-summary --coverageReporters=html",
"test:fast": "jest --coverage --testPathIgnorePatterns '<rootDir>/src/__integration-tests__/' '\\.integration\\.test\\.ts$'",
Expand Down Expand Up @@ -982,6 +985,5 @@
"vscode": "^1.49.0"
},
"icon": "icon.png",
"nextTargetVersion": "Unreleased",
"pricing": "Free"
}
Loading
Loading