diff --git a/.buildkite/commands/sign-macos-binaries.sh b/.buildkite/commands/sign-macos-binaries.sh new file mode 100755 index 0000000..0603f27 --- /dev/null +++ b/.buildkite/commands/sign-macos-binaries.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# We don't care about the specific Go version, only that Go is available. +# `go build` will then fetch the desired version. +if ! command -v go >/dev/null 2>&1; then + echo "--- :package: installing go" + brew install go +fi +go version + +echo "--- :hammer_and_wrench: build macOS binaries" +GOOS=darwin GOARCH=amd64 ./build.sh -o bbctl-macos-amd64 +GOOS=darwin GOARCH=arm64 ./build.sh -o bbctl-macos-arm64 + +echo "--- :key: fetch Developer ID cert into the agent keychain" +install_gems +bundle exec fastlane set_up_signing + +echo "--- :apple: sign + notarize" +# sign_and_notarize comes from the CI toolkit plugin +sign_and_notarize bbctl-macos-amd64 bbctl-macos-arm64 + +echo "--- :lock: checksums" +shasum -a 256 bbctl-macos-amd64 bbctl-macos-arm64 > sha256sums.txt +cat sha256sums.txt diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 0000000..71b1314 --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,21 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json +--- + +agents: + queue: mac + +env: + IMAGE_ID: $IMAGE_ID + +steps: + - label: ":apple: Build, sign, notarize macOS binaries" + key: sign-macos + command: .buildkite/commands/sign-macos-binaries.sh + plugins: [$CI_TOOLKIT_PLUGIN] + artifact_paths: + - bbctl-macos-amd64 + - bbctl-macos-arm64 + - sha256sums.txt + notify: + - github_commit_status: + context: Sign & Notarize macOS diff --git a/.buildkite/shared-pipeline-vars b/.buildkite/shared-pipeline-vars new file mode 100644 index 0000000..a38a737 --- /dev/null +++ b/.buildkite/shared-pipeline-vars @@ -0,0 +1,12 @@ +#!/bin/sh + +# Sourced before `buildkite-agent pipeline upload` so the values land in the rendered pipeline. + +XCODE_VERSION=$(grep -Ev '^[[:space:]]*(#|$)' .xcode-version | head -n1 | sed -E 's/^[[:space:]]*//; s/^~> ?//; s/[[:space:]]*$//') +export IMAGE_ID="xcode-$XCODE_VERSION" + +# TEMPORARY: pinned to a commit on the `mokagio/macos-sign-and-notarize` branch +# adding the macOS `sign_and_notarize` command. Revert to a released tag +# (>= the version that ships it) before merging. +CI_TOOLKIT_PLUGIN_VERSION='8a67edfc19a7fd04de7033d790bd1a7a4f0f8b4d' +export CI_TOOLKIT_PLUGIN="automattic/a8c-ci-toolkit#$CI_TOOLKIT_PLUGIN_VERSION" diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 0000000..5429866 --- /dev/null +++ b/.bundle/config @@ -0,0 +1,4 @@ +--- +BUNDLE_PATH: "vendor/bundle" +BUNDLE_SPECIFIC_PLATFORM: "false" +BUNDLE_FORCE_RUBY_PLATFORM: "true" diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml index a3e79ed..5441f37 100644 --- a/.github/workflows/go.yaml +++ b/.github/workflows/go.yaml @@ -59,20 +59,6 @@ jobs: path: bbctl-linux-arm64 if-no-files-found: error - - name: Upload macos/amd64 artifact - uses: actions/upload-artifact@v6 - with: - name: bbctl-macos-amd64 - path: bbctl-macos-amd64 - if-no-files-found: error - - - name: Upload macos/arm64 artifact - uses: actions/upload-artifact@v6 - with: - name: bbctl-macos-arm64 - path: bbctl-macos-arm64 - if-no-files-found: error - build-docker: runs-on: ${{ matrix.runs-on }} strategy: diff --git a/.gitignore b/.gitignore index ab22752..99e7125 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /bbctl +vendor/bundle/ diff --git a/.xcode-version b/.xcode-version new file mode 100644 index 0000000..1575509 --- /dev/null +++ b/.xcode-version @@ -0,0 +1,4 @@ +# Pinned: nokogiri 1.19.3 won't compile from source on the Xcode 26.5 image +# (its clang breaks the bundled gumbo build). 26.3 builds it. Bump once a newer +# image compiles nokogiri from source (we force the Ruby platform via .bundle/config). +26.3 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..29ed5e0 --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'fastlane', '~> 2.236' +gem 'fastlane-plugin-wpmreleasetoolkit', '~> 14.6' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..99fbe5d --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,303 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.8) + abbrev (0.1.2) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + artifactory (3.0.17) + atomos (0.1.3) + aws-eventstream (1.4.0) + aws-partitions (1.1259.0) + aws-sdk-core (3.251.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sdk-kms (1.129.0) + aws-sdk-core (~> 3, >= 3.248.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.225.0) + aws-sdk-core (~> 3, >= 3.248.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.2) + buildkit (1.6.1) + sawyer (>= 0.6) + chroma (0.2.0) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + csv (3.3.5) + declarative (0.0.20) + diffy (3.4.4) + digest-crc (0.7.0) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.6.20240107) + dotenv (2.8.1) + emoji_regex (3.2.3) + erubi (1.13.1) + excon (0.112.0) + faraday (1.10.5) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.8) + faraday (>= 0.8.0) + http-cookie (>= 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.1) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.2.0) + multipart-post (~> 2.0) + faraday-net_http (1.0.2) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.4) + faraday_middleware (1.2.1) + faraday (~> 1.0) + fastimage (2.4.1) + fastlane (2.236.0) + CFPropertyList (>= 2.3, < 5.0.0) + abbrev (~> 0.1) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.197) + babosa (>= 1.0.3, < 2.0.0) + base64 (~> 0.2) + benchmark (>= 0.1.0) + bundler (>= 2.4.0, < 5.0.0) + colored (~> 1.2) + commander (~> 4.6) + csv (~> 3.3) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + fastlane-sirp (>= 1.1.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.3.0) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + http-cookie (~> 1.0.5) + json (< 3.0.0) + jwt (>= 2.10.3, < 4) + logger (>= 1.6, < 2.0) + mini_magick (>= 4.9.4, < 5.0.0) + multi_json (~> 1.12) + multipart-post (>= 2.0.0, < 3.0.0) + mutex_m (~> 0.3) + naturally (~> 2.2) + nkf (~> 0.2) + optparse (>= 0.1.1, < 1.0.0) + ostruct (>= 0.1.0) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.5) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (~> 3) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.4.1) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + fastlane-plugin-wpmreleasetoolkit (14.6.0) + buildkit (~> 1.5) + chroma (= 0.2.0) + diffy (~> 3.3) + dotenv (~> 2.8) + fastlane (~> 2.231) + gettext (~> 3.5) + git (~> 1.3) + google-cloud-storage (~> 1.31) + java-properties (~> 0.3.0) + nokogiri (~> 1.19, >= 1.19.3) + octokit (~> 6.1) + parallel (~> 1.14) + plist (~> 3.1) + progress_bar (~> 1.3) + rake (>= 12.3, < 14.0) + rake-compiler (~> 1.0) + xcodeproj (~> 1.22) + fastlane-sirp (1.1.0) + fiddle (1.1.8) + forwardable (1.4.0) + gettext (3.5.2) + erubi + locale (>= 2.0.5) + prime + racc + text (>= 1.3.0) + gh_inspector (1.1.3) + git (1.19.1) + addressable (~> 2.8) + rchardet (~> 1.8) + google-apis-androidpublisher_v3 (0.102.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-core (0.18.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 1.9) + httpclient (>= 2.8.3, < 3.a) + mini_mime (~> 1.0) + mutex_m + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + google-apis-iamcredentials_v1 (0.27.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-playcustomapp_v1 (0.17.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-storage_v1 (0.63.0) + google-apis-core (>= 0.15.0, < 2.a) + google-cloud-core (1.8.0) + google-cloud-env (>= 1.0, < 3.a) + google-cloud-errors (~> 1.0) + google-cloud-env (2.2.2) + base64 (~> 0.2) + faraday (>= 1.0, < 3.a) + google-cloud-errors (1.6.0) + google-cloud-storage (1.60.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-core (>= 0.18, < 2) + google-apis-iamcredentials_v1 (~> 0.18) + google-apis-storage_v1 (>= 0.42) + google-cloud-core (~> 1.6) + googleauth (~> 1.9) + mini_mime (~> 1.0) + google-logging-utils (0.2.0) + googleauth (1.17.0) + faraday (>= 1.0, < 3.a) + google-cloud-env (~> 2.2) + google-logging-utils (~> 0.1) + jwt (>= 1.4, < 4.0) + os (>= 0.9, < 2.0) + pstore (~> 0.1) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.8) + domain_name (~> 0.5) + httpclient (2.9.0) + mutex_m + java-properties (0.3.0) + jmespath (1.6.2) + json (2.19.8) + jwt (3.2.0) + base64 + locale (2.1.5) + fiddle + logger (1.7.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + mini_portile2 (2.8.9) + multi_json (1.21.1) + multipart-post (2.4.1) + mutex_m (0.3.0) + nanaimo (0.4.0) + naturally (2.3.0) + nkf (0.2.0) + nokogiri (1.19.3) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) + octokit (6.1.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) + options (2.3.2) + optparse (0.8.1) + os (1.1.4) + ostruct (0.6.3) + parallel (1.28.0) + plist (3.7.2) + prime (0.1.4) + forwardable + singleton + progress_bar (1.3.4) + highline (>= 1.6) + options (~> 2.3.0) + pstore (0.2.1) + public_suffix (7.0.5) + racc (1.8.1) + rake (13.4.2) + rake-compiler (1.3.1) + rake + rchardet (1.10.2) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.8.0) + rexml (3.4.4) + rouge (3.28.0) + ruby2_keywords (0.0.5) + rubyzip (2.4.1) + sawyer (0.9.3) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + security (0.1.5) + signet (0.22.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 4.0) + simctl (1.6.10) + CFPropertyList + naturally + singleton (0.3.0) + terminal-notifier (2.0.0) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + text (1.3.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.2) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unicode-display_width (2.6.0) + word_wrap (1.0.0) + xcodeproj (1.27.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.4.0) + rexml (>= 3.3.6, < 4.0) + xcpretty (0.4.1) + rouge (~> 3.28.0) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane (~> 2.236) + fastlane-plugin-wpmreleasetoolkit (~> 14.6) + +BUNDLED WITH + 2.5.11 diff --git a/ci-build-all.sh b/ci-build-all.sh index 28403f1..087e3cb 100755 --- a/ci-build-all.sh +++ b/ci-build-all.sh @@ -1,5 +1,3 @@ #!/bin/sh GOOS=linux GOARCH=amd64 ./build.sh -o bbctl-linux-amd64 GOOS=linux GOARCH=arm64 ./build.sh -o bbctl-linux-arm64 -GOOS=darwin GOARCH=amd64 ./build.sh -o bbctl-macos-amd64 -GOOS=darwin GOARCH=arm64 ./build.sh -o bbctl-macos-arm64 diff --git a/fastlane/.gitignore b/fastlane/.gitignore new file mode 100644 index 0000000..56e5e3d --- /dev/null +++ b/fastlane/.gitignore @@ -0,0 +1,2 @@ +README.md +report.xml diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 0000000..07d93ea --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +UI.user_error!('Please run fastlane via `bundle exec`') unless FastlaneCore::Helper.bundler? + +APPLE_TEAM_ID = 'PZYM8XX95Q' + +CODE_SIGNING_STORAGE_OPTIONS = { + storage_mode: 's3', + s3_bucket: 'a8c-fastlane-match', + s3_region: 'us-east-2' +}.freeze + +CODE_SIGNING_ENV_VARS = %w[ + MATCH_S3_ACCESS_KEY + MATCH_S3_SECRET_ACCESS_KEY + MATCH_PASSWORD +].freeze + +ASC_API_KEY_ENV_VARS = %w[ + APP_STORE_CONNECT_API_KEY_KEY_ID + APP_STORE_CONNECT_API_KEY_ISSUER_ID + APP_STORE_CONNECT_API_KEY_KEY +].freeze + +require 'fastlane/plugin/wpmreleasetoolkit' + +EnvManager = Fastlane::Wpmreleasetoolkit::EnvManager + +before_all do + # Sets up a temporary keychain so match works in CI. No-op locally. + setup_ci + + # `set_up` is needed even with no `.env` file so EnvManager has a configured + # instance; on CI the vars come from the Buildkite agent. + EnvManager.set_up(env_file_name: 'bridge-manager.env') +end + +desc 'Fetch the Developer ID Application certificate into the keychain' +lane :set_up_signing do |readonly: true| + CODE_SIGNING_ENV_VARS.each { |k| EnvManager.get_required_env!(k) } + ASC_API_KEY_ENV_VARS.each { |k| EnvManager.get_required_env!(k) } unless readonly + + sync_code_signing( + type: 'developer_id', + platform: 'macos', + team_id: APPLE_TEAM_ID, + app_identifier: [], + api_key: readonly ? nil : app_store_connect_api_key, + readonly: readonly, + **CODE_SIGNING_STORAGE_OPTIONS + ) +end