Skip to content

feat: add release pipeline and auto-reinstall#20

Merged
AndreJorgeLopes merged 11 commits into
mainfrom
feat/release-pipeline-and-reinstall
Apr 6, 2026
Merged

feat: add release pipeline and auto-reinstall#20
AndreJorgeLopes merged 11 commits into
mainfrom
feat/release-pipeline-and-reinstall

Conversation

@AndreJorgeLopes
Copy link
Copy Markdown
Owner

Summary

  • Add automated release pipeline triggered by conventional commits on push to main
  • Add auto-reinstall watchdog extension that keeps the local devflow binary current after merges
  • Full test coverage: 48 unit tests covering commit parsing, semver, version bump, install mode detection, and auto-reinstall guards

Changes

Release Pipeline (lib/release.sh, .github/workflows/release.yml)

  • Conventional commit parser (_parse_conventional_commits) determines version bump from feat:/fix:/feat!:/BREAKING CHANGE:
  • Semver arithmetic in pure bash
  • bump_all_versions updates Makefile, utils.sh, plugin.json, marketplace.json, and all command badges using portable sed
  • GitHub Actions workflow: single-push architecture (version bump + Formula update in one commit), concurrency guard, [skip release] support, workflow_dispatch for manual overrides
  • CLI commands: devflow version-bump <version>, devflow release (preview)

Auto-Reinstall (lib/watch.sh)

  • _detect_install_mode: distinguishes symlink (make link), copy (make install), Homebrew (warn only)
  • _auto_reinstall_check: SHA-based staleness detection, opt-in via devflow watch setup
  • Dry-run support, error handling with retry (SHA not updated on failure), full error logging

Test plan

  • 48/48 unit tests pass (bats tests/unit/)
  • Smoke tests pass (make test)
  • Version consistency validated (make check-version)
  • devflow release preview works
  • devflow help shows all new commands
  • GitHub Actions workflow will be tested on first merge to main

AndreJorgeLopes and others added 10 commits March 19, 2026 00:28
GitHub Actions workflow triggered on push to main. Parses conventional
commits for version bump, updates all version files, creates GitHub
Release with tarball, and updates Homebrew formula — single atomic push.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extends the watchdog watcher with SHA-based staleness detection to
auto-update the local devflow installation when main gets new commits.
Opt-in via devflow watch setup, handles symlink/copy/Homebrew modes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9 tasks across 5 chunks: conventional commit parser, semver arithmetic,
version bump script, CLI wiring, GitHub Actions workflow, install mode
detection, auto-reinstall check, documentation, and final verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_parse_conventional_commits scans commits since last tag for feat:/fix:/
feat!:/BREAKING CHANGE: prefixes. _semver_bump does pure-bash version
arithmetic. [skip release] only checked on HEAD commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
bump_all_versions uses portable sed for all 5+ version files. Standalone
scripts/bump-version.sh for CI use. bin/devflow routes version-bump and
release commands. Formula update test added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Triggers on push to main, parses conventional commits, bumps versions,
creates tarball, updates Homebrew formula, and creates GitHub Release.
Single atomic push with [skip release] guard. Supports workflow_dispatch
for manual overrides and dry-run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects install mode (symlink/copy/Homebrew), compares origin/main SHA
against last-installed SHA, runs make install/link when stale. Opt-in
via devflow watch setup. Supports dry-run, error logging with retry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Release Process and Auto-Reinstall sections to CLAUDE.md. Add
release.sh to project structure tree.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add watch, check-version, version-bump, and release to the CLI commands
reference table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New skill that guides deep technical walkthroughs before implementation:
- Traces end-to-end flows with actual code and file paths
- Shows side effects (events, billing, observability) branching off main flow
- Creates prioritized files-to-read lists
- Verifies assumptions against tickets before stating them

Added as optional step 5 in the new-feature flow, offered before brainstorming.
Registered in skills/registry.json and converted to plugin command.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 6, 2026 15:26
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a conventional-commit–driven release pipeline (CLI + GitHub Actions) and extends the watchdog to optionally auto-reinstall devflow when origin/main advances, along with supporting docs, tests, and plugin/skill updates.

Changes:

  • Introduces lib/release.sh + .github/workflows/release.yml to compute semver bumps from conventional commits and publish releases automatically.
  • Adds scripts/bump-version.sh and a make version-bump target to update all version-bearing files consistently.
  • Extends lib/watch.sh with install-mode detection and an opt-in auto-reinstall step; updates skills/plugin command docs accordingly.

Reviewed changes

Copilot reviewed 36 out of 37 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
visualizations/architecture/devflow-ecosystem.md Documents new CLI commands in the ecosystem diagram/table.
tests/unit/watch.bats Adds unit tests for install-mode detection and auto-reinstall guards.
tests/unit/release.bats Adds unit tests for conventional commit parsing, semver bumping, and version bump behavior.
skills/worktree-flow/new-feature.md Adds optional “codebase walkthrough” step before brainstorming.
skills/registry.json Registers the new codebase-walkthrough skill.
skills/process-discipline/codebase-walkthrough.md Adds the new walkthrough skill definition/content.
scripts/bump-version.sh Adds a standalone version bump script used by CLI/CI.
Makefile Adds version-bump phony target and wiring to bump script.
lib/watch.sh Adds auto-reinstall functionality and setup opt-in; integrates into watcher run steps.
lib/release.sh Adds conventional commit parsing, semver bumping, and CLI wrappers for release/version bump.
docs/plans/2026-03-19-release-and-reinstall-plan.md Adds an implementation plan doc for the feature set.
docs/plans/2026-03-18-release-pipeline-design.md Adds design doc for the release pipeline.
docs/plans/2026-03-18-auto-reinstall-design.md Adds design doc for the auto-reinstall extension.
devflow-plugin/hooks/hooks.json Adds a Stop hook to remind about session wrap-up commands.
devflow-plugin/commands/writing-plans.md Updates the writing-plans command content (agent-deck handoff flow).
devflow-plugin/commands/visualizations-config.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/update-visualizations.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/spec-feature.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/session-summary.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/scope-check.md Deletes this command doc.
devflow-plugin/commands/retain-learning.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/reflect-session.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/pre-push-check.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/pr-strategy.md Deletes this command doc.
devflow-plugin/commands/dependency-update.md Removes version badge from description; keeps command intent.
devflow-plugin/commands/create-pr.md Simplifies PR creation guidance to GitHub-only flow.
devflow-plugin/commands/new-feature.md Simplifies new-feature flow; adds optional walkthrough hook.
devflow-plugin/commands/finish-feature.md Simplifies finish-feature flow; removes VCS-aware/MR branching.
devflow-plugin/commands/task-prioritize.md Deletes this command doc.
devflow-plugin/commands/task-complete.md Deletes this command doc.
devflow-plugin/commands/check-sensitive.md Deletes this command doc.
devflow-plugin/commands/codebase-walkthrough.md Adds plugin command file for the walkthrough (mirrors skill content).
CLAUDE.md Documents release process + auto-reinstall; adds lib/release.sh to structure.
bin/devflow Sources lib/release.sh and adds version-bump / release command dispatch + help.
.github/workflows/release.yml Adds automated release workflow for pushes to main and manual dispatch.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/release.sh Outdated
Comment on lines +19 to +32
# Determine commit range
local range
if [[ -n "$last_tag" ]]; then
range="${last_tag}..HEAD"
else
# No previous tag — scan from initial commit
local initial_commit
initial_commit="$(git -C "$project_dir" rev-list --max-parents=0 HEAD 2>/dev/null | head -1)"
range="${initial_commit}..HEAD"
fi

# Get full commit messages (subject + body)
local commits
commits="$(git -C "$project_dir" log "$range" --format='%B---COMMIT_SEP---' 2>/dev/null || echo "")"
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

When no previous tag exists, the computed range ${initial_commit}..HEAD excludes the initial (root) commit itself. For a repo with only one commit (the root), git log <root>..HEAD returns nothing, so the parser will incorrectly return none and skip the first release. Consider scanning all commits when last_tag is empty (e.g., git log --format ... HEAD), or using an inclusive range (e.g., --reverse --format ... $(git rev-list --max-parents=0 HEAD)), so the root commit is included.

Suggested change
# Determine commit range
local range
if [[ -n "$last_tag" ]]; then
range="${last_tag}..HEAD"
else
# No previous tag — scan from initial commit
local initial_commit
initial_commit="$(git -C "$project_dir" rev-list --max-parents=0 HEAD 2>/dev/null | head -1)"
range="${initial_commit}..HEAD"
fi
# Get full commit messages (subject + body)
local commits
commits="$(git -C "$project_dir" log "$range" --format='%B---COMMIT_SEP---' 2>/dev/null || echo "")"
# Determine log target
local log_target
if [[ -n "$last_tag" ]]; then
log_target="${last_tag}..HEAD"
else
# No previous tag — scan all commits reachable from HEAD, including the root commit
log_target="HEAD"
fi
# Get full commit messages (subject + body)
local commits
commits="$(git -C "$project_dir" log "$log_target" --format='%B---COMMIT_SEP---' 2>/dev/null || echo "")"

Copilot uses AI. Check for mistakes.
Comment thread lib/release.sh Outdated
Comment on lines +30 to +33
# Get full commit messages (subject + body)
local commits
commits="$(git -C "$project_dir" log "$range" --format='%B---COMMIT_SEP---' 2>/dev/null || echo "")"
if [[ -z "$commits" ]]; then
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

Commit parsing currently stores the full log output in a bash variable and then tries to inject NUL separators via sed 's/.../\x00/g'. BSD/macOS sed does not reliably support \xNN escapes, and bash variables cannot hold NUL bytes anyway, so this approach is fragile across platforms. Prefer streaming directly from git log using git’s built-in %x00 to emit NUL separators (and avoid the intermediate variable), then iterate with read -d ''.

Copilot uses AI. Check for mistakes.
Comment thread lib/watch.sh Outdated
Comment on lines +302 to +306
# Log full make output for debugging
mkdir -p "${HOME}/.devflow"
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] make ${make_target} FAILED output:" >> "${HOME}/.devflow/watch.log"
echo "$make_output" >> "${HOME}/.devflow/watch.log"
_watch_notify "devflow auto-update FAILED: make ${make_target} exited with code $?" "$headless"
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

In the failure path, the notification uses $? after writing to the log, so it will report the exit code of the last echo/mkdir, not the failing make command. Capture make's exit status immediately (e.g., into a local make_rc) before doing any other commands, and use that value in the notify/log message.

Suggested change
# Log full make output for debugging
mkdir -p "${HOME}/.devflow"
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] make ${make_target} FAILED output:" >> "${HOME}/.devflow/watch.log"
echo "$make_output" >> "${HOME}/.devflow/watch.log"
_watch_notify "devflow auto-update FAILED: make ${make_target} exited with code $?" "$headless"
local make_rc=$?
# Log full make output for debugging
mkdir -p "${HOME}/.devflow"
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] make ${make_target} FAILED output:" >> "${HOME}/.devflow/watch.log"
echo "$make_output" >> "${HOME}/.devflow/watch.log"
_watch_notify "devflow auto-update FAILED: make ${make_target} exited with code ${make_rc}" "$headless"

Copilot uses AI. Check for mistakes.
Comment thread lib/release.sh Outdated
Comment on lines +65 to +73
feat:*|feat\(*)
[[ "$bump" != "major" ]] && bump="minor"
feat_msgs+="feat|${subject}\n"
;;
fix:*|fix\(*)
[[ "$bump" == "none" ]] && bump="patch"
fix_msgs+="fix|${subject}\n"
;;
docs:*|chore:*|refactor:*|test:*|ci:*|style:*|perf:*)
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The categorization case patterns only match types with a literal : (e.g., refactor:) or type(, so conventional-commit variants with breaking markers like refactor!: / docs!: won’t be captured into any of the feat|fix|other lists. This leads to missing entries in the preview/release notes even though the bump may be detected as major. Consider allowing an optional ! before : (and after scope) for the non-feat/fix categories as well, or normalizing the subject before matching.

Suggested change
feat:*|feat\(*)
[[ "$bump" != "major" ]] && bump="minor"
feat_msgs+="feat|${subject}\n"
;;
fix:*|fix\(*)
[[ "$bump" == "none" ]] && bump="patch"
fix_msgs+="fix|${subject}\n"
;;
docs:*|chore:*|refactor:*|test:*|ci:*|style:*|perf:*)
feat:*|feat!:*|feat\(*)
[[ "$bump" != "major" ]] && bump="minor"
feat_msgs+="feat|${subject}\n"
;;
fix:*|fix!:*|fix\(*)
[[ "$bump" == "none" ]] && bump="patch"
fix_msgs+="fix|${subject}\n"
;;
docs:*|docs!:*|docs\(*|chore:*|chore!:*|chore\(*|refactor:*|refactor!:*|refactor\(*|test:*|test!:*|test\(*|ci:*|ci!:*|ci\(*|style:*|style!:*|style\(*|perf:*|perf!:*|perf\(*)

Copilot uses AI. Check for mistakes.
- Use `HEAD` instead of `initial_commit..HEAD` when no tags exist,
  so the root commit is included in the first release
- Use git's `%x00` format for NUL-separated commit parsing instead
  of piping through `sed 's/.../\x00/g'` (portable, no bash NUL issues)
- Capture `make` exit code immediately with `local make_rc=$?` before
  logging commands overwrite `$?`
- Add `type!:` breaking-change variants to all case patterns so
  `refactor!:`, `docs!:`, etc. are categorized in release notes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AndreJorgeLopes
Copy link
Copy Markdown
Owner Author

AndreJorgeLopes commented Apr 6, 2026

review the code after the changes and if you find any required change, do the changes yourself! Also, resolve the conversations if not needed anymore @copilot

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 4df03dd3-0882-4268-94c3-63afc0bca0a2

5 similar comments
Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 4df03dd3-0882-4268-94c3-63afc0bca0a2

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 4df03dd3-0882-4268-94c3-63afc0bca0a2

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 4df03dd3-0882-4268-94c3-63afc0bca0a2

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 4df03dd3-0882-4268-94c3-63afc0bca0a2

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 4df03dd3-0882-4268-94c3-63afc0bca0a2

@AndreJorgeLopes
Copy link
Copy Markdown
Owner Author

@copilot

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 12f8c425-c44d-4934-92d6-bd64d3537d5c

@AndreJorgeLopes
Copy link
Copy Markdown
Owner Author

@copilot

Copy link
Copy Markdown

Copilot AI commented Apr 6, 2026

@AndreJorgeLopes The model is not available for your account. This can happen if the model was disabled by your organization's policy or if your Copilot plan doesn't include access to it.

You can try again without specifying a model (just @copilot) to use the default, or choose a different model from the model picker.

If you want to contact GitHub about this error, please mention the following identifier so they can better serve you: 12f8c425-c44d-4934-92d6-bd64d3537d5c

@AndreJorgeLopes
Copy link
Copy Markdown
Owner Author

@claude[agent]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants