Release #27
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: | |
| mode: | |
| description: Release workflow mode. | |
| required: true | |
| default: prepare | |
| type: choice | |
| options: | |
| - prepare | |
| - publish | |
| version: | |
| description: Version without v, e.g. 0.3.2. | |
| required: true | |
| type: string | |
| release_date: | |
| description: Optional release date in YYYY-MM-DD format. Defaults to today. | |
| required: false | |
| default: "" | |
| type: string | |
| dry_run: | |
| description: Validate without opening a PR. | |
| required: false | |
| default: true | |
| type: boolean | |
| push: | |
| tags: | |
| - 'v*' | |
| concurrency: | |
| group: release-${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }} | |
| cancel-in-progress: false | |
| jobs: | |
| prepare-release-notes: | |
| if: ${{ github.event_name == 'workflow_dispatch' && inputs.mode == 'prepare' }} | |
| runs-on: macos-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Resolve release inputs | |
| id: release | |
| run: | | |
| version="${{ inputs.version }}" | |
| version="${version#v}" | |
| release_date="${{ inputs.release_date }}" | |
| if [ -z "$release_date" ]; then | |
| release_date="$(date +%Y-%m-%d)" | |
| fi | |
| case "$version" in | |
| *[!A-Za-z0-9.+-]*) | |
| echo "Unsupported version: use SemVer-compatible characters." >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| safe_version="$(printf '%s' "$version" | tr '+.' '--')" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| echo "release_date=$release_date" >> "$GITHUB_OUTPUT" | |
| echo "branch=codex/release-notes/v${safe_version}" >> "$GITHUB_OUTPUT" | |
| - name: Make Scripts Executable | |
| run: chmod +x scripts/*.sh | |
| - name: Add dry-run fragment | |
| if: ${{ inputs.dry_run && endsWith(steps.release.outputs.version, '-test') }} | |
| run: | | |
| if ! find changelog.d -maxdepth 1 -type f -name '*.md' ! -name 'README.md' | grep -q .; then | |
| printf -- '- Exercise release preparation dry-run.\n' > changelog.d/dry-run.changed.md | |
| fi | |
| - name: Prepare Changelog | |
| run: ./scripts/prepare-changelog-release.sh "${{ steps.release.outputs.version }}" "${{ steps.release.outputs.release_date }}" | |
| - name: Validate Release Notes | |
| run: ./scripts/extract-release-notes.sh "${{ steps.release.outputs.version }}" | |
| - name: Show dry-run diff | |
| if: ${{ inputs.dry_run }} | |
| run: git diff -- CHANGELOG.md changelog.d | |
| - name: Open release notes PR | |
| if: ${{ !inputs.dry_run }} | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| branch: ${{ steps.release.outputs.branch }} | |
| delete-branch: false | |
| add-paths: | | |
| CHANGELOG.md | |
| changelog.d | |
| commit-message: "chore(release): prepare v${{ steps.release.outputs.version }} notes" | |
| title: "chore(release): prepare v${{ steps.release.outputs.version }} notes" | |
| body: | | |
| Prepares the finalized `CHANGELOG.md` section for `v${{ steps.release.outputs.version }}`. | |
| Review the release notes before merging. Publishing should happen only after this PR lands on `main`. | |
| publish-release: | |
| if: ${{ (github.event_name == 'workflow_dispatch' && inputs.mode == 'publish') || startsWith(github.ref, 'refs/tags/v') }} | |
| runs-on: macos-latest | |
| environment: release | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: latest-stable | |
| - name: Install XcodeGen | |
| run: brew install xcodegen | |
| - name: Resolve Release | |
| id: release | |
| run: | | |
| if [ "${GITHUB_REF#refs/tags/}" != "$GITHUB_REF" ]; then | |
| version="${GITHUB_REF#refs/tags/v}" | |
| create_tag="false" | |
| dry_run="false" | |
| else | |
| version="${{ inputs.version }}" | |
| version="${version#v}" | |
| create_tag="true" | |
| dry_run="${{ inputs.dry_run }}" | |
| fi | |
| if [ -z "$version" ]; then | |
| echo "Could not resolve a release version." >&2 | |
| exit 1 | |
| fi | |
| case "$version" in | |
| *[!A-Za-z0-9.+-]*) | |
| echo "Unsupported version: use SemVer-compatible characters." >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| echo "tag=v$version" >> "$GITHUB_OUTPUT" | |
| echo "create_tag=$create_tag" >> "$GITHUB_OUTPUT" | |
| echo "dry_run=$dry_run" >> "$GITHUB_OUTPUT" | |
| - name: Make Scripts Executable | |
| run: chmod +x scripts/*.sh | |
| - name: Check Tag Availability | |
| id: tag_check | |
| if: ${{ steps.release.outputs.create_tag == 'true' }} | |
| run: | | |
| git fetch --tags --force | |
| if git rev-parse -q --verify "refs/tags/${{ steps.release.outputs.tag }}" >/dev/null; then | |
| echo "Tag already exists: ${{ steps.release.outputs.tag }}." >&2 | |
| exit 1 | |
| fi | |
| echo "publish=true" >> "$GITHUB_OUTPUT" | |
| - name: Validate Release Notes | |
| if: ${{ steps.release.outputs.create_tag != 'true' || steps.tag_check.outputs.publish == 'true' }} | |
| run: ./scripts/extract-release-notes.sh "${{ steps.release.outputs.version }}" >/dev/null | |
| - name: Run Quality Gate | |
| if: ${{ steps.release.outputs.create_tag != 'true' || steps.tag_check.outputs.publish == 'true' }} | |
| run: ./scripts/swift-quality-gate.sh local | |
| - name: Build and Package | |
| if: ${{ steps.release.outputs.create_tag != 'true' || steps.tag_check.outputs.publish == 'true' }} | |
| run: ./scripts/build-release.sh ${{ steps.release.outputs.version }} | |
| - name: Extract Release Notes | |
| if: ${{ steps.release.outputs.create_tag != 'true' || steps.tag_check.outputs.publish == 'true' }} | |
| id: extract_notes | |
| run: | | |
| VERSION="${{ steps.release.outputs.version }}" | |
| NOTES_FILE="$RUNNER_TEMP/release-notes.md" | |
| ./scripts/extract-release-notes.sh "$VERSION" > "$NOTES_FILE" | |
| echo "NOTES<<EOF" >> $GITHUB_OUTPUT | |
| cat "$NOTES_FILE" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Upload Release Artifact | |
| if: ${{ steps.release.outputs.create_tag != 'true' || steps.tag_check.outputs.publish == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: Kubebar-${{ steps.release.outputs.tag }} | |
| path: Kubebar.zip | |
| - name: Create Tag | |
| if: ${{ steps.release.outputs.dry_run != 'true' && steps.release.outputs.create_tag == 'true' && steps.tag_check.outputs.publish == 'true' }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag -a "${{ steps.release.outputs.tag }}" -m "Release ${{ steps.release.outputs.tag }}" | |
| git push origin "${{ steps.release.outputs.tag }}" | |
| - name: Create GitHub Release | |
| if: ${{ steps.release.outputs.dry_run != 'true' && (steps.release.outputs.create_tag != 'true' || steps.tag_check.outputs.publish == 'true') }} | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.release.outputs.tag }} | |
| files: Kubebar.zip | |
| body: | | |
| ${{ steps.extract_notes.outputs.NOTES }} | |
| --- | |
| **Installation Note (Ad-hoc Signature)**: | |
| Kubebar is currently distributed with an Ad-hoc signature. To run the app: | |
| 1. Download and extract `Kubebar.zip`. | |
| 2. **Right-click** `Kubebar.app` and select **Open**. | |
| 3. Click **Open** again in the security dialog. | |
| 4. Alternatively, run `xattr -cr /Applications/Kubebar.app` in your terminal to remove the quarantine flag. | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |