Release #37
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release' | |
| required: true | |
| dry_run: | |
| description: 'Run in dry-run mode (do not push to CocoaPods)' | |
| type: boolean | |
| default: false | |
| required: false | |
| test_fail: | |
| description: 'Intentionally fail at a specific stage (for testing)' | |
| type: string | |
| default: 'none' | |
| required: false | |
| jobs: | |
| release: | |
| runs-on: macos-latest | |
| outputs: | |
| commit_sha: ${{ steps.save_commit_info.outputs.commit_sha }} | |
| version: ${{ github.event.inputs.version }} | |
| dry_run: ${{ github.event.inputs.dry_run }} | |
| tag_name: ${{ steps.create_tag.outputs.tag_name }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v2 | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.2.2' | |
| - name: Install Ruby Gems | |
| run: sudo bundle install | |
| - name: Use Latest Stable Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: latest-stable | |
| - name: Ensure Platforms are Downloaded | |
| run: | | |
| xcodebuild -runFirstLaunch | |
| xcrun simctl list | |
| for platform in iOS watchOS tvOS visionOS; do | |
| echo "Downloading $platform platform..." | |
| xcodebuild -downloadPlatform $platform | |
| xcodebuild -runFirstLaunch | |
| done | |
| - name: Test failure - Early stage | |
| if: ${{ github.event.inputs.test_fail == 'early' }} | |
| run: | | |
| echo "Intentionally failing at early stage for testing" | |
| exit 1 | |
| - name: Update version in podspec | |
| run: sed -i '' 's/s.version = "[^"]*"/s.version = "${{ github.event.inputs.version }}"/' KSCrash.podspec | |
| - name: Update version in source code | |
| run: | | |
| formatted_version_number=$(echo "${{ github.event.inputs.version }}" | awk -F. '{printf("%d.%02d%02d\n", $1, $2, $3)}') | |
| sed -i '' 's/const double KSCrashFrameworkVersionNumber = [^;]*/const double KSCrashFrameworkVersionNumber = '"$formatted_version_number"'/' Sources/KSCrashRecording/KSCrash.m | |
| sed -i '' 's/const unsigned char KSCrashFrameworkVersionString\[\] = "[^"]*"/const unsigned char KSCrashFrameworkVersionString[] = "${{ github.event.inputs.version }}"/' Sources/KSCrashRecording/KSCrash.m | |
| - name: Update README | |
| run: | | |
| # Update SPM version | |
| sed -i '' "s/\.package(url: \"https:\/\/github.com\/kstenerud\/KSCrash.git\", .upToNextMajor(from: \"[^\"]*\"))/\.package(url: \"https:\/\/github.com\/kstenerud\/KSCrash.git\", .upToNextMajor(from: \"${{ github.event.inputs.version }}\"))/" README.md | |
| # Update CocoaPods version | |
| VERSION="${{ github.event.inputs.version }}" | |
| if [[ "$VERSION" == *"-"* ]]; then | |
| # It's a pre-release version, use the full version | |
| sed -i '' "s/pod 'KSCrash'.*$/pod 'KSCrash', '~> $VERSION'/" README.md | |
| else | |
| # It's a release version, use major.minor | |
| sed -i '' "s/pod 'KSCrash'.*$/pod 'KSCrash', '~> ${VERSION%.*}'/" README.md | |
| fi | |
| echo "README.md updated with version ${{ github.event.inputs.version }}" | |
| - name: Commit version update | |
| id: commit_version | |
| run: | | |
| git config --global user.name 'github-actions[bot]' | |
| git config --global user.email 'github-actions[bot]@users.noreply.github.com' | |
| git add . | |
| git commit -m "Update version to ${{ github.event.inputs.version }}" | |
| git push | |
| - name: Save commit information | |
| id: save_commit_info | |
| run: | | |
| COMMIT_SHA=$(git rev-parse HEAD) | |
| echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT | |
| - name: Test failure - After commit | |
| if: ${{ github.event.inputs.test_fail == 'mid' }} | |
| run: | | |
| echo "Intentionally failing after commit but before tag for testing" | |
| exit 1 | |
| - name: Create git tag | |
| id: create_tag | |
| run: | | |
| if [[ "${{ github.event.inputs.dry_run }}" == "true" ]]; then | |
| TAG_NAME="dry-run-${{ github.event.inputs.version }}" | |
| else | |
| TAG_NAME="${{ github.event.inputs.version }}" | |
| fi | |
| git tag $TAG_NAME | |
| git push origin $TAG_NAME | |
| echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT | |
| - name: Test failure - After tag | |
| if: ${{ github.event.inputs.test_fail == 'late' }} | |
| run: | | |
| echo "Intentionally failing after tag but before publishing for testing" | |
| exit 1 | |
| - name: Publish to CocoaPods | |
| if: ${{ !github.event.inputs.dry_run && github.event.inputs.test_fail != 'any' }} | |
| env: | |
| COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_PASSWORD }} | |
| run: pod trunk push KSCrash.podspec --verbose | |
| - name: Skip publishing | |
| if: ${{ github.event.inputs.dry_run || github.event.inputs.test_fail != 'none' }} | |
| run: | | |
| echo "Publishing skipped - running in test or dry-run mode" | |
| - name: Test failure - During publishing | |
| if: ${{ github.event.inputs.test_fail == 'publish' }} | |
| run: | | |
| echo "Intentionally failing during publishing stage for testing" | |
| exit 1 | |
| rollback: | |
| runs-on: macos-15 | |
| needs: release | |
| if: failure() | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Fetch all tags | |
| run: | | |
| git fetch --tags | |
| - name: Delete git tag locally | |
| run: | | |
| # Use tag from outputs or construct it | |
| if [[ -n "${{ needs.release.outputs.tag_name }}" ]]; then | |
| TAG_TO_DELETE="${{ needs.release.outputs.tag_name }}" | |
| elif [[ "${{ needs.release.outputs.dry_run }}" == "true" ]]; then | |
| TAG_TO_DELETE="dry-run-${{ needs.release.outputs.version }}" | |
| else | |
| TAG_TO_DELETE="${{ needs.release.outputs.version }}" | |
| fi | |
| git tag -d $TAG_TO_DELETE || echo "Tag not found locally" | |
| echo "TAG_TO_DELETE=$TAG_TO_DELETE" >> $GITHUB_ENV | |
| - name: Delete git tag remotely | |
| run: | | |
| git push --delete origin ${{ env.TAG_TO_DELETE }} || echo "Tag not found on remote" | |
| - name: Pull latest changes | |
| run: | | |
| git pull origin "$(git branch --show-current)" | |
| - name: Check for version commit | |
| id: check_commit | |
| run: | | |
| if [[ -n "${{ needs.release.outputs.commit_sha }}" ]]; then | |
| echo "Version commit found from outputs: ${{ needs.release.outputs.commit_sha }}" | |
| echo "SHOULD_REVERT=true" >> $GITHUB_ENV | |
| echo "COMMIT_SHA=${{ needs.release.outputs.commit_sha }}" >> $GITHUB_ENV | |
| else | |
| # Fallback: search by commit message | |
| SEARCH_MSG="Update version to ${{ needs.release.outputs.version || github.event.inputs.version }}" | |
| FOUND_COMMIT=$(git log --format="%H" --grep="$SEARCH_MSG" -n 1) | |
| if [[ -n "$FOUND_COMMIT" ]]; then | |
| echo "Found commit by message: $FOUND_COMMIT" | |
| echo "SHOULD_REVERT=true" >> $GITHUB_ENV | |
| echo "COMMIT_SHA=$FOUND_COMMIT" >> $GITHUB_ENV | |
| else | |
| echo "No version commit found, nothing to revert." | |
| echo "SHOULD_REVERT=false" >> $GITHUB_ENV | |
| fi | |
| fi | |
| - name: Revert version commit | |
| if: env.SHOULD_REVERT == 'true' | |
| run: | | |
| echo "Reverting commit ${{ env.COMMIT_SHA }}..." | |
| git log --oneline -n 3 | |
| git revert --no-commit ${{ env.COMMIT_SHA }} | |
| git status -s | |
| git config --global user.name 'github-actions[bot]' | |
| git config --global user.email 'github-actions[bot]@users.noreply.github.com' | |
| git commit -m "Revert version update due to failed release" | |
| - name: Push revert | |
| if: env.SHOULD_REVERT == 'true' | |
| run: | | |
| git push || { git status; exit 1; } |