Skip to content

Commit 6f526de

Browse files
committed
fix: implement robust release workflow with complete success validation
πŸ”§ CRITICAL WORKFLOW IMPROVEMENTS: βœ… Robust Crates.io Publication: - Replace permissive error handling with strict validation - Distinguish real errors from 'already published' cases - Validate each crate is available on crates.io before proceeding - Fail entire workflow if any critical crate fails to publish βœ… Complete Release Validation: - Validate ALL 9 workspace crates are published successfully - Multi-attempt validation with crates.io propagation delays - Critical path protection for codeprism-mcp availability βœ… Docker Build Protection: - Pre-build validation ensures codeprism-mcp is available - 3-attempt retry logic with 60-second delays - Graceful failure with clear error messages βœ… Success-Only Operations: - Community notifications only on complete success - Docker builds only when all crates validated - Clear release status categorization βœ… Comprehensive Status Reporting: - Detailed job status for each release component - Clear user guidance based on what succeeded - Complete/Partial/Failed status classification RESOLVES: False success reporting when codeprism-mcp fails to publish PREVENTS: Docker build failures due to missing crates on crates.io ENSURES: Release workflow only succeeds when users can actually install codeprism-mcp
1 parent 00cc5b4 commit 6f526de

File tree

2 files changed

+193
-26
lines changed

2 files changed

+193
-26
lines changed

β€Ž.github/workflows/release.ymlβ€Ž

Lines changed: 192 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -374,40 +374,128 @@ jobs:
374374
fi
375375
cargo login ${{ secrets.CRATES_IO_TOKEN }}
376376
377-
- name: Publish Crates (in dependency order)
377+
- name: Publish Crates (in dependency order with error handling)
378378
run: |
379-
# Publish in correct dependency order
380-
set -e
379+
# Robust publication with proper error handling
380+
set -e # Exit on any error
381+
382+
# Get the expected version
383+
VERSION="${{ needs.check-release.outputs.new_version }}"
384+
echo "Publishing all crates for version: $VERSION"
381385
382-
echo "Publishing independent crates first..."
383-
echo "Publishing codeprism-storage..."
384-
cargo publish -p codeprism-storage --allow-dirty || echo "codeprism-storage may already be published"
386+
# Function to publish a crate with proper error handling
387+
publish_crate() {
388+
local crate_name=$1
389+
echo "Publishing $crate_name..."
390+
391+
# Try to publish the crate
392+
if cargo publish -p "$crate_name" --allow-dirty; then
393+
echo "βœ… Successfully published $crate_name"
394+
return 0
395+
else
396+
# Check if it failed because it's already published
397+
local exit_code=$?
398+
echo "⚠️ Publication failed for $crate_name, checking if already published..."
399+
400+
# Wait a moment for potential index update
401+
sleep 10
402+
403+
# Check if the expected version exists on crates.io
404+
if cargo search "$crate_name" --limit 1 | grep -q "= \"$VERSION\""; then
405+
echo "βœ… $crate_name version $VERSION already published - continuing"
406+
return 0
407+
else
408+
echo "❌ FATAL: $crate_name failed to publish and version $VERSION not found on crates.io"
409+
echo "Exit code: $exit_code"
410+
return 1
411+
fi
412+
fi
413+
}
414+
415+
# Publish crates in dependency order
416+
echo "=== Phase 1: Independent crates ==="
417+
publish_crate "codeprism-storage"
385418
sleep 30
386419
387-
echo "Publishing codeprism-dev-tools..."
388-
cargo publish -p codeprism-dev-tools --allow-dirty || echo "codeprism-dev-tools may already be published"
420+
publish_crate "codeprism-dev-tools"
389421
sleep 30
390422
391-
echo "Publishing language parsers (no dependencies)..."
392-
cargo publish -p codeprism-lang-js --allow-dirty || echo "codeprism-lang-js may already be published"
423+
echo "=== Phase 2: Language parsers (no dependencies) ==="
424+
publish_crate "codeprism-lang-js"
393425
sleep 30
394-
cargo publish -p codeprism-lang-python --allow-dirty || echo "codeprism-lang-python may already be published"
426+
427+
publish_crate "codeprism-lang-python"
395428
sleep 30
396-
cargo publish -p codeprism-lang-java --allow-dirty || echo "codeprism-lang-java may already be published"
429+
430+
publish_crate "codeprism-lang-java"
397431
sleep 30
398-
cargo publish -p codeprism-lang-rust --allow-dirty || echo "codeprism-lang-rust may already be published"
432+
433+
publish_crate "codeprism-lang-rust"
399434
sleep 30
400435
401-
echo "Publishing codeprism-core (depends on language parsers)..."
402-
cargo publish -p codeprism-core --allow-dirty || echo "codeprism-core may already be published"
436+
echo "=== Phase 3: Core (depends on language parsers) ==="
437+
publish_crate "codeprism-core"
403438
sleep 30
404439
405-
echo "Publishing codeprism-analysis (depends on core)..."
406-
cargo publish -p codeprism-analysis --allow-dirty || echo "codeprism-analysis may already be published"
440+
echo "=== Phase 4: Analysis (depends on core) ==="
441+
publish_crate "codeprism-analysis"
407442
sleep 30
408443
409-
echo "Publishing main MCP server (depends on all)..."
410-
cargo publish -p codeprism-mcp --allow-dirty || echo "codeprism-mcp may already be published"
444+
echo "=== Phase 5: MCP Server (depends on all) ==="
445+
publish_crate "codeprism-mcp"
446+
447+
echo "πŸŽ‰ All crates published successfully!"
448+
449+
- name: Validate All Crates Published
450+
run: |
451+
# Validate that ALL expected crates are available on crates.io
452+
set -e
453+
VERSION="${{ needs.check-release.outputs.new_version }}"
454+
455+
echo "Validating all crates are available on crates.io for version $VERSION"
456+
457+
# List of all crates that must be published
458+
REQUIRED_CRATES=(
459+
"codeprism-storage"
460+
"codeprism-dev-tools"
461+
"codeprism-lang-js"
462+
"codeprism-lang-python"
463+
"codeprism-lang-java"
464+
"codeprism-lang-rust"
465+
"codeprism-core"
466+
"codeprism-analysis"
467+
"codeprism-mcp"
468+
)
469+
470+
echo "Waiting 60 seconds for crates.io index to fully propagate..."
471+
sleep 60
472+
473+
failed_crates=()
474+
475+
for crate in "${REQUIRED_CRATES[@]}"; do
476+
echo "Checking $crate..."
477+
if cargo search "$crate" --limit 1 | grep -q "= \"$VERSION\""; then
478+
echo "βœ… $crate version $VERSION found on crates.io"
479+
else
480+
echo "❌ $crate version $VERSION NOT found on crates.io"
481+
failed_crates+=("$crate")
482+
fi
483+
done
484+
485+
if [ ${#failed_crates[@]} -ne 0 ]; then
486+
echo ""
487+
echo "πŸ’₯ CRITICAL: The following crates failed validation:"
488+
for crate in "${failed_crates[@]}"; do
489+
echo " - $crate"
490+
done
491+
echo ""
492+
echo "Release cannot proceed. Docker build would fail."
493+
exit 1
494+
fi
495+
496+
echo ""
497+
echo "πŸŽ‰ SUCCESS: All required crates are available on crates.io!"
498+
echo "Release validation complete - Docker build can proceed safely."
411499
412500
# Build and push Docker images
413501
docker:
@@ -423,10 +511,31 @@ jobs:
423511
with:
424512
ref: v${{ needs.check-release.outputs.new_version }}
425513

426-
- name: Wait for crates.io to update
514+
- name: Validate Crates Available Before Docker Build
427515
run: |
428-
echo "Waiting 60 seconds for crates.io index to propagate..."
429-
sleep 60
516+
# Double-check that codeprism-mcp is available before Docker build
517+
VERSION="${{ needs.check-release.outputs.new_version }}"
518+
519+
echo "Final validation: Ensuring codeprism-mcp@$VERSION is available for Docker build..."
520+
521+
# Try up to 3 times with increasing delays for crates.io propagation
522+
for attempt in 1 2 3; do
523+
echo "Attempt $attempt: Checking codeprism-mcp availability..."
524+
525+
if cargo search codeprism-mcp --limit 1 | grep -q "= \"$VERSION\""; then
526+
echo "βœ… codeprism-mcp@$VERSION confirmed available on crates.io"
527+
break
528+
else
529+
if [ $attempt -eq 3 ]; then
530+
echo "❌ FATAL: codeprism-mcp@$VERSION still not available after 3 attempts"
531+
echo "Docker build cannot proceed as it would fail to install the crate"
532+
exit 1
533+
else
534+
echo "⏳ codeprism-mcp@$VERSION not yet available, waiting 60 seconds..."
535+
sleep 60
536+
fi
537+
fi
538+
done
430539
431540
- name: Set up Docker Buildx
432541
uses: docker/setup-buildx-action@v3
@@ -464,9 +573,10 @@ jobs:
464573
465574
# Notify community
466575
notify:
467-
name: Notify Community
576+
name: Notify Community
468577
needs: [check-release, release, publish-crates, docker]
469-
if: needs.check-release.outputs.should_release == 'true'
578+
# Only notify if ALL steps succeeded (including Docker)
579+
if: needs.check-release.outputs.should_release == 'true' && needs.publish-crates.result == 'success' && needs.docker.result == 'success'
470580
runs-on: ubuntu-latest
471581
steps:
472582
- name: Create Discussion Post
@@ -561,4 +671,61 @@ jobs:
561671
echo "πŸ’‘ Manual discussion can be created at: https://github.com/${{ github.repository }}/discussions/new"
562672
fi
563673
echo ""
564-
echo "The AI developer continues to evolve! πŸ€–πŸš€"
674+
echo "The AI developer continues to evolve! πŸ€–πŸš€"
675+
676+
# Final release status summary
677+
release-summary:
678+
name: Release Summary
679+
needs: [check-release, release, publish-crates, docker, notify]
680+
if: always() && needs.check-release.outputs.should_release == 'true'
681+
runs-on: ubuntu-latest
682+
steps:
683+
- name: Generate Release Summary
684+
run: |
685+
echo "# πŸ“Š Release v${{ needs.check-release.outputs.new_version }} Summary"
686+
echo "================================================"
687+
echo ""
688+
689+
# Check status of each job
690+
echo "## Job Status"
691+
echo "- βœ… Pre-Release Testing: ${{ needs.test.result }}"
692+
echo "- βœ… Binary Build: ${{ needs.build.result }}"
693+
echo "- βœ… GitHub Release: ${{ needs.release.result }}"
694+
echo "- πŸ¦€ Crates.io Publication: ${{ needs.publish-crates.result }}"
695+
echo "- 🐳 Docker Build: ${{ needs.docker.result }}"
696+
echo "- πŸ“’ Community Notification: ${{ needs.notify.result }}"
697+
echo ""
698+
699+
# Overall status
700+
if [[ "${{ needs.publish-crates.result }}" == "success" && "${{ needs.docker.result }}" == "success" ]]; then
701+
echo "## πŸŽ‰ RELEASE STATUS: βœ… COMPLETE SUCCESS"
702+
echo ""
703+
echo "βœ… All components successfully released!"
704+
echo "βœ… codeprism-mcp@${{ needs.check-release.outputs.new_version }} available on crates.io"
705+
echo "βœ… Docker images pushed to ghcr.io/rustic-ai/codeprism:v${{ needs.check-release.outputs.new_version }}"
706+
echo "βœ… Binaries available for all platforms"
707+
echo ""
708+
echo "Users can now install with:"
709+
echo "- cargo install codeprism-mcp@${{ needs.check-release.outputs.new_version }}"
710+
echo "- docker pull ghcr.io/rustic-ai/codeprism:v${{ needs.check-release.outputs.new_version }}"
711+
elif [[ "${{ needs.publish-crates.result }}" == "success" ]]; then
712+
echo "## ⚠️ RELEASE STATUS: πŸ”Ά PARTIAL SUCCESS"
713+
echo ""
714+
echo "βœ… Crates.io publication successful"
715+
echo "❌ Docker build failed"
716+
echo ""
717+
echo "Users can install via:"
718+
echo "- cargo install codeprism-mcp@${{ needs.check-release.outputs.new_version }}"
719+
echo "- Download binaries from GitHub releases"
720+
else
721+
echo "## ❌ RELEASE STATUS: πŸ”΄ FAILED"
722+
echo ""
723+
echo "❌ Critical failure in crates.io publication"
724+
echo "❌ codeprism-mcp@${{ needs.check-release.outputs.new_version }} NOT available"
725+
echo ""
726+
echo "Release cannot be considered successful without primary package availability."
727+
fi
728+
729+
echo ""
730+
echo "================================================"
731+
echo "Release process completed at $(date)"

β€ŽCargo.tomlβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ members = [
1313
]
1414

1515
[workspace.package]
16-
version = "0.3.2"
16+
version = "0.3.3"
1717
edition = "2021"
1818
authors = ["The Rustic Initiative"]
1919
license = "MIT OR Apache-2.0"

0 commit comments

Comments
Β (0)