From 465c40e08a7a97b7eed9859cdeb8f7440ac41941 Mon Sep 17 00:00:00 2001 From: Taha Bebek Date: Thu, 7 Nov 2024 08:07:47 -0800 Subject: [PATCH 1/4] delete retry --- preternatural-build/action.yml | 55 ---------------------------------- 1 file changed, 55 deletions(-) diff --git a/preternatural-build/action.yml b/preternatural-build/action.yml index 9f62ff2..f340e74 100644 --- a/preternatural-build/action.yml +++ b/preternatural-build/action.yml @@ -61,62 +61,7 @@ runs: echo "Executing command: $COMMAND" eval $COMMAND - continue-on-error: true - - name: Clear caches and retry build - id: retry_build - if: steps.build.outcome == 'failure' - shell: bash - run: | - echo "Initial build failed. Clearing caches and retrying..." - - # Allow individual commands to fail without stopping the script - set +e - - # Clear SwiftPM caches - if [ "${{ !env.ACT }}" == "true" ]; then - rm -rf $HOME/Library/org.swift.swiftpm - rm -rf $HOME/Library/Caches/org.swift.swiftpm - fi - - # Force package update - rm -rf .build - swift package update - swift package resolve - - # Clear derived data - if [ -n "${{ inputs.derived_data_path }}" ]; then - rm -rf "${{ inputs.derived_data_path }}" - else - rm -rf $HOME/Library/Developer/Xcode/DerivedData - fi - - # Retry build - COMMAND="preternatural build" - if [ -n "${{ inputs.derived_data_path }}" ]; then - COMMAND="$COMMAND --derived-data-path '${{ inputs.derived_data_path }}'" - fi - - # Handle platforms array - PLATFORMS="${{ join(fromJSON(inputs.platforms), ',') }}" - if [ -n "$PLATFORMS" ]; then - COMMAND="$COMMAND --platforms '$PLATFORMS'" - fi - - # Handle configurations array - CONFIGS="${{ join(fromJSON(inputs.configurations), ',') }}" - if [ -n "$CONFIGS" ]; then - COMMAND="$COMMAND --configurations '$CONFIGS'" - fi - - echo "Retrying command: $COMMAND" - eval $COMMAND - - # Capture the exit code of the last command (the build retry) - BUILD_EXIT_CODE=$? - # Exit with the build's exit code - exit $BUILD_EXIT_CODE - - name: Find and copy all xcactivity logs if: failure() shell: bash From 852dc5d2785ca1969f129d5f9a9637522fbb6379 Mon Sep 17 00:00:00 2001 From: Taha Bebek Date: Thu, 7 Nov 2024 09:48:12 -0800 Subject: [PATCH 2/4] refactor --- .github/workflows/test.yml | 13 +++ preternatural-build/action.yml | 188 +++++++++++++++++++++++++-------- 2 files changed, 158 insertions(+), 43 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..be62d98 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,13 @@ +name: 'Test Preternatural Build Action' +on: + pull_request: + branches: [ main ] + +jobs: + test-swift-package: + runs-on: ghcr.io/cirruslabs/macos-runner:sonoma + steps: + - name: Test Swift Package Basic Functionality + uses: tahabebek/MockPackage/BuildAction@main + with: + path: ${{ github.sha }} diff --git a/preternatural-build/action.yml b/preternatural-build/action.yml index f340e74..690bdd4 100644 --- a/preternatural-build/action.yml +++ b/preternatural-build/action.yml @@ -1,76 +1,178 @@ name: 'Preternatural Build Action' description: 'Run Preternatural build command on repositories with a specified Xcode version' inputs: - derived_data_path: - description: 'The path to the derived data folder' + xcode-version: + description: 'Xcode version to use' required: false + default: 'latest-stable' platforms: description: 'Target platforms (array of: iOS, macOS, tvOS, watchOS, visionOS, all)' required: false default: '["macOS"]' - xcode-version: - description: 'Xcode version to use' - required: true configurations: description: 'Build configurations (array of: debug, release)' required: false default: '["debug", "release"]' + derived_data_path: + description: 'The path to the derived data folder' + required: false + default: DerivedData/ProjectBuild + runs: using: 'composite' steps: + - name: Setup Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ inputs.xcode-version }} + - name: Install Preternatural - if: ${{ !env.ACT }} # Skipping when run locally. + if: ${{ !env.ACT }} shell: bash run: | brew tap PreternaturalAI/preternatural brew install preternatural - - name: Cache derived data - uses: actions/cache@v3 - if: ${{ !env.ACT }} # Skipping when run locally. - with: - path: ${{ inputs.derived_data_path || '~/Library/Developer/Xcode/DerivedData' }} - key: ${{ runner.os }}-derived-data-xcode-${{ inputs.xcode-version }} - restore-keys: | - ${{ runner.os }}-derived-data-xcode-${{ inputs.xcode-version }} - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: ${{ inputs.xcode-version }} - - - name: Execute Preternatural build command - id: build + + - name: Generate project cache key + id: cache-key shell: bash run: | - defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES - COMMAND="preternatural build" - if [ -n "${{ inputs.derived_data_path }}" ]; then - COMMAND="$COMMAND --derived-data-path '${{ inputs.derived_data_path }}'" + if ls *.xcodeproj/project.pbxproj 1> /dev/null 2>&1; then + echo "Found Xcode project" + PROJECT_NAME=$(basename *.xcodeproj .xcodeproj) + HASH=$(shasum *.xcodeproj/project.pbxproj | cut -d' ' -f1) + elif ls *.xcworkspace/contents.xcworkspacedata 1> /dev/null 2>&1; then + echo "Found Xcode workspace" + PROJECT_NAME=$(basename *.xcworkspace .xcworkspace) + HASH=$(shasum *.xcworkspace/contents.xcworkspacedata | cut -d' ' -f1) + elif [ -f "Package.swift" ]; then + echo "Found Swift package" + PROJECT_NAME=$(swift package describe --type json | awk '/^{/,/^}/' 2>/dev/null | jq -r '.name') + if [ -f "Package.resolved" ]; then + HASH=$(shasum Package.resolved | cut -d' ' -f1) + else + HASH=$(shasum Package.swift | cut -d' ' -f1) + fi + else + echo "No recognized project structure found" + PROJECT_NAME="unknown" + HASH=$(date +%s | shasum | cut -d' ' -f1) fi + + echo "project-name=$PROJECT_NAME" >> $GITHUB_OUTPUT + + PLATFORMS_KEY=$(echo '${{ inputs.platforms }}' | tr -d '[]"' | sed 's/, /-/g' | sed 's/,/-/g') + echo "platforms-key=$PLATFORMS_KEY" >> $GITHUB_OUTPUT + echo "package-hash=$HASH" >> $GITHUB_OUTPUT - # Handle platforms array - PLATFORMS="${{ join(fromJSON(inputs.platforms), ',') }}" - if [ -n "$PLATFORMS" ]; then - COMMAND="$COMMAND --platforms '$PLATFORMS'" - fi + - name: Cache project derived data + id: cache-derived-data + uses: actions/cache@v4 + if: ${{ !env.ACT }} + with: + path: ${{ github.workspace }}/${{ inputs.derived_data_path }} + key: ${{ steps.cache-key.outputs.project-name }}-derived-data-v1-${{ runner.os }}-xcode${{ inputs.xcode-version }}-platforms-${{ steps.cache-key.outputs.platforms-key }}-${{ steps.cache-key.outputs.package-hash }} + restore-keys: | + ${{ steps.cache-key.outputs.project-name }}-derived-data-v1-${{ runner.os }}-xcode${{ inputs.xcode-version }}-platforms- + + - name: Debug Cache Status + if: ${{ !env.ACT }} + shell: bash + run: | + echo "==== Cache Status ====" - # Handle configurations array - CONFIGS="${{ join(fromJSON(inputs.configurations), ',') }}" - if [ -n "$CONFIGS" ]; then - COMMAND="$COMMAND --configurations '$CONFIGS'" + echo "Project Cache:" + echo "Cache key components:" + echo "- Runner OS: ${{ runner.os }}" + echo "- Xcode Version: ${{ inputs.xcode-version }}" + echo "- Platforms: ${{ inputs.platforms }}" + echo "- Package.resolved hash: ${{ hashFiles('Package.resolved') }}" + echo "- Package.swift hash: ${{ hashFiles('Package.swift') }}" + + PROJECT_DERIVED_DATA=${{ github.workspace }}/${{ inputs.derived_data_path }} + echo "Project derived data path: $PROJECT_DERIVED_DATA" + + if [ "${{ steps.cache-derived-data.outputs.cache-hit }}" == "true" ]; then + echo "Project cache: HIT" + if [ -d "$PROJECT_DERIVED_DATA" ]; then + echo "Directory exists and contains:" + find "$PROJECT_DERIVED_DATA" -type d -maxdepth 2 + echo "Total size:" + du -sh "$PROJECT_DERIVED_DATA" + else + echo "WARNING: Project cache hit but directory doesn't exist!" + fi + else + echo "Project cache: MISS" fi + echo "==================================" + + - name: Create project build script + shell: bash + run: | + echo "==== Create Project Build Script ====" + + PLATFORMS=$(echo '${{ inputs.platforms }}' | tr -d '[]' | sed 's/, /,/g') + CONFIGURATIONS=$(echo '${{ inputs.configurations }}' | tr -d '[]' | sed 's/, /,/g') + DERIVED_DATA_PATH=${{ github.workspace }}/${{ inputs.derived_data_path }} + echo "Processed values:" + echo "PLATFORMS: $PLATFORMS" + echo "CONFIGURATIONS: $CONFIGURATIONS" + echo "DERIVED_DATA_PATH: $DERIVED_DATA_PATH" + + cat > project_build_utils.sh << EOF + #!/bin/bash + PLATFORMS="${PLATFORMS}" + CONFIGURATIONS="${CONFIGURATIONS}" + DERIVED_DATA_PATH="${DERIVED_DATA_PATH}" + + project_build_cmd() { + cmd="preternatural build" + if [[ -n "\${DERIVED_DATA_PATH}" ]]; then + cmd="\$cmd --derived-data-path \$(printf %q "\${DERIVED_DATA_PATH}")" + fi + if [[ -n "\${PLATFORMS}" ]]; then + cmd="\$cmd --platforms \${PLATFORMS}" + fi + if [[ -n "\${CONFIGURATIONS}" ]]; then + cmd="\$cmd --configurations \${CONFIGURATIONS}" + fi + if [[ -n "\${BUILD_DIR}" ]]; then + cmd="\$cmd --symroot \${BUILD_DIR}" + fi + if [[ -n "\${SCHEME}" ]]; then + cmd="\$cmd --scheme \${SCHEME}" + fi + echo "\$cmd" + } + EOF + chmod +x project_build_utils.sh + export PLATFORMS + export CONFIGURATIONS + export DERIVED_DATA_PATH + echo "==================================" + + - name: Execute project build command + id: build + shell: bash + run: | + echo "==== Execute Project Build Command ====" + source project_build_utils.sh + echo "Loaded project_build_utils.sh" + defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES + echo "Set IDESkipMacroFingerprintValidation" + COMMAND=$(project_build_cmd) echo "Executing command: $COMMAND" - eval $COMMAND + eval "$COMMAND" + echo "Command execution completed with status: $?" + echo "==================================" - name: Find and copy all xcactivity logs if: failure() shell: bash run: | - if [ -n "${{ inputs.derived_data_path }}" ]; then - DERIVED_DATA_PATH="${{ inputs.derived_data_path }}" - else - DERIVED_DATA_PATH="$HOME/Library/Developer/Xcode/DerivedData" - fi + DERIVED_DATA_PATH=${{ github.workspace }}/${{ inputs.derived_data_path }} echo "Searching for logs in: $DERIVED_DATA_PATH" mkdir -p ./artifacts @@ -106,7 +208,7 @@ runs: mkdir -p ./json_logs for log in ./artifacts/*.xcactivitylog; do json_file="./json_logs/$(basename "$log" .xcactivitylog).json" - xclogparser parse --file "$log" --output "$json_file" + xclogparser parse --file "$log" --reporter json --output "$json_file" echo "Contents of $json_file:" cat "$json_file" echo "--------------------------------" @@ -114,7 +216,7 @@ runs: - name: Upload xcactivity logs (JSON) if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: xcactivity-logs-json path: ./json_logs/*.json @@ -122,7 +224,7 @@ runs: - name: Upload xcactivity logs (Raw) if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: xcactivity-logs-raw path: ./artifacts/*.xcactivitylog From ac6a44f0c7987693e31dd0316d7122c480c4e26d Mon Sep 17 00:00:00 2001 From: Taha Bebek Date: Thu, 7 Nov 2024 12:08:09 -0800 Subject: [PATCH 3/4] added USING.md --- README.md | 58 +++++++------------- USING.md | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 40 deletions(-) create mode 100644 USING.md diff --git a/README.md b/README.md index 3fe4357..4bae161 100644 --- a/README.md +++ b/README.md @@ -2,53 +2,31 @@ This repository contains GitHub Actions for use with [Preternatural CLI](https://github.com/PreternaturalAI/CLI-release). +## Actions -## Preternatural Build Action - -This action allows you to run the Preternatural CLI build command on your repositories with support for a specific Xcode version. - -### Inputs - -- `xcode-version`: (Required) Xcode version to use. -- `derived_data_path`: (Optional) The path to the derived data folder. -- `build_all_platforms`: (Optional) Set to `true` to build for all supported platforms. Defaults to `false`. -- `configuration`: (Optional) Build configuration (debug or release). Defaults to `debug`. - -#### Example Usage +### 1. Preternatural Build Action +Runs the Preternatural CLI build command on your repositories. ```yaml -name: Run Preternatural Build -uses: PreternaturalAI/github-action/preternatural-build@main -with: - xcode-version: '16' - build_all_platforms: 'false' - derived_data_path: '~/Library/Developer/Xcode/DerivedData' - configuration: 'release' +- uses: PreternaturalAI/preternatural-build-action@v1 ``` -## Preternatural Archive & Notarize Action +### 2. Preternatural Archive & Notarize Action +Archives and notarizes macOS applications using the Preternatural CLI. -This action allows you to archive and notarize a MacOS application using the Preternatural CLI. +```yaml +- uses: PreternaturalAI/preternatural-archive-action@v1 + with: + notarization_username: ${{ secrets.NOTARIZATION_USERNAME }} + notarization_password: ${{ secrets.NOTARIZATION_PASSWORD }} + build_certificate_base64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + p12_password: ${{ secrets.P12_PASSWORD }} +``` -### Inputs +## Documentation -- `xcode-version`: (Required) Xcode version to use. -- `notarization_username`: (Required) Your Apple ID email. -- `notarization_password`: (Required) App specific password to use for notarization. See [here](https://support.apple.com/en-us/102654) for steps on how to create one. -- `notarization_team_id`: (Optional) App Store Connect Team ID for notarization. If not provided, this will be automatically extracted from the Xcode project. The Team ID provided here should match the Team ID of the certificate. -- `build_certificate_base64`: (Required) Your Apple Developer ID Certificate encoded in base64. Follow the steps in [this tutorial](https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions) to get the base64 string of your certificate. -- `p12_password`: (Required) Password for the `Developer ID Application` certificate. +See [USING.md](./USING.md) for detailed documentation, examples, and troubleshooting. -#### Example Usage +## License -```yaml -name: Archive and Notarize MacOS App -uses: PreternaturalAI/github-action/preternatural-archive@main -with: - xcode-version: '16' - notarization_username: ${{ secrets.NOTARIZATION_USERNAME }} - notarization_password: ${{ secrets.NOTARIZATION_PASSWORD }} - notarization_team_id: ${{ secrets.NOTARIZATION_TEAM_ID }} - build_certificate_base64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} - p12_password: ${{ secrets.P12_PASSWORD }} -``` +[License Type] - See LICENSE file for details diff --git a/USING.md b/USING.md new file mode 100644 index 0000000..df52c5d --- /dev/null +++ b/USING.md @@ -0,0 +1,158 @@ +# Preternatural GitHub Actions Usage Guide + +This document catalogs the available Preternatural GitHub Actions and their usage examples. + +## Table of Contents +- [Build Action](#build-action) +- [Archive & Notarize Action](#archive--notarize-action) + +## Action Source Files + +- [Build Action Source](preternatural-build/action.yml) - Implementation of the build action +- [Archive Action Source](preternatural-archive/action.yml) - Implementation of the archive and notarize action + +## Build Action + +The Build Action runs Preternatural build commands on repositories with specified Xcode configurations. + +### Build Action Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `xcode-version` | Xcode version to use for building | No | `latest-stable` | +| `platforms` | Target platforms to build for | No | `["macOS"]` | +| `configurations` | Build configurations to use | No | `["debug", "release"]` | +| `derived_data_path` | Path to the derived data folder | No | `DerivedData/ProjectBuild` | + +### Build Action Examples + +#### Basic Build +```yaml +steps: + - uses: PreternaturalAI/preternatural-build-action@v1 +``` + +#### Multi-Platform Build +```yaml +steps: + - uses: PreternaturalAI/preternatural-build-action@v1 + with: + platforms: '["iOS", "macOS", "tvOS"]' +``` + +#### Debug-Only Build with Custom Derived Data +```yaml +steps: + - uses: PreternaturalAI/preternatural-build-action@v1 + with: + configurations: '["debug"]' + derived_data_path: 'CustomDerivedData' +``` + +#### All Platforms Release Build +```yaml +steps: + - uses: PreternaturalAI/preternatural-build-action@v1 + with: + platforms: '["iOS", "macOS", "tvOS", "watchOS", "visionOS"]' + configurations: '["release"]' +``` + +#### Build with Specific Xcode Version +```yaml +steps: + - uses: PreternaturalAI/preternatural-build-action@v1 + with: + xcode-version: '14.3.1' + platforms: '["macOS"]' +``` + +## Archive & Notarize Action + +The Archive & Notarize Action creates and notarizes a macOS application using the Preternatural CLI. + +### Archive Action Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `xcode-version` | Xcode version to use | Yes | `latest-stable` | +| `notarization_username` | App Store Connect Username | Yes | - | +| `notarization_password` | App Store Connect Password | Yes | - | +| `notarization_team_id` | App Store Connect Team ID | No | - | +| `build_certificate_base64` | Base64-encoded Apple certificate | Yes | - | +| `p12_password` | Password for the P12 certificate | Yes | - | + +### Archive Action Examples + +#### Basic Archive and Notarize +```yaml +steps: + - uses: PreternaturalAI/preternatural-archive-action@v1 + with: + notarization_username: ${{ secrets.NOTARIZATION_USERNAME }} + notarization_password: ${{ secrets.NOTARIZATION_PASSWORD }} + build_certificate_base64: ${{ secrets.BUILD_CERTIFICATE }} + p12_password: ${{ secrets.P12_PASSWORD }} +``` + +#### Archive with Team ID and Specific Xcode Version +```yaml +steps: + - uses: PreternaturalAI/preternatural-archive-action@v1 + with: + xcode-version: '15.2' + notarization_username: ${{ secrets.NOTARIZATION_USERNAME }} + notarization_password: ${{ secrets.NOTARIZATION_PASSWORD }} + notarization_team_id: 'YOUR_TEAM_ID' + build_certificate_base64: ${{ secrets.BUILD_CERTIFICATE }} + p12_password: ${{ secrets.P12_PASSWORD }} +``` + +#### Archive with Custom Team Setup +```yaml +steps: + - uses: PreternaturalAI/preternatural-archive-action@v1 + with: + xcode-version: '15.2' + notarization_username: ${{ secrets.NOTARIZATION_USERNAME }} + notarization_password: ${{ secrets.NOTARIZATION_PASSWORD }} + notarization_team_id: ${{ secrets.TEAM_ID }} + build_certificate_base64: ${{ secrets.ENTERPRISE_CERTIFICATE }} + p12_password: ${{ secrets.ENTERPRISE_CERT_PASSWORD }} +``` + +#### Archive for Enterprise Distribution +```yaml +steps: + - uses: PreternaturalAI/preternatural-archive-action@v1 + with: + notarization_username: ${{ secrets.ENTERPRISE_USERNAME }} + notarization_password: ${{ secrets.ENTERPRISE_PASSWORD }} + notarization_team_id: ${{ secrets.ENTERPRISE_TEAM_ID }} + build_certificate_base64: ${{ secrets.ENTERPRISE_CERTIFICATE }} + p12_password: ${{ secrets.ENTERPRISE_CERT_PASSWORD }} +``` + +## Features + +### Build Action Features +- Derived data caching +- Detailed build logs +- Multi-platform support +- Various project structure support + +### Archive Action Features +- Automatic certificate installation +- Notarization process handling +- Artifact uploading +- Team ID support +- Secure secrets handling + +## Requirements + +- macOS runner +- GitHub Actions environment +- For notarization: + - Valid Apple Developer account + - App Store Connect credentials + - Valid certificate and provisioning profile From 5a604dc0289c3952b3ea9fac117787fe94401b63 Mon Sep 17 00:00:00 2001 From: Taha Bebek Date: Thu, 7 Nov 2024 13:52:14 -0800 Subject: [PATCH 4/4] remove non-existing inputs --- preternatural-build/action.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/preternatural-build/action.yml b/preternatural-build/action.yml index 690bdd4..a0dbe5e 100644 --- a/preternatural-build/action.yml +++ b/preternatural-build/action.yml @@ -138,12 +138,6 @@ runs: if [[ -n "\${CONFIGURATIONS}" ]]; then cmd="\$cmd --configurations \${CONFIGURATIONS}" fi - if [[ -n "\${BUILD_DIR}" ]]; then - cmd="\$cmd --symroot \${BUILD_DIR}" - fi - if [[ -n "\${SCHEME}" ]]; then - cmd="\$cmd --scheme \${SCHEME}" - fi echo "\$cmd" } EOF