Skip to content

Commit 07992bf

Browse files
committed
refactor: implement workflow_dispatch release pattern
Replace automatic tagging with manual release workflow, matching kods-core pattern. **Changes**: New files: - scripts/compute_plugin_version.py: Computes next semantic version based on git tags - .github/workflows/release.yml: Manual release workflow with workflow_dispatch Modified: - .github/workflows/version-validation.yml: Simplified to only check version consistency - VERSIONING.md: Rewritten to document the new release process Removed: - .github/workflows/release-tags.yml: Automatic tagging is replaced by manual workflow **How it works**: 1. Trigger .github/workflows/release.yml from GitHub Actions 2. Provide plugin name and bump type (patch/minor/major) 3. Workflow computes new version from git tags 4. Automatically updates plugin.json and marketplace.json 5. Creates commit and git tags (canonical + aliases) **Benefits**: - Source of truth is git tags, not file versions - Explicit release control via workflow_dispatch - Automatic version computation prevents human error - Consistent with kods-core release pattern - Self-hosted runner execution
1 parent 066204f commit 07992bf

5 files changed

Lines changed: 305 additions & 359 deletions

File tree

.github/workflows/release-tags.yml

Lines changed: 0 additions & 73 deletions
This file was deleted.

.github/workflows/release.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: Release Plugin
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
plugin:
7+
description: Plugin to release
8+
required: true
9+
type: choice
10+
options:
11+
- rdi
12+
- python-dev
13+
bump:
14+
description: Version bump type
15+
required: true
16+
type: choice
17+
options:
18+
- patch
19+
- minor
20+
- major
21+
22+
permissions:
23+
contents: write
24+
25+
jobs:
26+
release:
27+
name: Release ${{ inputs.plugin }}
28+
runs-on: self-hosted
29+
steps:
30+
- uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 0
33+
34+
- name: Configure git identity
35+
run: |
36+
git config user.name "github-actions[bot]"
37+
git config user.email "github-actions[bot]@users.noreply.github.com"
38+
39+
- name: Fetch tags
40+
run: git fetch --force --tags origin
41+
42+
- name: Compute release version
43+
id: version
44+
run: |
45+
python3 scripts/compute_plugin_version.py \
46+
--plugin "${{ inputs.plugin }}" \
47+
--bump "${{ inputs.bump }}" \
48+
--github-output "$GITHUB_OUTPUT"
49+
50+
- name: Update plugin.json
51+
run: |
52+
python3 - <<'PYTHON'
53+
import json
54+
from pathlib import Path
55+
56+
plugin_json_path = Path("plugins/${{ inputs.plugin }}/.claude-plugin/plugin.json")
57+
data = json.loads(plugin_json_path.read_text())
58+
data["version"] = "${{ steps.version.outputs.new_version }}"
59+
plugin_json_path.write_text(json.dumps(data, indent=2) + "\n")
60+
PYTHON
61+
62+
- name: Update marketplace.json
63+
run: |
64+
python3 - <<'PYTHON'
65+
import json
66+
from pathlib import Path
67+
68+
marketplace_path = Path(".claude-plugin/marketplace.json")
69+
data = json.loads(marketplace_path.read_text())
70+
71+
for plugin in data.get("plugins", []):
72+
if plugin["name"] == "${{ inputs.plugin }}":
73+
plugin["version"] = "${{ steps.version.outputs.new_version }}"
74+
break
75+
76+
marketplace_path.write_text(json.dumps(data, indent=2) + "\n")
77+
PYTHON
78+
79+
- name: Commit version bump
80+
run: |
81+
git add plugins/${{ inputs.plugin }}/.claude-plugin/plugin.json
82+
git add .claude-plugin/marketplace.json
83+
git commit -m "chore: release ${{ inputs.plugin }} v${{ steps.version.outputs.new_version }}"
84+
85+
- name: Push commit
86+
run: git push origin main
87+
88+
- name: Create canonical tag
89+
run: |
90+
git tag -a "${{ steps.version.outputs.canonical_tag }}" \
91+
-m "release: ${{ steps.version.outputs.canonical_tag }}"
92+
git push origin "${{ steps.version.outputs.canonical_tag }}"
93+
94+
- name: Create and push alias tags
95+
run: |
96+
for tag in $(echo "${{ steps.version.outputs.alias_tags }}" | tr ',' ' '); do
97+
git tag -fa "$tag" -m "release alias: $tag"
98+
git push origin "refs/tags/$tag" --force
99+
done
100+
101+
- name: Summary
102+
run: |
103+
echo "✅ Release complete!"
104+
echo ""
105+
echo "Plugin: ${{ inputs.plugin }}"
106+
echo "Version: v${{ steps.version.outputs.new_version }}"
107+
echo ""
108+
echo "📌 Tags created:"
109+
echo " Canonical: ${{ steps.version.outputs.canonical_tag }}"
110+
echo " Aliases: ${{ steps.version.outputs.alias_tags }}"

.github/workflows/version-validation.yml

Lines changed: 4 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -50,78 +50,15 @@ jobs:
5050
fi
5151
done
5252
53-
- name: Check version bump on code changes
54-
if: github.event_name == 'pull_request'
55-
run: |
56-
echo "📋 Checking if versions were bumped for code changes..."
57-
58-
plugins=("rdi" "python-dev")
59-
60-
for plugin in "${plugins[@]}"; do
61-
plugin_dir="plugins/$plugin"
62-
63-
# Check if plugin code changed (excluding version files)
64-
code_changed=$(git diff origin/main...HEAD -- "$plugin_dir" | \
65-
grep -v '.version' | \
66-
grep -v '.claude-plugin/plugin.json' | \
67-
grep -v '\.claude-plugin/marketplace.json' | \
68-
grep '^+\|^-' | \
69-
wc -l)
70-
71-
if [ "$code_changed" -gt 0 ]; then
72-
# Check if version was bumped
73-
version_changed=$(git diff origin/main...HEAD -- \
74-
"plugins/$plugin/.claude-plugin/plugin.json" \
75-
".claude-plugin/marketplace.json" | \
76-
grep -c '"version"' || true)
77-
78-
if [ "$version_changed" -eq 0 ]; then
79-
echo "❌ Code changed in $plugin but version not bumped!"
80-
echo " ✓ Update both:"
81-
echo " - plugins/$plugin/.claude-plugin/plugin.json"
82-
echo " - .claude-plugin/marketplace.json"
83-
exit 1
84-
else
85-
echo "✓ $plugin version was bumped"
86-
fi
87-
else
88-
echo "ℹ️ No code changes in $plugin"
89-
fi
90-
done
91-
92-
- name: Validate git tags on main
93-
if: github.ref == 'refs/heads/main'
94-
run: |
95-
echo "🏷️ Validating git tags..."
96-
97-
plugins=("rdi" "python-dev")
98-
99-
for plugin in "${plugins[@]}"; do
100-
plugin_json="plugins/$plugin/.claude-plugin/plugin.json"
101-
102-
if [ -f "$plugin_json" ]; then
103-
version=$(jq -r '.version' "$plugin_json")
104-
tag="$plugin@$version"
105-
106-
# Check if tag exists
107-
if git rev-parse --verify "$tag" >/dev/null 2>&1; then
108-
echo "✓ Tag exists: $tag"
109-
else
110-
echo "⚠️ Tag missing: $tag (will be created by release job)"
111-
fi
112-
fi
113-
done
11453
11554
- name: Summary
11655
run: |
11756
echo ""
11857
echo "✅ Version validation passed!"
11958
echo ""
120-
echo "📌 Versioning guidelines:"
121-
echo " - PATCH: bug fixes, docs, config changes"
122-
echo " - MINOR: new features, new agents/skills"
123-
echo " - MAJOR: breaking changes"
124-
echo ""
125-
echo "📝 Always update both:"
59+
echo "📌 Versions must match between:"
12660
echo " - plugins/PLUGIN/.claude-plugin/plugin.json"
12761
echo " - .claude-plugin/marketplace.json"
62+
echo ""
63+
echo "ℹ️ Version bumps are handled by: .github/workflows/release.yml"
64+
echo " Trigger with: workflow_dispatch on GitHub Actions"

0 commit comments

Comments
 (0)