diff --git a/.github/workflows/publish-factorykit-binary.yml b/.github/workflows/publish-factorykit-binary.yml new file mode 100644 index 00000000..aef43285 --- /dev/null +++ b/.github/workflows/publish-factorykit-binary.yml @@ -0,0 +1,62 @@ +name: Publish FactoryKit Binary + +on: + workflow_dispatch: + inputs: + release_tag: + description: Git tag and release name for the published binary artifact + required: true + type: string + xcode_version: + description: Exact Xcode version used to build the artifact + required: true + default: "26.3" + type: string + +permissions: + contents: write + +jobs: + publish: + runs-on: macos-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Select Xcode version + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ inputs.xcode_version }} + + - name: Build FactoryKit XCFramework + id: build + run: | + Scripts/build_factorykit_xcframework.sh \ + --output-dir "$RUNNER_TEMP/factorykit-binary" \ + --artifact-name "FactoryKit-xcode${{ inputs.xcode_version }}.xcframework" + + - name: Upload workflow artifact + uses: actions/upload-artifact@v4 + with: + name: factorykit-xcode${{ inputs.xcode_version }} + path: | + ${{ steps.build.outputs.zip_path }} + ${{ steps.build.outputs.sha256_path }} + + - name: Publish GitHub release asset + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ inputs.release_tag }} + target_commitish: ${{ github.sha }} + files: | + ${{ steps.build.outputs.zip_path }} + ${{ steps.build.outputs.sha256_path }} + body: | + FactoryKit binary artifact built from `${{ github.sha }}`. + + Xcode: `${{ steps.build.outputs.xcode_version }}` + Swift: `${{ steps.build.outputs.swift_version }}` + SHA256: `${{ steps.build.outputs.sha256 }}` diff --git a/.gitignore b/.gitignore index cd008543..05032676 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ playground.xcworkspace .swiftpm .build/ +BuildArtifacts/ # CocoaPods # diff --git a/Scripts/build_factorykit_xcframework.sh b/Scripts/build_factorykit_xcframework.sh new file mode 100755 index 00000000..8ac1a9b5 --- /dev/null +++ b/Scripts/build_factorykit_xcframework.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: Scripts/build_factorykit_xcframework.sh [options] + +Build a release-mode XCFramework for FactoryKit and package it as a zip. + +Options: + --output-dir PATH Directory for the built artifact. Default: ./BuildArtifacts + --artifact-name NAME XCFramework directory name. Default: FactoryKit.xcframework + --bundle-id ID Bundle identifier for the generated framework target + --ios-version VERSION iOS deployment target. Default: 13.0 + --macos-version VER macOS deployment target. Default: 10.15 + --help Show this help text +EOF +} + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +OUTPUT_DIR="$REPO_ROOT/BuildArtifacts" +ARTIFACT_NAME="FactoryKit.xcframework" +BUNDLE_ID="ai.perplexity.factorykit.binary" +IOS_VERSION="13.0" +MACOS_VERSION="10.15" + +while [[ $# -gt 0 ]]; do + case "$1" in + --output-dir) + OUTPUT_DIR="$2" + shift 2 + ;; + --artifact-name) + ARTIFACT_NAME="$2" + shift 2 + ;; + --bundle-id) + BUNDLE_ID="$2" + shift 2 + ;; + --ios-version) + IOS_VERSION="$2" + shift 2 + ;; + --macos-version) + MACOS_VERSION="$2" + shift 2 + ;; + --help) + usage + exit 0 + ;; + *) + echo "Unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +if [[ "$ARTIFACT_NAME" != *.xcframework ]]; then + echo "--artifact-name must end with .xcframework" >&2 + exit 1 +fi + +if ! command -v xcodegen >/dev/null 2>&1; then + echo "xcodegen is required but was not found on PATH" >&2 + exit 1 +fi + +TEMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/factorykit-binary.XXXXXX")" +cleanup() { + rm -rf "$TEMP_DIR" +} +trap cleanup EXIT + +PROJECT_SPEC="$TEMP_DIR/project.yml" +PROJECT_NAME="FactoryKitBinaryBuilder.xcodeproj" +ARTIFACT_DIR="$OUTPUT_DIR/$ARTIFACT_NAME" +ZIP_PATH="$OUTPUT_DIR/$ARTIFACT_NAME.zip" +SHA_PATH="$ZIP_PATH.sha256" +TEMP_ARTIFACT_DIR="$TEMP_DIR/$ARTIFACT_NAME" + +mkdir -p "$OUTPUT_DIR" +rm -rf "$ARTIFACT_DIR" "$ZIP_PATH" "$SHA_PATH" + +cat > "$PROJECT_SPEC" < "$SHA_PATH" + +XCODE_VERSION="$(xcodebuild -version | tr '\n' ' ' | sed 's/[[:space:]]*$//')" +SWIFT_VERSION="$( + swift --version 2>&1 | grep -o 'Apple Swift version[^[:cntrl:]]*' | head -n 1 +)" + +echo "Built $ZIP_PATH" +echo "SHA256: $CHECKSUM" +echo "Xcode: $XCODE_VERSION" +echo "Swift: $SWIFT_VERSION" + +if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + { + echo "artifact_dir=$ARTIFACT_DIR" + echo "zip_path=$ZIP_PATH" + echo "sha256=$CHECKSUM" + echo "sha256_path=$SHA_PATH" + echo "xcode_version=$XCODE_VERSION" + echo "swift_version=$SWIFT_VERSION" + } >> "$GITHUB_OUTPUT" +fi