-
Notifications
You must be signed in to change notification settings - Fork 1
ci: add v* tag release pipeline for universal binaries #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
013e5ac
cf958fa
54c59ad
ee5690d
998d89b
9d5a453
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - "v*" | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Test | ||
| runs-on: macos-15 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Swift 6.2 | ||
| uses: swift-actions/setup-swift@v2 | ||
| with: | ||
| swift-version: "6.2" | ||
|
|
||
| - name: Run tests | ||
| run: swift test -Xswiftc -strict-concurrency=minimal | ||
|
|
||
| build-arm64: | ||
| name: Build (arm64) | ||
| needs: test | ||
| runs-on: macos-15 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Swift 6.2 | ||
| uses: swift-actions/setup-swift@v2 | ||
| with: | ||
| swift-version: "6.2" | ||
|
|
||
| - name: Build release binaries | ||
| run: scripts/build-release.sh --arch arm64 --version "${GITHUB_REF_NAME}" --dist-root dist | ||
|
|
||
| - name: Upload arm64 artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: dist-arm64 | ||
| path: dist/arm64 | ||
| if-no-files-found: error | ||
|
|
||
| build-x86_64: | ||
| name: Build (x86_64) | ||
| needs: test | ||
| runs-on: macos-15 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Swift 6.2 | ||
| uses: swift-actions/setup-swift@v2 | ||
| with: | ||
| swift-version: "6.2" | ||
|
|
||
| - name: Build release binaries | ||
| run: scripts/build-release.sh --arch x86_64 --version "${GITHUB_REF_NAME}" --dist-root dist | ||
|
|
||
| - name: Upload x86_64 artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: dist-x86_64 | ||
| path: dist/x86_64 | ||
| if-no-files-found: error | ||
|
|
||
| release: | ||
| name: Package and Publish | ||
| needs: | ||
| - build-arm64 | ||
| - build-x86_64 | ||
| runs-on: macos-15 | ||
| permissions: | ||
| contents: write | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Swift 6.2 | ||
| uses: swift-actions/setup-swift@v2 | ||
| with: | ||
| swift-version: "6.2" | ||
|
|
||
| - name: Download arm64 artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: dist-arm64 | ||
| path: dist/arm64 | ||
|
|
||
| - name: Download x86_64 artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: dist-x86_64 | ||
| path: dist/x86_64 | ||
|
|
||
| - name: Package release archives | ||
| run: scripts/package-universal.sh --dist-root dist --output-dir release | ||
|
|
||
| - name: Publish GitHub Release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| files: | | ||
| release/*.tar.gz | ||
| release/SHA256SUMS.txt | ||
| generate_release_notes: true | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,3 +7,5 @@ DerivedData/ | |
| .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata | ||
| .netrc | ||
| .codex/tmp/ | ||
| /dist | ||
| /release | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -23,6 +23,34 @@ See [Architecture](Docs/architecture.md) for the process overview. | |||||
| swift run -c release xcode-mcp-proxy-install | ||||||
| ``` | ||||||
|
|
||||||
| ### Install from GitHub Releases | ||||||
|
|
||||||
| Each release tag (`v*`) publishes: | ||||||
|
|
||||||
| - `xcode-mcp-proxy.tar.gz` (universal binary) | ||||||
| - `xcode-mcp-proxy-darwin-arm64.tar.gz` | ||||||
| - `xcode-mcp-proxy-darwin-x86_64.tar.gz` | ||||||
| - `SHA256SUMS.txt` | ||||||
|
|
||||||
| Example: | ||||||
|
|
||||||
| ```bash | ||||||
| VERSION=v0.1.0 | ||||||
| BASE_URL="https://github.com/<owner>/XcodeMCPKit/releases/download/${VERSION}" | ||||||
|
||||||
| BASE_URL="https://github.com/<owner>/XcodeMCPKit/releases/download/${VERSION}" | |
| BASE_URL="https://github.com/<OWNER>/XcodeMCPKit/releases/download/${VERSION}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| usage() { | ||
| cat <<'EOF' | ||
| Usage: scripts/build-release.sh --arch <arm64|x86_64> --version <tag> [--dist-root <dir>] | ||
|
|
||
| Builds release binaries and stages them under: | ||
| <dist-root>/<arch>/bin/ | ||
| EOF | ||
| } | ||
|
|
||
| arch="" | ||
| version="" | ||
| dist_root="dist" | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --arch) | ||
| arch="${2:-}" | ||
| shift 2 | ||
| ;; | ||
| --version) | ||
| version="${2:-}" | ||
| shift 2 | ||
| ;; | ||
| --dist-root) | ||
| dist_root="${2:-}" | ||
| shift 2 | ||
| ;; | ||
| -h|--help) | ||
| usage | ||
| exit 0 | ||
| ;; | ||
| *) | ||
| echo "Unknown argument: $1" >&2 | ||
| usage | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| if [[ -z "$arch" ]]; then | ||
| echo "--arch is required." >&2 | ||
| usage | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ -z "$version" ]]; then | ||
| echo "--version is required." >&2 | ||
| usage | ||
| exit 1 | ||
| fi | ||
|
|
||
| case "$arch" in | ||
| arm64|x86_64) ;; | ||
| *) | ||
| echo "Unsupported arch: $arch (expected arm64 or x86_64)" >&2 | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | ||
| if [[ "$dist_root" = /* ]]; then | ||
| dist_base="$dist_root" | ||
| else | ||
| dist_base="$repo_root/$dist_root" | ||
| fi | ||
|
|
||
| out_dir="$dist_base/$arch" | ||
| bin_out="$out_dir/bin" | ||
| products=( | ||
| "xcode-mcp-proxy" | ||
| "xcode-mcp-proxy-server" | ||
| "xcode-mcp-proxy-install" | ||
| ) | ||
|
|
||
| pushd "$repo_root" >/dev/null | ||
|
|
||
| for product in "${products[@]}"; do | ||
| swift build -c release \ | ||
| -Xswiftc -strict-concurrency=minimal \ | ||
| --arch "$arch" \ | ||
| --product "$product" | ||
| done | ||
|
Comment on lines
+55
to
+85
|
||
|
|
||
| bin_path="$(swift build -c release --arch "$arch" --show-bin-path)" | ||
| rm -rf "$out_dir" | ||
| mkdir -p "$bin_out" | ||
|
|
||
| for product in "${products[@]}"; do | ||
| source_path="$bin_path/$product" | ||
| if [[ ! -f "$source_path" ]]; then | ||
| source_path="$(find "$repo_root/.build" -type f -path "*/release/$product" | head -n 1 || true)" | ||
| fi | ||
| if [[ -z "$source_path" || ! -f "$source_path" ]]; then | ||
| echo "Failed to locate built binary: $product" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| target_path="$bin_out/$product" | ||
| cp "$source_path" "$target_path" | ||
| chmod +x "$target_path" | ||
| if command -v codesign >/dev/null 2>&1; then | ||
| codesign --remove-signature "$target_path" >/dev/null 2>&1 || true | ||
| fi | ||
| done | ||
|
|
||
| cat > "$out_dir/manifest.txt" <<EOF | ||
| version=$version | ||
| arch=$arch | ||
| built_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | ||
| EOF | ||
|
|
||
| popd >/dev/null | ||
|
|
||
| echo "Staged release binaries at: $out_dir" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| usage() { | ||
| cat <<'EOF' | ||
| Usage: scripts/package-universal.sh [--dist-root <dir>] [--output-dir <dir>] | ||
|
|
||
| Requires staged binaries from: | ||
| <dist-root>/arm64/bin/ | ||
| <dist-root>/x86_64/bin/ | ||
|
|
||
| Outputs: | ||
| <output-dir>/xcode-mcp-proxy.tar.gz | ||
| <output-dir>/xcode-mcp-proxy-darwin-arm64.tar.gz | ||
| <output-dir>/xcode-mcp-proxy-darwin-x86_64.tar.gz | ||
| <output-dir>/SHA256SUMS.txt | ||
| EOF | ||
| } | ||
|
|
||
| dist_root="dist" | ||
| output_dir="release" | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --dist-root) | ||
| dist_root="${2:-}" | ||
| shift 2 | ||
| ;; | ||
| --output-dir) | ||
| output_dir="${2:-}" | ||
| shift 2 | ||
| ;; | ||
| -h|--help) | ||
| usage | ||
| exit 0 | ||
| ;; | ||
| *) | ||
| echo "Unknown argument: $1" >&2 | ||
| usage | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | ||
| if [[ "$dist_root" = /* ]]; then | ||
| dist_base="$dist_root" | ||
| else | ||
| dist_base="$repo_root/$dist_root" | ||
| fi | ||
| if [[ "$output_dir" = /* ]]; then | ||
| output_base="$output_dir" | ||
| else | ||
| output_base="$repo_root/$output_dir" | ||
| fi | ||
|
|
||
| arm_bin="$dist_base/arm64/bin" | ||
| x86_bin="$dist_base/x86_64/bin" | ||
| for path in "$arm_bin" "$x86_bin"; do | ||
| if [[ ! -d "$path" ]]; then | ||
| echo "Missing staged directory: $path" >&2 | ||
| exit 1 | ||
| fi | ||
| done | ||
|
|
||
| tmp_dir="$(mktemp -d)" | ||
| trap 'rm -rf "$tmp_dir"' EXIT | ||
|
|
||
| mkdir -p "$output_base" | ||
|
|
||
| universal_archive="$output_base/xcode-mcp-proxy.tar.gz" | ||
| arm_archive="$output_base/xcode-mcp-proxy-darwin-arm64.tar.gz" | ||
| x86_archive="$output_base/xcode-mcp-proxy-darwin-x86_64.tar.gz" | ||
| find "$output_base" -maxdepth 1 -type f -name 'xcode-mcp-proxy*.tar.gz' -delete | ||
| rm -f "$output_base/SHA256SUMS.txt" | ||
|
|
||
| products=( | ||
| "xcode-mcp-proxy" | ||
| "xcode-mcp-proxy-server" | ||
| "xcode-mcp-proxy-install" | ||
| ) | ||
|
|
||
| for product in "${products[@]}"; do | ||
| arm_product="$arm_bin/$product" | ||
| x86_product="$x86_bin/$product" | ||
| if [[ ! -f "$arm_product" ]]; then | ||
| echo "Missing staged binary: $arm_product" >&2 | ||
| exit 1 | ||
| fi | ||
| if [[ ! -f "$x86_product" ]]; then | ||
| echo "Missing staged binary: $x86_product" >&2 | ||
| exit 1 | ||
| fi | ||
| done | ||
|
|
||
| mkdir -p "$tmp_dir/universal/bin" | ||
| for product in "${products[@]}"; do | ||
| target="$tmp_dir/universal/bin/$product" | ||
| lipo -create -output "$target" "$arm_bin/$product" "$x86_bin/$product" | ||
| chmod +x "$target" | ||
| if command -v codesign >/dev/null 2>&1; then | ||
| codesign --remove-signature "$target" >/dev/null 2>&1 || true | ||
| fi | ||
| done | ||
|
|
||
| cp -R "$tmp_dir/universal/bin" "$tmp_dir/bin" | ||
| tar -C "$tmp_dir" -czf "$universal_archive" bin | ||
| rm -rf "$tmp_dir/bin" | ||
|
|
||
| cp -R "$arm_bin" "$tmp_dir/bin" | ||
| tar -C "$tmp_dir" -czf "$arm_archive" bin | ||
| rm -rf "$tmp_dir/bin" | ||
|
|
||
| cp -R "$x86_bin" "$tmp_dir/bin" | ||
| tar -C "$tmp_dir" -czf "$x86_archive" bin | ||
| rm -rf "$tmp_dir/bin" | ||
|
|
||
| ( | ||
| cd "$output_base" | ||
| shasum -a 256 \ | ||
| xcode-mcp-proxy.tar.gz \ | ||
| xcode-mcp-proxy-darwin-arm64.tar.gz \ | ||
| xcode-mcp-proxy-darwin-x86_64.tar.gz > SHA256SUMS.txt | ||
| ) | ||
|
|
||
| echo "Created release package: $universal_archive" | ||
| echo "Created release package: $arm_archive" | ||
| echo "Created release package: $x86_archive" | ||
| echo "Created checksum file: $output_base/SHA256SUMS.txt" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow builds the x86_64 slice on
macos-13, but this repo’sPackage.swiftdeclares// swift-tools-version: 6.2andplatforms: [.macOS(.v15)]. Unless the job installs/selects a Swift 6.2 / Xcode 16 toolchain,swift buildon macos-13 is likely to fail due to an incompatible default toolchain/SDK. Consider selecting an explicit Xcode version in the workflow (e.g., viaxcode-select/a setup action) or adjusting the runner strategy so the x86_64 job uses a runner with a compatible toolchain.