Skip to content

Contributing guide, CI, and automatic releases - #33

Merged
durw4rd merged 7 commits into
mainfrom
chore/contributing-ci-releases
Oct 16, 2026
Merged

durw4rd merged 7 commits into
mainfrom
chore/contributing-ci-releases

Conversation

@durw4rd

@durw4rd durw4rd commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

What and why

PR #32 merged with its notes still under [Unreleased] and no version bump, and that has happened before (3.0.0 and 3.1.0 never reached deno.json; no version was ever tagged). The cause is that nothing said when or how to release, and nothing checked. This PR makes the rule explicit and enforced:

  • Release per PR. A PR that changes behaviour runs deno task version:bump:<patch|minor|major> (bumps deno.json, dates the changelog section). The new release-gate check refuses the merge otherwise, unless the PR carries the no-release label (docs/CI/refactor). On merge, the Release workflow creates the tag vX.Y.Z and a GitHub Release from the changelog section. No manual tagging.
  • CI (checks): deno fmt --check, deno lint, deno check, unit tests, with a frozen lockfile.
  • CONTRIBUTING.md with setup, PR flow, changelog style, bump sizes in this tool's terms, what the gate checks and how to recover when two PRs race to the same version. PR template with the checklist.
  • Cleanup so CI is green: one format-only commit (deno fmt, markdown line breaks preserved), lint fixes (unused imports/vars, an unused fallback in revert_migration.ts, pinned jsr:/npm: imports), refreshed deno.lock, .deno-version 2.9.7. Two lint rules (no-import-prefix, no-explicit-any) are excluded until their cleanups land.
  • Scripts: scripts/release-check.sh (the gate, also deno task release:check), bump-version.sh refuses an empty Unreleased block and no longer asks for manual tags, version:show reports the tag state. Dead update-maintainers task removed.
  • README: "Contributing and Releases" section, task list regenerated from deno.json (the -- -f form was stale), deno task source → source-from-ld.

This PR itself is no-release. The #32 fixes plus these notes ship as 3.4.1 in a follow-up PR that only runs the bump, which also exercises the whole path end to end.

Commits are split by concern: format-only → lint cleanup → scripts/tasks → workflows → docs.

How it was tested

  • Locally: deno fmt --check, deno lint, deno check --frozen, deno test --frozen (182 tests) all pass.
  • scripts/release-check.sh exercised on every path: no-release OK, missing bump, lower version, missing heading, non-empty Unreleased, and a throwaway bump passing; bump-version.sh refuses an empty Unreleased block.
  • Workflow YAML parsed; the real runs are this PR's checks. Toggle the no-release label once to see release-gate fail and pass again.

After merge (maintainer)

  1. Backfill v3.4.0 on d7a606f (the 3.4.0 release merge) so the first automated release gets a compare link.
  2. Extend the "Base ruleset" on main: require a PR, require checks and release-gate, "require branches to be up to date".
  3. Merge the follow-up "Release 3.4.1" PR.

🤖 Generated with Claude Code

durw4rd and others added 5 commits October 16, 2026 18:18
Mechanical pass so that `deno fmt --check` can run in CI. Markdown keeps
its line breaks (`fmt.proseWrap: preserve` in deno.json), so changelog
entries stay one line per bullet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Drop unused imports, variables and catch bindings; remove the unused
  fetchFlagViews/findFlagsLinkedToView fallback in revert_migration.ts
  (nothing called it); `ask` in migrate is no longer async (it only
  calls the synchronous prompt()).
- Pin `jsr:@std/cli` and `npm:jsondiffpatch` in diff-payload to the
  versions already in deno.lock; regenerate deno.lock so it matches the
  specifiers in the code (CI runs with --frozen).
- deno.json: exclude `no-import-prefix` (the https://deno.land/std
  imports; moving them to jsr: is a follow-up) and `no-explicit-any`
  (typing cleanup) so `deno lint` can be enforced now.
- .deno-version 2.4.5 -> 2.9.7, the version CI pins to.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… tasks

- scripts/release-check.sh (deno task release:check): the gate CI runs on
  every PR. Verifies the version bump against the base branch, that the
  tag does not exist yet, that CHANGELOG.md has a dated section for the
  new version and nothing left under [Unreleased]. With NO_RELEASE=true
  (the no-release label) it only verifies the version is unchanged.
- scripts/bump-version.sh: refuses to release an empty [Unreleased]
  block, no longer tells you to create tags by hand (the Release
  workflow does that on merge), runs the gate as a self-check.
- scripts/check-version.sh: reports whether the version is tagged and
  only mentions unreleased entries when there are some (the heading
  alone used to trigger the warning every time).
- deno.json: tasks check, lint, fmt, fmt:check, release:check; the dead
  update-maintainers task (its script does not exist) is removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- ci.yml (check "checks"): deno fmt --check, deno lint, deno check and
  the unit tests, with --frozen so lockfile drift fails the build.
- release-gate.yml (check "release-gate"): runs scripts/release-check.sh
  against the PR's merge commit; re-runs when the no-release label is
  added or removed, which is why it is a separate workflow.
- release.yml: on push to main, when deno.json's version differs from
  the previous main commit, creates tag vX.Y.Z and a GitHub Release
  whose notes are that version's CHANGELOG.md section (plus a compare
  link to the previous tag). Unchanged version: no-op. Version changed
  but already tagged (two PRs raced to the same version): fails loudly.
  workflow_dispatch allows a retry.
- PR template with the contributing checklist; Dependabot for the
  actions themselves (its PRs are labelled no-release).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… notes

- CONTRIBUTING.md: setup, PR flow, changelog style, the release-per-PR
  rule and the bump sizes in this tool's terms, what the gate checks,
  how to recover when another PR released first, maintainer notes.
- README: "Contributing and Releases" replaces "Version Management";
  the Deno tasks section lists every task in deno.json (the snippet
  showed a stale `deno task workflow -- -f` form and omitted revert,
  source-from-split, diff and the development tasks); `deno task source`
  corrected to `source-from-ld`; `.deno-version` mentioned next to the
  Deno prerequisite; Support points at CONTRIBUTING.md.
- CHANGELOG: 3.0.1 was released on 2025-10-14, not 2025-01-14; notes for
  this change under [Unreleased] (released by the next bump).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@durw4rd durw4rd added no-release Docs/CI/refactor-only PR: no version bump, no release on merge and removed no-release Docs/CI/refactor-only PR: no version bump, no release on merge labels Oct 16, 2026
@durw4rd
durw4rd requested a balanced review from Copilot October 16, 2026 16:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Release scheduling and recovery can leave versions unpublished, and the reformatted preview example can permit unintended writes.

4 open findings
What changed in this PR

Adds contribution guidance, CI checks, and automated per-PR releases to prevent version and changelog updates from being missed.

Changes:

  • Introduces release validation, automatic tagging, and GitHub Releases.
  • Documents contributor setup, versioning, and recovery procedures.
  • Applies formatting and lint cleanup, pins imports, and updates development tasks.
File Description
src/​utils/​workflow_config.ts Formats workflow configuration helpers.
src/​utils/​views.ts Formats view API helpers.
src/​utils/​views_test.ts Formats view tests.
src/​utils/​unknown_segment_test.ts Formats segment-rule tests.
src/​utils/​sync_manifest.ts Formats manifest helpers.
src/​utils/​split/​mapping_test.ts Formats mapping tests and imports.
src/​utils/​split/​fixtures/​stub_server.ts Formats API fixtures.
src/​utils/​split/​client.ts Formats Split client code.
src/​utils/​split/​client_test.ts Formats client tests.
src/​utils/​semaphore_test.ts Removes an unused parameter; formats code.
src/​utils/​rate_limits.ts Formats rate-limit utilities.
src/​utils/​rate_limit_retry_test.ts Formats retry tests.
src/​utils/​big_segments.ts Formats big-segment utilities.
src/​utils/​api_keys.ts Formats key-loading diagnostics.
src/​utils/​account_guard.ts Formats account guard logic.
src/​utils/​account_guard_test.ts Formats guard tests.
src/​types/​deno.d.ts Removes trailing whitespace.
src/​scripts/​third-party-migrations/​split-readme.md Formats documentation tables.
src/​scripts/​third-party-migrations/​source_from_split.ts Removes an unused import; formats code.
src/​scripts/​third-party-migrations/​README.md Formats documentation spacing.
src/​scripts/​third-party-migrations/​import_flags_from_external.ts Cleans imports and formatting.
src/​scripts/​launchdarkly-migrations/​workflow_config_test.ts Formats workflow tests.
src/​scripts/​launchdarkly-migrations/​source_from_ld.ts Removes an unused import; formats code.
src/​scripts/​launchdarkly-migrations/​revert_migration_test.ts Formats revert tests.
src/​scripts/​launchdarkly-migrations/​README.md Formats documentation spacing.
src/​scripts/​launchdarkly-migrations/​map_members_between_ld_instances.ts Formats member mapping code.
src/​scripts/​launchdarkly-migrations/​estimate_migration_time.ts Formats estimation code.
src/​scripts/​diff-payload/​mod.ts Pins jsondiffpatch imports.
src/​scripts/​diff-payload/​diff_payload.ts Constrains CLI dependency; formats code.
scripts/​verify-segments.ts Formats verification code.
scripts/​release-check.sh Adds version and changelog validation.
scripts/​check-version.sh Reports release-tag status.
scripts/​bump-version.sh Rejects empty releases; updates release guidance.
examples/​workflow-third-party.yaml Formats YAML whitespace.
examples/​workflow-split.yaml Formats an inline comment.
examples/​workflow-revert-and-migrate.yaml Formats YAML comments and whitespace.
examples/​workflow-migrate-only.yaml Formats YAML whitespace.
examples/​workflow-full.yaml Formats YAML whitespace.
examples/​workflow-extract-only.yaml Formats YAML comments and whitespace.
examples/​workflow-extract-migrate-incremental.yaml Reformats commented migration options.
examples/​workflow-custom-steps.yaml Formats YAML whitespace.
examples/​revert-migration-example.yaml Formats comment whitespace.
examples/​README.md Formats headings, lists, and tables.
examples/​migration-config.yaml Formats YAML whitespace.
examples/​migration-config-simple.yaml Formats YAML whitespace.
examples/​migration-config-env-mapping.yaml Formats YAML whitespace.
examples/​migration-config-advanced.yaml Formats YAML whitespace.
examples/​flags_template.json Formats JSON objects.
docs/​split-migration-fix-plan.md Formats planning documentation.
docs/​SPLIT-MAPPING.md Formats mapping reference tables.
docs/​launchdarkly-migration-role.md Formats permission tables.
deno.lock Aligns dependency specifiers with imports.
deno.json Adds checks and formatting tasks; configures lint.
CONTRIBUTING.md Defines contribution and release procedures.
config/​tsconfig.json Adds a final newline.
config/​import_map.json Adds a final newline.
CHANGELOG.md Records tooling changes and corrects a historical date.
.github/​workflows/​release.yml Automates tags and GitHub Releases.
.github/​workflows/​release-gate.yml Enforces release requirements on PRs.
.github/​workflows/​ci.yml Adds formatting, lint, type, and test checks.
.github/​pull_request_template.md Adds contributor checklists.
.github/​dependabot.yml Configures weekly Actions updates.
.deno-version Updates the selected Deno version.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread examples/workflow-extract-migrate-incremental.yaml Outdated
…al keys

Review on #33 (Copilot) pointed out three recovery gaps in release.yml,
all from deciding on "did this push change the version" (HEAD vs HEAD^1):
a queued run replaced in the concurrency group left a bump untagged, a
manual re-run after a later no-release merge saw an unchanged version
and skipped, and re-running a successful run reported a false collision.

The workflow now reconciles the current version's release state: no tag
-> tag the first-parent main commit that introduced the version and
release; tag without release -> create the release; tag and release
present -> no-op, unless this push changed that version's changelog
section (a second PR merged under an already released version), which
fails loudly; tag pointing elsewhere -> fail. CONTRIBUTING's maintainer
notes updated to match.

examples/workflow-extract-migrate-incremental.yaml: the formatter
dedented the trailing commented-out options to the root, so uncommenting
`dryRun: true` would have been ignored (workflow.ts reads
migration.dryRun). The block now sits inside `migration`, before the
last active key, where the formatter keeps its indentation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Release reconciliation can reject successful reruns and leave skipped intermediate versions unpublished.

1 open finding
4 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Reconcile all outstanding version releases in first-parent order

.github/​workflows/​release.yml:57

Reconciliation repairs a skipped release only while that version remains current. If a pending 3.4.1 run is replaced by a 3.4.2 merge, or 3.4.1 publication fails before 3.4.2 merges, the surviving run publishes only 3.4.2. Later pushes and manual dispatches on main never revisit 3.4.1. Unlike the repaired no-release-merge case, this leaves an earlier version unpublished. Reconcile outstanding version-introducing commits in first-parent order, using each commit's changelog section.

🧠 Review effort: Balanced

Comment thread .github/workflows/release.yml
The collision check compared the version's changelog section between
HEAD^1 and HEAD, which is always a change on the commit that introduced
the version, so re-running that commit's successful release failed as a
collision (Copilot review on #33). The check now applies only to push
events of a commit other than the introducing one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@durw4rd

durw4rd commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator Author

Re Copilot's remaining summary finding ("reconcile all outstanding version releases in first-parent order"): leaving as is. It needs two version bumps to land within the ~15 s a release run takes, with the first run replaced in the queue. With the ruleset's up-to-date requirement, the second PR has to re-run CI after the first merges, which takes longer than that. Noted in CONTRIBUTING under the maintainer section's recovery paths; if it ever happens, a manual bump-and-release PR repairs it.

🤖 Posted by Claude Code

@durw4rd
durw4rd merged commit c6ac8f7 into main Oct 16, 2026
2 checks passed
@durw4rd
durw4rd deleted the chore/contributing-ci-releases branch October 16, 2026 17:57
@durw4rd durw4rd mentioned this pull request Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-release Docs/CI/refactor-only PR: no version bump, no release on merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants