qasim
September 12, 2026, 3:11am
1
Continuing the discussion from Indicate that internal targets prefer replacement with binary cache :
Expanding on this, I ran into a scenario where we needed to allowlist a specific set of external targets for replacement rather than the entire set of external targets. I’ve proposed a change here to have the except/and parameters to apply to external targets the same way they do for internal targets:
main ← qasim:qasim/cache-profile-include-external-targets
opened 03:56PM - 11 Sep 26 UTC
Building on <https://github.com/tuist/tuist/pull/8122> and the original [cache p… rofiles proposal](https://community.tuist.dev/t/indicate-that-internal-targets-prefer-replacement-with-binary-cache/701), this PR proposes extending `and:` target queries to external targets.
The original feature focused on selecting internal targets for binary replacement. This change makes the existing additive behavior consistent regardless of whether a target belongs to a local or external project.
## What changed
Cache profile target queries supplied through `and:` now apply to external as well as internal targets.
This allows a profile such as `.profile(.none, and: ["ExternalTarget"])` to make selected external targets eligible for cached binary replacement. Name and tag queries are both supported, and exclusions continue to take precedence.
## Why
The implementation currently evaluates `and:` queries only for local projects, while external targets are governed entirely by the base profile. As a result, a `.none` profile can selectively replace internal targets but not external targets, even when an external target matches one of its queries.
Since `and:` adds targets to the base profile and target queries do not otherwise distinguish between local and external targets, applying them consistently removes that implicit restriction without introducing a new API.
## Compatibility
The behavior changes only for custom profiles based on `.none` whose `and:` queries match an external target. Non-matching external targets remain source-based, while `.onlyExternal` and `.allPossible` profiles are unchanged because they already replace external targets.
## Validation
- Added coverage for matching external targets by name and tag, as well as a non-matching external target.
- `CacheProfileTargetReplacementDeciderTests`: 17 tests passed.
- `git diff --check`
There is a risk here that this changes expectations for people in the rare case that they have an external target in one of these lists in their custom profile definitions, as before it would do nothing but now it would actually apply. I think that risk is pretty minimal though, and may even be what some expect without looking at the code.