Skip to content

Commit b85937d

Browse files
committed
Auto merge of #160253 - Kobzol:csc-ci, r=<try>
Add CI job for checking stdlib semver compatibility try-job: x86_64-gnu-stdlib-semver-check
2 parents b430378 + f6f7f3b commit b85937d

7 files changed

Lines changed: 125 additions & 16 deletions

File tree

bootstrap.example.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,15 @@
935935
#
936936
#rust.parallel-frontend-threads = 1
937937

938+
# Baseline commit SHA for comparing semver breakages in the Rust standard library.
939+
# The in-tree stdlib API will be evaluated for semver breakages against this commit.
940+
# Used for the `./x test std-semver-check` command.
941+
# If unset, the first upstream parent commit will be used.
942+
#
943+
# The SHA must point to a merge commit merged into the mainline rust-lang/rust `main` branch,
944+
# because bootstrap will attempt to download the JSON docs data for this commit from its CI.
945+
#rust.stdlib-semver-baseline = "<commit-sha>"
946+
938947
# =============================================================================
939948
# Distribution options
940949
#

src/bootstrap/src/core/build_steps/test.rs

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4617,7 +4617,7 @@ impl CommandLineStep for RemoteTestClientTests {
46174617
}
46184618

46194619
fn check_if_cargo_semver_checks_is_installed(builder: &Builder<'_>) -> bool {
4620-
command("cargo")
4620+
command(&builder.initial_cargo)
46214621
.allow_failure()
46224622
.arg("semver-checks")
46234623
.arg("--version")
@@ -4630,6 +4630,9 @@ fn check_if_cargo_semver_checks_is_installed(builder: &Builder<'_>) -> bool {
46304630
/// Run cargo-semver-checks on the standard library and compare its API
46314631
/// versus a previous baseline, using rustdoc JSON data.
46324632
///
4633+
/// The baseline commit can be configured using `rust.stdlib-semver-baseline`.
4634+
/// If unset, the first upstream parent commit will be used.
4635+
///
46334636
/// Fails if a semver-breaking change is detected.
46344637
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
46354638
pub struct StdSemverCheck {
@@ -4651,19 +4654,22 @@ impl CommandLineStep for StdSemverCheck {
46514654
panic!("cargo-semver-checks was not found, please install it");
46524655
}
46534656

4654-
let baseline_commit = match get_closest_upstream_commit(
4655-
Some(&run.builder.config.src),
4656-
&run.builder.config.git_config(),
4657-
run.builder.config.ci_env,
4658-
) {
4659-
Ok(Some(commit)) => commit,
4660-
Ok(None) => {
4661-
panic!("No baseline parent commit found for std-semver-check");
4662-
}
4663-
Err(error) => {
4664-
panic!("Cannot get baseline parent commit for std-semver-check: {error:?}");
4665-
}
4666-
};
4657+
let baseline_commit =
4658+
run.builder.config.stdlib_semver_baseline.clone().unwrap_or_else(|| {
4659+
match get_closest_upstream_commit(
4660+
Some(&run.builder.config.src),
4661+
&run.builder.config.git_config(),
4662+
run.builder.config.ci_env,
4663+
) {
4664+
Ok(Some(commit)) => commit,
4665+
Ok(None) => {
4666+
panic!("No baseline parent commit found for std-semver-check");
4667+
}
4668+
Err(error) => {
4669+
panic!("Cannot get baseline parent commit for std-semver-check: {error:?}");
4670+
}
4671+
}
4672+
});
46674673

46684674
run.builder.ensure(Self {
46694675
build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
@@ -4687,7 +4693,7 @@ impl CommandLineStep for StdSemverCheck {
46874693

46884694
for library in ["core", "alloc", "std"] {
46894695
println!("Checking semver compatibility of {library}");
4690-
let mut cmd = command("cargo");
4696+
let mut cmd = command(&builder.initial_cargo);
46914697
cmd.arg("semver-checks")
46924698
.arg("-Z")
46934699
.arg("unstable-options")
@@ -4698,7 +4704,41 @@ impl CommandLineStep for StdSemverCheck {
46984704
.arg(directory.join(format!("{library}.json")))
46994705
.arg("--baseline-rustdoc")
47004706
.arg(baseline_dir.join(format!("{library}.json")));
4701-
cmd.run(builder);
4707+
4708+
// We use run_capture to get the exit status
4709+
let res = cmd.allow_failure().run_capture(builder);
4710+
match res.status() {
4711+
Some(status) if status.success() => {
4712+
println!("{}\n{}", res.stdout(), res.stderr());
4713+
}
4714+
// 101 marks that csc was unable to parse the JSON data, but it did not fail with a
4715+
// semver breakage.
4716+
Some(status) if status.code() == Some(101) => {
4717+
eprintln!(
4718+
"cargo-semver-checks was unable to process {library} (this is not a fatal error)\n{}\n{}",
4719+
res.stderr(),
4720+
res.stdout()
4721+
);
4722+
}
4723+
// 100 marks semver breakage
4724+
Some(status) if status.code() == Some(100) => {
4725+
let error = format!(
4726+
"cargo-semver-checks found semver breakage in {library}\n{}\n{}",
4727+
res.stderr(),
4728+
res.stdout()
4729+
);
4730+
if builder.fail_fast {
4731+
eprintln!("{error}",);
4732+
exit!(1);
4733+
} else {
4734+
builder.config.exec_ctx().add_to_delay_failure(error);
4735+
}
4736+
}
4737+
_ => {
4738+
eprintln!("cargo-semver-checks failed.\n{}\n{}", res.stderr(), res.stdout());
4739+
exit!(1);
4740+
}
4741+
}
47024742
}
47034743
}
47044744
}

src/bootstrap/src/core/config/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ pub struct Config {
240240
pub rustdoc_pgo: PgoConfig,
241241
pub cargo_pgo: PgoConfig,
242242

243+
pub stdlib_semver_baseline: Option<String>,
244+
243245
pub llvm_libunwind_default: Option<LlvmLibunwind>,
244246
pub enable_bolt_settings: bool,
245247

@@ -610,6 +612,7 @@ impl Config {
610612
std_features: rust_std_features,
611613
break_on_ice: rust_break_on_ice,
612614
rustflags: rust_rustflags,
615+
stdlib_semver_baseline: rust_stdlib_semver_baseline,
613616
} = toml_rust.unwrap_or_default();
614617

615618
let Llvm {
@@ -1595,6 +1598,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to
15951598
.or(rust_rustc_debug_assertions)
15961599
.unwrap_or(rust_debug == Some(true)),
15971600
stderr_is_tty: std::io::stderr().is_terminal(),
1601+
stdlib_semver_baseline: rust_stdlib_semver_baseline,
15981602
stdout_is_tty: std::io::stdout().is_terminal(),
15991603
submodules: build_submodules,
16001604
sysconfdir: install_sysconfdir.map(PathBuf::from),

src/bootstrap/src/core/config/toml/rust.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ define_config! {
7474
std_features: Option<BTreeSet<String>> = "std-features",
7575
break_on_ice: Option<bool> = "break-on-ice",
7676
parallel_frontend_threads: Option<u32> = "parallel-frontend-threads",
77+
stdlib_semver_baseline: Option<String> = "stdlib-semver-baseline",
7778
}
7879
}
7980

@@ -391,6 +392,7 @@ pub fn check_incompatible_options_for_ci_rustc(
391392
parallel_frontend_threads: _,
392393
bootstrap_override_lld: _,
393394
rustflags: _,
395+
stdlib_semver_baseline: _,
394396
} = ci_rust_config;
395397

396398
// There are two kinds of checks for CI rustc incompatible options:
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM ubuntu:26.04
2+
3+
ARG DEBIAN_FRONTEND=noninteractive
4+
RUN apt-get update && apt-get install -y --no-install-recommends \
5+
g++ \
6+
make \
7+
ninja-build \
8+
file \
9+
curl \
10+
ca-certificates \
11+
python3 \
12+
git \
13+
cmake \
14+
sudo \
15+
gdb \
16+
libssl-dev \
17+
pkg-config \
18+
xz-utils \
19+
mingw-w64 \
20+
zlib1g-dev \
21+
libzstd-dev \
22+
&& rm -rf /var/lib/apt/lists/*
23+
24+
COPY scripts/sccache.sh /scripts/
25+
RUN sh /scripts/sccache.sh
26+
27+
ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu"
28+
29+
COPY /scripts/std-semver-check.sh /tmp/std-semver-check.sh
30+
ENV SCRIPT="bash /tmp/std-semver-check.sh"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
BUILD_DIR=$(realpath ./build/x86_64-unknown-linux-gnu)
6+
7+
# Install the latest version of cargo-semver-checks, so that once the JSON doc format changes,
8+
# we will eventually get a csc version that supports it
9+
RUSTC="${BUILD_DIR}"/stage0/bin/rustc "${BUILD_DIR}"/stage0/bin/cargo install \
10+
cargo-semver-checks --locked
11+
12+
# Provide path to cargo-semver-checks
13+
export PATH=${PATH}:/cargo/bin
14+
15+
# Explicitly compute the baseline commit (the first git parent, which is the latest upstream main
16+
# commit), so that it is shown in the commit log and so that the command can be easily reproduced
17+
# locally.
18+
PARENT=$(git rev-parse HEAD^1)
19+
20+
# Run the test
21+
python3 ../x.py test std-semver-check --set rust.stdlib-semver-baseline=${PARENT}

src/ci/github-actions/jobs.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,9 @@ auto:
491491
- name: x86_64-gnu-miri
492492
<<: *job-linux-4c
493493

494+
- name: x86_64-gnu-stdlib-semver-check
495+
<<: *job-linux-4c
496+
494497
- name: optional-x86_64-gnu-autodiff
495498
continue_on_error: true
496499
doc_url: https://rustc-dev-guide.rust-lang.org/tests/autodiff-ci-job.html

0 commit comments

Comments
 (0)