forked from NVIDIA/Megatron-LM
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck_api_backwards_compatibility_workflow.yml
More file actions
274 lines (248 loc) · 12.6 KB
/
check_api_backwards_compatibility_workflow.yml
File metadata and controls
274 lines (248 loc) · 12.6 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
name: API Compatibility Check
on:
push:
branches:
- dev
- main
- 'pull-request/[0-9]+'
- 'deploy-release/*'
merge_group:
types: [checks_requested]
# Allow manual trigger
workflow_dispatch:
inputs:
baseline:
description: 'Baseline git reference (tag/branch/commit)'
required: true
jobs:
pre-flight:
name: Pre-flight check
runs-on: ubuntu-latest
outputs:
should_skip: ${{ steps.check_files.outputs.should_skip }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check if relevant files changed
id: check_files
run: |
# For manual triggers, never skip
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "should_skip=false" >> $GITHUB_OUTPUT
echo "Manual trigger - will run compatibility check"
exit 0
fi
# Determine base SHA based on event type
if [ "${{ github.event_name }}" == "merge_group" ]; then
BASE_SHA="${{ github.event.merge_group.base_sha }}"
echo "Merge group event - comparing against base: $BASE_SHA"
else
# For push events, use merge-base to find common ancestor
# This ensures we only detect changes actually made in this PR branch,
# not changes that happened in main after the branch was created
BASE_SHA=$(git merge-base origin/main HEAD 2>/dev/null || echo "")
if [ -z "$BASE_SHA" ]; then
# Fallback for pull-request/* branches targeting dev
BASE_SHA=$(git merge-base origin/dev HEAD 2>/dev/null || echo "")
fi
echo "Push event - comparing against merge-base: $BASE_SHA"
fi
if [ -z "$BASE_SHA" ]; then
echo "Could not determine base SHA - will run compatibility check"
echo "should_skip=false" >> $GITHUB_OUTPUT
exit 0
fi
# Check for changes in megatron/core Python files (excluding tests and legacy)
# Note: Using both *.py and **/*.py to match files at root and in subdirectories
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" HEAD -- \
'megatron/core/*.py' \
'megatron/core/**/*.py' \
':!megatron/core/tests/**' \
':!megatron/legacy/**' 2>/dev/null || echo "")
if [ -z "$CHANGED_FILES" ]; then
echo "should_skip=true" >> $GITHUB_OUTPUT
echo "No relevant megatron/core files changed - will skip compatibility check"
else
echo "should_skip=false" >> $GITHUB_OUTPUT
echo "Relevant files changed:"
echo "$CHANGED_FILES"
fi
check-compatibility:
needs: [pre-flight]
if: needs.pre-flight.outputs.should_skip != 'true'
name: Check API Backward Compatibility
runs-on: ubuntu-latest
# ============================================================================
# Configuration Parameters (modify here)
# ============================================================================
env:
# Default baseline for automatic PR checks
# Can be: branch name (e.g., 'main'), commit hash, or tag
# Will be resolved to commit hash during execution
DEFAULT_BASELINE: 'b51db3e07a97fed6af5464fae8fa43be1d0564b9'
# Tag pattern for auto-detection (e.g., 'core_r*', 'core_v*')
TAG_PATTERN: 'core_v*'
# Tag regex filter (e.g., '^core_v[0-9]+\.[0-9]+\.[0-9]+$' for stable versions only)
TAG_REGEX_FILTER: '^core_v[0-9]+\.[0-9]+\.[0-9]+$'
# ============================================================================
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history to access baseline ref
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install griffe
run: |
python -m pip install --upgrade pip
python -m pip install griffe
python -c "import griffe; print('Griffe installed successfully')"
python -c "from griffe import Object; print('Object import successful')" || echo "Object import from griffe failed"
python -c "from griffe.dataclasses import Object; print('Object import from dataclasses successful')" || echo "Object import from dataclasses failed"
- name: Determine baseline reference
id: baseline
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
# Use manually specified baseline (branch, tag, or commit hash)
BASELINE_REF="${{ github.event.inputs.baseline }}"
else
# Use the configured default baseline
BASELINE_REF="${{ env.DEFAULT_BASELINE }}"
# Uncomment below to auto-detect from tags instead:
# BASELINE_REF=$(git tag -l '${{ env.TAG_PATTERN }}' | grep -E '${{ env.TAG_REGEX_FILTER }}' | sort -V | tail -1)
# if [ -z "$BASELINE_REF" ]; then
# echo "Warning: No tags matching pattern found. Using default: ${{ env.DEFAULT_BASELINE }}" >&2
# BASELINE_REF="${{ env.DEFAULT_BASELINE }}"
# fi
fi
# Resolve baseline to commit hash (works for branches, tags, or commit hashes)
BASELINE_HASH=$(git rev-parse "$BASELINE_REF")
echo "baseline=$BASELINE_HASH" >> $GITHUB_OUTPUT
echo "Using baseline: $BASELINE_REF (resolved to commit: $BASELINE_HASH)"
- name: Run compatibility check
id: compat_check
run: |
# Save output to file for later display
python scripts/check_api_backwards_compatibility.py \
--baseline ${{ steps.baseline.outputs.baseline }} \
--verbose 2>&1 | tee compat_check_output.txt
# Capture exit code
EXIT_CODE=${PIPESTATUS[0]}
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
exit $EXIT_CODE
continue-on-error: true
- name: Fail job if breaking changes detected
if: steps.compat_check.outcome == 'failure'
run: |
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔍 WHAT IS THIS CHECK?"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "This check ensures that changes to Megatron Core's public API do not"
echo "break backward compatibility for users. It compares your PR against"
echo "the latest stable release to detect breaking changes in:"
echo ""
echo " • Function signatures (parameters, order, types)"
echo " • Class structures and methods"
echo " • Return types and public interfaces"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🛠️ HOW TO FIX THIS"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Choose ONE of these resolution strategies:"
echo ""
echo "1️⃣ REVERT THE BREAKING CHANGE (Recommended)"
echo " → Modify your code to preserve backward compatibility"
echo " → Add new parameters as optional (with defaults)"
echo " → Keep existing parameters in the same order"
echo ""
echo "2️⃣ MARK AS INTERNAL API (If this is internal code)"
echo " → Add @internal_api decorator from megatron.core.utils"
echo ""
echo " Example (for classes):"
echo " from megatron.core.utils import internal_api"
echo ""
echo " @internal_api"
echo " class ExperimentalFeature:"
echo " pass"
echo ""
echo " Example (for functions):"
echo " from megatron.core.utils import internal_api"
echo ""
echo " @internal_api"
echo " def internal_helper_function():"
echo " pass"
echo ""
echo "3️⃣ MARK AS EXPERIMENTAL API (If this is experimental code)"
echo " → Add @experimental_api decorator from megatron.core.utils"
echo ""
echo " Example:"
echo " from megatron.core.utils import experimental_api"
echo ""
echo " @experimental_api"
echo " class ExperimentalFeature:"
echo " pass"
echo ""
echo "4️⃣ USE DEPRECATION (For gradual API changes)"
echo " → Add @deprecated decorator for transition period"
echo " → Example:"
echo " from megatron.core.utils import deprecated"
echo ""
echo " @deprecated(version='1.0', removal_version='2.0',"
echo " alternative='new_function')"
echo " def old_function():"
echo " pass"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📋 BREAKING CHANGES DETECTED"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
cat compat_check_output.txt
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📚 MORE INFORMATION"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📖 Full documentation: docs/api-backwards-compatibility-check.md"
echo "🔧 Checker script: scripts/check_api_backwards_compatibility.py"
echo "❓ Questions? Check the docs or ask in #megatron-core"
echo ""
echo "::error::Breaking API changes detected. Please review the output above and choose a resolution strategy."
exit 1
- name: Success message
if: steps.compat_check.outcome == 'success'
run: |
echo "::notice::✅ No breaking API changes detected!"
api-backward-compatibility-summary:
needs: [pre-flight, check-compatibility]
runs-on: ubuntu-latest
name: API Backward Compatibility Check Summary
if: always() && !cancelled()
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Validate workflow result
shell: bash -x -e -u -o pipefail {0}
env:
GH_TOKEN: ${{ github.token }}
SKIPPING_IS_ALLOWED: ${{ needs.pre-flight.outputs.should_skip == 'true' }}
run: |
FAILED_JOBS=$(gh run view $GITHUB_RUN_ID --json jobs --jq '[.jobs[] | select(.status == "completed" and .conclusion != "success" and .name != "API Backward Compatibility Check Summary")] | length') || echo 0
if [ "${FAILED_JOBS:-0}" -eq 0 ] || [ "$SKIPPING_IS_ALLOWED" == "true" ]; then
if [ "$SKIPPING_IS_ALLOWED" == "true" ]; then
echo "✅ Compatibility check was skipped (no relevant files changed)"
else
echo "✅ All checks passed successfully"
fi
exit 0
else
echo "❌ Found $FAILED_JOBS failed job(s)"
gh run view $GITHUB_RUN_ID --json jobs --jq '.jobs[] | select(.status == "completed" and .conclusion != "success" and .name != "API Backward Compatibility Check Summary") | .name'
exit 1
fi