Build and Release #10
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: Build and Release | |
| on: | |
| push: | |
| tags: | |
| - "v*.*.*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag for the release (e.g., v1.0.0)" | |
| required: true | |
| type: string | |
| env: | |
| SWIFT_VERSION: "6.1" | |
| XCODE_VERSION: "16.2" | |
| jobs: | |
| build-and-release: | |
| name: Build and Release | |
| runs-on: macos-latest | |
| permissions: | |
| contents: write | |
| packages: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: "16.2" | |
| - name: Verify Swift version | |
| run: swift --version | |
| - name: Clean previous builds | |
| run: swift package clean | |
| - name: Resolve dependencies | |
| run: swift package resolve | |
| - name: Build in release mode | |
| run: swift build -c release --arch arm64 --arch x86_64 | |
| - name: Create release directory | |
| run: mkdir -p release | |
| - name: Copy built executable | |
| run: | | |
| cp .build/apple/Products/Release/RainCheck release/ | |
| chmod +x release/RainCheck | |
| - name: Get tag name | |
| id: tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create tag if workflow_dispatch | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag -a "${{ steps.tag.outputs.tag }}" -m "Release ${{ steps.tag.outputs.tag }}" | |
| git push origin "${{ steps.tag.outputs.tag }}" | |
| - name: Create app bundle (optional for macOS distribution) | |
| run: | | |
| mkdir -p release/RainCheck.app/Contents/MacOS | |
| mkdir -p release/RainCheck.app/Contents/Resources | |
| cp release/RainCheck release/RainCheck.app/Contents/MacOS/ | |
| if [ -d Sources/RainCheck/Assets.xcassets/AppIcon.appiconset ]; then | |
| mkdir -p AppIcon.iconset | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_16x16.png AppIcon.iconset/icon_16x16.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png AppIcon.iconset/icon_16x16@2x.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_32x32.png AppIcon.iconset/icon_32x32.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png AppIcon.iconset/icon_32x32@2x.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_128x128.png AppIcon.iconset/icon_128x128.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png AppIcon.iconset/icon_128x128@2x.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_256x256.png AppIcon.iconset/icon_256x256.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png AppIcon.iconset/icon_256x256@2x.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_512x512.png AppIcon.iconset/icon_512x512.png | |
| cp Sources/RainCheck/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png AppIcon.iconset/icon_512x512@2x.png | |
| iconutil -c icns AppIcon.iconset -o release/RainCheck.app/Contents/Resources/AppIcon.icns | |
| rm -rf AppIcon.iconset | |
| elif [ -f Resources/AppIcon.icns ]; then | |
| cp Resources/AppIcon.icns release/RainCheck.app/Contents/Resources/ | |
| elif [ -f AppIcon.icns ]; then | |
| cp AppIcon.icns release/RainCheck.app/Contents/Resources/ | |
| fi | |
| cat > release/RainCheck.app/Contents/Info.plist << 'EOF' | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| <plist version="1.0"> | |
| <dict> | |
| <key>CFBundleDisplayName</key> | |
| <string>RainCheck</string> | |
| <key>CFBundleExecutable</key> | |
| <string>RainCheck</string> | |
| <key>CFBundleIdentifier</key> | |
| <string>com.github.andersfischernielsen.raincheck</string> | |
| <key>CFBundleName</key> | |
| <string>RainCheck</string> | |
| <key>CFBundlePackageType</key> | |
| <string>APPL</string> | |
| <key>CFBundleShortVersionString</key> | |
| <string>${{ steps.tag.outputs.tag }}</string> | |
| <key>CFBundleVersion</key> | |
| <string>${{ steps.tag.outputs.tag }}</string> | |
| <key>CFBundleIconFile</key> | |
| <string>AppIcon</string> | |
| <key>LSMinimumSystemVersion</key> | |
| <string>13.0</string> | |
| <key>LSUIElement</key> | |
| <true/> | |
| <key>NSHumanReadableCopyright</key> | |
| <string>Copyright © 2025. All rights reserved.</string> | |
| <key>NSPrincipalClass</key> | |
| <string>NSApplication</string> | |
| </dict> | |
| </plist> | |
| EOF | |
| - name: Create ZIP archive | |
| run: | | |
| cd release | |
| zip -r RainCheck-${{ steps.tag.outputs.tag }}-macOS.zip RainCheck.app | |
| zip RainCheck-${{ steps.tag.outputs.tag }}-executable.zip RainCheck | |
| cd .. | |
| - name: Calculate checksums | |
| run: | | |
| cd release | |
| shasum -a 256 *.zip > checksums.txt | |
| cd .. | |
| - name: Generate release notes | |
| id: release_notes | |
| run: | | |
| TAG_NAME="${{ steps.tag.outputs.tag }}" | |
| PREV_TAG=$(git tag --sort=-version:refname | grep -A 1 "$TAG_NAME" | tail -n 1) | |
| if [ -n "$PREV_TAG" ] && [ "$PREV_TAG" != "$TAG_NAME" ]; then | |
| echo "## What's Changed" > release_notes.md | |
| echo "" >> release_notes.md | |
| git log --pretty=format:"- %s (%h)" "$PREV_TAG".."$TAG_NAME" >> release_notes.md | |
| echo "" >> release_notes.md | |
| else | |
| echo "## RainCheck ${TAG_NAME}" > release_notes.md | |
| echo "" >> release_notes.md | |
| echo "Initial release of RainCheck - a macOS menu bar app for rain forecasts along cycling routes." >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| echo "## Installation" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "### App Bundle (Recommended)" >> release_notes.md | |
| echo "1. Download \`RainCheck-${TAG_NAME}-macOS.zip\`" >> release_notes.md | |
| echo "2. Extract the ZIP file" >> release_notes.md | |
| echo "3. Move \`RainCheck.app\` to your Applications folder" >> release_notes.md | |
| echo "4. Right-click the app and select \"Open\" (required for unsigned apps)" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "### Command Line Executable" >> release_notes.md | |
| echo "1. Download \`RainCheck-${TAG_NAME}-executable.zip\`" >> release_notes.md | |
| echo "2. Extract the ZIP file" >> release_notes.md | |
| echo "3. Run \`./RainCheck\` from the terminal" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "## System Requirements" >> release_notes.md | |
| echo "- macOS 13.0 or later" >> release_notes.md | |
| echo "- Intel or Apple Silicon Mac" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "## Checksums" >> release_notes.md | |
| echo "\`\`\`" >> release_notes.md | |
| cat release/checksums.txt >> release_notes.md | |
| echo "\`\`\`" >> release_notes.md | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ steps.tag.outputs.tag }} | |
| name: RainCheck ${{ steps.tag.outputs.tag }} | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: false | |
| files: | | |
| release/RainCheck-${{ steps.tag.outputs.tag }}-macOS.zip | |
| release/RainCheck-${{ steps.tag.outputs.tag }}-executable.zip | |
| release/checksums.txt | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: RainCheck-${{ steps.tag.outputs.tag }} | |
| path: | | |
| release/ | |
| !release/RainCheck | |
| retention-days: 30 |