1+ name : Automated Version Management
2+
3+ # Comprehensive version synchronization and management workflow
4+ # Integrates with existing release-please and CI/CD infrastructure
5+
6+ on :
7+ push :
8+ branches : [main]
9+ paths :
10+ - ' crates/*/Cargo.toml'
11+ - ' .github/.release-please-manifest.json'
12+ - ' CHANGELOG.md'
13+ pull_request :
14+ branches : [main]
15+ paths :
16+ - ' crates/*/Cargo.toml'
17+ - ' .github/.release-please-manifest.json'
18+ workflow_dispatch :
19+ inputs :
20+ target_version :
21+ description : ' Target version to sync all crates to (e.g., 0.2.3)'
22+ required : false
23+ type : string
24+ sync_type :
25+ description : ' Type of version sync to perform'
26+ required : true
27+ type : choice
28+ options :
29+ - ' auto-detect'
30+ - ' bump-patch'
31+ - ' bump-minor'
32+ - ' bump-major'
33+ - ' manual'
34+ default : ' auto-detect'
35+
36+ permissions :
37+ contents : write
38+ pull-requests : write
39+ issues : write
40+
41+ concurrency :
42+ group : version-sync-${{ github.ref }}
43+ cancel-in-progress : false
44+
45+ env :
46+ CARGO_TERM_COLOR : always
47+
48+ jobs :
49+ analyze-versions :
50+ name : Analyze Current Version State
51+ runs-on : ubuntu-latest
52+ outputs :
53+ versions_aligned : ${{ steps.check.outputs.versions_aligned }}
54+ current_versions : ${{ steps.check.outputs.current_versions }}
55+ target_version : ${{ steps.check.outputs.target_version }}
56+ needs_sync : ${{ steps.check.outputs.needs_sync }}
57+ sync_strategy : ${{ steps.check.outputs.sync_strategy }}
58+ steps :
59+ - uses : actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
60+ with :
61+ fetch-depth : 0
62+
63+ - name : Analyze version state
64+ id : check
65+ run : |
66+ echo "## 🔍 Version Analysis Report" >> $GITHUB_STEP_SUMMARY
67+ echo "" >> $GITHUB_STEP_SUMMARY
68+
69+ # Extract current versions from all crates
70+ declare -A versions
71+ versions[core]=$(grep '^version = ' crates/core/Cargo.toml | cut -d'"' -f2)
72+ versions[cli]=$(grep '^version = ' crates/cli/Cargo.toml | cut -d'"' -f2)
73+ versions[output]=$(grep '^version = ' crates/output/Cargo.toml | cut -d'"' -f2)
74+ versions[storage]=$(grep '^version = ' crates/storage/Cargo.toml | cut -d'"' -f2)
75+
76+ # Get release-please manifest version
77+ manifest_version=$(jq -r '."."' .github/.release-please-manifest.json)
78+
79+ # Display current state
80+ echo "### Current Version State" >> $GITHUB_STEP_SUMMARY
81+ echo "| Crate | Version |" >> $GITHUB_STEP_SUMMARY
82+ echo "|-------|---------|" >> $GITHUB_STEP_SUMMARY
83+ for crate in core cli output storage; do
84+ echo "| $crate | ${versions[$crate]} |" >> $GITHUB_STEP_SUMMARY
85+ done
86+ echo "| release-please | $manifest_version |" >> $GITHUB_STEP_SUMMARY
87+ echo "" >> $GITHUB_STEP_SUMMARY
88+
89+ # Check if all versions are aligned
90+ unique_versions=($(printf '%s\n' "${versions[@]}" | sort -u))
91+ versions_aligned="true"
92+ if [ ${#unique_versions[@]} -gt 1 ]; then
93+ versions_aligned="false"
94+ fi
95+
96+ # Determine target version based on input or auto-detection
97+ target_version="${{ github.event.inputs.target_version }}"
98+ sync_type="${{ github.event.inputs.sync_type }}"
99+
100+ if [ -z "$target_version" ] || [ "$sync_type" == "auto-detect" ]; then
101+ # Auto-detect: use the highest version or manifest version
102+ highest_version=$(printf '%s\n' "${versions[@]}" "$manifest_version" | sort -V | tail -1)
103+ target_version="$highest_version"
104+
105+ if [ "$versions_aligned" == "false" ]; then
106+ sync_strategy="align-to-highest"
107+ else
108+ sync_strategy="no-sync-needed"
109+ fi
110+ else
111+ case "$sync_type" in
112+ "bump-patch")
113+ # Extract major.minor and increment patch
114+ base_version=$(echo "$target_version" | cut -d'.' -f1-2)
115+ patch=$(echo "$target_version" | cut -d'.' -f3)
116+ target_version="$base_version.$((patch + 1))"
117+ sync_strategy="bump-patch"
118+ ;;
119+ "bump-minor")
120+ # Extract major and increment minor, reset patch
121+ major=$(echo "$target_version" | cut -d'.' -f1)
122+ minor=$(echo "$target_version" | cut -d'.' -f2)
123+ target_version="$major.$((minor + 1)).0"
124+ sync_strategy="bump-minor"
125+ ;;
126+ "bump-major")
127+ # Increment major, reset minor and patch
128+ major=$(echo "$target_version" | cut -d'.' -f1)
129+ target_version="$((major + 1)).0.0"
130+ sync_strategy="bump-major"
131+ ;;
132+ "manual")
133+ sync_strategy="manual-version"
134+ ;;
135+ esac
136+ fi
137+
138+ # Determine if sync is needed
139+ needs_sync="false"
140+ if [ "$versions_aligned" == "false" ] || [ "$target_version" != "${versions[core]}" ]; then
141+ needs_sync="true"
142+ fi
143+
144+ # Output results
145+ echo "versions_aligned=$versions_aligned" >> $GITHUB_OUTPUT
146+ echo "current_versions=$(printf '%s,' "${versions[@]}" | sed 's/,$//')" >> $GITHUB_OUTPUT
147+ echo "target_version=$target_version" >> $GITHUB_OUTPUT
148+ echo "needs_sync=$needs_sync" >> $GITHUB_OUTPUT
149+ echo "sync_strategy=$sync_strategy" >> $GITHUB_OUTPUT
150+
151+ # Summary
152+ echo "### Analysis Results" >> $GITHUB_STEP_SUMMARY
153+ echo "- **Versions Aligned**: $versions_aligned" >> $GITHUB_STEP_SUMMARY
154+ echo "- **Target Version**: $target_version" >> $GITHUB_STEP_SUMMARY
155+ echo "- **Needs Sync**: $needs_sync" >> $GITHUB_STEP_SUMMARY
156+ echo "- **Sync Strategy**: $sync_strategy" >> $GITHUB_STEP_SUMMARY
157+
158+ version-sync :
159+ name : Synchronize Versions
160+ runs-on : ubuntu-latest
161+ needs : analyze-versions
162+ if : needs.analyze-versions.outputs.needs_sync == 'true'
163+ steps :
164+ - uses : actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
165+ with :
166+ token : ${{ secrets.GITHUB_TOKEN }}
167+ fetch-depth : 0
168+
169+ - uses : ./.github/actions/setup-rust
170+
171+ - name : Apply version synchronization
172+ id : sync
173+ run : |
174+ TARGET_VERSION="${{ needs.analyze-versions.outputs.target_version }}"
175+ SYNC_STRATEGY="${{ needs.analyze-versions.outputs.sync_strategy }}"
176+
177+ echo "## 🔄 Version Synchronization" >> $GITHUB_STEP_SUMMARY
178+ echo "Synchronizing all crates to version: **$TARGET_VERSION**" >> $GITHUB_STEP_SUMMARY
179+ echo "Strategy: **$SYNC_STRATEGY**" >> $GITHUB_STEP_SUMMARY
180+ echo "" >> $GITHUB_STEP_SUMMARY
181+
182+ # Update all crate versions
183+ crates=("core" "cli" "output" "storage")
184+ updated_files=()
185+
186+ for crate in "${crates[@]}"; do
187+ current_version=$(grep '^version = ' "crates/$crate/Cargo.toml" | cut -d'"' -f2)
188+ if [ "$current_version" != "$TARGET_VERSION" ]; then
189+ echo "Updating $crate: $current_version → $TARGET_VERSION"
190+ sed -i "s/^version = \".*\"/version = \"$TARGET_VERSION\"/" "crates/$crate/Cargo.toml"
191+ updated_files+=("crates/$crate/Cargo.toml")
192+ echo "- ✅ **$crate**: $current_version → $TARGET_VERSION" >> $GITHUB_STEP_SUMMARY
193+ else
194+ echo "- ⏭️ **$crate**: Already at $TARGET_VERSION" >> $GITHUB_STEP_SUMMARY
195+ fi
196+ done
197+
198+ # Update release-please manifest
199+ current_manifest=$(jq -r '."."' .github/.release-please-manifest.json)
200+ if [ "$current_manifest" != "$TARGET_VERSION" ]; then
201+ echo "Updating release-please manifest: $current_manifest → $TARGET_VERSION"
202+ jq --arg version "$TARGET_VERSION" '."." = $version' .github/.release-please-manifest.json > tmp.json
203+ mv tmp.json .github/.release-please-manifest.json
204+ updated_files+=(".github/.release-please-manifest.json")
205+ echo "- ✅ **release-please manifest**: $current_manifest → $TARGET_VERSION" >> $GITHUB_STEP_SUMMARY
206+ else
207+ echo "- ⏭️ **release-please manifest**: Already at $TARGET_VERSION" >> $GITHUB_STEP_SUMMARY
208+ fi
209+
210+ # Set outputs
211+ if [ ${#updated_files[@]} -gt 0 ]; then
212+ echo "files_updated=true" >> $GITHUB_OUTPUT
213+ echo "updated_files=$(printf '%s,' "${updated_files[@]}" | sed 's/,$//')" >> $GITHUB_OUTPUT
214+ else
215+ echo "files_updated=false" >> $GITHUB_OUTPUT
216+ fi
217+
218+ - name : Validate workspace after sync
219+ if : steps.sync.outputs.files_updated == 'true'
220+ run : |
221+ echo "## 🧪 Validation Results" >> $GITHUB_STEP_SUMMARY
222+ echo "" >> $GITHUB_STEP_SUMMARY
223+
224+ # Check workspace builds
225+ if cargo check --workspace; then
226+ echo "- ✅ Workspace builds successfully" >> $GITHUB_STEP_SUMMARY
227+ else
228+ echo "- ❌ Workspace build failed" >> $GITHUB_STEP_SUMMARY
229+ exit 1
230+ fi
231+
232+ # Verify version consistency
233+ echo "### Final Version State" >> $GITHUB_STEP_SUMMARY
234+ echo "| Crate | Version |" >> $GITHUB_STEP_SUMMARY
235+ echo "|-------|---------|" >> $GITHUB_STEP_SUMMARY
236+ for crate in core cli output storage; do
237+ version=$(grep '^version = ' "crates/$crate/Cargo.toml" | cut -d'"' -f2)
238+ echo "| $crate | $version |" >> $GITHUB_STEP_SUMMARY
239+ done
240+ manifest_version=$(jq -r '."."' .github/.release-please-manifest.json)
241+ echo "| release-please | $manifest_version |" >> $GITHUB_STEP_SUMMARY
242+
243+ - name : Update CHANGELOG with version sync
244+ if : steps.sync.outputs.files_updated == 'true'
245+ run : |
246+ TARGET_VERSION="${{ needs.analyze-versions.outputs.target_version }}"
247+
248+ # Check if there's already an entry for this version
249+ if ! grep -q "## \[$TARGET_VERSION\]" CHANGELOG.md; then
250+ # Create new entry at the top
251+ temp_file=$(mktemp)
252+
253+ # Extract header
254+ sed -n '1,/^## \[/p' CHANGELOG.md | head -n -1 > "$temp_file"
255+
256+ # Add new version entry
257+ echo "" >> "$temp_file"
258+ echo "## [$TARGET_VERSION] - $(date +%Y-%m-%d)" >> "$temp_file"
259+ echo "" >> "$temp_file"
260+ echo "### 🔄 Version Management" >> "$temp_file"
261+ echo "" >> "$temp_file"
262+ echo "- Synchronized all workspace crates to version $TARGET_VERSION" >> "$temp_file"
263+ echo "- Updated release-please manifest configuration" >> "$temp_file"
264+ echo "- Applied automated version management workflow" >> "$temp_file"
265+ echo "" >> "$temp_file"
266+
267+ # Append rest of changelog
268+ sed -n '/^## \[/,$p' CHANGELOG.md >> "$temp_file"
269+
270+ mv "$temp_file" CHANGELOG.md
271+ echo "✅ Added CHANGELOG entry for version $TARGET_VERSION"
272+ else
273+ echo "ℹ️ CHANGELOG entry for $TARGET_VERSION already exists"
274+ fi
275+
276+ - name : Commit and push changes
277+ if : steps.sync.outputs.files_updated == 'true'
278+ run : |
279+ TARGET_VERSION="${{ needs.analyze-versions.outputs.target_version }}"
280+ SYNC_STRATEGY="${{ needs.analyze-versions.outputs.sync_strategy }}"
281+
282+ git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
283+ git config --local user.name "github-actions[bot]"
284+
285+ if ! git diff --quiet; then
286+ git add .
287+
288+ # Create detailed commit message
289+ commit_msg="chore: synchronize workspace versions to v$TARGET_VERSION
290+
291+ Applied $SYNC_STRATEGY strategy and updated all crate versions to $TARGET_VERSION.
292+ Synchronized release-please manifest and updated CHANGELOG.md with version sync details.
293+
294+ [skip ci] version sync only"
295+
296+ git commit -m "$commit_msg"
297+ git push
298+
299+ echo "✅ Version synchronization changes pushed successfully!"
300+ echo "🏷️ All workspace crates now at version **$TARGET_VERSION**" >> $GITHUB_STEP_SUMMARY
301+ else
302+ echo "ℹ️ No changes to commit"
303+ fi
304+
305+ notify-completion :
306+ name : Notify Completion
307+ runs-on : ubuntu-latest
308+ needs : [analyze-versions, version-sync]
309+ if : always()
310+ steps :
311+ - name : Create completion summary
312+ run : |
313+ echo "## 🎯 Version Management Workflow Complete" >> $GITHUB_STEP_SUMMARY
314+ echo "" >> $GITHUB_STEP_SUMMARY
315+
316+ if [[ "${{ needs.analyze-versions.outputs.needs_sync }}" == "true" ]]; then
317+ if [[ "${{ needs.version-sync.result }}" == "success" ]]; then
318+ echo "✅ **Status**: Version synchronization completed successfully" >> $GITHUB_STEP_SUMMARY
319+ echo "🏷️ **Target Version**: ${{ needs.analyze-versions.outputs.target_version }}" >> $GITHUB_STEP_SUMMARY
320+ echo "📋 **Strategy**: ${{ needs.analyze-versions.outputs.sync_strategy }}" >> $GITHUB_STEP_SUMMARY
321+ else
322+ echo "❌ **Status**: Version synchronization failed" >> $GITHUB_STEP_SUMMARY
323+ echo "Please check the logs for errors and resolve manually" >> $GITHUB_STEP_SUMMARY
324+ fi
325+ else
326+ echo "ℹ️ **Status**: No version synchronization needed" >> $GITHUB_STEP_SUMMARY
327+ echo "All crates are already aligned to version ${{ needs.analyze-versions.outputs.target_version }}" >> $GITHUB_STEP_SUMMARY
328+ fi
329+
330+ echo "" >> $GITHUB_STEP_SUMMARY
331+ echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
332+ echo "- Version changes will trigger existing CI/CD workflows" >> $GITHUB_STEP_SUMMARY
333+ echo "- Release-please will detect changes and prepare next release" >> $GITHUB_STEP_SUMMARY
334+ echo "- Auto-fix workflow will apply any necessary code quality improvements" >> $GITHUB_STEP_SUMMARY
0 commit comments