Skip to content

Commit 42f6002

Browse files
committed
Add a --build flag to buck2 test
1 parent 350dada commit 42f6002

File tree

3 files changed

+41
-26
lines changed

3 files changed

+41
-26
lines changed

app/buck2_cli_proto/daemon.proto

+3
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ message TestRequest {
472472

473473
// Should you add tests that are on the `tests` attribute of the target.
474474
bool ignore_tests_attribute = 13;
475+
476+
// Whether all targets matching `target_patterns` should be built instead of only test ones.
477+
bool build = 15;
475478
}
476479

477480
message BxlRequest {

app/buck2_client/src/commands/test.rs

+4
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ If include patterns are present, regardless of whether exclude patterns are pres
157157
#[clap(long)]
158158
test_executor_stderr: Option<OutputDestinationArg>,
159159

160+
#[clap(long)]
161+
build: bool,
162+
160163
/// Additional arguments passed to the test executor.
161164
///
162165
/// Test executor is expected to have `--env` flag to pass environment variables.
@@ -225,6 +228,7 @@ impl StreamingCommand for TestCommand {
225228
.transpose()
226229
.context("Invalid `timeout`")?,
227230
ignore_tests_attribute: self.ignore_tests_attribute,
231+
build: self.build,
228232
},
229233
ctx.stdin()
230234
.console_interaction_stream(&self.common_opts.console_opts),

app/buck2_test/src/command.rs

+34-26
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use buck2_build_api::analysis::calculation::RuleAnalysisCalculation;
2020
use buck2_build_api::artifact_groups::calculation::ArtifactGroupCalculation;
2121
use buck2_build_api::artifact_groups::ArtifactGroup;
2222
use buck2_build_api::interpreter::rule_defs::cmd_args::SimpleCommandLineArtifactVisitor;
23+
use buck2_build_api::interpreter::rule_defs::provider::builtin::default_info::FrozenDefaultInfo;
2324
use buck2_build_api::interpreter::rule_defs::provider::collection::FrozenProviderCollection;
2425
use buck2_build_api::interpreter::rule_defs::provider::test_provider::TestProvider;
2526
use buck2_cli_proto::HasClientContext;
@@ -354,6 +355,7 @@ async fn test(
354355
.transpose()
355356
.context("Invalid `duration`")?;
356357

358+
let only_build_tests = !request.build;
357359
let test_outcome = test_targets(
358360
ctx,
359361
resolved_pattern,
@@ -373,6 +375,7 @@ async fn test(
373375
MissingTargetBehavior::from_skip(build_opts.skip_missing_targets),
374376
timeout,
375377
request.ignore_tests_attribute,
378+
only_build_tests,
376379
)
377380
.await?;
378381

@@ -448,6 +451,7 @@ async fn test_targets(
448451
missing_target_behavior: MissingTargetBehavior,
449452
timeout: Option<Duration>,
450453
ignore_tests_attribute: bool,
454+
only_build_tests: bool,
451455
) -> anyhow::Result<TestOutcome> {
452456
let session = Arc::new(session);
453457

@@ -531,6 +535,7 @@ async fn test_targets(
531535
working_dir_cell,
532536
missing_target_behavior,
533537
ignore_tests_attribute,
538+
only_build_tests,
534539
});
535540

536541
driver.push_pattern(
@@ -657,6 +662,7 @@ pub(crate) struct TestDriverState<'a, 'e> {
657662
working_dir_cell: CellName,
658663
missing_target_behavior: MissingTargetBehavior,
659664
ignore_tests_attribute: bool,
665+
only_build_tests: bool,
660666
}
661667

662668
/// Maintains the state of an ongoing test execution.
@@ -839,6 +845,7 @@ impl<'a, 'e> TestDriver<'a, 'e> {
839845
state.label_filtering.dupe(),
840846
state.cell_resolver,
841847
state.working_dir_cell,
848+
state.only_build_tests,
842849
)
843850
.await?;
844851
anyhow::Ok(vec![])
@@ -893,17 +900,18 @@ async fn test_target(
893900
label_filtering: Arc<TestLabelFiltering>,
894901
cell_resolver: &CellResolver,
895902
working_dir_cell: CellName,
903+
only_build_tests: bool,
896904
) -> anyhow::Result<Option<ConfiguredProvidersLabel>> {
897905
// NOTE: We fail if we hit an incompatible target here. This can happen if we reach an
898906
// incompatible target via `tests = [...]`. This should perhaps change, but that's how it works
899907
// in v1: https://fb.workplace.com/groups/buckeng/posts/8520953297953210
900908
let frozen_providers = ctx.get_providers(&target).await?.require_compatible()?;
901909
let providers = frozen_providers.provider_collection();
902-
build_artifacts(ctx, providers, &label_filtering).await?;
910+
build_artifacts(ctx, providers, &label_filtering, only_build_tests).await?;
903911

904912
let fut = match <dyn TestProvider>::from_collection(providers) {
905913
Some(test_info) => {
906-
if skip_run_based_on_labels(test_info, &label_filtering) {
914+
if label_filtering.is_excluded(test_info.labels()) {
907915
return Ok(None);
908916
}
909917
run_tests(
@@ -929,46 +937,46 @@ async fn test_target(
929937
fut.await
930938
}
931939

932-
fn skip_run_based_on_labels(
933-
provider: &dyn TestProvider,
940+
fn skip_build_based_on_labels<'a>(
941+
labels_fn: &dyn Fn() -> Vec<&'a str>,
934942
label_filtering: &TestLabelFiltering,
935943
) -> bool {
936-
let target_labels = provider.labels();
937-
label_filtering.is_excluded(target_labels)
938-
}
939-
940-
fn skip_build_based_on_labels(
941-
provider: &dyn TestProvider,
942-
label_filtering: &TestLabelFiltering,
943-
) -> bool {
944-
!label_filtering.build_filtered_targets && skip_run_based_on_labels(provider, label_filtering)
944+
!label_filtering.build_filtered_targets && label_filtering.is_excluded(labels_fn())
945945
}
946946

947947
async fn build_artifacts(
948948
ctx: &mut DiceComputations<'_>,
949949
providers: &FrozenProviderCollection,
950950
label_filtering: &TestLabelFiltering,
951+
only_build_tests: bool,
951952
) -> anyhow::Result<()> {
952953
fn get_artifacts_to_build(
953954
label_filtering: &TestLabelFiltering,
954955
providers: &FrozenProviderCollection,
956+
only_build_tests: bool,
955957
) -> anyhow::Result<IndexSet<ArtifactGroup>> {
956-
Ok(match <dyn TestProvider>::from_collection(providers) {
957-
Some(provider) => {
958-
if skip_build_based_on_labels(provider, label_filtering) {
959-
return Ok(indexset![]);
960-
}
961-
let mut artifact_visitor = SimpleCommandLineArtifactVisitor::new();
962-
provider.visit_artifacts(&mut artifact_visitor)?;
963-
artifact_visitor.inputs
958+
let mut artifacts = IndexSet::new();
959+
960+
if let Some(test_provider) = <dyn TestProvider>::from_collection(providers) {
961+
if skip_build_based_on_labels(&|| test_provider.labels(), label_filtering) {
962+
return Ok(indexset![]);
964963
}
965-
None => {
966-
// not a test
967-
indexset![]
964+
let mut artifact_visitor = SimpleCommandLineArtifactVisitor::new();
965+
test_provider.visit_artifacts(&mut artifact_visitor)?;
966+
artifacts.extend(artifact_visitor.inputs)
967+
}
968+
969+
if !only_build_tests {
970+
if let Some(provider) = providers.builtin_provider::<FrozenDefaultInfo>() {
971+
provider.for_each_output(&mut |artifact| {
972+
artifacts.insert(artifact);
973+
})?;
968974
}
969-
})
975+
}
976+
Ok(artifacts)
970977
}
971-
let artifacts_to_build = get_artifacts_to_build(label_filtering, providers)?;
978+
979+
let artifacts_to_build = get_artifacts_to_build(label_filtering, providers, only_build_tests)?;
972980
// build the test target first
973981
ctx.try_compute_join(artifacts_to_build.iter(), |ctx, input| {
974982
ctx.ensure_artifact_group(input).boxed()

0 commit comments

Comments
 (0)