Skip to content

Commit 8673066

Browse files
committed
feat: add workflow
1 parent 81717c0 commit 8673066

File tree

3 files changed

+221
-0
lines changed

3 files changed

+221
-0
lines changed

.github/assets/.gitkeep

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
182 KB
Loading
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
name: Publish Codemod
2+
3+
on:
4+
push:
5+
tags:
6+
- "*@v*" # eg: [email protected] or @scopename/[email protected]
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: "Tag to publish (format: [email protected] or @scopename/[email protected])"
11+
required: true
12+
type: string
13+
14+
jobs:
15+
validate-and-publish:
16+
name: Validate and Publish Codemod
17+
runs-on: ubuntu-latest
18+
19+
outputs:
20+
version: ${{ steps.parse-tag.outputs.version }}
21+
codemod-name: ${{ steps.parse-tag.outputs.codemod-name }}
22+
codemod-path: ${{ steps.find-codemod.outputs.codemod-path }}
23+
24+
steps:
25+
- name: Harden Runner
26+
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
27+
with:
28+
egress-policy: audit
29+
30+
- name: Checkout repository
31+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
32+
with:
33+
fetch-depth: 0
34+
35+
- name: Parse tag and extract metadata
36+
id: parse-tag
37+
env:
38+
EVENT_NAME: ${{ github.event_name }}
39+
INPUT_TAG: ${{ github.event.inputs.tag }}
40+
GITHUB_REF: ${{ github.ref }}
41+
run: |
42+
# Determine the tag based on trigger type
43+
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
44+
TAG="$INPUT_TAG"
45+
echo "Using manually provided tag: $TAG"
46+
else
47+
TAG="${GITHUB_REF#refs/tags/}"
48+
echo "Using pushed tag: $TAG"
49+
fi
50+
51+
# Validate tag format
52+
# Supports: @scopename/[email protected] or [email protected]
53+
# Does NOT support: codemodname/[email protected] (non-scoped packages can't have slashes)
54+
if [[ ! "$TAG" =~ ^(@[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+|[a-zA-Z0-9_-]+)@v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
55+
echo "❌ Invalid tag format: $TAG"
56+
echo "Expected formats:"
57+
echo " - @scopename/[email protected] (scoped packages)"
58+
echo " - [email protected] (non-scoped packages)"
59+
echo "Note: Non-scoped packages cannot contain slashes"
60+
exit 1
61+
fi
62+
63+
# Extract components
64+
CODEMOD_NAME="${TAG%@v*}" # Everything before @v (handles both scoped and non-scoped)
65+
VERSION="v${TAG#*@v}" # Everything after @v, with v prefix
66+
67+
# Set outputs
68+
echo "version=$VERSION" >> $GITHUB_OUTPUT
69+
echo "codemod-name=$CODEMOD_NAME" >> $GITHUB_OUTPUT
70+
71+
echo "✓ Parsed tag - Version: $VERSION, Codemod: $CODEMOD_NAME"
72+
73+
- name: Find codemod directory by searching codemod.yaml files
74+
id: find-codemod
75+
env:
76+
CODEMOD_NAME: ${{ steps.parse-tag.outputs.codemod-name }}
77+
VERSION: ${{ steps.parse-tag.outputs.version }}
78+
run: |
79+
echo "🔍 Searching for codemod '$CODEMOD_NAME' in all codemod.yaml files..."
80+
81+
# Find all codemod.yaml files in the codemods directory
82+
CODEMOD_FILES=$(find codemods -name "codemod.yaml" -type f 2>/dev/null || true)
83+
84+
if [[ -z "$CODEMOD_FILES" ]]; then
85+
echo "❌ No codemod.yaml files found in codemods directory"
86+
echo "Available files:"
87+
find codemods -type f -name "*.yaml" -o -name "*.yml" 2>/dev/null || echo "No YAML files found"
88+
exit 1
89+
fi
90+
91+
echo "Found codemod.yaml files:"
92+
echo "$CODEMOD_FILES"
93+
echo ""
94+
95+
FOUND_PATH=""
96+
97+
# Search through each codemod.yaml file
98+
while IFS= read -r yaml_file; do
99+
if [[ ! -f "$yaml_file" ]]; then
100+
continue
101+
fi
102+
103+
echo "Checking: $yaml_file"
104+
105+
# Extract name from yaml file using yq or basic grep/sed
106+
# First try with yq if available, otherwise use grep/sed
107+
if command -v yq >/dev/null 2>&1; then
108+
YAML_NAME=$(yq eval '.name' "$yaml_file" 2>/dev/null || echo "")
109+
YAML_VERSION=$(yq eval '.version' "$yaml_file" 2>/dev/null || echo "")
110+
else
111+
# Fallback to grep/sed for basic YAML parsing
112+
YAML_NAME=$(grep -E '^[[:space:]]*name[[:space:]]*:' "$yaml_file" | head -1 | sed 's/^[[:space:]]*name[[:space:]]*:[[:space:]]*//' | sed 's/[[:space:]]*$//' | sed 's/^["\x27]//' | sed 's/["\x27]$//' || echo "")
113+
YAML_VERSION=$(grep -E '^[[:space:]]*version[[:space:]]*:' "$yaml_file" | head -1 | sed 's/^[[:space:]]*version[[:space:]]*:[[:space:]]*//' | sed 's/[[:space:]]*$//' | sed 's/^["\x27]//' | sed 's/["\x27]$//' || echo "")
114+
fi
115+
116+
echo " - Name in file: '$YAML_NAME'"
117+
echo " - Version in file: '$YAML_VERSION'"
118+
119+
if [[ "$YAML_NAME" == "$CODEMOD_NAME" && "v$YAML_VERSION" == "$VERSION" ]]; then
120+
FOUND_PATH=$(dirname "$yaml_file")
121+
echo " ✅ Match found!"
122+
break
123+
fi
124+
done <<< "$CODEMOD_FILES"
125+
126+
if [[ -z "$FOUND_PATH" ]]; then
127+
echo "❌ Codemod '$CODEMOD_NAME' not found in any codemod.yaml files"
128+
echo ""
129+
echo "Available codemods:"
130+
while IFS= read -r yaml_file; do
131+
if [[ -f "$yaml_file" ]]; then
132+
if command -v yq >/dev/null 2>&1; then
133+
NAME=$(yq eval '.name' "$yaml_file" 2>/dev/null || echo "unknown")
134+
else
135+
NAME=$(grep -E '^[[:space:]]*name[[:space:]]*:' "$yaml_file" | head -1 | sed 's/^[[:space:]]*name[[:space:]]*:[[:space:]]*//' | sed 's/[[:space:]]*$//' | sed 's/^["\x27]//' | sed 's/["\x27]$//' || echo "unknown")
136+
fi
137+
echo " - $NAME (in $yaml_file)"
138+
fi
139+
done <<< "$CODEMOD_FILES"
140+
exit 1
141+
fi
142+
143+
echo "codemod-path=$FOUND_PATH" >> $GITHUB_OUTPUT
144+
echo "✅ Found codemod at: $FOUND_PATH"
145+
146+
- name: Verify codemod directory
147+
env:
148+
CODEMOD_PATH: ${{ steps.find-codemod.outputs.codemod-path }}
149+
run: |
150+
echo "✓ Using codemod directory: $CODEMOD_PATH"
151+
echo "Directory contents:"
152+
ls -lah "$CODEMOD_PATH"
153+
154+
# Verify required files exist
155+
if [[ ! -f "$CODEMOD_PATH/codemod.yaml" ]]; then
156+
echo "❌ codemod.yaml not found in $CODEMOD_PATH"
157+
exit 1
158+
fi
159+
160+
echo "✅ codemod.yaml found"
161+
162+
- uses: actions/setup-node@v4
163+
with:
164+
node-version: 22
165+
166+
- name: Install project dependencies
167+
run: |
168+
npm install --no-frozen-lockfile
169+
npm install -g codemod@latest
170+
171+
# Run test before login to not waste time if it fails
172+
- name: Validate workflow
173+
working-directory: ${{ steps.find-codemod.outputs.codemod-path }}
174+
run: npx codemod@latest workflow validate --workflow workflow.yaml
175+
176+
- name: Check if package.json exists
177+
id: check-package-json
178+
working-directory: ${{ steps.find-codemod.outputs.codemod-path }}
179+
run: |
180+
if [[ -f "package.json" ]]; then
181+
echo "has-package-json=true" >> $GITHUB_OUTPUT
182+
else
183+
echo "has-package-json=false" >> $GITHUB_OUTPUT
184+
fi
185+
186+
- name: Run javascript ast-grep codemod Tests
187+
if: steps.check-package-json.outputs.has-package-json == 'true'
188+
working-directory: ${{ steps.find-codemod.outputs.codemod-path }}
189+
run: npm test
190+
191+
- name: Authenticate with Codemod registry
192+
env:
193+
CODEMOD_API_KEY: ${{ secrets.CODEMOD_API_KEY }}
194+
run: npx codemod@latest login --api-key "$CODEMOD_API_KEY"
195+
196+
- name: Publish codemod
197+
working-directory: ${{ steps.find-codemod.outputs.codemod-path }}
198+
run: npx codemod@latest publish
199+
200+
- name: Create release summary
201+
env:
202+
CODEMOD_NAME: ${{ steps.parse-tag.outputs.codemod-name }}
203+
VERSION: ${{ steps.parse-tag.outputs.version }}
204+
CODEMOD_PATH: ${{ steps.find-codemod.outputs.codemod-path }}
205+
TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }}
206+
TRIGGER: ${{ github.event_name == 'workflow_dispatch' && 'Manual' || 'Tag Push' }}
207+
ACTOR: ${{ github.triggering_actor }}
208+
run: |
209+
cat >> $GITHUB_STEP_SUMMARY << EOF
210+
# 🚀 Codemod Publication Summary
211+
212+
**Codemod:** \`$CODEMOD_NAME\`
213+
**Version:** \`$VERSION\`
214+
**Path:** \`$CODEMOD_PATH\`
215+
**Tag:** \`$TAG\`
216+
**Trigger:** $TRIGGER by $ACTOR
217+
218+
✅ Codemod has been successfully published to the registry!
219+
EOF

0 commit comments

Comments
 (0)