Skip to content

Commit a440d46

Browse files
authored
Merge pull request #9 from a5m0/claude/check-plugin-auto-update-ZvoVl
feat: add plugin version auto-update infrastructure
2 parents ae71033 + 67fd6c5 commit a440d46

6 files changed

Lines changed: 354 additions & 2 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"name": "playwright-skill",
1414
"source": "./",
1515
"description": "Claude Code Skill for general-purpose browser automation with Playwright. Claude autonomously writes and executes custom automation for testing pages, validating UX, and any browser task.",
16-
"version": "4.1.0",
16+
"version": "5.0.0",
1717
"author": {
1818
"name": "lackeyjb+a5m0"
1919
},

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "playwright-skill",
3-
"version": "4.1.0",
3+
"version": "5.0.0",
44
"description": "Claude Code Skill for general-purpose browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp, and autonomously handles any browser automation task.",
55
"author": {
66
"name": "lackeyjb+a5m0"

.github/workflows/release.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Validate version consistency
19+
run: |
20+
# Extract versions from all files
21+
PLUGIN_VERSION=$(grep '"version"' .claude-plugin/plugin.json | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/')
22+
MARKETPLACE_VERSION=$(python3 -c "import json; print(json.load(open('.claude-plugin/marketplace.json'))['plugins'][0]['version'])")
23+
PYPROJECT_VERSION=$(grep '^version = ' skills/playwright-skill/pyproject.toml | sed 's/version = "\([^"]*\)"/\1/')
24+
TAG_VERSION=${GITHUB_REF#refs/tags/v}
25+
26+
echo "Tag version: $TAG_VERSION"
27+
echo "plugin.json version: $PLUGIN_VERSION"
28+
echo "marketplace.json version: $MARKETPLACE_VERSION"
29+
echo "pyproject.toml version: $PYPROJECT_VERSION"
30+
31+
# Check all versions match
32+
if [[ "$PLUGIN_VERSION" != "$TAG_VERSION" ]]; then
33+
echo "❌ plugin.json version ($PLUGIN_VERSION) doesn't match tag ($TAG_VERSION)"
34+
exit 1
35+
fi
36+
if [[ "$MARKETPLACE_VERSION" != "$TAG_VERSION" ]]; then
37+
echo "❌ marketplace.json version ($MARKETPLACE_VERSION) doesn't match tag ($TAG_VERSION)"
38+
exit 1
39+
fi
40+
if [[ "$PYPROJECT_VERSION" != "$TAG_VERSION" ]]; then
41+
echo "❌ pyproject.toml version ($PYPROJECT_VERSION) doesn't match tag ($TAG_VERSION)"
42+
exit 1
43+
fi
44+
45+
echo "✅ All versions match: $TAG_VERSION"
46+
47+
- name: Generate release notes
48+
id: release_notes
49+
run: |
50+
# Get the previous tag
51+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
52+
53+
if [[ -n "$PREV_TAG" ]]; then
54+
echo "Generating changelog from $PREV_TAG to ${GITHUB_REF#refs/tags/}"
55+
CHANGES=$(git log --pretty=format:"- %s" $PREV_TAG..HEAD)
56+
else
57+
echo "First release, including all commits"
58+
CHANGES=$(git log --pretty=format:"- %s")
59+
fi
60+
61+
# Write to file for multiline support
62+
echo "$CHANGES" > /tmp/changes.txt
63+
echo "changes_file=/tmp/changes.txt" >> $GITHUB_OUTPUT
64+
65+
- name: Create GitHub Release
66+
uses: softprops/action-gh-release@v1
67+
with:
68+
generate_release_notes: true
69+
body_path: /tmp/changes.txt
70+
env:
71+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Version Check
2+
3+
on:
4+
pull_request:
5+
branches: [main, master]
6+
push:
7+
branches: [main, master]
8+
9+
jobs:
10+
check-version-sync:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Check version consistency
17+
run: |
18+
echo "Checking version consistency across all manifest files..."
19+
20+
# Extract versions from all files
21+
PLUGIN_VERSION=$(grep '"version"' .claude-plugin/plugin.json | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/')
22+
MARKETPLACE_VERSION=$(python3 -c "import json; print(json.load(open('.claude-plugin/marketplace.json'))['plugins'][0]['version'])")
23+
PYPROJECT_VERSION=$(grep '^version = ' skills/playwright-skill/pyproject.toml | sed 's/version = "\([^"]*\)"/\1/')
24+
25+
echo "plugin.json version: $PLUGIN_VERSION"
26+
echo "marketplace.json version: $MARKETPLACE_VERSION"
27+
echo "pyproject.toml version: $PYPROJECT_VERSION"
28+
29+
# Check all versions match
30+
if [[ "$PLUGIN_VERSION" != "$MARKETPLACE_VERSION" ]]; then
31+
echo ""
32+
echo "❌ Version mismatch!"
33+
echo " plugin.json: $PLUGIN_VERSION"
34+
echo " marketplace.json: $MARKETPLACE_VERSION"
35+
echo ""
36+
echo "Run './scripts/bump-version.sh <version>' to sync versions"
37+
exit 1
38+
fi
39+
40+
if [[ "$PLUGIN_VERSION" != "$PYPROJECT_VERSION" ]]; then
41+
echo ""
42+
echo "❌ Version mismatch!"
43+
echo " plugin.json: $PLUGIN_VERSION"
44+
echo " pyproject.toml: $PYPROJECT_VERSION"
45+
echo ""
46+
echo "Run './scripts/bump-version.sh <version>' to sync versions"
47+
exit 1
48+
fi
49+
50+
echo ""
51+
echo "✅ All versions synchronized: $PLUGIN_VERSION"
52+
53+
- name: Validate version format
54+
run: |
55+
VERSION=$(grep '"version"' .claude-plugin/plugin.json | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/')
56+
57+
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
58+
echo "❌ Invalid version format: $VERSION"
59+
echo " Expected semantic versioning: X.Y.Z"
60+
exit 1
61+
fi
62+
63+
echo "✅ Version format valid: $VERSION"

scripts/bump-version.sh

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#!/bin/bash
2+
# Version bump script for playwright-skill
3+
# Usage: ./scripts/bump-version.sh [major|minor|patch] or ./scripts/bump-version.sh <version>
4+
# Example: ./scripts/bump-version.sh patch -> 5.0.0 becomes 5.0.1
5+
# Example: ./scripts/bump-version.sh 6.0.0 -> sets version to 6.0.0
6+
7+
set -e
8+
9+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
11+
12+
# Files containing version information
13+
PLUGIN_JSON="$ROOT_DIR/.claude-plugin/plugin.json"
14+
MARKETPLACE_JSON="$ROOT_DIR/.claude-plugin/marketplace.json"
15+
PYPROJECT_TOML="$ROOT_DIR/skills/playwright-skill/pyproject.toml"
16+
17+
# Get current version from plugin.json (source of truth)
18+
get_current_version() {
19+
grep '"version"' "$PLUGIN_JSON" | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/'
20+
}
21+
22+
# Calculate new version based on bump type
23+
calculate_new_version() {
24+
local current="$1"
25+
local bump_type="$2"
26+
27+
IFS='.' read -r major minor patch <<< "$current"
28+
29+
case "$bump_type" in
30+
major)
31+
echo "$((major + 1)).0.0"
32+
;;
33+
minor)
34+
echo "$major.$((minor + 1)).0"
35+
;;
36+
patch)
37+
echo "$major.$minor.$((patch + 1))"
38+
;;
39+
*)
40+
# Assume it's a direct version string
41+
if [[ "$bump_type" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
42+
echo "$bump_type"
43+
else
44+
echo "Error: Invalid version format. Use major|minor|patch or X.Y.Z" >&2
45+
exit 1
46+
fi
47+
;;
48+
esac
49+
}
50+
51+
# Update version in all files
52+
update_version() {
53+
local new_version="$1"
54+
55+
echo "Updating versions to $new_version..."
56+
57+
# Update plugin.json
58+
if [[ -f "$PLUGIN_JSON" ]]; then
59+
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$new_version\"/" "$PLUGIN_JSON"
60+
echo " ✓ Updated $PLUGIN_JSON"
61+
fi
62+
63+
# Update marketplace.json (plugin version, not metadata version)
64+
if [[ -f "$MARKETPLACE_JSON" ]]; then
65+
# Use a more specific pattern to only update the plugin version, not metadata version
66+
python3 -c "
67+
import json
68+
with open('$MARKETPLACE_JSON', 'r') as f:
69+
data = json.load(f)
70+
for plugin in data.get('plugins', []):
71+
plugin['version'] = '$new_version'
72+
with open('$MARKETPLACE_JSON', 'w') as f:
73+
json.dump(data, f, indent=2)
74+
f.write('\n')
75+
"
76+
echo " ✓ Updated $MARKETPLACE_JSON"
77+
fi
78+
79+
# Update pyproject.toml
80+
if [[ -f "$PYPROJECT_TOML" ]]; then
81+
sed -i "s/^version = \"[^\"]*\"/version = \"$new_version\"/" "$PYPROJECT_TOML"
82+
echo " ✓ Updated $PYPROJECT_TOML"
83+
fi
84+
}
85+
86+
# Verify all versions match
87+
verify_versions() {
88+
local expected="$1"
89+
local all_match=true
90+
91+
echo "Verifying versions..."
92+
93+
# Check plugin.json
94+
local plugin_version=$(grep '"version"' "$PLUGIN_JSON" | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/')
95+
if [[ "$plugin_version" == "$expected" ]]; then
96+
echo " ✓ plugin.json: $plugin_version"
97+
else
98+
echo " ✗ plugin.json: $plugin_version (expected $expected)"
99+
all_match=false
100+
fi
101+
102+
# Check marketplace.json
103+
local marketplace_version=$(python3 -c "import json; print(json.load(open('$MARKETPLACE_JSON'))['plugins'][0]['version'])")
104+
if [[ "$marketplace_version" == "$expected" ]]; then
105+
echo " ✓ marketplace.json: $marketplace_version"
106+
else
107+
echo " ✗ marketplace.json: $marketplace_version (expected $expected)"
108+
all_match=false
109+
fi
110+
111+
# Check pyproject.toml
112+
local pyproject_version=$(grep '^version = ' "$PYPROJECT_TOML" | sed 's/version = "\([^"]*\)"/\1/')
113+
if [[ "$pyproject_version" == "$expected" ]]; then
114+
echo " ✓ pyproject.toml: $pyproject_version"
115+
else
116+
echo " ✗ pyproject.toml: $pyproject_version (expected $expected)"
117+
all_match=false
118+
fi
119+
120+
if [[ "$all_match" == "true" ]]; then
121+
echo ""
122+
echo "All versions synchronized to $expected"
123+
return 0
124+
else
125+
echo ""
126+
echo "Version mismatch detected!"
127+
return 1
128+
fi
129+
}
130+
131+
# Main
132+
main() {
133+
if [[ $# -eq 0 ]]; then
134+
echo "Usage: $0 [major|minor|patch|<version>]"
135+
echo ""
136+
echo "Current version: $(get_current_version)"
137+
echo ""
138+
echo "Examples:"
139+
echo " $0 patch # Bump patch version (5.0.0 -> 5.0.1)"
140+
echo " $0 minor # Bump minor version (5.0.0 -> 5.1.0)"
141+
echo " $0 major # Bump major version (5.0.0 -> 6.0.0)"
142+
echo " $0 5.2.0 # Set specific version"
143+
exit 0
144+
fi
145+
146+
local current_version=$(get_current_version)
147+
local new_version=$(calculate_new_version "$current_version" "$1")
148+
149+
echo "Bumping version: $current_version -> $new_version"
150+
echo ""
151+
152+
update_version "$new_version"
153+
echo ""
154+
verify_versions "$new_version"
155+
156+
echo ""
157+
echo "Next steps:"
158+
echo " 1. Review changes: git diff"
159+
echo " 2. Commit: git commit -am 'chore: bump version to $new_version'"
160+
echo " 3. Tag: git tag -a v$new_version -m 'Release v$new_version'"
161+
echo " 4. Push: git push && git push --tags"
162+
}
163+
164+
main "$@"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/bin/bash
2+
# Pre-commit hook to validate version consistency
3+
# Install: cp scripts/pre-commit-version-check.sh .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
4+
5+
set -e
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
9+
# Handle both direct execution and hook execution
10+
if [[ -d "$SCRIPT_DIR/../.claude-plugin" ]]; then
11+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
12+
elif [[ -d "$SCRIPT_DIR/../../.claude-plugin" ]]; then
13+
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
14+
else
15+
echo "Error: Could not find repository root"
16+
exit 1
17+
fi
18+
19+
PLUGIN_JSON="$ROOT_DIR/.claude-plugin/plugin.json"
20+
MARKETPLACE_JSON="$ROOT_DIR/.claude-plugin/marketplace.json"
21+
PYPROJECT_TOML="$ROOT_DIR/skills/playwright-skill/pyproject.toml"
22+
23+
# Check if any version files are being committed
24+
VERSION_FILES_CHANGED=false
25+
if git diff --cached --name-only | grep -qE "(plugin\.json|marketplace\.json|pyproject\.toml)"; then
26+
VERSION_FILES_CHANGED=true
27+
fi
28+
29+
# Extract versions
30+
PLUGIN_VERSION=$(grep '"version"' "$PLUGIN_JSON" | head -1 | sed 's/.*"version": "\([^"]*\)".*/\1/')
31+
MARKETPLACE_VERSION=$(python3 -c "import json; print(json.load(open('$MARKETPLACE_JSON'))['plugins'][0]['version'])")
32+
PYPROJECT_VERSION=$(grep '^version = ' "$PYPROJECT_TOML" | sed 's/version = "\([^"]*\)"/\1/')
33+
34+
# Check version consistency
35+
if [[ "$PLUGIN_VERSION" != "$MARKETPLACE_VERSION" ]] || [[ "$PLUGIN_VERSION" != "$PYPROJECT_VERSION" ]]; then
36+
echo "❌ Version mismatch detected!"
37+
echo ""
38+
echo " plugin.json: $PLUGIN_VERSION"
39+
echo " marketplace.json: $MARKETPLACE_VERSION"
40+
echo " pyproject.toml: $PYPROJECT_VERSION"
41+
echo ""
42+
echo "Please run: ./scripts/bump-version.sh $PLUGIN_VERSION"
43+
echo "Or specify the version you want: ./scripts/bump-version.sh <major|minor|patch|X.Y.Z>"
44+
exit 1
45+
fi
46+
47+
# Validate version format
48+
if [[ ! "$PLUGIN_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
49+
echo "❌ Invalid version format: $PLUGIN_VERSION"
50+
echo " Expected semantic versioning: X.Y.Z"
51+
exit 1
52+
fi
53+
54+
echo "✅ Version check passed: $PLUGIN_VERSION"

0 commit comments

Comments
 (0)