prepare changelog and docs for release 1.8.0 #631
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 macOS Universal | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - "*" | |
| pull_request: | |
| branches: | |
| - "**" | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| version: | |
| name: Resolve Version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.set-version.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Checkout raygeo source | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: barebaric/raygeo | |
| path: external/raygeo | |
| - name: Set Version | |
| id: set-version | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.ref_type }}" == "tag" ]]; then | |
| VERSION=${{ github.ref_name }} | |
| else | |
| SHORT_SHA=$(git rev-parse --short HEAD) | |
| if git describe --tags --abbrev=0 >/dev/null 2>&1; then | |
| BASE_VERSION=$(git describe --tags --abbrev=0) | |
| else | |
| BASE_VERSION="v0.0.0" | |
| fi | |
| VERSION="${BASE_VERSION}-${SHORT_SHA}" | |
| fi | |
| if [ -z "$VERSION" ]; then | |
| echo "Error: No git version number found" | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "Version: $VERSION" | |
| build-intel: | |
| name: Build macOS Intel Bundle | |
| needs: version | |
| runs-on: macos-26-intel | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Checkout raygeo source | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: barebaric/raygeo | |
| path: external/raygeo | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| cache: "pip" | |
| cache-dependency-path: requirements.txt | |
| - name: Install macOS dependencies | |
| run: bash scripts/mac/mac_setup.sh --install | |
| - name: Build macOS artifacts | |
| run: | | |
| printf "5\n" | bash scripts/mac/mac_build.sh --version "${VERSION}" | |
| - name: Smoke test Intel app | |
| run: | | |
| APP_BIN="dist/Rayforge.app/Contents/MacOS/Rayforge" | |
| if [ ! -x "$APP_BIN" ]; then | |
| echo "Rayforge executable not found at $APP_BIN" | |
| exit 1 | |
| fi | |
| "$APP_BIN" --version | |
| "$APP_BIN" --exit | |
| - name: Package Intel app | |
| run: | | |
| APP_PATH="dist/Rayforge.app" | |
| if [ ! -d "$APP_PATH" ]; then | |
| echo "App bundle not found at $APP_PATH" | |
| exit 1 | |
| fi | |
| ZIP_NAME="rayforge-${VERSION}-macos-intel-app.zip" | |
| ditto -c -k --keepParent "$APP_PATH" "$ZIP_NAME" | |
| - name: Upload Intel app artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rayforge-${{ env.VERSION }}-macos-intel-app.zip | |
| path: rayforge-${{ env.VERSION }}-macos-intel-app.zip | |
| compression-level: 9 | |
| build-arm: | |
| name: Build macOS Apple Silicon Bundle | |
| needs: version | |
| runs-on: macos-26 | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Checkout raygeo source | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: barebaric/raygeo | |
| path: external/raygeo | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| cache: "pip" | |
| cache-dependency-path: requirements.txt | |
| - name: Install macOS dependencies | |
| run: bash scripts/mac/mac_setup.sh --install | |
| - name: Build macOS artifacts | |
| run: | | |
| printf "5\n" | bash scripts/mac/mac_build.sh --version "${VERSION}" | |
| - name: Smoke test ARM app | |
| run: | | |
| APP_BIN="dist/Rayforge.app/Contents/MacOS/Rayforge" | |
| if [ ! -x "$APP_BIN" ]; then | |
| echo "Rayforge executable not found at $APP_BIN" | |
| exit 1 | |
| fi | |
| "$APP_BIN" --version | |
| "$APP_BIN" --exit | |
| - name: Package ARM app | |
| run: | | |
| APP_PATH="dist/Rayforge.app" | |
| if [ ! -d "$APP_PATH" ]; then | |
| echo "App bundle not found at $APP_PATH" | |
| exit 1 | |
| fi | |
| ZIP_NAME="rayforge-${VERSION}-macos-arm-app.zip" | |
| ditto -c -k --keepParent "$APP_PATH" "$ZIP_NAME" | |
| - name: Upload ARM app artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rayforge-${{ env.VERSION }}-macos-arm-app.zip | |
| path: rayforge-${{ env.VERSION }}-macos-arm-app.zip | |
| compression-level: 9 | |
| merge-universal: | |
| name: Merge Universal App and DMG | |
| needs: [version, build-intel, build-arm] | |
| runs-on: macos-26 | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| steps: | |
| - name: Download Intel app artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rayforge-${{ env.VERSION }}-macos-intel-app.zip | |
| path: artifacts/intel | |
| - name: Download ARM app artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rayforge-${{ env.VERSION }}-macos-arm-app.zip | |
| path: artifacts/arm | |
| - name: Create universal app | |
| shell: bash | |
| run: | | |
| mkdir -p build-universal | |
| ditto -x -k "artifacts/intel/rayforge-${VERSION}-macos-intel-app.zip" \ | |
| artifacts/intel/unpacked | |
| ditto -x -k "artifacts/arm/rayforge-${VERSION}-macos-arm-app.zip" \ | |
| artifacts/arm/unpacked | |
| INTEL_APP="artifacts/intel/unpacked/Rayforge.app" | |
| ARM_APP="artifacts/arm/unpacked/Rayforge.app" | |
| UNI_APP="build-universal/Rayforge.app" | |
| if [ ! -d "$INTEL_APP" ] || [ ! -d "$ARM_APP" ]; then | |
| echo "Intel or ARM app bundle not found after extraction" | |
| exit 1 | |
| fi | |
| cp -R "$ARM_APP" "$UNI_APP" | |
| rsync -a --ignore-existing "$INTEL_APP/" "$UNI_APP/" | |
| find "$ARM_APP" -type f | while read -r arm_file; do | |
| rel="${arm_file#"$ARM_APP"/}" | |
| intel_file="$INTEL_APP/$rel" | |
| uni_file="$UNI_APP/$rel" | |
| if [ ! -f "$intel_file" ]; then | |
| continue | |
| fi | |
| arm_type=$(file -b "$arm_file") | |
| intel_type=$(file -b "$intel_file") | |
| if [[ "$arm_type" != *"Mach-O"* ]] || \ | |
| [[ "$intel_type" != *"Mach-O"* ]]; then | |
| continue | |
| fi | |
| lipo -create -output "$uni_file" "$arm_file" "$intel_file" | |
| if [ -x "$arm_file" ]; then | |
| chmod +x "$uni_file" | |
| fi | |
| done | |
| - name: Set architecture priority | |
| shell: bash | |
| run: | | |
| PLIST="build-universal/Rayforge.app/Contents/Info.plist" | |
| if [ -f "$PLIST" ]; then | |
| /usr/libexec/PlistBuddy -c "Delete :LSArchitecturePriority" \ | |
| "$PLIST" >/dev/null 2>&1 || true | |
| /usr/libexec/PlistBuddy -c "Add :LSArchitecturePriority array" \ | |
| "$PLIST" | |
| /usr/libexec/PlistBuddy \ | |
| -c "Add :LSArchitecturePriority:0 string arm64" "$PLIST" | |
| /usr/libexec/PlistBuddy \ | |
| -c "Add :LSArchitecturePriority:1 string x86_64" "$PLIST" | |
| fi | |
| - name: Re-sign universal app | |
| shell: bash | |
| run: | | |
| APP_PATH="$(pwd)/build-universal/Rayforge.app" | |
| if [ ! -d "$APP_PATH" ]; then | |
| echo "Universal app bundle not found at $APP_PATH" | |
| exit 1 | |
| fi | |
| chmod -R u+w "$APP_PATH" | |
| rm -rf "$APP_PATH/Contents/_CodeSignature" | |
| if ! codesign --force --deep --sign - "$APP_PATH"; then | |
| echo "Initial deep re-sign failed, retrying..." | |
| sleep 1 | |
| codesign --force --deep --sign - "$APP_PATH" | |
| fi | |
| if ! codesign --verify --deep --strict --verbose=2 "$APP_PATH"; then | |
| echo "Warning: codesign verification failed for $APP_PATH" | |
| fi | |
| spctl --assess --type execute --verbose=2 "$APP_PATH" || true | |
| "$APP_PATH/Contents/MacOS/Rayforge" --version | |
| "$APP_PATH/Contents/MacOS/Rayforge" --exit | |
| - name: Package universal app | |
| shell: bash | |
| run: | | |
| APP_ZIP="rayforge-${VERSION}-macos-universal-app.zip" | |
| ditto -c -k --keepParent "build-universal/Rayforge.app" "$APP_ZIP" | |
| TMP_DIR=$(mktemp -d) | |
| ditto -x -k "$APP_ZIP" "$TMP_DIR" | |
| "$TMP_DIR/Rayforge.app/Contents/MacOS/Rayforge" --version | |
| "$TMP_DIR/Rayforge.app/Contents/MacOS/Rayforge" --exit | |
| rm -rf "$TMP_DIR" | |
| - name: Build universal DMG with retry | |
| shell: bash | |
| run: | | |
| mkdir -p build-universal/dmg | |
| cp -R "build-universal/Rayforge.app" "build-universal/dmg/" | |
| ln -sfn /Applications "build-universal/dmg/Applications" | |
| DMG_NAME="rayforge-${VERSION}-macos-universal.dmg" | |
| tries=0 | |
| max_tries=10 | |
| until hdiutil create -volname "Rayforge" \ | |
| -srcfolder "build-universal/dmg" -ov -format ULMO "$DMG_NAME" | |
| do | |
| tries=$((tries + 1)) | |
| if [ "$tries" -ge "$max_tries" ]; then | |
| echo "Error: hdiutil failed after ${max_tries} attempts" | |
| exit 1 | |
| fi | |
| sleep 2 | |
| done | |
| - name: Upload universal app artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rayforge-${{ env.VERSION }}-macos-universal-app.zip | |
| path: rayforge-${{ env.VERSION }}-macos-universal-app.zip | |
| compression-level: 9 | |
| - name: Upload universal DMG artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rayforge-${{ env.VERSION }}-macos-universal-dmg | |
| path: rayforge-${{ env.VERSION }}-macos-universal.dmg | |
| release: | |
| name: Create GitHub Release (Universal) | |
| needs: [version, merge-universal] | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') && github.repository == 'barebaric/rayforge' | |
| permissions: | |
| contents: write | |
| outputs: | |
| is_prerelease: ${{ steps.release_info.outputs.is_prerelease }} | |
| steps: | |
| - name: Determine release type | |
| id: release_info | |
| shell: bash | |
| run: | | |
| TAG="${{ github.ref_name }}" | |
| if [[ "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+- ]]; then | |
| echo "is_prerelease=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is_prerelease=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Download Intel app artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rayforge-${{ needs.version.outputs.version }}-macos-intel-app.zip | |
| - name: Download ARM app artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rayforge-${{ needs.version.outputs.version }}-macos-arm-app.zip | |
| - name: Download universal app artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rayforge-${{ needs.version.outputs.version }}-macos-universal-app.zip | |
| - name: Download universal DMG artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rayforge-${{ needs.version.outputs.version }}-macos-universal-dmg | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| rayforge-${{ needs.version.outputs.version }}-macos-intel-app.zip | |
| rayforge-${{ needs.version.outputs.version }}-macos-arm-app.zip | |
| rayforge-${{ needs.version.outputs.version }}-macos-universal-app.zip | |
| rayforge-${{ needs.version.outputs.version }}-macos-universal.dmg | |
| draft: false | |
| prerelease: ${{ steps.release_info.outputs.is_prerelease }} | |
| name: Release ${{ needs.version.outputs.version }} | |
| tag_name: ${{ github.ref_name }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |