forked from Reya-Labs/reya-python-sdk
-
Notifications
You must be signed in to change notification settings - Fork 1
453 lines (391 loc) · 19.3 KB
/
version-consistency.yml
File metadata and controls
453 lines (391 loc) · 19.3 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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
name: Version Check
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
version-consistency:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
submodules: true
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y jq
npm install -g @openapitools/openapi-generator-cli @asyncapi/cli @asyncapi/modelina-cli
pip install tomli
- name: Check specs submodule points to a tag
run: |
cd specs
# Get the current commit hash
CURRENT_COMMIT=$(git rev-parse HEAD)
echo "Current specs commit: $CURRENT_COMMIT"
# Check if this commit is tagged
TAGS=$(git tag --points-at $CURRENT_COMMIT)
if [ -z "$TAGS" ]; then
echo "❌ ERROR: specs submodule is not pointing to a tagged commit"
echo "Current commit $CURRENT_COMMIT has no tags"
exit 1
fi
# Get the first tag (in case there are multiple)
SPECS_TAG=$(echo "$TAGS" | head -n1)
echo "Specs is pointing to tag: $SPECS_TAG"
echo "SPECS_TAG=$SPECS_TAG" >> $GITHUB_ENV
- name: Check if PR and detect specs tag changes
if: github.event_name == 'pull_request'
run: |
# Get base branch specs submodule commit
git fetch origin ${{ github.base_ref }}
BASE_SHA=$(git merge-base HEAD origin/${{ github.base_ref }})
# Get the specs submodule commit hash from base branch
echo "DEBUG: BASE_SHA = $BASE_SHA"
echo "DEBUG: git ls-tree output for base:"
git ls-tree $BASE_SHA specs
echo "DEBUG: git ls-tree output for HEAD:"
git ls-tree HEAD specs
BASE_SPECS_COMMIT=$(git ls-tree $BASE_SHA specs | awk '{print $3}')
CURRENT_SPECS_COMMIT=$(git ls-tree HEAD specs | awk '{print $3}')
echo "Base specs commit: $BASE_SPECS_COMMIT"
echo "Current specs commit: $CURRENT_SPECS_COMMIT"
# Get specs tag from base branch commit
cd specs
git fetch --tags origin # Make sure we have all tags
# Get tag for base commit
BASE_TAGS=$(git tag --points-at $BASE_SPECS_COMMIT 2>/dev/null || echo "")
if [ -z "$BASE_TAGS" ]; then
echo "Base specs commit $BASE_SPECS_COMMIT has no tags"
BASE_SPECS_TAG="unknown"
else
BASE_SPECS_TAG=$(echo "$BASE_TAGS" | head -n1)
fi
cd ..
echo "Base specs tag: $BASE_SPECS_TAG"
echo "Current specs tag: $SPECS_TAG"
echo "BASE_SPECS_TAG=$BASE_SPECS_TAG" >> $GITHUB_ENV
# Check if specs commit changed (more reliable than just tag comparison)
if [ "$BASE_SPECS_COMMIT" = "$CURRENT_SPECS_COMMIT" ]; then
echo "SPECS_TAG_CHANGED=false" >> $GITHUB_ENV
echo "Specs commit unchanged: $CURRENT_SPECS_COMMIT (tag: $SPECS_TAG)"
else
echo "SPECS_TAG_CHANGED=true" >> $GITHUB_ENV
echo "Specs commit changed from $BASE_SPECS_COMMIT to $CURRENT_SPECS_COMMIT"
echo "Specs tag changed from $BASE_SPECS_TAG to $SPECS_TAG"
fi
- name: Check if version was manually modified in PR
if: github.event_name == 'pull_request'
run: |
# Check if pyproject.toml version line was modified in this PR
BASE_SHA=$(git merge-base HEAD origin/${{ github.base_ref }})
if git diff $BASE_SHA HEAD -- pyproject.toml | grep -q '^\+.*version = '; then
echo "VERSION_MANUALLY_MODIFIED=true" >> $GITHUB_ENV
echo "Version was manually modified in this PR"
else
echo "VERSION_MANUALLY_MODIFIED=false" >> $GITHUB_ENV
echo "Version was not manually modified in this PR"
fi
- name: Extract version components
run: |
# Extract version from pyproject.toml (this is the source of truth)
SDK_VERSION=$(python -c "
import tomli
with open('pyproject.toml', 'rb') as f:
data = tomli.load(f)
print(data['project']['version'])
")
echo "SDK_VERSION: $SDK_VERSION"
echo "SDK_VERSION=$SDK_VERSION" >> $GITHUB_ENV
# If this is a PR, get the base version for comparison
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE_SHA=$(git merge-base HEAD origin/${{ github.base_ref }})
BASE_SDK_VERSION=$(git show $BASE_SHA:pyproject.toml | python -c "
import sys, tomli
try:
data = tomli.loads(sys.stdin.read())
print(data['project']['version'])
except:
print('unknown')
" 2>/dev/null || echo "unknown")
echo "BASE_SDK_VERSION: $BASE_SDK_VERSION"
echo "BASE_SDK_VERSION=$BASE_SDK_VERSION" >> $GITHUB_ENV
fi
# Extract first 3 components from specs tag (remove 'v' prefix if present)
SPECS_TAG_CLEAN=$(echo "$SPECS_TAG" | sed 's/^v//')
SPECS_VERSION_PREFIX=$(echo "$SPECS_TAG_CLEAN" | cut -d. -f1-3)
echo "SPECS_VERSION_PREFIX: $SPECS_VERSION_PREFIX"
echo "SPECS_VERSION_PREFIX=$SPECS_VERSION_PREFIX" >> $GITHUB_ENV
# Extract first 3 components from SDK_VERSION
SDK_VERSION_PREFIX=$(echo "$SDK_VERSION" | cut -d. -f1-3)
echo "SDK_VERSION_PREFIX: $SDK_VERSION_PREFIX"
echo "SDK_VERSION_PREFIX=$SDK_VERSION_PREFIX" >> $GITHUB_ENV
- name: Automatic version bump (specs unchanged)
if: github.event_name == 'pull_request' && env.SPECS_TAG_CHANGED == 'false' && env.VERSION_MANUALLY_MODIFIED == 'false'
run: |
echo "Conditions met for automatic version bump:"
echo "- This is a PR: ✅"
echo "- Specs tag unchanged: ✅ ($SPECS_TAG)"
echo "- Version not manually modified: ✅"
# Parse current version (X.Y.Z.W)
IFS='.' read -r MAJOR MINOR PATCH BUILD <<< "$SDK_VERSION"
# Increment the last digit (build number)
NEW_BUILD=$((BUILD + 1))
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}.${NEW_BUILD}"
echo "Bumping version from $SDK_VERSION to $NEW_VERSION"
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
# Update pyproject.toml
sed -i "s/^version = \".*\"$/version = \"$NEW_VERSION\"/" pyproject.toml
echo "✅ Updated pyproject.toml to version $NEW_VERSION"
- name: Automatic version update for specs tag change
if: github.event_name == 'pull_request' && env.SPECS_TAG_CHANGED == 'true' && env.VERSION_MANUALLY_MODIFIED == 'false'
run: |
echo "Conditions met for automatic version update due to specs tag change:"
echo "- This is a PR: ✅"
echo "- Specs tag changed: ✅ (from $BASE_SPECS_TAG to $SPECS_TAG)"
echo "- Version not manually modified: ✅"
# Update SDK version to match new specs version with .0 build number
NEW_VERSION="${SPECS_VERSION_PREFIX}.0"
echo "Updating version from $SDK_VERSION to $NEW_VERSION to match specs tag $SPECS_TAG"
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
# Update pyproject.toml
sed -i "s/^version = \".*\"$/version = \"$NEW_VERSION\"/" pyproject.toml
echo "✅ Updated pyproject.toml to version $NEW_VERSION"
- name: Commit version bump
if: github.event_name == 'pull_request' && env.NEW_VERSION != ''
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add pyproject.toml
git commit -m "chore: bump SDK version to $NEW_VERSION"
git push origin HEAD:${{ github.head_ref }}
echo "✅ Committed and pushed version bump to $NEW_VERSION"
- name: Validate version progression (for manual changes)
if: github.event_name == 'pull_request' && env.VERSION_MANUALLY_MODIFIED == 'true'
run: |
echo "Manual version change detected, validating progression..."
echo "Previous version: $BASE_SDK_VERSION"
echo "Current version: $SDK_VERSION"
# Check for version regression using version comparison
if [ "$BASE_SDK_VERSION" != "unknown" ]; then
# Parse versions for comparison
IFS='.' read -r BASE_MAJOR BASE_MINOR BASE_PATCH BASE_BUILD <<< "$BASE_SDK_VERSION"
IFS='.' read -r CURR_MAJOR CURR_MINOR CURR_PATCH CURR_BUILD <<< "$SDK_VERSION"
# Convert to comparable integers (assuming reasonable version numbers < 1000)
BASE_NUM=$((BASE_MAJOR*1000000000 + BASE_MINOR*1000000 + BASE_PATCH*1000 + BASE_BUILD))
CURR_NUM=$((CURR_MAJOR*1000000000 + CURR_MINOR*1000000 + CURR_PATCH*1000 + CURR_BUILD))
if [ "$CURR_NUM" -lt "$BASE_NUM" ]; then
echo "❌ ERROR: Version regression detected!"
echo "Previous version: $BASE_SDK_VERSION"
echo "Current version: $SDK_VERSION"
echo "New version must be higher than or equal to the previous version."
exit 1
elif [ "$CURR_NUM" -eq "$BASE_NUM" ]; then
echo "⚠️ Version unchanged: $SDK_VERSION"
else
# Check that the bump is reasonable (no more than 1 in any component)
MAJOR_DIFF=$((CURR_MAJOR - BASE_MAJOR))
MINOR_DIFF=$((CURR_MINOR - BASE_MINOR))
PATCH_DIFF=$((CURR_PATCH - BASE_PATCH))
BUILD_DIFF=$((CURR_BUILD - BASE_BUILD))
if [ "$MAJOR_DIFF" -gt 1 ] || [ "$MINOR_DIFF" -gt 1 ] || [ "$PATCH_DIFF" -gt 1 ] || [ "$BUILD_DIFF" -gt 1 ]; then
echo "❌ ERROR: Version bump is too large!"
echo "Previous: $BASE_SDK_VERSION"
echo "Current: $SDK_VERSION"
echo "Version should only be incremented by 1 in a single component."
exit 1
fi
echo "✅ Version progression verified: $BASE_SDK_VERSION → $SDK_VERSION"
fi
else
echo "⚠️ Cannot determine previous version, skipping progression check"
fi
- name: Check version consistency
run: |
# If version was auto-bumped, use the new version
if [ -n "$NEW_VERSION" ]; then
CURRENT_SDK_VERSION="$NEW_VERSION"
else
CURRENT_SDK_VERSION="$SDK_VERSION"
fi
echo "Checking version consistency..."
echo "Specs tag: $SPECS_TAG"
echo "Specs version prefix: $SPECS_VERSION_PREFIX"
echo "SDK version (from pyproject.toml): $CURRENT_SDK_VERSION"
# Check 1: SDK_VERSION must have exactly 4 digits (X.Y.Z.W format)
SDK_VERSION_PARTS=$(echo "$CURRENT_SDK_VERSION" | tr '.' '\n' | wc -l)
if [ "$SDK_VERSION_PARTS" -ne 4 ]; then
echo "❌ ERROR: SDK_VERSION must have exactly 4 digits (X.Y.Z.W format)"
echo "Found $SDK_VERSION_PARTS parts in version: $CURRENT_SDK_VERSION"
echo "Expected format: X.Y.Z.W (e.g., 2.0.3.0)"
exit 1
fi
echo "✅ SDK version has 4 digits: $CURRENT_SDK_VERSION"
# Check 2: First 3 digits of SDK version must match specs tag
CURRENT_SDK_VERSION_PREFIX=$(echo "$CURRENT_SDK_VERSION" | cut -d. -f1-3)
if [ "$CURRENT_SDK_VERSION_PREFIX" != "$SPECS_VERSION_PREFIX" ]; then
echo "❌ ERROR: First 3 digits of SDK_VERSION ($CURRENT_SDK_VERSION_PREFIX) do not match specs tag ($SPECS_VERSION_PREFIX)"
echo "SDK version $CURRENT_SDK_VERSION should start with $SPECS_VERSION_PREFIX"
exit 1
fi
echo "✅ SDK version prefix matches specs tag"
- name: Store initial git state
run: |
echo "Storing initial git state..."
# Store the current state of tracked files
git ls-files | sort > /tmp/files_before.txt
git status --porcelain > /tmp/status_before.txt
# Create checksums for all tracked files (filter out directories)
git ls-files -z | xargs -0 -I {} sh -c 'test -f "{}" && sha256sum "{}"' | sort > /tmp/checksums_before.txt
- name: Run API generation script
run: |
echo "Running API generation script..."
chmod +x scripts/generate-api.sh
scripts/generate-api.sh
- name: Run WS generation script
run: |
echo "Running WebSocket generation script..."
chmod +x scripts/generate-ws.sh
scripts/generate-ws.sh
- name: Check for changes after script execution
run: |
echo "Storing state after running scripts..."
# Store the state after running scripts
git ls-files | sort > /tmp/files_after.txt
git status --porcelain > /tmp/status_after.txt
git ls-files -z | xargs -0 -I {} sh -c 'test -f "{}" && sha256sum "{}"' | sort > /tmp/checksums_after.txt
echo "Checking for file changes..."
# Check if any tracked files were modified
if ! cmp -s /tmp/status_before.txt /tmp/status_after.txt; then
echo "❌ ERROR: Git status changed after running generation scripts"
echo "Status before:"
cat /tmp/status_before.txt
echo "Status after:"
cat /tmp/status_after.txt
echo ""
echo "Detailed changes:"
git status
git diff --name-only
exit 1
fi
# Check if file list changed (new files created)
if ! cmp -s /tmp/files_before.txt /tmp/files_after.txt; then
echo "❌ ERROR: File list changed after running generation scripts"
echo "New or removed files detected:"
diff /tmp/files_before.txt /tmp/files_after.txt || true
exit 1
fi
# Check if any file contents changed
if ! cmp -s /tmp/checksums_before.txt /tmp/checksums_after.txt; then
echo "❌ ERROR: File contents changed after running generation scripts"
echo "Files with different checksums:"
diff /tmp/checksums_before.txt /tmp/checksums_after.txt || true
echo ""
echo "Git diff:"
git diff
exit 1
fi
# Check for any untracked files that might have been created
UNTRACKED_FILES=$(git ls-files --others --exclude-standard)
if [ -n "$UNTRACKED_FILES" ]; then
echo "❌ ERROR: Generation scripts created new untracked files:"
echo "$UNTRACKED_FILES"
exit 1
fi
echo "✅ No changes detected after running generation scripts"
- name: Add PR comment about version changes
uses: actions/github-script@v7
if: github.event_name == 'pull_request' && always()
with:
script: |
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
// Remove existing bot comments
for (const comment of comments) {
if (comment.body.includes('🤖 SDK Version Check')) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
});
}
}
const newVersion = '${{ env.NEW_VERSION }}';
const versionModified = '${{ env.VERSION_MANUALLY_MODIFIED }}' === 'true';
const specsTagChanged = '${{ env.SPECS_TAG_CHANGED }}' === 'true';
const sdkVersion = '${{ env.SDK_VERSION }}';
const specsTag = '${{ env.SPECS_TAG }}';
let message = '🤖 **SDK Version Check**\n\n';
if (newVersion && !specsTagChanged) {
message += `✅ **Version automatically bumped to \`${newVersion}\`**\n`;
message += `- Previous version: \`${sdkVersion}\`\n`;
message += `- Reason: Specs tag unchanged (${specsTag}), no manual version changes\n`;
message += `- Change committed automatically\n`;
} else if (newVersion && specsTagChanged) {
message += `✅ **Version automatically updated to \`${newVersion}\`**\n`;
message += `- Previous version: \`${sdkVersion}\`\n`;
message += `- Reason: Specs tag changed to ${specsTag}, version updated to match\n`;
message += `- Change committed automatically\n`;
} else if (versionModified) {
message += '📝 **Manual version changes detected**\n\n';
message += `✅ Version validation passed: \`${sdkVersion}\`\n`;
message += '- Version progression validated (no regression)\n';
message += '- Version bump is reasonable (≤ 1 increment per component)\n';
} else if (specsTagChanged) {
message += '📋 **Specs tag updated**\n\n';
message += `✅ No automatic version bump needed\n`;
message += `- Specs tag changed to: \`${specsTag}\`\n`;
message += `- SDK version: \`${sdkVersion}\`\n`;
message += '- Version alignment with specs verified\n';
} else {
message += '✅ **Version check passed**\n\n';
message += `- SDK version: \`${sdkVersion}\`\n`;
message += `- Specs tag: \`${specsTag}\`\n`;
message += '- All consistency checks passed\n';
}
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});
- name: Summary
run: |
# Determine final version (could be auto-bumped version)
if [ -n "$NEW_VERSION" ]; then
FINAL_VERSION="$NEW_VERSION"
VERSION_STATUS="auto-bumped to $NEW_VERSION"
else
FINAL_VERSION="$SDK_VERSION"
VERSION_STATUS="$SDK_VERSION"
fi
echo "🎉 All version consistency checks passed!"
echo "✅ Specs submodule points to tag: $SPECS_TAG"
echo "✅ SDK version: $VERSION_STATUS"
echo "✅ SDK version has required 4-digit format (X.Y.Z.W)"
echo "✅ First 3 digits match specs version: $SPECS_VERSION_PREFIX"
echo "✅ Generation scripts produced no changes"
if [ "${{ github.event_name }}" = "pull_request" ]; then
if [ -n "$NEW_VERSION" ]; then
echo "🚀 Version automatically bumped and committed"
elif [ "$VERSION_MANUALLY_MODIFIED" = "true" ]; then
echo "📝 Manual version changes validated"
elif [ "$SPECS_TAG_CHANGED" = "true" ]; then
echo "📋 Specs tag change detected and validated"
else
echo "✅ No version changes needed"
fi
fi