diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c33215e..fa9fc91 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,9 @@ name: release -# Manually-triggered stable release via goreleaser. Pick bump -# (patch/minor/major); the next vX.Y.Z tag is computed from the -# latest stable tag. +# Manually-triggered stable release. Pick a bump (patch/minor/major) — +# the next vX.Y.Z tag is computed from the latest stable tag. The `notes` +# input is used verbatim as the release body and is also attached to the +# release as `CHANGELOG.md`. Nothing is committed back to the repo. on: workflow_dispatch: inputs: @@ -15,6 +16,10 @@ on: - patch - minor - major + notes: + description: "Release notes in Markdown. Becomes the release body and the attached CHANGELOG.md asset. Use \\n for newlines if passing via CLI." + required: true + type: string permissions: read-all @@ -159,68 +164,28 @@ jobs: pattern: binary-* path: downloaded/ - - name: Resolve release notes from CHANGELOG.md + - name: Prepare release notes id: notes env: TAG: ${{ needs.tag.outputs.tag }} + NOTES: ${{ inputs.notes }} run: | set -eu - # Extract the block under `## []` up to the next `## [` heading. - extract_section() { - awk -v h="$1" ' - $0 ~ "^## \\[" h "\\]" { found=1; next } - found && /^## \[/ { exit } - found { print } - ' CHANGELOG.md - } - - has_content() { printf '%s' "$1" | grep -Eq '[^[:space:]]'; } - - # The tag arrives as vX.Y.Z; CHANGELOG convention is [X.Y.Z] (no v). - TAG_STRIPPED="${TAG#v}" - - body="" - for candidate in "$TAG" "$TAG_STRIPPED"; do - body=$(extract_section "$candidate") - if has_content "$body"; then break; fi - done - - if ! has_content "$body"; then - # Promote [Unreleased] → [TAG_STRIPPED] — YYYY-MM-DD and insert a fresh empty Unreleased. - unreleased=$(extract_section 'Unreleased') - if ! has_content "$unreleased"; then - echo "::error::CHANGELOG.md has neither a '## [${TAG}]' / '## [${TAG_STRIPPED}]' section nor a non-empty '## [Unreleased]' section." - echo "::error::Add a '## [${TAG_STRIPPED}] — YYYY-MM-DD' section (or populate Unreleased) before releasing." - exit 1 - fi - - echo "Promoting [Unreleased] → [${TAG_STRIPPED}] in CHANGELOG.md" - date_iso=$(date -u +%Y-%m-%d) - python3 - < dist/CHANGELOG.md + + # Emit the body to GITHUB_OUTPUT for the next step. The Verify + # footer is appended in the create-release step. { echo 'body<<__RN_EOF__' - printf '%s' "$body" + printf '%s' "$NOTES" echo echo '__RN_EOF__' } >> "$GITHUB_OUTPUT" @@ -287,7 +252,7 @@ jobs: gh release create "$TAG" \ --title "$TAG" \ --notes-file release-notes.md \ - dist/docsiq-* dist/SHA256SUMS dist/SHA256SUMS.sig dist/SHA256SUMS.pem + dist/docsiq-* dist/SHA256SUMS dist/SHA256SUMS.sig dist/SHA256SUMS.pem dist/CHANGELOG.md - name: Generate SLSA build provenance id: attest diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dc2c71..ec1d9c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,90 +1,30 @@ # Changelog -All notable changes to docsiq are documented here in a human-readable -form. The full per-commit history is available on -[GitHub Releases](https://github.com/RandomCodeSpace/docsiq/releases), -but this file is the curated summary. +Curated release notes for each version are published on +**[GitHub Releases](https://github.com/RandomCodeSpace/docsiq/releases)**. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -Each release ships signed binaries (cosign keyless + Rekor), a signed -`SHA256SUMS`, and SLSA build provenance. +Every release includes: -> **Contributors:** add bullets under `## [Unreleased]` as part of any -> PR worth mentioning in release notes. When the release workflow runs, -> it promotes `[Unreleased]` → `[vX.Y.Z] — YYYY-MM-DD` automatically and -> uses that section as the GitHub release body. If no non-empty -> `[Unreleased]` section exists at release time, the workflow fails. +- A human-readable summary of changes (the release body). +- A `CHANGELOG.md` asset attached to the release, containing the same + curated notes. +- Signed binaries (cosign keyless + Rekor), a signed `SHA256SUMS`, and + SLSA build provenance. -## [Unreleased] +## Release procedure -### Added -- `CODE_OF_CONDUCT.md`, `GOVERNANCE.md`, `.github/CODEOWNERS`, - `.github/release.yml`, `docs/ACCESSIBILITY.md` — project governance - and community files (OpenSSF BestPractices passing tier). -- `.bestpractices.json` tracking the full OpenSSF BestPractices matrix - at repo root (78 Met / 10 N/A / 0 Unknown). +Release notes are provided at release time, not maintained in-repo: -### Changed -- `SECURITY.md`: added a "Report archive" section clarifying that - GitHub Issues archives non-sensitive reports and Security Advisories - archives coordinated-disclosure reports. -- Release pipeline: dropped GoReleaser (its `prebuilt` builder is a - Pro-only feature and wasn't parsing in OSS goreleaser). The release - job now computes SHA256SUMS, signs with cosign keyless, and creates - the GitHub release directly — signing, provenance, and categorised - release notes are all preserved. -- CI: dropped macOS from the test matrix; Linux-only is sufficient to - gate PRs. The release workflow still builds darwin-arm64 binaries - natively on macOS runners. -- CI: removed `push: main` trigger from `ci.yml` and `fuzz.yml`; - `pull/N/merge` already validates the merged tree. Saves ~2 min of - runner time per merged PR. `codeql.yml` still runs on push to main - (the Security tab's default-branch data requires it). +```sh +gh workflow run release.yml --ref main \ + -f bump=patch \ + -f notes=$'### Changed\n\n- Describe major changes...\n\n### Upgrade impact\n\nDrop-in replacement — no schema/API changes.' +``` -## [0.0.2] — 2026-04-23 +The workflow uses the `notes` input verbatim as the release body and +also uploads it as `CHANGELOG.md` on the release page. The repository +never auto-commits a CHANGELOG entry — this file is static. -### Changed - -- **Scorecard workflow cadence.** `scorecard.yml` now runs on release - completion and weekly on schedule instead of firing on every push to - `main`. The policy being scored is unchanged; this simply stops - re-scoring commits that don't move any Scorecard-visible state. - -### Upgrade impact - -Safe drop-in upgrade from v0.0.1. No API, CLI, or on-disk schema -changes — replace the binary in place. - -GitHub Release: - -## [0.0.1] — 2026-04-23 - -First non-beta release. Establishes the feature set and API surface -that subsequent 0.0.x patches will maintain back-compat against. - -### Added - -- **GraphRAG indexing pipeline** — five-phase ingestion: chunk, extract - entities/relationships/claims, community-detect (Louvain), embed, - persist. -- **Document loaders** — PDF (langchaingo), DOCX, TXT, Markdown, and a - polite web crawler with robots.txt + allow-list + MIME checks. -- **Multi-provider LLM layer** — Azure OpenAI, OpenAI, and Ollama - behind a single `internal/llm` abstraction. -- **Query engine** — hybrid local (vector + FTS5) and global - (community-summary) search. -- **Surfaces** — CLI (`docsiq index|search|serve`), REST API, MCP - server, and an embedded React SPA served by `docsiq serve`. -- **Storage** — single SQLite file with `sqlite_fts5` and `sqlite-vec` - for vector search. No external DB to deploy. -- **Signed releases** — cosign keyless via Sigstore (Rekor-anchored), - signed `SHA256SUMS`, and SLSA build provenance. - -### Known limitations - -- Darwin support is limited to `arm64`; `amd64` is not built (cgo + - sqlite-vec cross-compile complexity). -- Pre-1.0: APIs and on-disk schema are not yet frozen. - -GitHub Release: +The project follows +[Semantic Versioning](https://semver.org/spec/v2.0.0.html) and each +release is identified by its immutable `vX.Y.Z` tag.