Skip to content

Commit ff65eb4

Browse files
[claude] Add automation workflows for adapter releases
- Add auto-approve workflow for PRs from allowed branches - Add auto-tag workflow that creates SPM tags from Package.swift changes - Add manual-tag workflow for manual release creation Adapter versions (X.Y.Z.W) are converted to SPM tags (XYYZZWW.0.0) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 613c198 commit ff65eb4

3 files changed

Lines changed: 271 additions & 0 deletions

File tree

.github/workflows/auto-approve.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Auto Approve PRs
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
7+
permissions:
8+
pull-requests: write
9+
contents: write
10+
11+
jobs:
12+
auto-approve:
13+
runs-on: ubuntu-latest
14+
if: |
15+
startsWith(github.head_ref, 'feature/') ||
16+
startsWith(github.head_ref, 'bugfix/') ||
17+
startsWith(github.head_ref, 'claude/') ||
18+
startsWith(github.head_ref, 'release/') ||
19+
startsWith(github.head_ref, 'update/')
20+
steps:
21+
- name: Approve PR
22+
env:
23+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
PR_URL: ${{ github.event.pull_request.html_url }}
25+
run: |
26+
gh pr review "$PR_URL" --approve
27+
echo "✅ Auto-approved PR: $PR_URL"
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: Auto Tag Release
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches:
7+
- main
8+
paths:
9+
- 'Package.swift'
10+
11+
permissions:
12+
contents: write
13+
pull-requests: write
14+
15+
jobs:
16+
auto-tag:
17+
if: github.event.pull_request.merged == true
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Extract version from Package.swift
26+
id: extract_version
27+
run: |
28+
# For adapters, extract version from the URL path
29+
# Looking for patterns like /3.7.1.0/ in the binary target URL
30+
VERSION=$(grep -oE '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/' Package.swift | head -1 | tr -d '/')
31+
32+
if [ -z "$VERSION" ]; then
33+
echo "❌ No adapter version found in Package.swift"
34+
exit 1
35+
fi
36+
37+
# Convert to SPM tag format (e.g., 3.7.1.0 -> 3070100.0.0)
38+
IFS='.' read -ra PARTS <<< "$VERSION"
39+
MAJOR="${PARTS[0]}"
40+
MINOR=$(printf "%02d" "${PARTS[1]}")
41+
PATCH=$(printf "%02d" "${PARTS[2]}")
42+
ADAPTER=$(printf "%02d" "${PARTS[3]:-0}")
43+
44+
SPM_TAG="${MAJOR}${MINOR}${PATCH}${ADAPTER}.0.0"
45+
46+
echo "✅ Found version: $VERSION"
47+
echo "✅ SPM tag: $SPM_TAG"
48+
echo "version=$VERSION" >> $GITHUB_OUTPUT
49+
echo "spm_tag=$SPM_TAG" >> $GITHUB_OUTPUT
50+
51+
- name: Check if tag exists
52+
id: check_tag
53+
run: |
54+
SPM_TAG="${{ steps.extract_version.outputs.spm_tag }}"
55+
if git rev-parse "refs/tags/$SPM_TAG" >/dev/null 2>&1; then
56+
echo "⚠️ Tag $SPM_TAG already exists"
57+
echo "exists=true" >> $GITHUB_OUTPUT
58+
else
59+
echo "✅ Tag $SPM_TAG does not exist, will create"
60+
echo "exists=false" >> $GITHUB_OUTPUT
61+
fi
62+
63+
- name: Create and push tag
64+
if: steps.check_tag.outputs.exists == 'false'
65+
run: |
66+
git config user.name "github-actions[bot]"
67+
git config user.email "github-actions[bot]@users.noreply.github.com"
68+
69+
VERSION="${{ steps.extract_version.outputs.version }}"
70+
SPM_TAG="${{ steps.extract_version.outputs.spm_tag }}"
71+
72+
# Create annotated tag
73+
git tag -a "$SPM_TAG" -m "Release $VERSION
74+
75+
Auto-generated from PR #${{ github.event.pull_request.number }}
76+
77+
PR Title: ${{ github.event.pull_request.title }}
78+
PR Author: ${{ github.event.pull_request.user.login }}
79+
Merged by: ${{ github.event.pull_request.merged_by.login }}
80+
Merge commit: ${{ github.event.pull_request.merge_commit_sha }}"
81+
82+
# Push the tag
83+
git push origin "$SPM_TAG"
84+
85+
echo "✅ Successfully created and pushed tag: $SPM_TAG"
86+
87+
- name: Comment on PR
88+
if: steps.check_tag.outputs.exists == 'false'
89+
uses: actions/github-script@v7
90+
with:
91+
github-token: ${{ secrets.GITHUB_TOKEN }}
92+
script: |
93+
const version = '${{ steps.extract_version.outputs.version }}';
94+
const spmTag = '${{ steps.extract_version.outputs.spm_tag }}';
95+
96+
await github.rest.issues.createComment({
97+
owner: context.repo.owner,
98+
repo: context.repo.repo,
99+
issue_number: ${{ github.event.pull_request.number }},
100+
body: `## 🎉 Release Tag Created
101+
102+
**Adapter Version:** \`${version}\`
103+
**SPM Tag:** \`${spmTag}\`
104+
105+
The adapter is now available at:
106+
\`\`\`swift
107+
.package(url: "https://github.com/${context.repo.owner}/${context.repo.repo}.git", exact: "${spmTag}")
108+
\`\`\`
109+
110+
---
111+
*This tag was automatically created by GitHub Actions*`
112+
});
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
name: Manual Tag Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
adapter_version:
7+
description: 'Adapter version (e.g., 3.7.1.0)'
8+
required: true
9+
type: string
10+
update_package_swift:
11+
description: 'Update Package.swift URLs to this version'
12+
required: false
13+
type: boolean
14+
default: false
15+
16+
permissions:
17+
contents: write
18+
pull-requests: write
19+
20+
jobs:
21+
create-tag:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Validate version format
25+
run: |
26+
VERSION="${{ github.event.inputs.adapter_version }}"
27+
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
28+
echo "❌ Invalid adapter version format: $VERSION"
29+
echo "Version must be in format: X.Y.Z.W (e.g., 3.7.1.0)"
30+
exit 1
31+
fi
32+
echo "✅ Version format is valid: $VERSION"
33+
34+
- name: Convert to SPM tag
35+
id: convert_tag
36+
run: |
37+
VERSION="${{ github.event.inputs.adapter_version }}"
38+
39+
# Convert to SPM tag format (e.g., 3.7.1.0 -> 3070100.0.0)
40+
IFS='.' read -ra PARTS <<< "$VERSION"
41+
MAJOR="${PARTS[0]}"
42+
MINOR=$(printf "%02d" "${PARTS[1]}")
43+
PATCH=$(printf "%02d" "${PARTS[2]}")
44+
ADAPTER=$(printf "%02d" "${PARTS[3]}")
45+
46+
SPM_TAG="${MAJOR}${MINOR}${PATCH}${ADAPTER}.0.0"
47+
48+
echo "✅ SPM tag: $SPM_TAG"
49+
echo "spm_tag=$SPM_TAG" >> $GITHUB_OUTPUT
50+
51+
- name: Checkout repository
52+
uses: actions/checkout@v4
53+
with:
54+
fetch-depth: 0
55+
56+
- name: Check if tag exists
57+
run: |
58+
SPM_TAG="${{ steps.convert_tag.outputs.spm_tag }}"
59+
if git rev-parse "refs/tags/$SPM_TAG" >/dev/null 2>&1; then
60+
echo "❌ Tag $SPM_TAG already exists!"
61+
exit 1
62+
fi
63+
echo "✅ Tag $SPM_TAG does not exist, proceeding..."
64+
65+
- name: Update Package.swift if requested
66+
if: github.event.inputs.update_package_swift == 'true'
67+
run: |
68+
VERSION="${{ github.event.inputs.adapter_version }}"
69+
70+
# Update version in binary target URL
71+
sed -i "s|/[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+/|/${VERSION}/|g" Package.swift
72+
73+
# Check if changes were made
74+
if git diff --quiet Package.swift; then
75+
echo "⚠️ No changes needed in Package.swift"
76+
else
77+
echo "✅ Updated Package.swift with version $VERSION"
78+
git add Package.swift
79+
git config user.name "github-actions[bot]"
80+
git config user.email "github-actions[bot]@users.noreply.github.com"
81+
git commit -m "Update Package.swift to version $VERSION"
82+
git push origin main
83+
fi
84+
85+
- name: Create and push tag
86+
run: |
87+
git config user.name "github-actions[bot]"
88+
git config user.email "github-actions[bot]@users.noreply.github.com"
89+
90+
VERSION="${{ github.event.inputs.adapter_version }}"
91+
SPM_TAG="${{ steps.convert_tag.outputs.spm_tag }}"
92+
93+
# Create annotated tag
94+
git tag -a "$SPM_TAG" -m "Release $VERSION
95+
96+
Manual release created by: ${{ github.actor }}
97+
Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
98+
99+
# Push the tag
100+
git push origin "$SPM_TAG"
101+
102+
echo "✅ Successfully created and pushed tag: $SPM_TAG"
103+
104+
- name: Create GitHub Release
105+
uses: actions/github-script@v7
106+
with:
107+
github-token: ${{ secrets.GITHUB_TOKEN }}
108+
script: |
109+
const version = '${{ github.event.inputs.adapter_version }}';
110+
const spmTag = '${{ steps.convert_tag.outputs.spm_tag }}';
111+
112+
const release = await github.rest.repos.createRelease({
113+
owner: context.repo.owner,
114+
repo: context.repo.repo,
115+
tag_name: spmTag,
116+
name: `Version ${version}`,
117+
body: `## Adapter Version ${version}
118+
119+
### Swift Package Manager
120+
121+
Add this adapter to your project:
122+
\`\`\`swift
123+
.package(url: "https://github.com/${context.repo.owner}/${context.repo.repo}.git", exact: "${spmTag}")
124+
\`\`\`
125+
126+
---
127+
*Released by @${{ github.actor }}*`,
128+
draft: false,
129+
prerelease: false
130+
});
131+
132+
console.log(`Created release: ${release.data.html_url}`);

0 commit comments

Comments
 (0)