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
1 change: 1 addition & 0 deletions .beads/issues.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{"id":"devloop-8km","title":"Implement config and workflow engine","description":"Load config, watch paths, classify events, and execute ordered workflows against named processes and hooks.","status":"closed","priority":2,"issue_type":"feature","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-03-24T01:15:00Z","created_by":"Daniel Vianna","updated_at":"2026-03-24T02:09:33Z","closed_at":"2026-03-24T02:09:33Z","close_reason":"Closed","dependencies":[{"issue_id":"devloop-8km","depends_on_id":"devloop-0nx","type":"blocks","created_at":"2026-03-24T12:15:07Z","created_by":"Daniel Vianna","metadata":"{}"}]}
{"id":"devloop-c6l","title":"Polish 0.8.0 release docs and test ergonomics","status":"closed","priority":2,"issue_type":"task","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-04-08T07:12:58Z","created_by":"Daniel Vianna","updated_at":"2026-04-08T07:20:27Z","closed_at":"2026-04-08T07:20:27Z","close_reason":"Closed"}
{"id":"devloop-d81","title":"Move real client config out of devloop examples","description":"Keep only generic examples in devloop and move the working blog config into the client repository root.","status":"closed","priority":2,"issue_type":"task","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-03-24T02:31:27Z","created_by":"Daniel Vianna","updated_at":"2026-03-24T02:39:07Z","closed_at":"2026-03-24T02:39:07Z","close_reason":"Kept only generic examples in devloop and moved the working blog config into the client repo root."}
{"id":"devloop-dxz","title":"Use changelog-driven GitHub release notes and backfill old releases","status":"closed","priority":2,"issue_type":"task","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-04-08T08:18:49Z","created_by":"Daniel Vianna","updated_at":"2026-04-08T08:26:59Z","closed_at":"2026-04-08T08:26:59Z","close_reason":"Closed"}
{"id":"devloop-dzy","title":"Make client hook paths repo-relative","description":"Resolve devloop config command paths relative to the client repo or config, not the tool checkout.","status":"closed","priority":2,"issue_type":"task","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-03-24T02:16:34Z","created_by":"Daniel Vianna","updated_at":"2026-03-24T02:22:17Z","closed_at":"2026-03-24T02:22:17Z","close_reason":"Closed"}
{"id":"devloop-mml","title":"Address roborev findings on state ownership and client-specific URL composition","status":"closed","priority":1,"issue_type":"task","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-03-24T02:44:51Z","created_by":"Daniel Vianna","updated_at":"2026-03-24T02:53:31Z","closed_at":"2026-03-24T02:53:31Z","close_reason":"Shared session state is now owned in memory, generic state templating replaced blog-specific derivation, redundant writes are skipped, and the review job was addressed."}
{"id":"devloop-nmu","title":"Add blog client example and verification","description":"Create example config/hooks for the blog repo and verify the tool runs against it.","status":"closed","priority":2,"issue_type":"task","owner":"1708810+dmvianna@users.noreply.github.com","created_at":"2026-03-24T01:15:00Z","created_by":"Daniel Vianna","updated_at":"2026-03-24T02:09:33Z","closed_at":"2026-03-24T02:09:33Z","close_reason":"Closed","dependencies":[{"issue_id":"devloop-nmu","depends_on_id":"devloop-8km","type":"blocks","created_at":"2026-03-24T12:15:07Z","created_by":"Daniel Vianna","metadata":"{}"}]}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linux-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
runner: ubuntu-latest
target: x86_64-unknown-linux-gnu
archive_name: devloop-x86_64-unknown-linux-gnu.tar.gz
generate_release_notes: true
publish_release_notes: true
2 changes: 1 addition & 1 deletion .github/workflows/macos-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
runner: macos-14
target: aarch64-apple-darwin
archive_name: devloop-aarch64-apple-darwin.tar.gz
generate_release_notes: false
publish_release_notes: false
19 changes: 17 additions & 2 deletions .github/workflows/release-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
archive_name:
required: true
type: string
generate_release_notes:
publish_release_notes:
required: true
type: boolean

Expand Down Expand Up @@ -56,9 +56,24 @@ jobs:
cp "target/${{ inputs.target }}/release/devloop" dist/devloop
tar -C dist -czf "${{ inputs.archive_name }}" devloop

- name: Extract release notes from changelog
if: inputs.publish_release_notes
shell: bash
run: |
set -euo pipefail
./scripts/release-notes-from-changelog.sh "${GITHUB_REF_NAME#v}" "${GITHUB_REPOSITORY}" > release-notes.md

- name: Publish GitHub release asset
if: inputs.publish_release_notes
uses: softprops/action-gh-release@v2
with:
files: ${{ inputs.archive_name }}
body_path: release-notes.md
fail_on_unmatched_files: true

- name: Publish GitHub release asset without notes
if: ${{ !inputs.publish_release_notes }}
uses: softprops/action-gh-release@v2
with:
files: ${{ inputs.archive_name }}
generate_release_notes: ${{ inputs.generate_release_notes }}
fail_on_unmatched_files: true
10 changes: 10 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ cargo clippy --all-targets --all-features -- -D warnings
checks that `devloop run` can start, begin watching, react to one file
change, and shut down cleanly.

## Releases

`devloop` releases are tag-driven. Push a tag such as `v0.8.0` and the
platform release workflows publish the Linux and macOS archives.

GitHub release notes are generated from the matching section in
`CHANGELOG.md`, not from GitHub's automatic PR summary. The Linux
release job publishes the changelog text and compare link; the macOS job
only attaches its archive asset to that same release.

## Opt-in watch flake smoke

The repeated-edit watch flake smoke test is intentionally opt-in. It is
Expand Down
50 changes: 50 additions & 0 deletions scripts/release-notes-from-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -lt 1 || $# -gt 2 ]]; then
echo "usage: $0 <version> [repo-slug]" >&2
exit 1
fi

version="$1"
repo_slug="${2:-}"
changelog_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/CHANGELOG.md"

section="$(
awk -v version="$version" '
$0 ~ "^## \\[" version "\\] - " { in_section=1 }
in_section {
if ($0 ~ "^## \\[" && $0 !~ "^## \\[" version "\\] - ") {
exit
}
print
}
' "$changelog_path"
)"

if [[ -z "$section" ]]; then
echo "could not find changelog section for version $version" >&2
exit 1
fi

printf '%s\n' "$section"

if [[ -n "$repo_slug" ]]; then
previous_version="$(
awk -v version="$version" '
$0 ~ "^## \\[" version "\\] - " { found=1; next }
found && $0 ~ /^## \[[^]]+\] - / {
line = $0
sub(/^## \[/, "", line)
sub(/\].*/, "", line)
print line
exit
}
' "$changelog_path"
)"

if [[ -n "$previous_version" && "$previous_version" != "Unreleased" ]]; then
printf '\n**Full Changelog**: https://github.com/%s/compare/v%s...v%s\n' \
"$repo_slug" "$previous_version" "$version"
fi
fi