From 91ffa3f69df98b6c149605bf891e96220d4d0932 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Tue, 9 Sep 2025 01:26:28 +0200 Subject: [PATCH 01/10] feat: create bitrise step --- bitrise.yml | 49 +++++ bitrise/steps/remote-build/step.sh | 276 ++++++++++++++++++++++++++++ bitrise/steps/remote-build/step.yml | 116 ++++++++++++ 3 files changed, 441 insertions(+) create mode 100644 bitrise.yml create mode 100755 bitrise/steps/remote-build/step.sh create mode 100644 bitrise/steps/remote-build/step.yml diff --git a/bitrise.yml b/bitrise.yml new file mode 100644 index 0000000..05f6463 --- /dev/null +++ b/bitrise.yml @@ -0,0 +1,49 @@ +format_version: 11 +default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git + +workflows: + test-rock-remote-build-ios: + meta: + bitrise.io: + stack: osx-xcode-15.4.x + machine_type_id: g2-m1.8core + + envs: + - WORKING_DIRECTORY: ./test # path to a local directory with a rock project + - DESTINATION: simulator + - SCHEME: AppScheme # name of the scheme to build + - CONFIGURATION: Release + - RE_SIGN: "false" + - AD_HOC: "false" + - ROCK_BUILD_EXTRA_PARAMS: "" + - CERTIFICATE_BASE64: "" + - CERTIFICATE_PASSWORD: "" + - PROVISIONING_PROFILE_BASE64: "" + - PROVISIONING_PROFILE_NAME: "" + - KEYCHAIN_PASSWORD: "" + + steps: + - path::bitrise/steps/remote-build: + title: Rock Remote Build - iOS (local) + inputs: + - WORKING_DIRECTORY: $WORKING_DIRECTORY + - DESTINATION: $DESTINATION + - SCHEME: $SCHEME + - CONFIGURATION: $CONFIGURATION + - RE_SIGN: $RE_SIGN + - AD_HOC: $AD_HOC + - ROCK_BUILD_EXTRA_PARAMS: $ROCK_BUILD_EXTRA_PARAMS + - CERTIFICATE_BASE64: $CERTIFICATE_BASE64 + - CERTIFICATE_PASSWORD: $CERTIFICATE_PASSWORD + - PROVISIONING_PROFILE_BASE64: $PROVISIONING_PROFILE_BASE64 + - PROVISIONING_PROFILE_NAME: $PROVISIONING_PROFILE_NAME + - KEYCHAIN_PASSWORD: $KEYCHAIN_PASSWORD + + - script@1: + title: Show Step Outputs + inputs: + - content: |- + #!/usr/bin/env bash + set -e + echo "ARTIFACT_URL=${ARTIFACT_URL:-}" + echo "ARTIFACT_ID=${ARTIFACT_ID:-}" \ No newline at end of file diff --git a/bitrise/steps/remote-build/step.sh b/bitrise/steps/remote-build/step.sh new file mode 100755 index 0000000..c527e05 --- /dev/null +++ b/bitrise/steps/remote-build/step.sh @@ -0,0 +1,276 @@ +#!/usr/bin/env bash +set -euo pipefail + +log() { echo "[$(date +'%H:%M:%S')] $*"; } +fail() { echo "ERROR: $*" >&2; exit 1; } + +# Inputs mapped from the original GitHub Action +WORKING_DIRECTORY="${WORKING_DIRECTORY:-$BITRISE_SOURCE_DIR}" +DESTINATION="${DESTINATION:-simulator}" +SCHEME="${SCHEME:-}" +CONFIGURATION="${CONFIGURATION:-}" +RE_SIGN="${RE_SIGN:-}" +AD_HOC="${AD_HOC:-false}" + +CERTIFICATE_BASE64="${CERTIFICATE_BASE64:-}" +CERTIFICATE_PASSWORD="${CERTIFICATE_PASSWORD:-}" +PROVISIONING_PROFILE_BASE64="${PROVISIONING_PROFILE_BASE64:-}" +PROVISIONING_PROFILE_NAME="${PROVISIONING_PROFILE_NAME:-}" +KEYCHAIN_PASSWORD="${KEYCHAIN_PASSWORD:-}" + +ROCK_BUILD_EXTRA_PARAMS="${ROCK_BUILD_EXTRA_PARAMS:-}" + +RUNNER_TEMP="${RUNNER_TEMP:-${TMPDIR:-/tmp}}" + +# Validate inputs (mirror composite action behavior) +if [ "$DESTINATION" != "simulator" ] && [ "$DESTINATION" != "device" ]; then + fail "Invalid input 'destination': '$DESTINATION'. Allowed values: 'simulator' or 'device'." +fi + +if [ "$DESTINATION" = "device" ]; then + [ -z "$CERTIFICATE_BASE64" ] && fail "Input 'certificate-base64' is required for device builds." + [ -z "$CERTIFICATE_PASSWORD" ] && fail "Input 'certificate-password' is required for device builds." + [ -z "$PROVISIONING_PROFILE_BASE64" ] && fail "Input 'provisioning-profile-base64' is required for device builds." + [ -z "$PROVISIONING_PROFILE_NAME" ] && fail "Input 'provisioning-profile-name' is required for device builds." + [ -z "$KEYCHAIN_PASSWORD" ] && fail "Input 'keychain-password' is required for device builds." +fi + +# Provisioning profile dir +PROFILE_DIR="$HOME/Library/MobileDevice/Provisioning Profiles" +envman add --key PROFILE_DIR --value "$PROFILE_DIR" + +# Fingerprint +pushd "$WORKING_DIRECTORY" >/dev/null +log "Generating fingerprint" +if ! FINGERPRINT_OUTPUT="$(npx rock fingerprint -p ios --raw 2>&1)"; then + echo "$FINGERPRINT_OUTPUT" + fail "Fingerprint failed" +fi +FINGERPRINT="$FINGERPRINT_OUTPUT" +envman add --key FINGERPRINT --value "$FINGERPRINT" +popd >/dev/null + +# Detect provider and fail early if GitHub (not supported from this Bitrise step) +pushd "$WORKING_DIRECTORY" >/dev/null +log "Detecting provider name" +if ! PROVIDER_NAME="$(npx rock remote-cache get-provider-name 2>&1)"; then + echo "$PROVIDER_NAME" + fail "remote-cache get-provider-name failed" +fi +popd >/dev/null + +if [ "$PROVIDER_NAME" = "GitHub" ]; then + fail "Provider 'GitHub' is not supported from this Bitrise step. Please configure Rock remote cache with a non-GitHub provider." +fi + +# Artifact discovery +ARTIFACT_NAME="${ARTIFACT_NAME:-}" +ARTIFACT_URL="${ARTIFACT_URL:-}" +ARTIFACT_ID="${ARTIFACT_ID:-}" + +# PR-specific artifact (avoid overwriting the main artifact with new JS bundle) +if [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ] && [ "$RE_SIGN" = "true" ]; then + ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION},${BITRISE_PULL_REQUEST:-}" + envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" + + OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || true)" + if [ -n "$OUTPUT" ]; then + ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" + ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" + ARTIFACT_NAME="$(echo "$OUTPUT" | jq -r '.name')" + envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" + envman add --key ARTIFACT_ID --value "$ARTIFACT_ID" + envman add --key ARTIFACT_NAME --value "$ARTIFACT_NAME" + fi +fi + +# Regular artifact +if [ -z "$ARTIFACT_NAME" ]; then + ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION}" + envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" + + OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || true)" + if [ -n "$OUTPUT" ]; then + ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" + ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" + ARTIFACT_NAME="$(echo "$OUTPUT" | jq -r '.name')" + envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" + envman add --key ARTIFACT_ID --value "$ARTIFACT_ID" + envman add --key ARTIFACT_NAME --value "$ARTIFACT_NAME" + fi +fi + +# Set Artifact Name (if not set) +if [ -z "$ARTIFACT_NAME" ]; then + ARTIFACT_TRAITS_HYPHENATED="$(echo "$ARTIFACT_TRAITS" | tr ',' '-')" + ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT="${ARTIFACT_TRAITS_HYPHENATED}-${FINGERPRINT}" + ARTIFACT_NAME="rock-ios-${ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT}" + envman add --key ARTIFACT_NAME --value "$ARTIFACT_NAME" +fi + +# Setup Code Signing (device builds only) +if { [ "$RE_SIGN" = "true" ] && [ "$DESTINATION" = "device" ]; } || { [ -z "$ARTIFACT_URL" ] && [ "$DESTINATION" = "device" ]; }; then + KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + CERTIFICATE_PATH="$RUNNER_TEMP/certificate.p12" + echo -n "$CERTIFICATE_BASE64" | base64 --decode -o "$CERTIFICATE_PATH" + security import "$CERTIFICATE_PATH" -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" + + IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -oE '([0-9A-F]{40})' | head -n 1 || true)" + echo "Certificate identity: $IDENTITY" + envman add --key IDENTITY --value "$IDENTITY" + + mkdir -p "$PROFILE_DIR" + PROFILE_PATH="$PROFILE_DIR/$PROVISIONING_PROFILE_NAME.mobileprovision" + echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode -o "$PROFILE_PATH" +fi + +# Build if no artifact was found +if [ -z "$ARTIFACT_URL" ]; then + pushd "$WORKING_DIRECTORY" >/dev/null + JSON_OUTPUT="$(npx rock config -p ios || true)" + IOS_SOURCE_DIR="$(echo "$JSON_OUTPUT" | jq -r '.project.ios.sourceDir')" + log "Resolved ios.sourceDir: ${IOS_SOURCE_DIR:-}" + envman add --key IOS_SOURCE_DIR --value "$IOS_SOURCE_DIR" + + # Build iOS with safe extra params handling (no eval) + BUILD_ARGS=(--scheme "$SCHEME" --configuration "$CONFIGURATION" --build-folder build --destination "$DESTINATION" --verbose) + if [ "$DESTINATION" = "device" ]; then + BUILD_ARGS+=("--archive") + fi + + if [ -n "$ROCK_BUILD_EXTRA_PARAMS" ]; then + IFS=' ' read -r -a EXTRA_ARR <<< "$ROCK_BUILD_EXTRA_PARAMS" + BUILD_ARGS+=("${EXTRA_ARR[@]}") + fi + + npx rock build:ios "${BUILD_ARGS[@]}" + popd >/dev/null + + # Find Build Artifact + if [ "$DESTINATION" = "device" ]; then + IPA_PATH="$(find .rock/cache/ios/export -maxdepth 1 -name '*.ipa' -type f | head -1)" + echo "IPA_PATH $IPA_PATH" + envman add --key ARTIFACT_PATH --value "$IPA_PATH" + else + APP_PATH="$(find "$IOS_SOURCE_DIR"/build -name '*.app' -type d | head -1 )" + APP_DIR="$(dirname "$APP_PATH")" + APP_BASENAME="$(basename "$APP_PATH")" + + ARTIFACT_PATH="$APP_DIR/app.tar.gz" + tar -C "$APP_DIR" -czvf "$ARTIFACT_PATH" "$APP_BASENAME" + envman add --key ARTIFACT_PATH --value "$ARTIFACT_PATH" + fi +fi + +# PR re-sign: download and (re)sign/rebundle +if [ -n "$ARTIFACT_URL" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ]; then + log "Downloading cached artifact from remote cache: name=$ARTIFACT_NAME" + DOWNLOAD_OUTPUT="$(npx rock remote-cache download --name "$ARTIFACT_NAME" --json || true)" + DL_PATH="$(echo "$DOWNLOAD_OUTPUT" | jq -r '.path')" + + if [ "$DESTINATION" = "device" ]; then + envman add --key ARTIFACT_PATH --value "$DL_PATH" + log "Re-signing IPA with new JS bundle: path=$DL_PATH identity=${IDENTITY:-unset}" + pushd "$WORKING_DIRECTORY" >/dev/null + npx rock sign:ios "$DL_PATH" --build-jsbundle --identity "$IDENTITY" + popd >/dev/null + else + APP_DIR="$(dirname "$DL_PATH")" + log "Unpacking APP tarball: $DL_PATH" + tar -C "$APP_DIR" -xzf "$DL_PATH" + EXTRACTED_APP="$(find "$APP_DIR" -name '*.app' -type d | head -1)" + envman add --key ARTIFACT_PATH --value "$DL_PATH" + envman add --key ARTIFACT_TAR_PATH --value "$EXTRACTED_APP" + + log "Re-bundling APP with new JS: app=$EXTRACTED_APP" + pushd "$WORKING_DIRECTORY" >/dev/null + npx rock sign:ios "$EXTRACTED_APP" --build-jsbundle --app + popd >/dev/null + fi + + # Update Artifact Name for re-signed builds + ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION},${BITRISE_PULL_REQUEST:-}" + ARTIFACT_TRAITS_HYPHENATED="$(echo "$ARTIFACT_TRAITS" | tr ',' '-')" + ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT="${ARTIFACT_TRAITS_HYPHENATED}-${FINGERPRINT}" + ARTIFACT_NAME="rock-ios-${ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT}" + envman add --key ARTIFACT_NAME --value "$ARTIFACT_NAME" + envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" +fi + +# Find artifact URL again before uploading +OUTPUT="$(npx rock remote-cache list --name "$ARTIFACT_NAME" --json || true)" +if [ -n "$OUTPUT" ]; then + ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" + ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" + envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" + envman add --key ARTIFACT_ID --value "$ARTIFACT_ID" +fi + +# Copy artifact to Bitrise Deploy dir (parity with "Upload Artifact to GitHub" intent) +if { [ -z "${ARTIFACT_URL:-}" ] || { [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ]; }; } && [ -n "${ARTIFACT_PATH:-}" ]; then + if [ -n "${BITRISE_DEPLOY_DIR:-}" ]; then + TARGET_PATH="$BITRISE_DEPLOY_DIR/$ARTIFACT_NAME" + log "Copying artifact to Bitrise Deploy dir: $TARGET_PATH" + cp "$ARTIFACT_PATH" "$TARGET_PATH" + # Optional outputs (like your Bitrise port) + envman add --key UPLOAD_ARTIFACT_URL --value "${BITRISE_BUILD_URL:-}/artifacts" + envman add --key UPLOAD_ARTIFACT_ID --value "bitrise-$ARTIFACT_NAME" + fi +fi + +# Upload to Remote Cache for re-signed builds (PR) +if [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ] && [ -n "${ARTIFACT_PATH:-}" ]; then + OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json || true)" + if [ -n "$OUTPUT" ]; then + ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" + envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" + fi +fi + +# Upload to Remote Cache for regular builds +if [ -z "${ARTIFACT_URL:-}" ]; then + OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --json || true)" + if [ -n "$OUTPUT" ]; then + ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" + envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" + fi +fi + +# Upload for Ad-hoc distribution +if [ "$AD_HOC" = "true" ] && [ -n "${ARTIFACT_PATH:-}" ]; then + OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json --ad-hoc || true)" + if [ -n "$OUTPUT" ]; then + ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" + envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" + fi +fi + +# Delete Old Re-Signed Artifacts +if [ -n "${ARTIFACT_URL:-}" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ]; then + npx rock remote-cache delete --name "$ARTIFACT_NAME" --all-but-latest --json || true +fi + +# Clean Up Code Signing (device builds only, when we built locally) +if [ -z "${ARTIFACT_URL:-}" ] && [ "$DESTINATION" = "device" ]; then + KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" + security delete-keychain "$KEYCHAIN_PATH" || true + + PROFILE_PATH="$PROFILE_DIR/$PROVISIONING_PROFILE_NAME.mobileprovision" + rm -f "$PROFILE_PATH" || true +fi + +# Cleanup Cache glue +rm -rf .rock/cache/project.json || true + +# Outputs +[ -n "${ARTIFACT_URL:-}" ] && envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" +[ -n "${ARTIFACT_ID:-}" ] && envman add --key ARTIFACT_ID --value "$ARTIFACT_ID" + +log "Done." diff --git a/bitrise/steps/remote-build/step.yml b/bitrise/steps/remote-build/step.yml new file mode 100644 index 0000000..b267829 --- /dev/null +++ b/bitrise/steps/remote-build/step.yml @@ -0,0 +1,116 @@ +title: Rock Remote Build - iOS +summary: Build iOS apps using Rock. +description: | + This step builds iOS apps with Rock, optionally re-signing IPAs + for PRs or device builds. Supports simulator and device targets. +website: https://github.com/callstackincubator/ios +source_code_url: https://github.com/callstackincubator/ios/bitrise/steps/remote-build +support_url: https://github.com/callstackincubator/ios/issues + +project_type_tags: + - ios + - react-native + +type_tags: + - build + +toolkit: + bash: + entry_file: step.sh + +deps: + brew: + - name: jq + +inputs: + - WORKING_DIRECTORY: + opts: + title: Working directory for the build + summary: Path where the build command should be run + description: Can be relative or absolute. Defaults to "." + is_required: false + is_expand: true + value: "." + + - DESTINATION: + opts: + title: Destination for the build + summary: "Use 'simulator' or 'device'. Device builds require signing." + is_required: true + value: "simulator" + + - SCHEME: + opts: + title: Xcode scheme + is_required: true + value: "" + + - CONFIGURATION: + opts: + title: Xcode configuration + is_required: true + value: "" + + - RE_SIGN: + opts: + title: Re-sign IPA with new JS bundle + summary: No signing is done for simulator builds + is_required: false + value: "" + + - AD_HOC: + opts: + title: Upload IPA for ad-hoc distribution + is_required: false + value: "false" + + - CERTIFICATE_BASE64: + opts: + title: Base64 encoded P12 file (device builds) + is_required: false + is_sensitive: true + value: "" + + - CERTIFICATE_PASSWORD: + opts: + title: P12 password (device builds) + is_required: false + is_sensitive: true + value: "" + + - PROVISIONING_PROFILE_BASE64: + opts: + title: Base64 encoded provisioning profile + is_required: false + is_sensitive: true + value: "" + + - PROVISIONING_PROFILE_NAME: + opts: + title: Name of provisioning profile (without extension) + is_required: false + value: "" + + - KEYCHAIN_PASSWORD: + opts: + title: Keychain password (device builds) + is_required: false + is_sensitive: true + value: "" + + - ROCK_BUILD_EXTRA_PARAMS: + opts: + title: Extra parameters to pass to "rock build:ios" + is_required: false + value: "" + +outputs: + - ARTIFACT_URL: + opts: + title: URL of the built iOS artifact + summary: May be cached + + - ARTIFACT_ID: + opts: + title: ID of the built iOS artifact + summary: May be cached \ No newline at end of file From 43b229be58fecccdc8cc8b6c58c265e0e5bf9220 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Tue, 9 Sep 2025 01:27:22 +0200 Subject: [PATCH 02/10] chore: line ends --- bitrise.yml | 2 +- bitrise/steps/remote-build/step.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bitrise.yml b/bitrise.yml index 05f6463..5725c4e 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -46,4 +46,4 @@ workflows: #!/usr/bin/env bash set -e echo "ARTIFACT_URL=${ARTIFACT_URL:-}" - echo "ARTIFACT_ID=${ARTIFACT_ID:-}" \ No newline at end of file + echo "ARTIFACT_ID=${ARTIFACT_ID:-}" diff --git a/bitrise/steps/remote-build/step.yml b/bitrise/steps/remote-build/step.yml index b267829..20b0c2b 100644 --- a/bitrise/steps/remote-build/step.yml +++ b/bitrise/steps/remote-build/step.yml @@ -113,4 +113,4 @@ outputs: - ARTIFACT_ID: opts: title: ID of the built iOS artifact - summary: May be cached \ No newline at end of file + summary: May be cached From 7aa83e64512ca36890d23ad761ef217e47340990 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Tue, 9 Sep 2025 01:36:28 +0200 Subject: [PATCH 03/10] chore: remove placeholder --- bitrise/steps/remote-build/step.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/bitrise/steps/remote-build/step.yml b/bitrise/steps/remote-build/step.yml index 20b0c2b..7671de6 100644 --- a/bitrise/steps/remote-build/step.yml +++ b/bitrise/steps/remote-build/step.yml @@ -108,9 +108,7 @@ outputs: - ARTIFACT_URL: opts: title: URL of the built iOS artifact - summary: May be cached - ARTIFACT_ID: opts: title: ID of the built iOS artifact - summary: May be cached From 0ba4bff4ab6a5ec00f314ebe250b76d192b00766 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Tue, 9 Sep 2025 20:15:31 +0200 Subject: [PATCH 04/10] chore: rock workflow ios --- bitrise/steps/remote-build/step.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bitrise/steps/remote-build/step.sh b/bitrise/steps/remote-build/step.sh index c527e05..b48111e 100755 --- a/bitrise/steps/remote-build/step.sh +++ b/bitrise/steps/remote-build/step.sh @@ -42,7 +42,7 @@ envman add --key PROFILE_DIR --value "$PROFILE_DIR" # Fingerprint pushd "$WORKING_DIRECTORY" >/dev/null log "Generating fingerprint" -if ! FINGERPRINT_OUTPUT="$(npx rock fingerprint -p ios --raw 2>&1)"; then +if ! FINGERPRINT_OUTPUT="$(npx rock fingerprint -p ios --raw)"; then echo "$FINGERPRINT_OUTPUT" fail "Fingerprint failed" fi @@ -53,7 +53,7 @@ popd >/dev/null # Detect provider and fail early if GitHub (not supported from this Bitrise step) pushd "$WORKING_DIRECTORY" >/dev/null log "Detecting provider name" -if ! PROVIDER_NAME="$(npx rock remote-cache get-provider-name 2>&1)"; then +if ! PROVIDER_NAME="$(npx rock remote-cache get-provider-name)"; then echo "$PROVIDER_NAME" fail "remote-cache get-provider-name failed" fi @@ -219,7 +219,6 @@ if { [ -z "${ARTIFACT_URL:-}" ] || { [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT TARGET_PATH="$BITRISE_DEPLOY_DIR/$ARTIFACT_NAME" log "Copying artifact to Bitrise Deploy dir: $TARGET_PATH" cp "$ARTIFACT_PATH" "$TARGET_PATH" - # Optional outputs (like your Bitrise port) envman add --key UPLOAD_ARTIFACT_URL --value "${BITRISE_BUILD_URL:-}/artifacts" envman add --key UPLOAD_ARTIFACT_ID --value "bitrise-$ARTIFACT_NAME" fi From 6f83721c92dbe63e608011edbf84ec957ba39ecc Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Wed, 10 Sep 2025 12:41:23 +0200 Subject: [PATCH 05/10] refactor: move workflow on root --- bitrise.yml | 96 ++++++++++--------- bitrise/steps/remote-build/step.sh => step.sh | 0 .../steps/remote-build/step.yml => step.yml | 2 +- 3 files changed, 52 insertions(+), 46 deletions(-) rename bitrise/steps/remote-build/step.sh => step.sh (100%) rename bitrise/steps/remote-build/step.yml => step.yml (96%) diff --git a/bitrise.yml b/bitrise.yml index 5725c4e..1143fdf 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -1,49 +1,55 @@ -format_version: 11 +--- +format_version: '23' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git - +project_type: react-native +meta: + bitrise.io: + stack: osx-xcode-16.4.x + machine_type_id: g2.mac.large workflows: - test-rock-remote-build-ios: - meta: - bitrise.io: - stack: osx-xcode-15.4.x - machine_type_id: g2-m1.8core - + rock-remote-build-ios: + description: 'Install and build iOS app with Rock' envs: - - WORKING_DIRECTORY: ./test # path to a local directory with a rock project - - DESTINATION: simulator - - SCHEME: AppScheme # name of the scheme to build - - CONFIGURATION: Release - - RE_SIGN: "false" - - AD_HOC: "false" - - ROCK_BUILD_EXTRA_PARAMS: "" - - CERTIFICATE_BASE64: "" - - CERTIFICATE_PASSWORD: "" - - PROVISIONING_PROFILE_BASE64: "" - - PROVISIONING_PROFILE_NAME: "" - - KEYCHAIN_PASSWORD: "" - + - WORKING_DIRECTORY: "$BITRISE_SOURCE_DIR" + - DESTINATION: simulator + - SCHEME: ReactNativeRocks + - CONFIGURATION: Release + - RE_SIGN: 'false' + - AD_HOC: 'false' + - ROCK_BUILD_EXTRA_PARAMS: '' + - CERTIFICATE_BASE64: '' + - CERTIFICATE_PASSWORD: '' + - PROVISIONING_PROFILE_BASE64: '' + - PROVISIONING_PROFILE_NAME: '' + - KEYCHAIN_PASSWORD: '' steps: - - path::bitrise/steps/remote-build: - title: Rock Remote Build - iOS (local) - inputs: - - WORKING_DIRECTORY: $WORKING_DIRECTORY - - DESTINATION: $DESTINATION - - SCHEME: $SCHEME - - CONFIGURATION: $CONFIGURATION - - RE_SIGN: $RE_SIGN - - AD_HOC: $AD_HOC - - ROCK_BUILD_EXTRA_PARAMS: $ROCK_BUILD_EXTRA_PARAMS - - CERTIFICATE_BASE64: $CERTIFICATE_BASE64 - - CERTIFICATE_PASSWORD: $CERTIFICATE_PASSWORD - - PROVISIONING_PROFILE_BASE64: $PROVISIONING_PROFILE_BASE64 - - PROVISIONING_PROFILE_NAME: $PROVISIONING_PROFILE_NAME - - KEYCHAIN_PASSWORD: $KEYCHAIN_PASSWORD - - - script@1: - title: Show Step Outputs - inputs: - - content: |- - #!/usr/bin/env bash - set -e - echo "ARTIFACT_URL=${ARTIFACT_URL:-}" - echo "ARTIFACT_ID=${ARTIFACT_ID:-}" + - activate-ssh-key@4: {} + - git-clone@8: {} + - npm@1: + title: npm install + inputs: + - workdir: "$WORKING_DIRECTORY" + - command: install + - git::https://github.com/callstackincubator/ios@main: + title: Rock Remote Build - iOS + inputs: + - WORKING_DIRECTORY: "$WORKING_DIRECTORY" + - DESTINATION: "$DESTINATION" + - SCHEME: "$SCHEME" + - CONFIGURATION: "$CONFIGURATION" + - RE_SIGN: "$RE_SIGN" + - AD_HOC: "$AD_HOC" + - ROCK_BUILD_EXTRA_PARAMS: "$ROCK_BUILD_EXTRA_PARAMS" + - CERTIFICATE_BASE64: "$CERTIFICATE_BASE64" + - CERTIFICATE_PASSWORD: "$CERTIFICATE_PASSWORD" + - PROVISIONING_PROFILE_BASE64: "$PROVISIONING_PROFILE_BASE64" + - PROVISIONING_PROFILE_NAME: "$PROVISIONING_PROFILE_NAME" + - KEYCHAIN_PASSWORD: "$KEYCHAIN_PASSWORD" + - script@1: + title: Show Step Outputs + inputs: + - content: |- + #!/usr/bin/env bash + set -e + echo "ARTIFACT_URL=${ARTIFACT_URL:-}" + echo "ARTIFACT_ID=${ARTIFACT_ID:-}" diff --git a/bitrise/steps/remote-build/step.sh b/step.sh similarity index 100% rename from bitrise/steps/remote-build/step.sh rename to step.sh diff --git a/bitrise/steps/remote-build/step.yml b/step.yml similarity index 96% rename from bitrise/steps/remote-build/step.yml rename to step.yml index 7671de6..35751d1 100644 --- a/bitrise/steps/remote-build/step.yml +++ b/step.yml @@ -4,7 +4,7 @@ description: | This step builds iOS apps with Rock, optionally re-signing IPAs for PRs or device builds. Supports simulator and device targets. website: https://github.com/callstackincubator/ios -source_code_url: https://github.com/callstackincubator/ios/bitrise/steps/remote-build +source_code_url: https://github.com/callstackincubator/ios support_url: https://github.com/callstackincubator/ios/issues project_type_tags: From 173d43167437ee790d0272b68d5e2f5c2a4a35c9 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Fri, 12 Sep 2025 18:54:21 +0200 Subject: [PATCH 06/10] docs: add docs for bitrise workflow --- BITRISE.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 13 +++++---- 2 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 BITRISE.md diff --git a/BITRISE.md b/BITRISE.md new file mode 100644 index 0000000..9ab5d03 --- /dev/null +++ b/BITRISE.md @@ -0,0 +1,83 @@ +# Rock iOS Bitrise Step + +This Bitrise step enables remote building of iOS applications using [Rock](https://rockjs.dev). It supports both simulator and device builds, with automatic artifact caching and code signing capabilities. + +## Usage + +```yaml +--- +format_version: '23' +default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git +project_type: react-native +meta: + bitrise.io: + stack: osx-xcode-16.4.x + machine_type_id: g2.mac.large +workflows: + rock-remote-build-ios: + description: 'Rock Remote Build - iOS' + envs: + - WORKING_DIRECTORY: "$BITRISE_SOURCE_DIR" + - DESTINATION: simulator + - SCHEME: RockRemoteBuildTest + - CONFIGURATION: Release + - RE_SIGN: 'false' + - AD_HOC: 'false' + - ROCK_BUILD_EXTRA_PARAMS: '' + - CERTIFICATE_BASE64: '' + - CERTIFICATE_PASSWORD: '' + - PROVISIONING_PROFILE_BASE64: '' + - PROVISIONING_PROFILE_NAME: '' + - KEYCHAIN_PASSWORD: '' + steps: + - activate-ssh-key@4: {} + - git-clone@8: {} + - npm@1: + title: npm install + inputs: + - workdir: "$WORKING_DIRECTORY" + - command: install + - git::https://github.com/callstackincubator/ios@main: + title: Rock Remote Build - iOS + inputs: + - WORKING_DIRECTORY: "$WORKING_DIRECTORY" + - DESTINATION: "$DESTINATION" + - SCHEME: "$SCHEME" + - CONFIGURATION: "$CONFIGURATION" + - RE_SIGN: "$RE_SIGN" + - AD_HOC: "$AD_HOC" + - ROCK_BUILD_EXTRA_PARAMS: "$ROCK_BUILD_EXTRA_PARAMS" + - CERTIFICATE_BASE64: "$CERTIFICATE_BASE64" + - CERTIFICATE_PASSWORD: "$CERTIFICATE_PASSWORD" + - PROVISIONING_PROFILE_BASE64: "$PROVISIONING_PROFILE_BASE64" + - PROVISIONING_PROFILE_NAME: "$PROVISIONING_PROFILE_NAME" + - KEYCHAIN_PASSWORD: "$KEYCHAIN_PASSWORD" +``` + +## Bitrise Inputs + +| Input | Description | Required | Default | +| ----------------------------- | ------------------------------------------------------------------------------- | -------- | ----------- | +| `WORKING_DIRECTORY` | Working directory for the build command | No | `.` | +| `DESTINATION` | Build destination: "simulator" or "device" | Yes | `simulator` | +| `SCHEME` | Xcode scheme | Yes | - | +| `CONFIGURATION` | Xcode configuration | Yes | - | +| `RE_SIGN` | Re-sign the app bundle with new JS bundle | No | `false` | +| `AD_HOC` | Upload the IPA for ad-hoc distribution to easily install on provisioned devices | No | `false` | +| `CERTIFICATE_BASE64` | Base64 encoded P12 file for device builds | No | - | +| `CERTIFICATE_PASSWORD` | Password for the P12 file | No | - | +| `PROVISIONING_PROFILE_BASE64` | Base64 encoded provisioning profile | No | - | +| `PROVISIONING_PROFILE_NAME` | Name of the provisioning profile | No | - | +| `KEYCHAIN_PASSWORD` | Password for temporary keychain | No | - | +| `ROCK_BUILD_EXTRA_PARAMS` | Extra parameters for rock build:ios | No | - | + +## Bitrise Outputs + +| Output | Description | +| -------------- | ------------------------- | +| `ARTIFACT_URL` | URL of the build artifact | +| `ARTIFACT_ID` | ID of the build artifact | + +## License + +MIT diff --git a/README.md b/README.md index e7ed31e..6ebb929 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock iOS GitHub Action +# Rock iOS Workflow -This GitHub Action enables remote building of iOS applications using [Rock](https://rockjs.dev). It supports both simulator and device builds, with automatic artifact caching and code signing capabilities. +This repository provides workflows for building iOS applications using [Rock](https://rockjs.dev). It supports both simulator and device builds, with automatic artifact caching and code signing capabilities. ## Features @@ -11,7 +11,10 @@ This GitHub Action enables remote building of iOS applications using [Rock](http - Native fingerprint-based caching - Configurable build parameters -## Usage +> [!NOTE] +> **Looking for Bitrise?** See [BITRISE.md](./BITRISE.md) for Bitrise-specific documentation. + +## GitHub Actions Usage ```yaml name: iOS Build @@ -44,7 +47,7 @@ jobs: # ad-hoc: true ``` -## Inputs +## GitHub Actions Inputs | Input | Description | Required | Default | | ----------------------------- | ------------------------------------------------------------------------------- | -------- | ----------- | @@ -63,7 +66,7 @@ jobs: | `rock-build-extra-params` | Extra parameters for rock build:ios | No | - | | `comment-bot` | Whether to comment PR with build link | No | `true` | -## Outputs +## GitHub Actions Outputs | Output | Description | | -------------- | ------------------------- | From 374ceb8816d0b6fc848892d5c1dc2f348d794f02 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Sun, 14 Sep 2025 18:10:19 +0200 Subject: [PATCH 07/10] fix: use no truthy fallback --- step.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/step.sh b/step.sh index b48111e..20ba59f 100755 --- a/step.sh +++ b/step.sh @@ -73,7 +73,7 @@ if [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ] && [ "$RE_SIGN" = "true" ] ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION},${BITRISE_PULL_REQUEST:-}" envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" - OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || true)" + OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || (echo "$OUTPUT" && exit 1))" if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" @@ -89,7 +89,7 @@ if [ -z "$ARTIFACT_NAME" ]; then ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION}" envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" - OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || true)" + OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || (echo "$OUTPUT" && exit 1))" if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" @@ -122,7 +122,7 @@ if { [ "$RE_SIGN" = "true" ] && [ "$DESTINATION" = "device" ]; } || { [ -z "$ART security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security list-keychain -d user -s "$KEYCHAIN_PATH" - IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -oE '([0-9A-F]{40})' | head -n 1 || true)" + IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -oE '([0-9A-F]{40})' | head -n 1 || (echo "$IDENTITY" && exit 1))" echo "Certificate identity: $IDENTITY" envman add --key IDENTITY --value "$IDENTITY" @@ -134,7 +134,7 @@ fi # Build if no artifact was found if [ -z "$ARTIFACT_URL" ]; then pushd "$WORKING_DIRECTORY" >/dev/null - JSON_OUTPUT="$(npx rock config -p ios || true)" + JSON_OUTPUT="$(npx rock config -p ios || (echo "$JSON_OUTPUT" && exit 1))" IOS_SOURCE_DIR="$(echo "$JSON_OUTPUT" | jq -r '.project.ios.sourceDir')" log "Resolved ios.sourceDir: ${IOS_SOURCE_DIR:-}" envman add --key IOS_SOURCE_DIR --value "$IOS_SOURCE_DIR" @@ -172,7 +172,7 @@ fi # PR re-sign: download and (re)sign/rebundle if [ -n "$ARTIFACT_URL" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ]; then log "Downloading cached artifact from remote cache: name=$ARTIFACT_NAME" - DOWNLOAD_OUTPUT="$(npx rock remote-cache download --name "$ARTIFACT_NAME" --json || true)" + DOWNLOAD_OUTPUT="$(npx rock remote-cache download --name "$ARTIFACT_NAME" --json || (echo "$DOWNLOAD_OUTPUT" && exit 1))" DL_PATH="$(echo "$DOWNLOAD_OUTPUT" | jq -r '.path')" if [ "$DESTINATION" = "device" ]; then @@ -205,7 +205,7 @@ if [ -n "$ARTIFACT_URL" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_T fi # Find artifact URL again before uploading -OUTPUT="$(npx rock remote-cache list --name "$ARTIFACT_NAME" --json || true)" +OUTPUT="$(npx rock remote-cache list --name "$ARTIFACT_NAME" --json || (echo "$OUTPUT" && exit 1))" if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" @@ -226,7 +226,7 @@ fi # Upload to Remote Cache for re-signed builds (PR) if [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ] && [ -n "${ARTIFACT_PATH:-}" ]; then - OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json || true)" + OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json || (echo "$OUTPUT" && exit 1))" if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" @@ -235,7 +235,7 @@ fi # Upload to Remote Cache for regular builds if [ -z "${ARTIFACT_URL:-}" ]; then - OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --json || true)" + OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --json || (echo "$OUTPUT" && exit 1))" if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" @@ -244,7 +244,7 @@ fi # Upload for Ad-hoc distribution if [ "$AD_HOC" = "true" ] && [ -n "${ARTIFACT_PATH:-}" ]; then - OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json --ad-hoc || true)" + OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json --ad-hoc || (echo "$OUTPUT" && exit 1))" if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" @@ -253,20 +253,20 @@ fi # Delete Old Re-Signed Artifacts if [ -n "${ARTIFACT_URL:-}" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ]; then - npx rock remote-cache delete --name "$ARTIFACT_NAME" --all-but-latest --json || true + npx rock remote-cache delete --name "$ARTIFACT_NAME" --all-but-latest --json fi # Clean Up Code Signing (device builds only, when we built locally) if [ -z "${ARTIFACT_URL:-}" ] && [ "$DESTINATION" = "device" ]; then KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" - security delete-keychain "$KEYCHAIN_PATH" || true + security delete-keychain "$KEYCHAIN_PATH" PROFILE_PATH="$PROFILE_DIR/$PROVISIONING_PROFILE_NAME.mobileprovision" - rm -f "$PROFILE_PATH" || true + rm -f "$PROFILE_PATH" fi # Cleanup Cache glue -rm -rf .rock/cache/project.json || true +rm -rf .rock/cache/project.json # Outputs [ -n "${ARTIFACT_URL:-}" ] && envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" From 395dd0163df75eb7c43f235afabc06d0645e9177 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Sun, 14 Sep 2025 19:01:44 +0200 Subject: [PATCH 08/10] fix: remove double quotes --- step.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/step.sh b/step.sh index 20ba59f..8956118 100755 --- a/step.sh +++ b/step.sh @@ -73,7 +73,7 @@ if [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ] && [ "$RE_SIGN" = "true" ] ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION},${BITRISE_PULL_REQUEST:-}" envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" - OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || (echo "$OUTPUT" && exit 1))" + OUTPUT=$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || (echo "$OUTPUT" && exit 1)) if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" @@ -89,7 +89,7 @@ if [ -z "$ARTIFACT_NAME" ]; then ARTIFACT_TRAITS="${DESTINATION},${CONFIGURATION}" envman add --key ARTIFACT_TRAITS --value "$ARTIFACT_TRAITS" - OUTPUT="$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || (echo "$OUTPUT" && exit 1))" + OUTPUT=$(npx rock remote-cache list -p ios --traits "${ARTIFACT_TRAITS}" --json || (echo "$OUTPUT" && exit 1)) if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" @@ -122,7 +122,7 @@ if { [ "$RE_SIGN" = "true" ] && [ "$DESTINATION" = "device" ]; } || { [ -z "$ART security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security list-keychain -d user -s "$KEYCHAIN_PATH" - IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -oE '([0-9A-F]{40})' | head -n 1 || (echo "$IDENTITY" && exit 1))" + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -oE '([0-9A-F]{40})' | head -n 1 || (echo "$IDENTITY" && exit 1)) echo "Certificate identity: $IDENTITY" envman add --key IDENTITY --value "$IDENTITY" @@ -134,7 +134,7 @@ fi # Build if no artifact was found if [ -z "$ARTIFACT_URL" ]; then pushd "$WORKING_DIRECTORY" >/dev/null - JSON_OUTPUT="$(npx rock config -p ios || (echo "$JSON_OUTPUT" && exit 1))" + JSON_OUTPUT=$(npx rock config -p ios || (echo "$JSON_OUTPUT" && exit 1)) IOS_SOURCE_DIR="$(echo "$JSON_OUTPUT" | jq -r '.project.ios.sourceDir')" log "Resolved ios.sourceDir: ${IOS_SOURCE_DIR:-}" envman add --key IOS_SOURCE_DIR --value "$IOS_SOURCE_DIR" @@ -172,7 +172,7 @@ fi # PR re-sign: download and (re)sign/rebundle if [ -n "$ARTIFACT_URL" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ]; then log "Downloading cached artifact from remote cache: name=$ARTIFACT_NAME" - DOWNLOAD_OUTPUT="$(npx rock remote-cache download --name "$ARTIFACT_NAME" --json || (echo "$DOWNLOAD_OUTPUT" && exit 1))" + DOWNLOAD_OUTPUT=$(npx rock remote-cache download --name "$ARTIFACT_NAME" --json || (echo "$DOWNLOAD_OUTPUT" && exit 1)) DL_PATH="$(echo "$DOWNLOAD_OUTPUT" | jq -r '.path')" if [ "$DESTINATION" = "device" ]; then @@ -205,7 +205,7 @@ if [ -n "$ARTIFACT_URL" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_T fi # Find artifact URL again before uploading -OUTPUT="$(npx rock remote-cache list --name "$ARTIFACT_NAME" --json || (echo "$OUTPUT" && exit 1))" +OUTPUT=$(npx rock remote-cache list --name "$ARTIFACT_NAME" --json || (echo "$OUTPUT" && exit 1)) if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" ARTIFACT_ID="$(echo "$OUTPUT" | jq -r '.id')" @@ -226,7 +226,7 @@ fi # Upload to Remote Cache for re-signed builds (PR) if [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_TYPE:-}" = "pull_request" ] && [ -n "${ARTIFACT_PATH:-}" ]; then - OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json || (echo "$OUTPUT" && exit 1))" + OUTPUT=$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json || (echo "$OUTPUT" && exit 1)) if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" @@ -235,7 +235,7 @@ fi # Upload to Remote Cache for regular builds if [ -z "${ARTIFACT_URL:-}" ]; then - OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --json || (echo "$OUTPUT" && exit 1))" + OUTPUT=$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --json || (echo "$OUTPUT" && exit 1)) if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" @@ -244,7 +244,7 @@ fi # Upload for Ad-hoc distribution if [ "$AD_HOC" = "true" ] && [ -n "${ARTIFACT_PATH:-}" ]; then - OUTPUT="$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json --ad-hoc || (echo "$OUTPUT" && exit 1))" + OUTPUT=$(npx rock remote-cache upload --name "$ARTIFACT_NAME" --binary-path "$ARTIFACT_PATH" --json --ad-hoc || (echo "$OUTPUT" && exit 1)) if [ -n "$OUTPUT" ]; then ARTIFACT_URL="$(echo "$OUTPUT" | jq -r '.url')" envman add --key ARTIFACT_URL --value "$ARTIFACT_URL" From b578ca17a552bdbea449090712604b70dd6b14b3 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Sun, 14 Sep 2025 19:24:17 +0200 Subject: [PATCH 09/10] feat: let consumers handle signature setup --- BITRISE.md | 25 ++++++++----------------- step.sh | 54 +++++++----------------------------------------------- 2 files changed, 15 insertions(+), 64 deletions(-) diff --git a/BITRISE.md b/BITRISE.md index 9ab5d03..ff678a6 100644 --- a/BITRISE.md +++ b/BITRISE.md @@ -1,6 +1,9 @@ # Rock iOS Bitrise Step -This Bitrise step enables remote building of iOS applications using [Rock](https://rockjs.dev). It supports both simulator and device builds, with automatic artifact caching and code signing capabilities. +This Bitrise step enables remote building of iOS applications using [Rock](https://rockjs.dev). It supports both simulator and device builds, with automatic artifact caching. Code signing should be configured separately in your workflow before using this step. + +> [!NOTE] +> **Code Signing Required**: This step assumes that iOS code signing is already configured in your workflow before using this step. For device builds and re-signing, certificates and provisioning profiles must be available in the keychain. See the [Bitrise iOS Code Signing documentation](https://docs.bitrise.io/en/bitrise-ci/code-signing/ios-code-signing/ios-code-signing.html) for setup instructions. ## Usage @@ -24,11 +27,7 @@ workflows: - RE_SIGN: 'false' - AD_HOC: 'false' - ROCK_BUILD_EXTRA_PARAMS: '' - - CERTIFICATE_BASE64: '' - - CERTIFICATE_PASSWORD: '' - - PROVISIONING_PROFILE_BASE64: '' - - PROVISIONING_PROFILE_NAME: '' - - KEYCHAIN_PASSWORD: '' + - SIGNING_IDENTITY: '' steps: - activate-ssh-key@4: {} - git-clone@8: {} @@ -47,11 +46,7 @@ workflows: - RE_SIGN: "$RE_SIGN" - AD_HOC: "$AD_HOC" - ROCK_BUILD_EXTRA_PARAMS: "$ROCK_BUILD_EXTRA_PARAMS" - - CERTIFICATE_BASE64: "$CERTIFICATE_BASE64" - - CERTIFICATE_PASSWORD: "$CERTIFICATE_PASSWORD" - - PROVISIONING_PROFILE_BASE64: "$PROVISIONING_PROFILE_BASE64" - - PROVISIONING_PROFILE_NAME: "$PROVISIONING_PROFILE_NAME" - - KEYCHAIN_PASSWORD: "$KEYCHAIN_PASSWORD" + - SIGNING_IDENTITY: "$SIGNING_IDENTITY" ``` ## Bitrise Inputs @@ -62,13 +57,9 @@ workflows: | `DESTINATION` | Build destination: "simulator" or "device" | Yes | `simulator` | | `SCHEME` | Xcode scheme | Yes | - | | `CONFIGURATION` | Xcode configuration | Yes | - | -| `RE_SIGN` | Re-sign the app bundle with new JS bundle | No | `false` | +| `RE_SIGN` | Re-sign the app bundle with new JS bundle. Requires certificates in keychain | No | `false` | | `AD_HOC` | Upload the IPA for ad-hoc distribution to easily install on provisioned devices | No | `false` | -| `CERTIFICATE_BASE64` | Base64 encoded P12 file for device builds | No | - | -| `CERTIFICATE_PASSWORD` | Password for the P12 file | No | - | -| `PROVISIONING_PROFILE_BASE64` | Base64 encoded provisioning profile | No | - | -| `PROVISIONING_PROFILE_NAME` | Name of the provisioning profile | No | - | -| `KEYCHAIN_PASSWORD` | Password for temporary keychain | No | - | +| `SIGNING_IDENTITY` | Code signing identity for re-signing. Auto-detects if not provided | No | - | | `ROCK_BUILD_EXTRA_PARAMS` | Extra parameters for rock build:ios | No | - | ## Bitrise Outputs diff --git a/step.sh b/step.sh index 8956118..4ee6d44 100755 --- a/step.sh +++ b/step.sh @@ -12,11 +12,7 @@ CONFIGURATION="${CONFIGURATION:-}" RE_SIGN="${RE_SIGN:-}" AD_HOC="${AD_HOC:-false}" -CERTIFICATE_BASE64="${CERTIFICATE_BASE64:-}" -CERTIFICATE_PASSWORD="${CERTIFICATE_PASSWORD:-}" -PROVISIONING_PROFILE_BASE64="${PROVISIONING_PROFILE_BASE64:-}" -PROVISIONING_PROFILE_NAME="${PROVISIONING_PROFILE_NAME:-}" -KEYCHAIN_PASSWORD="${KEYCHAIN_PASSWORD:-}" +SIGNING_IDENTITY="${SIGNING_IDENTITY:-}" ROCK_BUILD_EXTRA_PARAMS="${ROCK_BUILD_EXTRA_PARAMS:-}" @@ -27,17 +23,7 @@ if [ "$DESTINATION" != "simulator" ] && [ "$DESTINATION" != "device" ]; then fail "Invalid input 'destination': '$DESTINATION'. Allowed values: 'simulator' or 'device'." fi -if [ "$DESTINATION" = "device" ]; then - [ -z "$CERTIFICATE_BASE64" ] && fail "Input 'certificate-base64' is required for device builds." - [ -z "$CERTIFICATE_PASSWORD" ] && fail "Input 'certificate-password' is required for device builds." - [ -z "$PROVISIONING_PROFILE_BASE64" ] && fail "Input 'provisioning-profile-base64' is required for device builds." - [ -z "$PROVISIONING_PROFILE_NAME" ] && fail "Input 'provisioning-profile-name' is required for device builds." - [ -z "$KEYCHAIN_PASSWORD" ] && fail "Input 'keychain-password' is required for device builds." -fi -# Provisioning profile dir -PROFILE_DIR="$HOME/Library/MobileDevice/Provisioning Profiles" -envman add --key PROFILE_DIR --value "$PROFILE_DIR" # Fingerprint pushd "$WORKING_DIRECTORY" >/dev/null @@ -108,28 +94,6 @@ if [ -z "$ARTIFACT_NAME" ]; then envman add --key ARTIFACT_NAME --value "$ARTIFACT_NAME" fi -# Setup Code Signing (device builds only) -if { [ "$RE_SIGN" = "true" ] && [ "$DESTINATION" = "device" ]; } || { [ -z "$ARTIFACT_URL" ] && [ "$DESTINATION" = "device" ]; }; then - KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" - - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - CERTIFICATE_PATH="$RUNNER_TEMP/certificate.p12" - echo -n "$CERTIFICATE_BASE64" | base64 --decode -o "$CERTIFICATE_PATH" - security import "$CERTIFICATE_PATH" -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security list-keychain -d user -s "$KEYCHAIN_PATH" - - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -oE '([0-9A-F]{40})' | head -n 1 || (echo "$IDENTITY" && exit 1)) - echo "Certificate identity: $IDENTITY" - envman add --key IDENTITY --value "$IDENTITY" - - mkdir -p "$PROFILE_DIR" - PROFILE_PATH="$PROFILE_DIR/$PROVISIONING_PROFILE_NAME.mobileprovision" - echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode -o "$PROFILE_PATH" -fi # Build if no artifact was found if [ -z "$ARTIFACT_URL" ]; then @@ -177,9 +141,13 @@ if [ -n "$ARTIFACT_URL" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVENT_T if [ "$DESTINATION" = "device" ]; then envman add --key ARTIFACT_PATH --value "$DL_PATH" - log "Re-signing IPA with new JS bundle: path=$DL_PATH identity=${IDENTITY:-unset}" + log "Re-signing IPA with new JS bundle: path=$DL_PATH identity=${SIGNING_IDENTITY:-auto-detect}" pushd "$WORKING_DIRECTORY" >/dev/null - npx rock sign:ios "$DL_PATH" --build-jsbundle --identity "$IDENTITY" + if [ -n "$SIGNING_IDENTITY" ]; then + npx rock sign:ios "$DL_PATH" --build-jsbundle --identity "$SIGNING_IDENTITY" + else + npx rock sign:ios "$DL_PATH" --build-jsbundle + fi popd >/dev/null else APP_DIR="$(dirname "$DL_PATH")" @@ -256,14 +224,6 @@ if [ -n "${ARTIFACT_URL:-}" ] && [ "$RE_SIGN" = "true" ] && [ "${BITRISE_GIT_EVE npx rock remote-cache delete --name "$ARTIFACT_NAME" --all-but-latest --json fi -# Clean Up Code Signing (device builds only, when we built locally) -if [ -z "${ARTIFACT_URL:-}" ] && [ "$DESTINATION" = "device" ]; then - KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" - security delete-keychain "$KEYCHAIN_PATH" - - PROFILE_PATH="$PROFILE_DIR/$PROVISIONING_PROFILE_NAME.mobileprovision" - rm -f "$PROFILE_PATH" -fi # Cleanup Cache glue rm -rf .rock/cache/project.json From 6db3bdd773134ae8700e13d28771f4b7a7c6af77 Mon Sep 17 00:00:00 2001 From: bacarybruno Date: Wed, 17 Sep 2025 19:31:37 +0200 Subject: [PATCH 10/10] chore: remove unused variables --- bitrise.yml | 12 ++---------- step.sh | 1 - step.yml | 40 +++++++--------------------------------- 3 files changed, 9 insertions(+), 44 deletions(-) diff --git a/bitrise.yml b/bitrise.yml index 1143fdf..4bcf1bc 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -17,11 +17,7 @@ workflows: - RE_SIGN: 'false' - AD_HOC: 'false' - ROCK_BUILD_EXTRA_PARAMS: '' - - CERTIFICATE_BASE64: '' - - CERTIFICATE_PASSWORD: '' - - PROVISIONING_PROFILE_BASE64: '' - - PROVISIONING_PROFILE_NAME: '' - - KEYCHAIN_PASSWORD: '' + - SIGNING_IDENTITY: '' steps: - activate-ssh-key@4: {} - git-clone@8: {} @@ -40,11 +36,7 @@ workflows: - RE_SIGN: "$RE_SIGN" - AD_HOC: "$AD_HOC" - ROCK_BUILD_EXTRA_PARAMS: "$ROCK_BUILD_EXTRA_PARAMS" - - CERTIFICATE_BASE64: "$CERTIFICATE_BASE64" - - CERTIFICATE_PASSWORD: "$CERTIFICATE_PASSWORD" - - PROVISIONING_PROFILE_BASE64: "$PROVISIONING_PROFILE_BASE64" - - PROVISIONING_PROFILE_NAME: "$PROVISIONING_PROFILE_NAME" - - KEYCHAIN_PASSWORD: "$KEYCHAIN_PASSWORD" + - SIGNING_IDENTITY: "$SIGNING_IDENTITY" - script@1: title: Show Step Outputs inputs: diff --git a/step.sh b/step.sh index 4ee6d44..a4de7fc 100755 --- a/step.sh +++ b/step.sh @@ -16,7 +16,6 @@ SIGNING_IDENTITY="${SIGNING_IDENTITY:-}" ROCK_BUILD_EXTRA_PARAMS="${ROCK_BUILD_EXTRA_PARAMS:-}" -RUNNER_TEMP="${RUNNER_TEMP:-${TMPDIR:-/tmp}}" # Validate inputs (mirror composite action behavior) if [ "$DESTINATION" != "simulator" ] && [ "$DESTINATION" != "device" ]; then diff --git a/step.yml b/step.yml index 35751d1..60e63a3 100644 --- a/step.yml +++ b/step.yml @@ -2,7 +2,8 @@ title: Rock Remote Build - iOS summary: Build iOS apps using Rock. description: | This step builds iOS apps with Rock, optionally re-signing IPAs - for PRs or device builds. Supports simulator and device targets. + for PRs or device builds. Code signing must be configured separately + in your workflow before using this step. website: https://github.com/callstackincubator/ios source_code_url: https://github.com/callstackincubator/ios support_url: https://github.com/callstackincubator/ios/issues @@ -35,7 +36,7 @@ inputs: - DESTINATION: opts: title: Destination for the build - summary: "Use 'simulator' or 'device'. Device builds require signing." + summary: "Use 'simulator' or 'device'. Code signing must be configured separately." is_required: true value: "simulator" @@ -54,7 +55,7 @@ inputs: - RE_SIGN: opts: title: Re-sign IPA with new JS bundle - summary: No signing is done for simulator builds + summary: Requires certificates in keychain. No signing for simulator builds. is_required: false value: "" @@ -64,38 +65,11 @@ inputs: is_required: false value: "false" - - CERTIFICATE_BASE64: + - SIGNING_IDENTITY: opts: - title: Base64 encoded P12 file (device builds) + title: Code signing identity for re-signing + summary: Optional. Auto-detects available certificates if not provided. is_required: false - is_sensitive: true - value: "" - - - CERTIFICATE_PASSWORD: - opts: - title: P12 password (device builds) - is_required: false - is_sensitive: true - value: "" - - - PROVISIONING_PROFILE_BASE64: - opts: - title: Base64 encoded provisioning profile - is_required: false - is_sensitive: true - value: "" - - - PROVISIONING_PROFILE_NAME: - opts: - title: Name of provisioning profile (without extension) - is_required: false - value: "" - - - KEYCHAIN_PASSWORD: - opts: - title: Keychain password (device builds) - is_required: false - is_sensitive: true value: "" - ROCK_BUILD_EXTRA_PARAMS: