From 17cf3a2a308e6126dbc56da475907e93efbbcc03 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 27 May 2026 11:16:02 +1000 Subject: [PATCH 1/6] Add Apps CDN visibility helper Encodes the rule that Nightly full installers are restricted to logged-in Automatticians (so the planned `/nightly` CDN link only resolves for internal users), while updates and all Beta/Production builds stay external. The helper is unused for now; the Fastfile change that calls it lands in the next commit so the move and the behavior change stay reviewable separately. Tests run with bare `ruby fastlane/test/studio_apps_cdn_upload_test.rb` (Minitest is stdlib). Related to AINFRA-2434. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 4.7 (1M context) --- fastlane/lib/studio_apps_cdn_upload.rb | 16 +++++++++ fastlane/test/studio_apps_cdn_upload_test.rb | 35 ++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 fastlane/lib/studio_apps_cdn_upload.rb create mode 100644 fastlane/test/studio_apps_cdn_upload_test.rb diff --git a/fastlane/lib/studio_apps_cdn_upload.rb b/fastlane/lib/studio_apps_cdn_upload.rb new file mode 100644 index 0000000000..444c74281b --- /dev/null +++ b/fastlane/lib/studio_apps_cdn_upload.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module StudioAppsCdnUpload + # Returns the Apps CDN visibility (`'internal'` or `'external'`) for a build. + # + # Nightly full installers are restricted to logged-in Automatticians via the + # Apps CDN visibility filter, so the `/nightly` link only resolves for + # internal users. Update binaries stay external — the in-app auto-updater is + # unauthenticated and would otherwise stop seeing nightly updates. Beta and + # Production stay external across the board. + def self.visibility_for(build_type:, install_type:) + return 'internal' if build_type == 'Nightly' && install_type == 'Full Install' + + 'external' + end +end diff --git a/fastlane/test/studio_apps_cdn_upload_test.rb b/fastlane/test/studio_apps_cdn_upload_test.rb new file mode 100644 index 0000000000..f28e58a1d9 --- /dev/null +++ b/fastlane/test/studio_apps_cdn_upload_test.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Sanity checks for fastlane/lib/studio_apps_cdn_upload.rb. +# +# Run with: `ruby fastlane/test/studio_apps_cdn_upload_test.rb` +# (No bundle / fastlane required — minitest ships with stdlib Ruby.) + +require 'minitest/autorun' +require_relative '../lib/studio_apps_cdn_upload' + +class StudioAppsCdnUploadTest < Minitest::Test + def test_nightly_full_install_is_internal + assert_equal 'internal', StudioAppsCdnUpload.visibility_for(build_type: 'Nightly', install_type: 'Full Install') + end + + def test_nightly_update_is_external + assert_equal 'external', StudioAppsCdnUpload.visibility_for(build_type: 'Nightly', install_type: 'Update') + end + + def test_beta_full_install_is_external + assert_equal 'external', StudioAppsCdnUpload.visibility_for(build_type: 'Beta', install_type: 'Full Install') + end + + def test_beta_update_is_external + assert_equal 'external', StudioAppsCdnUpload.visibility_for(build_type: 'Beta', install_type: 'Update') + end + + def test_production_full_install_is_external + assert_equal 'external', StudioAppsCdnUpload.visibility_for(build_type: 'Production', install_type: 'Full Install') + end + + def test_production_update_is_external + assert_equal 'external', StudioAppsCdnUpload.visibility_for(build_type: 'Production', install_type: 'Update') + end +end From 4345e69e18ad0ba5c7cedd48c4749491a14a67b5 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 27 May 2026 11:16:11 +1000 Subject: [PATCH 2/6] Upload nightly full installers to Apps CDN Trunk Buildkite builds already produce DMG/EXE/APPX installers; the `distribute_builds` lane was only uploading the auto-updater payloads (`.app.zip`, `.nupkg`). As a result the planned `/nightly` CDN link had nothing installable to resolve to. Uploading full installers on every build (not only when `release_tag` is set) unblocks AINFRA-2434. Visibility is decided via `StudioAppsCdnUpload.visibility_for`, so nightly full installs are Internal (Automatticians only) while updates stay External (the in-app auto-updater is unauthenticated and would otherwise stop seeing nightly updates). Related to AINFRA-2434. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 4.7 (1M context) --- fastlane/Fastfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 443ace5e2b..1828aec571 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -7,6 +7,7 @@ fastlane_require 'json' fastlane_require 'net/http' fastlane_require 'uri' +require_relative 'lib/studio_apps_cdn_upload' require_relative 'lib/studio_release_git' require_relative 'lib/studio_release_version' @@ -712,12 +713,14 @@ def distribute_builds( } } - builds_to_upload = release_tag.nil? ? update_builds : { **update_builds, **full_install_builds } + builds_to_upload = { **update_builds, **full_install_builds } - UI.message("Uploading #{builds_to_upload.count} builds (#{release_tag.nil? ? 'dev: updates only' : 'release: all builds'})") + UI.message("Uploading #{builds_to_upload.count} builds (#{build_type})") # Upload to Apps CDN builds_to_upload.each_value do |build| + visibility = StudioAppsCdnUpload.visibility_for(build_type: build_type, install_type: build[:install_type]) + result = upload_file_to_apps_cdn( site_id: WPCOM_STUDIO_SITE_ID, product: 'WordPress.com Studio', @@ -726,7 +729,7 @@ def distribute_builds( arch: build[:arch], build_type: build_type, install_type: build[:install_type], - visibility: 'external', + visibility: visibility, version: version, build_number: build_number, release_notes: release_notes, From 21233ae3ef1092041ca8c0295e1ec0fcd70e41fb Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 27 May 2026 11:16:20 +1000 Subject: [PATCH 3/6] Run fastlane helper tests in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App-validation jobs (lint/unit/e2e) treat `fastlane/**` and Gemfile-ish paths as non-code and skip on fastlane-only PRs — sensible for them, but it leaves the helper tests under `fastlane/test/` unprotected. Adds a `fastlane` job type that is the inverse of the existing skip rules: it runs only when at least one changed file is fastlane/ or Ruby setup related, via `pr_changed_files --any-match`. The new pipeline step sits next to Lint, on the Mac queue, and shells out to `bash` so it doesn't need the script's exec bit. Related to AINFRA-2434. --- Generated with the help of Claude Code, https://claude.ai/code Co-Authored-By: Claude Opus 4.7 (1M context) --- .buildkite/commands/run-fastlane-tests.sh | 13 ++++++++++++ .buildkite/commands/should-skip-job.sh | 26 +++++++++++++++++++++-- .buildkite/pipeline.yml | 10 +++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100755 .buildkite/commands/run-fastlane-tests.sh diff --git a/.buildkite/commands/run-fastlane-tests.sh b/.buildkite/commands/run-fastlane-tests.sh new file mode 100755 index 0000000000..b648ac0e8c --- /dev/null +++ b/.buildkite/commands/run-fastlane-tests.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if .buildkite/commands/should-skip-job.sh --job-type fastlane; then + exit 0 +fi + +echo '--- :ruby: Run Fastlane Helper Tests' +# Tests use stdlib minitest and don't require bundler — see fastlane/test/*. +for test_file in fastlane/test/*_test.rb; do + ruby "$test_file" +done diff --git a/.buildkite/commands/should-skip-job.sh b/.buildkite/commands/should-skip-job.sh index c2fcb47a4e..a5d403f057 100755 --- a/.buildkite/commands/should-skip-job.sh +++ b/.buildkite/commands/should-skip-job.sh @@ -14,6 +14,8 @@ set -eu # Since metrics measure app performance, test file changes don't affect them. # - build: Skip if changes are limited to documentation and config files. # Does NOT skip on localization changes since builds should include translation updates. +# - fastlane: Inverse of the others — only runs when fastlane/ or Ruby setup files change. +# Used for the standalone tests in fastlane/test/. App-only PRs skip it. # # Exit codes: # 0 - Job should be skipped @@ -76,6 +78,17 @@ TEST_PATTERNS=( "metrics/**" ) +# Fastlane / Ruby setup files - changes here affect the standalone fastlane +# helper tests. Anything that the test runner reads (Fastfile, lib/, test/) or +# that defines the Ruby environment belongs here. +FASTLANE_PATTERNS=( + "fastlane/**" + "Gemfile" + "Gemfile.lock" + ".ruby-version" + ".bundle/**" +) + show_skip_message() { local job_type=$1 local job_label="${BUILDKITE_LABEL:-$job_type}" @@ -107,7 +120,7 @@ done if [[ -z "$job_type" ]]; then echo "Error: --job-type is required" - echo "Usage: should-skip-job.sh --job-type " + echo "Usage: should-skip-job.sh --job-type " exit 1 fi @@ -147,9 +160,18 @@ case "$job_type" in fi ;; + "fastlane") + # Run only if at least one changed file is fastlane/ or Ruby-setup-related. + # Other job types treat fastlane changes as non-code; this one is the inverse. + if ! pr_changed_files --any-match "${FASTLANE_PATTERNS[@]}"; then + show_skip_message "$job_type" + exit 0 + fi + ;; + *) echo "Unknown job type: $job_type" - echo "Valid types: validation, metrics, build" + echo "Valid types: validation, metrics, build, fastlane" exit 1 ;; esac diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 4571f68666..eb37dec18e 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -38,6 +38,16 @@ steps: - github_commit_status: context: Lint + - label: ":ruby: Fastlane Helper Tests" + agents: + queue: mac + key: fastlane_tests + command: bash .buildkite/commands/run-fastlane-tests.sh + plugins: [$CI_TOOLKIT_PLUGIN] + notify: + - github_commit_status: + context: Fastlane Helper Tests + - label: Unit Tests on {{matrix}} key: unit_tests command: bash .buildkite/commands/run-unit-tests.sh "{{matrix}}" From 5793b436ecfe1d7996536c84667c2ffa6d162481 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 27 May 2026 11:34:07 +1000 Subject: [PATCH 4/6] Include CI script in fastlane patters driving CI execution Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .buildkite/commands/should-skip-job.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.buildkite/commands/should-skip-job.sh b/.buildkite/commands/should-skip-job.sh index a5d403f057..9b870fcc32 100755 --- a/.buildkite/commands/should-skip-job.sh +++ b/.buildkite/commands/should-skip-job.sh @@ -79,14 +79,17 @@ TEST_PATTERNS=( ) # Fastlane / Ruby setup files - changes here affect the standalone fastlane -# helper tests. Anything that the test runner reads (Fastfile, lib/, test/) or -# that defines the Ruby environment belongs here. +# helper tests. Anything that the test runner reads (Fastfile, lib/, test/), +# that defines the Ruby environment, or that implements this CI job's runner / +# skip logic belongs here. FASTLANE_PATTERNS=( "fastlane/**" "Gemfile" "Gemfile.lock" ".ruby-version" ".bundle/**" + ".buildkite/commands/run-fastlane-tests.sh" + ".buildkite/commands/should-skip-job.sh" ) show_skip_message() { From f07e158e63a9c29caa03eaac265c2e1dcef28efb Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 27 May 2026 11:36:36 +1000 Subject: [PATCH 5/6] s/Fastlane/fastlane/ Co-authored-by: Gio Lodi --- .buildkite/commands/run-fastlane-tests.sh | 2 +- .buildkite/pipeline.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.buildkite/commands/run-fastlane-tests.sh b/.buildkite/commands/run-fastlane-tests.sh index b648ac0e8c..1ad23a3016 100755 --- a/.buildkite/commands/run-fastlane-tests.sh +++ b/.buildkite/commands/run-fastlane-tests.sh @@ -6,7 +6,7 @@ if .buildkite/commands/should-skip-job.sh --job-type fastlane; then exit 0 fi -echo '--- :ruby: Run Fastlane Helper Tests' +echo '--- :fastlane: Run fastlane Helper Tests' # Tests use stdlib minitest and don't require bundler — see fastlane/test/*. for test_file in fastlane/test/*_test.rb; do ruby "$test_file" diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index eb37dec18e..9bdeafbaee 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -38,7 +38,7 @@ steps: - github_commit_status: context: Lint - - label: ":ruby: Fastlane Helper Tests" + - label: ":fastlane: fastlane Helper Tests" agents: queue: mac key: fastlane_tests @@ -46,7 +46,7 @@ steps: plugins: [$CI_TOOLKIT_PLUGIN] notify: - github_commit_status: - context: Fastlane Helper Tests + context: fastlane Helper Tests - label: Unit Tests on {{matrix}} key: unit_tests From 6113477567416fcc99988c1d163a4d67c19b1c49 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 27 May 2026 11:36:51 +1000 Subject: [PATCH 6/6] Remove noisy comment --- .buildkite/commands/run-fastlane-tests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.buildkite/commands/run-fastlane-tests.sh b/.buildkite/commands/run-fastlane-tests.sh index 1ad23a3016..3bfd1eb0fa 100755 --- a/.buildkite/commands/run-fastlane-tests.sh +++ b/.buildkite/commands/run-fastlane-tests.sh @@ -7,7 +7,6 @@ if .buildkite/commands/should-skip-job.sh --job-type fastlane; then fi echo '--- :fastlane: Run fastlane Helper Tests' -# Tests use stdlib minitest and don't require bundler — see fastlane/test/*. for test_file in fastlane/test/*_test.rb; do ruby "$test_file" done