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