Skip to content

[Build] Skip Remote Build Cache When Secrets Are Missing#16265

Open
ParaskP7 wants to merge 2 commits into
trunkfrom
build/skip-remote-build-cache-when-secrets-missing
Open

[Build] Skip Remote Build Cache When Secrets Are Missing#16265
ParaskP7 wants to merge 2 commits into
trunkfrom
build/skip-remote-build-cache-when-secrets-missing

Conversation

@ParaskP7

@ParaskP7 ParaskP7 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Closes: AINFRA-2560


Description

A fresh git clone of this repo cannot build the debug variant. ./gradlew assembleJalapenoDebug aborts during settings evaluation with:

The build requested remote build cache, but secrets file is not found. Please run bundle exec fastlane run configure_apply to apply secrets.

The cause is the combination of two deliberate behaviors: developer.properties-example ships with use_remote_build_cache_locally=true (a deliberate default from #15189, which this PR keeps), and settings.gradle falls back to that example when the developer has no developer.properties of their own — so every fresh clone implicitly "requests" the remote build cache and then hard-fails on the missing secrets it can never have. External contributors and secret-less machines are blocked before any task runs, even though the rest of the build degrades gracefully (secrets.propertiesdefaults.properties, google-services.json → example file).

This PR contains two commits:

  1. Register the remote build cache only when secrets are applied. When they are missing, a developer who explicitly opted in via their own developer.properties file still gets the hard stop (they are expected to have secrets), while a fresh clone — where the flag is true only through the example fallback — gets a warning and continues with the local build cache. Developers with secrets applied keep the default-on remote build cache unchanged, and checkForRemoteBuildCacheOptimizedExperience() stays aligned with the shared implementation in JP/WPAndroid. cd3de6d
  2. Drop install_gems + configure_apply from the CI jobs that do not need secrets (unit tests, gradle cache, manifest diff), so CI stops exposing secrets to jobs that never consume them and permanently exercises the same no-secrets path a fresh clone goes through. The jobs that genuinely need secrets keep them: release builds (upload keystore, Play Store credentials, sentry.properties), instrumented tests (the Firebase Test Lab service account at .configure-files/firebase.secrets.json plus real e2e API credentials), and prototype builds (the distributed APK must carry real OAuth and google-services values and be signed with the shared debug keystore). 88d0a0d

The resulting behavior matrix when use_remote_build_cache_locally=true:

Scenario Before After
CI Remote cache via env var Unchanged
Secrets applied Optimized-experience checks + remote cache Unchanged
No secrets, own developer.properties Hard stop Unchanged (hard stop)
No secrets, fresh clone (example fallback) Hard stop ⚠️ Warning, local cache only

Considered alternatives

  • Flipping use_remote_build_cache_locally=false in developer.properties-example fixes the fresh clone too, but reverts the deliberate default-on decision from #15189, so it was discarded.
  • Warning for everyone (no hard stop at all): simplest, but an internal developer who forgot configure_apply would silently lose the remote cache behind an easily-ignored warning — the hard stop exists precisely for them.
  • Distinguishing internal developers via git config user.email ending in @automattic.com/@a8c.com: identity-based and covers new machines, but adds process execution to settings evaluation; kept as a fallback idea.
  • Probing for internal-infra directories (e.g. the configure tool's output directory) was rejected outright — we do not want a public build script to reference internal secrets-infrastructure layout.

The chosen design (hard stop only behind an explicit, personally-created developer.properties) matches the semantics JP/WPAndroid already has: an explicit request for a secrets-dependent feature may fail hard; an implicit default never should.


Test Steps

All on a machine without applied secrets (~/.configure/woocommerce-android/secrets/secrets.properties absent):

  1. Fresh clone (no developer.properties): ./gradlew assembleJalapenoDebug succeeds and logs the ⚠️ remote-cache warning.
  2. Create developer.properties with use_remote_build_cache_locally=true: ./gradlew help fails with the original configure_apply error.
  3. Flip it to false: ./gradlew help succeeds with the plain ℹ️ disabled message.
  4. With secrets applied: behavior is unchanged (remote cache + optimized-experience checks).
  5. CI on this PR: the unit tests, gradle cache, and manifest diff jobs run without configure_apply and pass.
    • Manual Dependency Cache Build: 40672

Images/gif

N/A — build and CI configuration only.


  • I have considered if this change warrants release notes and have added them to RELEASE-NOTES.txt if necessary. Use the "[Internal]" label for non-user-facing changes.

ParaskP7 added 2 commits July 15, 2026 18:05
Fresh clones request the remote build cache by default
(use_remote_build_cache_locally=true in developer.properties-example)
but have no secrets applied, so settings evaluation failed with "The
build requested remote build cache, but secrets file is not found"
before any task could run — blocking external contributors entirely.

Register the remote build cache only when secrets are applied. When
they are missing, only a developer who explicitly opted in via their
own developer.properties file still gets the hard stop, since they
are expected to have secrets; when the flag is true only through the
committed developer.properties-example fallback (a fresh clone), log
a warning and continue with the local build cache instead. Developers
with secrets applied keep the default-on remote build cache unchanged.
The unit tests, gradle cache, and merged manifest diff jobs only run
Gradle tasks that work without secrets: build properties fall back to
the committed defaults.properties, google-services.json falls back to
its committed example file, and the remote build cache on CI
authenticates via the GRADLE_CACHE_NODE_PASSWORD environment variable
rather than the secrets file. Removing the gems and secrets setup
from these jobs stops exposing secrets to jobs that do not need them
and makes CI exercise the same no-secrets path that a fresh clone
goes through, guarding it against future hard secrets dependencies.

The other jobs keep configure_apply for a reason each: release-build
obviously needs the upload keystore, the Play Store credentials, and
sentry.properties for the source context upload; run-instrumented-
tests needs .configure-files/firebase.secrets.json (the Firebase Test
Lab service account Fladle authenticates with, which only exists
after configure_apply) plus the real e2e API credentials baked into
the instrumentation arguments; prototype-build only builds a
JalapenoDebug APK that would compile without secrets, but the
artifact is distributed to testers and must carry real OAuth and
google-services values and be signed with the shared debug keystore
to stay functional and updatable across CI agents.
@ParaskP7 ParaskP7 added this to the 25.3 milestone Jul 15, 2026
@ParaskP7
ParaskP7 requested a review from Copilot July 15, 2026 15:33
@ParaskP7 ParaskP7 added category: tooling Anything that involves building & maintaining the project, including scripts, `Fastfile`, etc. type: technical debt Represents or solves tech debt of the project. Core labels Jul 15, 2026
@dangermattic

Copy link
Copy Markdown
Collaborator
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts build configuration so local developers (and CI) don’t fail hard when remote build cache is requested but secrets haven’t been applied, and removes redundant secrets installation from several Buildkite commands.

Changes:

  • Gate local remote build cache configuration behind a secretsApplied() check, with a warning-only fallback for fresh clones.
  • Refactor secrets checking by introducing a secretsApplied() helper and reusing it in assertSecretsApplied().
  • Remove configure_apply (and gem setup) from select Buildkite commands that only run Gradle tasks.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
settings.gradle Skips configuring local remote build cache when secrets are missing; refactors secrets checks into a helper.
.buildkite/commands/run-unit-tests.sh Stops installing secrets/gems before running unit tests.
.buildkite/commands/gradle-cache-build.sh Stops installing secrets/gems before assembling debug build for cache priming.
.buildkite/commands/diff-merged-manifest.sh Stops installing secrets/gems before generating merged manifest diffs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread settings.gradle
@wpmobilebot

Copy link
Copy Markdown
Collaborator

App Icon📲 You can test the changes from this Pull Request in WooCommerce Android by scanning the QR code below to install the corresponding build.

App NameWooCommerce Android
Platform📱 Mobile
FlavorJalapeno
Build TypeDebug
Build Number772
Version25.2-rc-1
Application IDcom.woocommerce.android.prealpha
Commit88d0a0d
Installation URL48dterdtophso
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 41.15%. Comparing base (552970e) to head (88d0a0d).
⚠️ Report is 18 commits behind head on trunk.

Additional details and impacted files
@@            Coverage Diff            @@
##              trunk   #16265   +/-   ##
=========================================
  Coverage     41.15%   41.15%           
- Complexity    13501    13502    +1     
=========================================
  Files          2503     2503           
  Lines        146465   146465           
  Branches      21761    21761           
=========================================
+ Hits          60278    60279    +1     
  Misses        80089    80089           
+ Partials       6098     6097    -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@wpmobilebot

Copy link
Copy Markdown
Collaborator

App Icon📲 You can test the changes from this Pull Request in WooCommerce-Wear Android by scanning the QR code below to install the corresponding build.

App NameWooCommerce-Wear Android
Platform⌚️ Wear OS
FlavorJalapeno
Build TypeDebug
Commit88d0a0d
Direct Downloadwoocommerce-wear-prototype-build-pr16265-88d0a0d.apk

@ParaskP7
ParaskP7 marked this pull request as ready for review July 15, 2026 16:02
@ParaskP7
ParaskP7 requested a review from a team as a code owner July 15, 2026 16:02
@ParaskP7
ParaskP7 requested review from malinajirka and wzieba July 15, 2026 16:02

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Code Review - Found 1 potential issue.

I also investigated the concern raised by Copilot on settings.gradle and confirmed it is valid — details in the inline comment below.

PR housekeeping
  • Build-tooling / CI change (gradle build cache config + Buildkite scripts); no app-behaviour test plan required. The PR description clearly explains the what and why.
  • Investigated Copilot's inline review comment on settings.gradle and confirmed it with evidence from developer.properties-example and the property-merge logic.

Automatic review · claude-opus-4-8 · Workflow run

How to reply to a finding

Reply on this review (or inline at the line the finding refers to) with one of:

  • @claude addressed - I made the change. Bot verifies against the next diff before marking resolved.
  • @claude rejected: <reason> - Will not fix; reason gets quoted on the next review.
  • @claude not-applicable - Finding does not apply (wrong file, already covered elsewhere, etc.).

The bot honours these on the next review pass.

Comment thread settings.gradle
Comment thread settings.gradle
Comment on lines +84 to +98
if (secretsApplied()) {
checkForRemoteBuildCacheOptimizedExperience()

remote(HttpBuildCache) {
url = gradle.ext.secretProperties.get('gradleCacheNodeUrl')
push = false
credentials {
username = "developer"
password = gradle.ext.secretProperties.get('gradleCacheNodePassword')
}
}
} else if (file("${rootDir}/developer.properties").exists()) {
// The developer explicitly opted in to the remote build cache via their own
// developer.properties file, so they are expected to have secrets applied.
assertSecretsApplied()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure about the code flow here. The way I read it is:

if secretsApplied {
  ...
} else if ... {
 assertSecretsApplied // throws if secretsApplied == false
...

So, the else if branch runs only if secretsApplied == false but then it checks for the secrets to be applied, which we already know to be false, resulting in a throw.

What am I missing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👋 @mokagio and thanks for this comment, your reading is exactly right and the always-throws is intentional! The else if isn't there to re-check the secrets, it is there to distinguish who is missing them:

  • A developer with their own developer.properties (created by copying developer.properties-example, i.e. explicitly accepting the use_remote_build_cache_locally=true opt-in) but without secrets applied. That's almost certainly an internal developer who forgot configure_apply, and for them the branch deliberately keeps the pre-existing hard stop, with its actionable message.
  • A fresh clone (no personal developer.properties, the flag is true only via the developer.properties-example fallback) never reaches that branch. It falls through to the else below and gets the ⚠️ warn-and-continue instead, which is the whole point of this PR.

So in that branch assertSecretsApplied() is effectively "fail with the canonical message": we know it will throw, and calling it (instead of inlining a throw) keeps the error message defined in one place and checkForRemoteBuildCacheOptimizedExperience() byte-identical to JP/WPAndroid's. There's more on the why (and the rejected alternatives) in the PR description's "Considered alternatives" section, plus the bot thread above where the "own developer.properties = explicit opt-in" contract is spelled out.

Let me know what you think, happy to revisit, but indeed, I thoughts about this, on various angled, before deciding to go with this approach. 💭


FYI: It is traveling day for me today, I might be slow to reply.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @mokagio 's right on the flow and I'm not sure if the answer above addressed the concern: I don't think "asserting secrets applied after we check that secrets don't exist" is helpful here in any way.

Maybe instead, you just want a throw on line 98?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category: tooling Anything that involves building & maintaining the project, including scripts, `Fastfile`, etc. Core type: technical debt Represents or solves tech debt of the project.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants