From 7ee3a195c662fdd75cddd01e961c667b14acc16c Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:37:28 -0600 Subject: [PATCH 01/13] Sign a Simulator into WordPress.com from a launch-argument token Add `Scripts/sim-signin.sh`, a one-command wrapper around `xcrun simctl launch` that signs a Simulator into WordPress.com with a bearer token, and make the existing `-ui-test-wpcom-token` launch argument finish sign-in automatically instead of requiring a tap on "Continue with WordPress.com". `autoSignInUITestWPComAccountIfNeeded()` mirrors the existing `autoSignInUITestSite()` hook: it runs from `showSignInUI()`, no-ops unless the token argument is present and no account is signed in, then runs the real sign-in flow and swaps the window root with `windowManager.showUI()`. --- Scripts/sim-signin.sh | 75 +++++++++++++++++++ .../Root View/RootViewCoordinator.swift | 1 + .../Classes/System/WordPressAppDelegate.swift | 25 +++++++ docs/simulator-sign-in.md | 14 +++- 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100755 Scripts/sim-signin.sh diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh new file mode 100755 index 000000000000..f15aacc3c7f6 --- /dev/null +++ b/Scripts/sim-signin.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# +# Sign an iOS Simulator into WordPress.com with a bearer token, in one command. +# +# Wraps `xcrun simctl launch`, passing the `-ui-test-wpcom-token` launch argument the app +# reads on the login screen to finish WordPress.com sign-in automatically — no taps required. +# Build and install the app on the simulator first (e.g. from Xcode). + +set -euo pipefail + +usage() { + cat <<'EOF' +Sign an iOS Simulator into WordPress.com with a bearer token, in one command. + +Usage: + Scripts/sim-signin.sh [options] + +Options: + -a, --app App to sign in (default: jetpack) + -d, --device Target simulator (default: booted) + -r, --reset Wipe existing app data before signing in + -h, --help Show this help + +Examples: + Scripts/sim-signin.sh # Jetpack, booted simulator + Scripts/sim-signin.sh --app wordpress # WordPress + Scripts/sim-signin.sh --reset # wipe existing state first +EOF +} + +app="jetpack" +device="booted" +reset=false +token="" + +while [[ $# -gt 0 ]]; do + case "$1" in + -a|--app) app="${2:-}"; shift 2 ;; + -d|--device) device="${2:-}"; shift 2 ;; + -r|--reset) reset=true; shift ;; + -h|--help) usage; exit 0 ;; + -*) echo "error: unknown option '$1'" >&2; usage >&2; exit 1 ;; + *) + if [[ -n "$token" ]]; then + echo "error: unexpected argument '$1' (token already set)" >&2 + exit 1 + fi + token="$1"; shift ;; + esac +done + +if [[ -z "$token" ]]; then + echo "error: missing " >&2 + usage >&2 + exit 1 +fi + +case "$app" in + jetpack) bundle_id="com.automattic.jetpack" ;; + wordpress) bundle_id="org.wordpress" ;; + *) echo "error: unknown app '$app' (expected 'jetpack' or 'wordpress')" >&2; exit 1 ;; +esac + +echo "Signing $app ($bundle_id) into WordPress.com on simulator '$device'…" + +if [[ "$reset" == true ]]; then + echo "Resetting app data…" + xcrun simctl launch --terminate-running-process "$device" "$bundle_id" -ui-test-reset-everything + # Give the app a moment to wipe Core Data + UserDefaults before relaunching. + sleep 2 +fi + +xcrun simctl launch --terminate-running-process "$device" "$bundle_id" -ui-test-wpcom-token "$token" + +echo "Done. The app signs in automatically from the login screen." diff --git a/WordPress/Classes/System/Root View/RootViewCoordinator.swift b/WordPress/Classes/System/Root View/RootViewCoordinator.swift index 2de493c3b197..18cc8baf3eb2 100644 --- a/WordPress/Classes/System/Root View/RootViewCoordinator.swift +++ b/WordPress/Classes/System/Root View/RootViewCoordinator.swift @@ -92,6 +92,7 @@ class RootViewCoordinator { self.rootViewPresenter = nil WordPressAppDelegate.shared?.autoSignInUITestSite() + WordPressAppDelegate.shared?.autoSignInUITestWPComAccountIfNeeded() } private func createPresenter(_ appType: AppUIType) -> RootViewPresenter { diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index 3335dec34d24..2f71f459048a 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -901,4 +901,29 @@ extension WordPressAppDelegate { } ) } + + /// Completes WordPress.com sign-in automatically when a bearer token is supplied via the + /// `-ui-test-wpcom-token` launch argument, so a Simulator can be signed in with a single + /// `simctl launch` and no taps on the login screen. + /// + /// No-op when the argument is absent or a WordPress.com account is already signed in. + func autoSignInUITestWPComAccountIfNeeded() { + guard UserDefaults.standard.string(forKey: "ui-test-wpcom-token") != nil else { + return + } + guard (try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext)) == nil else { + return + } + guard let presenter = window?.topmostPresentedViewController else { + return + } + Task { @MainActor in + guard await WordPressDotComAuthenticator().signIn(from: presenter, context: .default) != nil else { + return + } + // Creating the account isn't enough on its own — without this the app stays on the + // login screen. Swap the window root to the signed-in app (no epilogue, so no taps). + windowManager.showUI() + } + } } diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index dc60b0721985..e4d24dc388ee 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -1,18 +1,24 @@ # Simulator Sign-In -Pass credentials as launch arguments, then tap through the sign-in screen to complete sign-in. +Pass credentials as launch arguments. WordPress.com sign-in then completes automatically; the self-hosted flow still needs a couple of taps. ## WordPress.com account -Launch with a bearer token: +The quickest path is the helper script — it launches the app with the token and, optionally, resets first: + +```bash +Scripts/sim-signin.sh # Jetpack, booted simulator +Scripts/sim-signin.sh --app wordpress # WordPress +Scripts/sim-signin.sh --reset # wipe existing state first +``` + +Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: ```bash xcrun simctl launch --terminate-running-process booted org.wordpress \ -ui-test-wpcom-token ``` -On the sign-in screen, tap **"Continue with WordPress.com"**. - ## Self-hosted site Launch with the site URL, a username, and an application password: From 4ea87bd3572a0d0b010879fdb12ac33657df1c24 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:43:31 -0600 Subject: [PATCH 02/13] Accept the WordPress.com token via --wpcom-token Add a named `-t, --wpcom-token ` option alongside the positional form, and reject a missing option value instead of shifting past the end. --- Scripts/sim-signin.sh | 38 ++++++++++++++++++++++++++------------ docs/simulator-sign-in.md | 6 +++--- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index f15aacc3c7f6..ae043c6f37b4 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -13,18 +13,20 @@ usage() { Sign an iOS Simulator into WordPress.com with a bearer token, in one command. Usage: - Scripts/sim-signin.sh [options] + Scripts/sim-signin.sh [options] --wpcom-token + Scripts/sim-signin.sh [options] Options: + -t, --wpcom-token WordPress.com bearer token (or pass it positionally) -a, --app App to sign in (default: jetpack) -d, --device Target simulator (default: booted) -r, --reset Wipe existing app data before signing in -h, --help Show this help Examples: - Scripts/sim-signin.sh # Jetpack, booted simulator - Scripts/sim-signin.sh --app wordpress # WordPress - Scripts/sim-signin.sh --reset # wipe existing state first + Scripts/sim-signin.sh --wpcom-token # Jetpack, booted simulator + Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress + Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first EOF } @@ -33,19 +35,31 @@ device="booted" reset=false token="" +set_token() { + if [[ -n "$token" ]]; then + echo "error: token already set (got '$1')" >&2 + exit 1 + fi + token="$1" +} + +require_value() { + # $1 = option name, $2 = remaining argument count ($#) + if [[ "$2" -lt 2 ]]; then + echo "error: $1 requires a value" >&2 + exit 1 + fi +} + while [[ $# -gt 0 ]]; do case "$1" in - -a|--app) app="${2:-}"; shift 2 ;; - -d|--device) device="${2:-}"; shift 2 ;; + -t|--wpcom-token) require_value "$1" "$#"; set_token "$2"; shift 2 ;; + -a|--app) require_value "$1" "$#"; app="$2"; shift 2 ;; + -d|--device) require_value "$1" "$#"; device="$2"; shift 2 ;; -r|--reset) reset=true; shift ;; -h|--help) usage; exit 0 ;; -*) echo "error: unknown option '$1'" >&2; usage >&2; exit 1 ;; - *) - if [[ -n "$token" ]]; then - echo "error: unexpected argument '$1' (token already set)" >&2 - exit 1 - fi - token="$1"; shift ;; + *) set_token "$1"; shift ;; esac done diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index e4d24dc388ee..ef6c0bf22481 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -7,9 +7,9 @@ Pass credentials as launch arguments. WordPress.com sign-in then completes autom The quickest path is the helper script — it launches the app with the token and, optionally, resets first: ```bash -Scripts/sim-signin.sh # Jetpack, booted simulator -Scripts/sim-signin.sh --app wordpress # WordPress -Scripts/sim-signin.sh --reset # wipe existing state first +Scripts/sim-signin.sh --wpcom-token # Jetpack, booted simulator +Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress +Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first ``` Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: From 6657667270e53498fa269da75ac18493300e953c Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:48:08 -0600 Subject: [PATCH 03/13] Read the token from -wpcom-token, with -ui-test-wpcom-token as a shim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce `WordPressDotComAuthenticator.launchArgumentToken`, which reads the new `-wpcom-token` launch argument and falls back to the legacy `-ui-test-wpcom-token`. Route both read sites — `attemptSignIn` and `autoSignInUITestWPComAccountIfNeeded()` — through it, and switch the helper script to pass `-wpcom-token`. --- Scripts/sim-signin.sh | 6 +++--- .../Classes/Login/WordPressDotComAuthenticator.swift | 11 ++++++++++- WordPress/Classes/System/WordPressAppDelegate.swift | 4 ++-- docs/simulator-sign-in.md | 4 +++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index ae043c6f37b4..27da5f76ebe7 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -2,8 +2,8 @@ # # Sign an iOS Simulator into WordPress.com with a bearer token, in one command. # -# Wraps `xcrun simctl launch`, passing the `-ui-test-wpcom-token` launch argument the app -# reads on the login screen to finish WordPress.com sign-in automatically — no taps required. +# Wraps `xcrun simctl launch`, passing the `-wpcom-token` launch argument the app reads on +# the login screen to finish WordPress.com sign-in automatically — no taps required. # Build and install the app on the simulator first (e.g. from Xcode). set -euo pipefail @@ -84,6 +84,6 @@ if [[ "$reset" == true ]]; then sleep 2 fi -xcrun simctl launch --terminate-running-process "$device" "$bundle_id" -ui-test-wpcom-token "$token" +xcrun simctl launch --terminate-running-process "$device" "$bundle_id" -wpcom-token "$token" echo "Done. The app signs in automatically from the login screen." diff --git a/WordPress/Classes/Login/WordPressDotComAuthenticator.swift b/WordPress/Classes/Login/WordPressDotComAuthenticator.swift index fba48eead683..1c3b4315cea4 100644 --- a/WordPress/Classes/Login/WordPressDotComAuthenticator.swift +++ b/WordPress/Classes/Login/WordPressDotComAuthenticator.swift @@ -57,6 +57,15 @@ struct WordPressDotComAuthenticator { rawValue: "WordPressDotComAuthenticatorCallbackURL" ) + /// A WordPress.com bearer token supplied as a launch argument, used to sign a Simulator in + /// without the web flow. Reads `-wpcom-token`, falling back to the legacy + /// `-ui-test-wpcom-token` argument for backward compatibility. + static var launchArgumentToken: String? { + let defaults = UserDefaults.standard + return defaults.string(forKey: "wpcom-token") + ?? defaults.string(forKey: "ui-test-wpcom-token") + } + static func redirectURI(for scheme: String) -> String { "\(scheme)://oauth2-callback" } @@ -131,7 +140,7 @@ struct WordPressDotComAuthenticator { let token: String do { - if let tokenLaunchArgument = UserDefaults.standard.string(forKey: "ui-test-wpcom-token") { + if let tokenLaunchArgument = Self.launchArgumentToken { token = tokenLaunchArgument } else { token = try await authenticate( diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index 2f71f459048a..0d5efd672533 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -903,12 +903,12 @@ extension WordPressAppDelegate { } /// Completes WordPress.com sign-in automatically when a bearer token is supplied via the - /// `-ui-test-wpcom-token` launch argument, so a Simulator can be signed in with a single + /// `-wpcom-token` launch argument, so a Simulator can be signed in with a single /// `simctl launch` and no taps on the login screen. /// /// No-op when the argument is absent or a WordPress.com account is already signed in. func autoSignInUITestWPComAccountIfNeeded() { - guard UserDefaults.standard.string(forKey: "ui-test-wpcom-token") != nil else { + guard WordPressDotComAuthenticator.launchArgumentToken != nil else { return } guard (try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext)) == nil else { diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index ef6c0bf22481..7856641d0afa 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -16,9 +16,11 @@ Or launch directly with the bearer token. The app finishes sign-in automatically ```bash xcrun simctl launch --terminate-running-process booted org.wordpress \ - -ui-test-wpcom-token + -wpcom-token ``` +The legacy `-ui-test-wpcom-token` argument is still accepted for backward compatibility. + ## Self-hosted site Launch with the site URL, a username, and an application password: From ae140b09a0957e8aa96aee6c30cbaf468a6041ae Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:09:58 -0600 Subject: [PATCH 04/13] Drop "UITest" from the auto-sign-in method name The launch argument is `-wpcom-token`, not UI-test-scoped, so `autoSignInUITestWPComAccountIfNeeded()` was misleading. Rename it to `autoSignInWPComAccountFromLaunchArgumentIfNeeded()`. --- WordPress/Classes/System/Root View/RootViewCoordinator.swift | 2 +- WordPress/Classes/System/WordPressAppDelegate.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/System/Root View/RootViewCoordinator.swift b/WordPress/Classes/System/Root View/RootViewCoordinator.swift index 18cc8baf3eb2..da952d486b5e 100644 --- a/WordPress/Classes/System/Root View/RootViewCoordinator.swift +++ b/WordPress/Classes/System/Root View/RootViewCoordinator.swift @@ -92,7 +92,7 @@ class RootViewCoordinator { self.rootViewPresenter = nil WordPressAppDelegate.shared?.autoSignInUITestSite() - WordPressAppDelegate.shared?.autoSignInUITestWPComAccountIfNeeded() + WordPressAppDelegate.shared?.autoSignInWPComAccountFromLaunchArgumentIfNeeded() } private func createPresenter(_ appType: AppUIType) -> RootViewPresenter { diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index 0d5efd672533..b5d7c0690973 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -907,7 +907,7 @@ extension WordPressAppDelegate { /// `simctl launch` and no taps on the login screen. /// /// No-op when the argument is absent or a WordPress.com account is already signed in. - func autoSignInUITestWPComAccountIfNeeded() { + func autoSignInWPComAccountFromLaunchArgumentIfNeeded() { guard WordPressDotComAuthenticator.launchArgumentToken != nil else { return } From 976ef69ae52f2105cd83913ca9e8d4eb59e90bf1 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:18:25 -0600 Subject: [PATCH 05/13] Resolve the token from WPCOM_TOKEN or ~/.wpcom-token when not passed So the token can be set once instead of pasted every launch, sim-signin.sh falls back to the WPCOM_TOKEN environment variable, then a ~/.wpcom-token file, when neither --wpcom-token nor a positional token is given. Precedence: flag > env var > file. --- Scripts/sim-signin.sh | 16 +++++++++++++++- docs/simulator-sign-in.md | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index 27da5f76ebe7..2d8df43f9d72 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -27,6 +27,11 @@ Examples: Scripts/sim-signin.sh --wpcom-token # Jetpack, booted simulator Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first + +Set the token once and omit it from the command line. Resolution order: + 1. --wpcom-token (or positional) + 2. WPCOM_TOKEN environment variable + 3. ~/.wpcom-token file EOF } @@ -63,8 +68,17 @@ while [[ $# -gt 0 ]]; do esac done +# Fall back to a token set once elsewhere, so it needn't be passed every launch: +# the WPCOM_TOKEN environment variable, then a ~/.wpcom-token file. +if [[ -z "$token" ]]; then + token="${WPCOM_TOKEN:-}" +fi +if [[ -z "$token" && -f "$HOME/.wpcom-token" ]]; then + token="$(tr -d '[:space:]' < "$HOME/.wpcom-token")" +fi + if [[ -z "$token" ]]; then - echo "error: missing " >&2 + echo "error: no token — pass --wpcom-token , set WPCOM_TOKEN, or write ~/.wpcom-token" >&2 usage >&2 exit 1 fi diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index 7856641d0afa..e3ec14ec4444 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -12,6 +12,8 @@ Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first ``` +To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. + Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: ```bash From e3dbe4827b60fc10cd951d52cbfc1e40dd6962ee Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:20:38 -0600 Subject: [PATCH 06/13] Add a make sim-login target for the Simulator sign-in script Wraps `Scripts/sim-signin.sh` behind `make sim-login`, forwarding optional `DEVICE`, `APP`, and `RESET=1` variables plus an `ARGS` passthrough. The token still resolves from `--wpcom-token`, `WPCOM_TOKEN`, or `~/.wpcom-token`. --- Makefile | 5 ++++- docs/simulator-sign-in.md | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3539ae12d1dd..e86c8ee0f5da 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,10 @@ -.PHONY: help dependencies +.PHONY: help dependencies sim-login help: ## Show available targets @grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | awk -F ':.*## ' '{printf " %-20s %s\n", $$1, $$2}' dependencies: ## Download and cache Gutenberg XCFrameworks ./Scripts/download-gutenberg-xcframeworks.sh + +sim-login: ## Sign an iOS Simulator into WordPress.com (vars: DEVICE, APP, RESET=1; token from ~/.wpcom-token) + ./Scripts/sim-signin.sh $(if $(APP),--app $(APP)) $(if $(DEVICE),--device $(DEVICE)) $(if $(RESET),--reset) $(ARGS) diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index e3ec14ec4444..dda73ac1abd5 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -12,6 +12,8 @@ Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first ``` +There's also a `make` shortcut that forwards to the script: `make sim-login DEVICE=`, with optional `APP=wordpress`, `RESET=1`, or `ARGS="…"` for any other flags. + To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: From 42723adf1951cfb0870801cf0b5512a23593ed65 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:29:12 -0600 Subject: [PATCH 07/13] Default the sim sign-in to the running simulator, prompting if several When --device is omitted, sim-signin.sh now resolves the target from the booted simulators: it uses the only one if a single device is booted, and otherwise lists them and prompts for a choice. Errors clearly when none are booted or no selection is made. An explicit --device still bypasses this. --- Scripts/sim-signin.sh | 54 +++++++++++++++++++++++++++++++++++++-- docs/simulator-sign-in.md | 2 +- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index 2d8df43f9d72..f2d713c0d681 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -19,7 +19,7 @@ Usage: Options: -t, --wpcom-token WordPress.com bearer token (or pass it positionally) -a, --app App to sign in (default: jetpack) - -d, --device Target simulator (default: booted) + -d, --device Target simulator (default: the running one; prompts if several) -r, --reset Wipe existing app data before signing in -h, --help Show this help @@ -36,7 +36,7 @@ EOF } app="jetpack" -device="booted" +device="" reset=false token="" @@ -56,6 +56,51 @@ require_value() { fi } +resolve_device() { + # Set `device` to a booted simulator: the only one if just one is booted, otherwise + # prompt to choose. Errors if none are booted. Called only when --device was omitted. + local udids=() names=() line udid name + while IFS= read -r line; do + udid=$(printf '%s\n' "$line" | grep -oiE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1) + [[ -z "$udid" ]] && continue + name=$(printf '%s\n' "$line" | sed -E 's/^[[:space:]]*//; s/[[:space:]]*\([0-9A-Fa-f-]{36}\).*$//') + udids+=("$udid") + names+=("$name") + done < <(xcrun simctl list devices booted | grep -F "(Booted)") + + local n=${#udids[@]} + if [[ "$n" -eq 0 ]]; then + echo "error: no booted simulator. Boot one (open Simulator, or 'xcrun simctl boot '), or pass --device ." >&2 + exit 1 + fi + if [[ "$n" -eq 1 ]]; then + device="${udids[0]}" + echo "Using the only booted simulator: ${names[0]} (${device})" + return + fi + + echo "Multiple simulators are booted — choose one:" >&2 + local i + for (( i = 0; i < n; i++ )); do + printf " %2d) %s (%s)\n" "$(( i + 1 ))" "${names[i]}" "${udids[i]}" >&2 + done + local sel + while true; do + printf "Select a simulator [1-%d]: " "$n" >&2 + if ! read -r sel; then + echo >&2 + echo "error: no selection made; re-run with --device ." >&2 + exit 1 + fi + if [[ "$sel" =~ ^[0-9]+$ ]] && [[ "$sel" -ge 1 ]] && [[ "$sel" -le "$n" ]]; then + device="${udids[sel - 1]}" + echo "Using ${names[sel - 1]} (${device})" + return + fi + echo " not a valid choice: '$sel'" >&2 + done +} + while [[ $# -gt 0 ]]; do case "$1" in -t|--wpcom-token) require_value "$1" "$#"; set_token "$2"; shift 2 ;; @@ -89,6 +134,11 @@ case "$app" in *) echo "error: unknown app '$app' (expected 'jetpack' or 'wordpress')" >&2; exit 1 ;; esac +# When no --device was given, target the running simulator (prompting if several are booted). +if [[ -z "$device" ]]; then + resolve_device +fi + echo "Signing $app ($bundle_id) into WordPress.com on simulator '$device'…" if [[ "$reset" == true ]]; then diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index dda73ac1abd5..4e7d4223d235 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -12,7 +12,7 @@ Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first ``` -There's also a `make` shortcut that forwards to the script: `make sim-login DEVICE=`, with optional `APP=wordpress`, `RESET=1`, or `ARGS="…"` for any other flags. +With no `--device`, the script targets the running simulator (and prompts if more than one is booted). There's also a `make` shortcut that forwards to it: `make sim-login`, with optional `DEVICE=`, `APP=wordpress`, `RESET=1`, or `ARGS="…"` for any other flags. To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. From 22b1cf30b9982d25b2896aa8bd1d93c420dfe171 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:35:37 -0600 Subject: [PATCH 08/13] Prompt for a WordPress.com token when none is configured If no token is found via --wpcom-token, WPCOM_TOKEN, or ~/.wpcom-token, sim-signin.sh now prompts for one instead of erroring out. Input is read hidden (it's a secret), whitespace-trimmed, and confirmed by length; cancelling with an empty entry still exits with the usage error. --- Scripts/sim-signin.sh | 13 ++++++++++++- docs/simulator-sign-in.md | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index f2d713c0d681..103eb87fad0c 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -32,6 +32,7 @@ Set the token once and omit it from the command line. Resolution order: 1. --wpcom-token (or positional) 2. WPCOM_TOKEN environment variable 3. ~/.wpcom-token file + 4. otherwise the script prompts you to paste one EOF } @@ -122,8 +123,18 @@ if [[ -z "$token" && -f "$HOME/.wpcom-token" ]]; then token="$(tr -d '[:space:]' < "$HOME/.wpcom-token")" fi +# Nothing found anywhere — prompt for one. Input is hidden, since it's a secret. if [[ -z "$token" ]]; then - echo "error: no token — pass --wpcom-token , set WPCOM_TOKEN, or write ~/.wpcom-token" >&2 + printf "No WordPress.com token found (--wpcom-token / WPCOM_TOKEN / ~/.wpcom-token).\n" >&2 + printf "Paste a bearer token (hidden), or press Return to cancel: " >&2 + read -rs token || true + printf "\n" >&2 + token="$(printf '%s' "$token" | tr -d '[:space:]')" + [[ -n "$token" ]] && printf "Token received (%s chars).\n" "${#token}" >&2 +fi + +if [[ -z "$token" ]]; then + echo "error: no token — pass --wpcom-token , set WPCOM_TOKEN, write ~/.wpcom-token, or paste one when prompted" >&2 usage >&2 exit 1 fi diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index 4e7d4223d235..7122c7ee28aa 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -14,7 +14,7 @@ Scripts/sim-signin.sh --reset --wpcom-token # wipe existing stat With no `--device`, the script targets the running simulator (and prompts if more than one is booted). There's also a `make` shortcut that forwards to it: `make sim-login`, with optional `DEVICE=`, `APP=wordpress`, `RESET=1`, or `ARGS="…"` for any other flags. -To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. +To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. If none is set, it prompts you to paste one. Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: From acb2c08d024f5296fc4509c5cdc9b7dcdfdd563b Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:56:22 -0600 Subject: [PATCH 09/13] Offer to save a prompted token to ~/.wpcom-token After the interactive prompt accepts a token, ask whether to persist it to ~/.wpcom-token so later runs pick it up automatically. Defaults to no, and writes owner-only (umask 077 + chmod 600) since it's a secret. --- Scripts/sim-signin.sh | 16 +++++++++++++++- docs/simulator-sign-in.md | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index 103eb87fad0c..e481ba7f3b04 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -130,7 +130,21 @@ if [[ -z "$token" ]]; then read -rs token || true printf "\n" >&2 token="$(printf '%s' "$token" | tr -d '[:space:]')" - [[ -n "$token" ]] && printf "Token received (%s chars).\n" "${#token}" >&2 + if [[ -n "$token" ]]; then + printf "Token received (%s chars).\n" "${#token}" >&2 + printf "Save it to ~/.wpcom-token for next time? [y/N] " >&2 + read -r save_reply || true + if [[ "$save_reply" =~ ^[Yy]$ ]]; then + token_file="$HOME/.wpcom-token" + # umask keeps the new file owner-only; chmod covers an existing, looser file. + if (umask 077; printf '%s\n' "$token" > "$token_file"); then + chmod 600 "$token_file" 2>/dev/null || true + printf "Saved to %s (mode 600).\n" "$token_file" >&2 + else + printf "warning: could not write %s; continuing without saving.\n" "$token_file" >&2 + fi + fi + fi fi if [[ -z "$token" ]]; then diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index 7122c7ee28aa..a4a262849e34 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -14,7 +14,7 @@ Scripts/sim-signin.sh --reset --wpcom-token # wipe existing stat With no `--device`, the script targets the running simulator (and prompts if more than one is booted). There's also a `make` shortcut that forwards to it: `make sim-login`, with optional `DEVICE=`, `APP=wordpress`, `RESET=1`, or `ARGS="…"` for any other flags. -To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. If none is set, it prompts you to paste one. +To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. If none is set, it prompts you to paste one and offers to save it to `~/.wpcom-token` for next time. Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: From 0a980fe59f98bc482d4881826da4502159a7c8fc Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:01:04 -0600 Subject: [PATCH 10/13] Feature make sim-login prominently in the sign-in docs Lead the simulator sign-in doc with `make sim-login` as the quickest path, and name the command inline in AGENTS.md so agents can sign a Simulator in without opening the doc first. --- AGENTS.md | 2 +- docs/simulator-sign-in.md | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 28c272393f12..2e20805b2bbb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,7 +41,7 @@ WordPress-iOS uses a modular architecture with the main app and separate Swift p - The WordPress scheme uses `WordPressUnitTests.xctestplan` for the full unit test suite, including tests in the `Modules` Swift package. - Add every unit test target to `WordPressUnitTests.xctestplan`. - Run the full suite with `xcodebuild -workspace WordPress.xcworkspace -scheme WordPress -testPlan WordPressUnitTests test`. Do not use `swift test`. -- To verify changes end-to-end on an iOS simulator, follow @docs/simulator-sign-in.md to sign in to the app. +- To sign a Simulator into WordPress.com end-to-end, run `make sim-login` (it targets the running simulator; the WordPress.com token comes from `~/.wpcom-token` or `WPCOM_TOKEN`, and it prompts if none is set). See @docs/simulator-sign-in.md for options and self-hosted sign-in. ### Important Considerations - **Multi-site Support**: Code must handle both WordPress.com and self-hosted sites diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index a4a262849e34..ec048a0469c6 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -4,17 +4,22 @@ Pass credentials as launch arguments. WordPress.com sign-in then completes autom ## WordPress.com account -The quickest path is the helper script — it launches the app with the token and, optionally, resets first: +The quickest path is **`make sim-login`** — it signs the running simulator into WordPress.com, prompting you to choose when more than one simulator is booted, and to paste a token if none is configured: ```bash -Scripts/sim-signin.sh --wpcom-token # Jetpack, booted simulator -Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress -Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first +make sim-login # sign the running simulator into Jetpack +make sim-login APP=wordpress # WordPress instead of Jetpack +make sim-login RESET=1 # wipe existing app state first +make sim-login DEVICE= # target a specific simulator ``` -With no `--device`, the script targets the running simulator (and prompts if more than one is booted). There's also a `make` shortcut that forwards to it: `make sim-login`, with optional `DEVICE=`, `APP=wordpress`, `RESET=1`, or `ARGS="…"` for any other flags. +`make sim-login` forwards to `Scripts/sim-signin.sh`, which you can run directly with the same options as flags — `--app`, `--device`, `--reset`, `--wpcom-token` (or pass `ARGS="…"` through `make` for any flag without a dedicated variable): -To set the token once and drop it from the command line, export `WPCOM_TOKEN` (e.g. in `~/.zshrc`) or write it to `~/.wpcom-token`; the script uses either when `--wpcom-token` is omitted. If none is set, it prompts you to paste one and offers to save it to `~/.wpcom-token` for next time. +```bash +Scripts/sim-signin.sh --app wordpress --reset +``` + +The token is resolved from `--wpcom-token`, then `WPCOM_TOKEN`, then `~/.wpcom-token`; if none is set it prompts you to paste one and offers to save it to `~/.wpcom-token` for next time. Set it once — export `WPCOM_TOKEN` in `~/.zshrc`, or write `~/.wpcom-token` — to skip the token entirely. Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: From ef2cc96c137a0d814826ea6e6ededa197580971e Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:04:08 -0600 Subject: [PATCH 11/13] Drop "end-to-end" from the sign-in note in AGENTS.md --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2e20805b2bbb..cad7dcc6379e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,7 +41,7 @@ WordPress-iOS uses a modular architecture with the main app and separate Swift p - The WordPress scheme uses `WordPressUnitTests.xctestplan` for the full unit test suite, including tests in the `Modules` Swift package. - Add every unit test target to `WordPressUnitTests.xctestplan`. - Run the full suite with `xcodebuild -workspace WordPress.xcworkspace -scheme WordPress -testPlan WordPressUnitTests test`. Do not use `swift test`. -- To sign a Simulator into WordPress.com end-to-end, run `make sim-login` (it targets the running simulator; the WordPress.com token comes from `~/.wpcom-token` or `WPCOM_TOKEN`, and it prompts if none is set). See @docs/simulator-sign-in.md for options and self-hosted sign-in. +- To sign a Simulator into WordPress.com, run `make sim-login` (it targets the running simulator; the WordPress.com token comes from `~/.wpcom-token` or `WPCOM_TOKEN`, and it prompts if none is set). See @docs/simulator-sign-in.md for options and self-hosted sign-in. ### Important Considerations - **Multi-site Support**: Code must handle both WordPress.com and self-hosted sites From c1fffa37b2a56f20b01ab1cf07d0e8863f4fb2ce Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:46:32 -0600 Subject: [PATCH 12/13] Sign in from the launch token only once per process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signing out returns to the login screen, where `showSignInUI()` runs the auto sign-in again. With the `-wpcom-token` argument still present and the account now gone, both guards passed and it signed straight back in — a logout could never reach a logged-out state. Gate the auto sign-in on a per-process flag so it attempts at most once. --- WordPress/Classes/System/WordPressAppDelegate.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index b5d7c0690973..493677ba4ce5 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -63,6 +63,10 @@ public class WordPressAppDelegate: UIResponder, UIApplicationDelegate { private let remoteFeatureFlagStore = RemoteFeatureFlagStore() private let remoteConfigStore = RemoteConfigStore() + /// Limits the `-wpcom-token` launch-argument sign-in to a single attempt per process, + /// so signing out (which returns to the login screen) doesn't immediately re-sign in. + private var didAttemptLaunchArgumentSignIn = false + private var mainContext: NSManagedObjectContext { ContextManager.shared.mainContext } @@ -906,17 +910,24 @@ extension WordPressAppDelegate { /// `-wpcom-token` launch argument, so a Simulator can be signed in with a single /// `simctl launch` and no taps on the login screen. /// - /// No-op when the argument is absent or a WordPress.com account is already signed in. + /// No-op when the argument is absent, a WordPress.com account is already signed in, or a + /// launch-argument sign-in was already attempted this process. The last case matters because + /// signing out returns to the login screen — without it, the still-present token would + /// immediately sign the account back in. func autoSignInWPComAccountFromLaunchArgumentIfNeeded() { guard WordPressDotComAuthenticator.launchArgumentToken != nil else { return } + guard !didAttemptLaunchArgumentSignIn else { + return + } guard (try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext)) == nil else { return } guard let presenter = window?.topmostPresentedViewController else { return } + didAttemptLaunchArgumentSignIn = true Task { @MainActor in guard await WordPressDotComAuthenticator().signIn(from: presenter, context: .default) != nil else { return From 6a719d5926363faba67a92539af8b250e9394d39 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:47:05 -0600 Subject: [PATCH 13/13] Read the sign-in token only from the environment or a file A token passed on the command line is saved to shell history, so drop the `--wpcom-token` flag and the positional form. The token now comes only from `WPCOM_TOKEN`, `~/.wpcom-token`, or a hidden prompt. While here, two more fixes from review: - `--reset` now uninstalls and reinstalls the app rather than running the in-app `-ui-test-reset-everything` wipe. Reinstalling clears the whole data container (caches and cookies too) and is synchronous, so it drops the `sleep 2` that could race the wipe. - The booted-simulator scan no longer aborts under `set -e` when a line has no UUID; `|| true` lets the skip logic run as intended. --- Scripts/sim-signin.sh | 79 +++++++++++++++++++++++---------------- docs/simulator-sign-in.md | 10 +++-- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/Scripts/sim-signin.sh b/Scripts/sim-signin.sh index e481ba7f3b04..e581a170bdb9 100755 --- a/Scripts/sim-signin.sh +++ b/Scripts/sim-signin.sh @@ -13,26 +13,26 @@ usage() { Sign an iOS Simulator into WordPress.com with a bearer token, in one command. Usage: - Scripts/sim-signin.sh [options] --wpcom-token - Scripts/sim-signin.sh [options] + Scripts/sim-signin.sh [options] Options: - -t, --wpcom-token WordPress.com bearer token (or pass it positionally) -a, --app App to sign in (default: jetpack) -d, --device Target simulator (default: the running one; prompts if several) - -r, --reset Wipe existing app data before signing in + -r, --reset Uninstall and reinstall the app first, for a clean slate -h, --help Show this help Examples: - Scripts/sim-signin.sh --wpcom-token # Jetpack, booted simulator - Scripts/sim-signin.sh --app wordpress --wpcom-token # WordPress - Scripts/sim-signin.sh --reset --wpcom-token # wipe existing state first - -Set the token once and omit it from the command line. Resolution order: - 1. --wpcom-token (or positional) - 2. WPCOM_TOKEN environment variable - 3. ~/.wpcom-token file - 4. otherwise the script prompts you to paste one + Scripts/sim-signin.sh # Jetpack, booted simulator + Scripts/sim-signin.sh --app wordpress # WordPress + Scripts/sim-signin.sh --reset # reinstall for a clean slate first + +The WordPress.com bearer token is read from (in order): + 1. WPCOM_TOKEN environment variable + 2. ~/.wpcom-token file + 3. otherwise the script prompts you to paste one (and offers to save it to ~/.wpcom-token) + +It is deliberately NOT accepted as a command-line flag: a token passed on the command line +would be saved in your shell history. Set WPCOM_TOKEN or write ~/.wpcom-token once. EOF } @@ -41,14 +41,6 @@ device="" reset=false token="" -set_token() { - if [[ -n "$token" ]]; then - echo "error: token already set (got '$1')" >&2 - exit 1 - fi - token="$1" -} - require_value() { # $1 = option name, $2 = remaining argument count ($#) if [[ "$2" -lt 2 ]]; then @@ -62,7 +54,9 @@ resolve_device() { # prompt to choose. Errors if none are booted. Called only when --device was omitted. local udids=() names=() line udid name while IFS= read -r line; do - udid=$(printf '%s\n' "$line" | grep -oiE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1) + # `|| true` so a UUID-less line (or a SIGPIPE from `head` under `pipefail`) doesn't + # trip `set -e` and abort the whole script before the `continue` below can skip it. + udid=$(printf '%s\n' "$line" | grep -oiE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1 || true) [[ -z "$udid" ]] && continue name=$(printf '%s\n' "$line" | sed -E 's/^[[:space:]]*//; s/[[:space:]]*\([0-9A-Fa-f-]{36}\).*$//') udids+=("$udid") @@ -102,20 +96,42 @@ resolve_device() { done } +reset_app() { + # A clean slate: uninstall the app (which removes its entire data container — Core Data, + # UserDefaults, caches, cookies) and reinstall the same bundle. Unlike the in-app + # `-ui-test-reset-everything` wipe, `simctl install` is synchronous, so there's no window to + # race before the sign-in launch, and it clears more than just Core Data + UserDefaults. + local app_bundle bundle_name + app_bundle=$(xcrun simctl get_app_container "$device" "$bundle_id" app 2>/dev/null || true) + if [[ -z "$app_bundle" || ! -d "$app_bundle" ]]; then + echo "error: can't reset — $app ($bundle_id) isn't installed on '$device'. Build and install it first (e.g. from Xcode)." >&2 + exit 1 + fi + bundle_name=$(basename "$app_bundle") + + # Uninstall deletes the installed bundle in place, so stage a copy to reinstall from. + # `reset_staging` is intentionally global so the EXIT trap can clean it up at script exit. + reset_staging=$(mktemp -d) + trap 'rm -rf "$reset_staging"' EXIT + cp -R "$app_bundle" "$reset_staging/$bundle_name" + + echo "Resetting $app (uninstall + reinstall for a clean slate)…" + xcrun simctl uninstall "$device" "$bundle_id" + xcrun simctl install "$device" "$reset_staging/$bundle_name" +} + while [[ $# -gt 0 ]]; do case "$1" in - -t|--wpcom-token) require_value "$1" "$#"; set_token "$2"; shift 2 ;; -a|--app) require_value "$1" "$#"; app="$2"; shift 2 ;; -d|--device) require_value "$1" "$#"; device="$2"; shift 2 ;; -r|--reset) reset=true; shift ;; -h|--help) usage; exit 0 ;; - -*) echo "error: unknown option '$1'" >&2; usage >&2; exit 1 ;; - *) set_token "$1"; shift ;; + *) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;; esac done -# Fall back to a token set once elsewhere, so it needn't be passed every launch: -# the WPCOM_TOKEN environment variable, then a ~/.wpcom-token file. +# The token is read from the WPCOM_TOKEN environment variable, then a ~/.wpcom-token file. +# It is intentionally not a command-line argument, to keep it out of shell history. if [[ -z "$token" ]]; then token="${WPCOM_TOKEN:-}" fi @@ -125,7 +141,7 @@ fi # Nothing found anywhere — prompt for one. Input is hidden, since it's a secret. if [[ -z "$token" ]]; then - printf "No WordPress.com token found (--wpcom-token / WPCOM_TOKEN / ~/.wpcom-token).\n" >&2 + printf "No WordPress.com token found (WPCOM_TOKEN / ~/.wpcom-token).\n" >&2 printf "Paste a bearer token (hidden), or press Return to cancel: " >&2 read -rs token || true printf "\n" >&2 @@ -148,7 +164,7 @@ if [[ -z "$token" ]]; then fi if [[ -z "$token" ]]; then - echo "error: no token — pass --wpcom-token , set WPCOM_TOKEN, write ~/.wpcom-token, or paste one when prompted" >&2 + echo "error: no token — set WPCOM_TOKEN, write ~/.wpcom-token, or paste one when prompted" >&2 usage >&2 exit 1 fi @@ -167,10 +183,7 @@ fi echo "Signing $app ($bundle_id) into WordPress.com on simulator '$device'…" if [[ "$reset" == true ]]; then - echo "Resetting app data…" - xcrun simctl launch --terminate-running-process "$device" "$bundle_id" -ui-test-reset-everything - # Give the app a moment to wipe Core Data + UserDefaults before relaunching. - sleep 2 + reset_app fi xcrun simctl launch --terminate-running-process "$device" "$bundle_id" -wpcom-token "$token" diff --git a/docs/simulator-sign-in.md b/docs/simulator-sign-in.md index ec048a0469c6..ca4a14f81d57 100644 --- a/docs/simulator-sign-in.md +++ b/docs/simulator-sign-in.md @@ -9,17 +9,19 @@ The quickest path is **`make sim-login`** — it signs the running simulator int ```bash make sim-login # sign the running simulator into Jetpack make sim-login APP=wordpress # WordPress instead of Jetpack -make sim-login RESET=1 # wipe existing app state first +make sim-login RESET=1 # reinstall the app first (clean slate) make sim-login DEVICE= # target a specific simulator ``` -`make sim-login` forwards to `Scripts/sim-signin.sh`, which you can run directly with the same options as flags — `--app`, `--device`, `--reset`, `--wpcom-token` (or pass `ARGS="…"` through `make` for any flag without a dedicated variable): +`make sim-login` forwards to `Scripts/sim-signin.sh`, which you can run directly with the same options as flags — `--app`, `--device`, `--reset`: ```bash Scripts/sim-signin.sh --app wordpress --reset ``` -The token is resolved from `--wpcom-token`, then `WPCOM_TOKEN`, then `~/.wpcom-token`; if none is set it prompts you to paste one and offers to save it to `~/.wpcom-token` for next time. Set it once — export `WPCOM_TOKEN` in `~/.zshrc`, or write `~/.wpcom-token` — to skip the token entirely. +`--reset` uninstalls and reinstalls the app for a clean slate — more thorough than the in-app data wipe (it also clears caches and cookies) and race-free (the reinstall is synchronous). The app must already be installed. + +The token is resolved from `WPCOM_TOKEN`, then `~/.wpcom-token`; if none is set the script prompts you to paste one (hidden) and offers to save it to `~/.wpcom-token` for next time. There's deliberately no command-line token flag — a token passed as an argument would be saved in your shell history. Set it once (export `WPCOM_TOKEN` in `~/.zshrc`, or write `~/.wpcom-token`) and you never pass it again. Or launch directly with the bearer token. The app finishes sign-in automatically while it sits on the login screen — no taps required: @@ -30,6 +32,8 @@ xcrun simctl launch --terminate-running-process booted org.wordpress \ The legacy `-ui-test-wpcom-token` argument is still accepted for backward compatibility. +This raw form also saves the token in your shell history — `make sim-login` avoids that, since you never type the token. (Either way the token appears briefly in `ps` while `simctl launch` runs; that's inherent to passing it as a launch argument.) + ## Self-hosted site Launch with the site URL, a username, and an application password: