Skip to content

Fix ci again

Fix ci again #167

Workflow file for this run

name: Build and Release
on:
push:
branches-ignore:
- main
tags:
- "v*.*.*"
- "v*.*.*-beta.*"
pull_request:
branches:
- main
permissions:
contents: write
pages: write
id-token: write
env:
XCODE_VERSION: "16.2.0"
BUNDLE_ID: "com.ameba.SwiftKey"
APP_NAME: "SwiftKey"
BETA_FEED_URL: "https://swiftkey.app/appcast_beta.xml"
PROD_FEED_URL: "https://swiftkey.app/appcast.xml"
jobs:
verify-release-notes:
if: startsWith(github.ref, 'refs/tags/v') && github.event_name != 'pull_request'
runs-on: ubuntu-latest
outputs:
release_notes: ${{ steps.read_notes.outputs.content }}
steps:
- uses: actions/checkout@v3
- name: Get version
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Check release notes exist
id: check_notes
run: |
VERSION=${{ steps.get_version.outputs.VERSION }}
NOTES_PATH="docs/release-notes/${VERSION}.md"
if [ ! -f "$NOTES_PATH" ]; then
echo "Error: Release notes not found for version ${VERSION}"
echo "Expected path: ${NOTES_PATH}"
exit 1
fi
- name: Read release notes
id: read_notes
run: |
VERSION=${{ steps.get_version.outputs.VERSION }}
NOTES_PATH="docs/release-notes/${VERSION}.md"
CONTENT=$(cat "$NOTES_PATH" | perl -p -e 's/%/%25/g' | perl -p -e 's/\n/%0A/g' | perl -p -e 's/\r/%0D/g')
echo "content=$CONTENT" >> $GITHUB_OUTPUT
build:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
runs-on: macos-latest
timeout-minutes: 30
outputs:
build_number: ${{ steps.get_commit_count.outputs.BUILD_NUMBER }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get Version Numbers
id: get_versions
run: |
# Get build number from commit count
BUILD_NUMBER=$(git rev-list --count HEAD)
echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_OUTPUT
# Initialize version variables
VERSION="0.0.0"
IS_RELEASE=false
# Check for tag
if [ -n "$GITHUB_REF_TYPE" ]; then
case "$GITHUB_REF_TYPE" in
"tag")
if [[ "$GITHUB_REF_NAME" == v* ]]; then
VERSION=${GITHUB_REF_NAME#v}
IS_RELEASE=true
fi
;;
"branch")
VERSION="0.0.0"
IS_RELEASE=false
;;
esac
fi
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "IS_RELEASE=$IS_RELEASE" >> $GITHUB_OUTPUT
# Debug output
echo "Debug information:"
echo "GITHUB_REF_TYPE: $GITHUB_REF_TYPE"
echo "GITHUB_REF_NAME: $GITHUB_REF_NAME"
echo "GITHUB_REF: $GITHUB_REF"
echo "BUILD_NUMBER: $BUILD_NUMBER"
echo "VERSION: $VERSION"
echo "IS_RELEASE: $IS_RELEASE"
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.XCODE_VERSION }}
- name: Build Application
env:
MARKETING_VERSION: ${{ steps.get_versions.outputs.VERSION }}
CURRENT_PROJECT_VERSION: ${{ steps.get_versions.outputs.BUILD_NUMBER }}
run: |
xcodebuild \
-scheme "${{ env.APP_NAME }}" \
-configuration Release \
-derivedDataPath build \
-arch arm64 -arch x86_64 \
ONLY_ACTIVE_ARCH=NO \
MARKETING_VERSION="$MARKETING_VERSION" \
CURRENT_PROJECT_VERSION="$CURRENT_PROJECT_VERSION" \
build
- name: Verify Universal Binary
run: |
echo "Checking binary architectures..."
lipo -archs "build/Build/Products/Release/${{ env.APP_NAME }}.app/Contents/MacOS/${{ env.APP_NAME }}"
- name: Package App Bundle
run: |
cd build/Build/Products/Release
ditto -c -k --keepParent "${{ env.APP_NAME }}.app" "${{ env.APP_NAME }}.app.zip"
- name: Upload App Bundle
uses: actions/upload-artifact@v4
with:
name: ${{ env.APP_NAME }}-Unsigned
path: build/Build/Products/Release/${{ env.APP_NAME }}.app.zip
retention-days: 5
sign:
needs: build
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Download Unsigned App
uses: actions/download-artifact@v4
with:
name: ${{ env.APP_NAME }}-Unsigned
path: .
- name: Unpack App Bundle
run: |
ditto -x -k "${{ env.APP_NAME }}.app.zip" .
- name: Sign Application
uses: ./.github/actions/sign
with:
certificate: ${{ secrets.CERTIFICATES_P12 }}
certificate-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
apple-team-id: ${{ secrets.TEAM_ID }}
app-path: "${{ env.APP_NAME }}.app"
entitlements-path: "SwiftKey/Resources/SwiftKey.entitlements"
- name: Package Signed App Bundle
run: |
ditto -c -k --keepParent "${{ env.APP_NAME }}.app" "${{ env.APP_NAME }}.app.zip"
- name: Upload Signed App Bundle
uses: actions/upload-artifact@v4
with:
name: ${{ env.APP_NAME }}-Signed
path: ${{ env.APP_NAME }}.app.zip
retention-days: 5
notarize:
needs: sign
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Download Signed App
uses: actions/download-artifact@v4
with:
name: ${{ env.APP_NAME }}-Signed
path: .
- name: Unpack App Bundle
run: |
ditto -x -k "${{ env.APP_NAME }}.app.zip" .
- name: Notarize Application
uses: ./.github/actions/notarize
with:
username: ${{ secrets.APPLE_ID }}
password: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
apple-team-id: ${{ secrets.TEAM_ID }}
app-path: "${{ env.APP_NAME }}.app"
- name: Package Notarized App Bundle
run: |
ditto -c -k --keepParent "${{ env.APP_NAME }}.app" "${{ env.APP_NAME }}.app.zip"
- name: Upload Notarized App Bundle
uses: actions/upload-artifact@v4
with:
name: ${{ env.APP_NAME }}-Notarized
path: ${{ env.APP_NAME }}.app.zip
retention-days: 5
release:
needs: [notarize, verify-release-notes]
if: startsWith(github.ref, 'refs/tags/v')
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Need full history for changelog
- name: Set version variables
run: |
echo "VERSION=$(echo ${{ github.ref_name }} | sed 's/v//')" >> $GITHUB_ENV
echo "IS_BETA=$(echo ${{ github.ref_name }} | grep -q 'beta' && echo 'true' || echo 'false')" >> $GITHUB_ENV
echo "TAG=$(echo ${{ github.ref_name }})" >> $GITHUB_ENV
- name: Download Notarized App
uses: actions/download-artifact@v4
with:
name: ${{ env.APP_NAME }}-Notarized
path: .
- name: Unpack App Bundle
run: |
ditto -x -k "${{ env.APP_NAME }}.app.zip" .
- name: Create Release Archive
run: |
ditto -c -k --keepParent "${{ env.APP_NAME }}.app" "${{ env.APP_NAME }}-${{ env.VERSION }}.zip"
- name: Calculate SHA256
run: |
echo "ZIP_SHA=$(shasum -a 256 ${{ env.APP_NAME }}-${{ env.VERSION }}.zip | cut -d' ' -f1)" >> $GITHUB_ENV
- name: Read Release Notes
id: release_notes
run: |
NOTES_PATH="docs/release-notes/${{ env.TAG }}.md"
if [ ! -f "$NOTES_PATH" ]; then
echo "Error: Release notes not found at $NOTES_PATH"
exit 1
fi
# Escape the content for GitHub Actions output
CONTENT=$(cat "$NOTES_PATH" | perl -p -e 's/%/%25/g' | perl -p -e 's/\n/%0A/g' | perl -p -e 's/\r/%0D/g')
echo "content=$CONTENT" >> $GITHUB_OUTPUT
# Also store raw content for the release
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
cat "$NOTES_PATH" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Generate Sparkle Signature
id: generate_signature
uses: ./.github/actions/sparkle-sign
with:
private-key: ${{ secrets.SPARKLE_PRIVATE_KEY }}
file-path: ${{ env.APP_NAME }}-${{ env.VERSION }}.zip
- name: Update Appcast
run: |
IS_BETA="${{ env.IS_BETA }}"
APPCAST_NAME="appcast$([ "$IS_BETA" == "true" ] && echo "_beta").xml"
APPCAST_FILE="docs/$APPCAST_NAME"
echo "$APPCAST_FILE"
cat > "$APPCAST_FILE" <<-EOF
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>${{ env.APP_NAME }} $([ "$IS_BETA" == "true" ] && echo "Beta ")Appcast</title>
<link>$([ "$IS_BETA" == "true" ] && echo "${{ env.BETA_FEED_URL }}" || echo "${{ env.PROD_FEED_URL }}")</link>
<description>${{ env.APP_NAME }} $([ "$IS_BETA" == "true" ] && echo "Beta ")Updates</description>
<language>en</language>
<item>
<title>${{ env.APP_NAME }} ${{ env.VERSION }}</title>
<sparkle:version>${{ env.VERSION }}</sparkle:version>
<sparkle:shortVersionString>${{ env.VERSION }}</sparkle:shortVersionString>
<description><![CDATA[${{ env.RELEASE_NOTES }}]]></description>
<pubDate>$(date -R)</pubDate>
<enclosure
url="https://github.com/${{ github.repository }}/releases/download/${{ env.TAG }}/${{ env.APP_NAME }}-${{ env.VERSION }}.zip"
sparkle:version="${{ env.VERSION }}"
sparkle:shortVersionString="${{ env.VERSION }}"
type="application/octet-stream"
${{ steps.generate_signature.outputs.signature }}
sparkle:sha256="${{ env.ZIP_SHA }}"
/>
</item>
</channel>
</rss>
EOF
echo "Appcast file successfully created and validated at $APPCAST_FILE"
- name: Update CHANGELOG.md
run: |
# Create temporary file
TEMP_FILE=$(mktemp)
# Add new release notes with header
echo "# ${{ env.TAG }} ($(date +'%Y-%m-%d'))" > "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
echo "${{ env.RELEASE_NOTES }}" >> "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
# Append existing changelog if it exists
if [ -f "CHANGELOG.md" ]; then
cat "CHANGELOG.md" >> "$TEMP_FILE"
fi
# Replace original changelog
mv "$TEMP_FILE" "CHANGELOG.md"
- name: Commit and Push Changes
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git add CHANGELOG.md
git add docs/appcast*.xml
git commit -m "docs: update CHANGELOG.md and appcast for ${{ env.TAG }}"
git push origin HEAD:main
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: ${{ env.APP_NAME }}-${{ env.VERSION }}.zip
body: ${{ env.RELEASE_NOTES }}
prerelease: ${{ env.IS_BETA == 'true' }}
draft: false
fail_on_unmatched_files: true
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
keep_files: true
notify:
needs: [build, sign, notarize]
if: always()
runs-on: ubuntu-latest
steps:
- name: Notify Status
run: |
echo "Build status: ${{ needs.build.result }}"
echo "Sign status: ${{ needs.sign.result }}"
echo "Notarize status: ${{ needs.notarize.result }}"