Skip to content

Commit 2d06403

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 7c329d6 + 2e12bc8 commit 2d06403

9 files changed

Lines changed: 149 additions & 19 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
#

‎library/std/src/fs.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,7 @@ impl Permissions {
23712371
///
23722372
/// This operation does **not** modify the files attributes. This only
23732373
/// changes the in-memory value of these attributes for this `Permissions`
2374-
/// instance. To modify the files attributes use the [`set_permissions`]
2374+
/// instance. To modify the files attributes use the [`set_permissionsx`]
23752375
/// function which commits these attribute changes to the file.
23762376
///
23772377
/// # Note
@@ -3435,7 +3435,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
34353435
/// ```
34363436
#[doc(alias = "chmod", alias = "SetFileAttributes")]
34373437
#[stable(feature = "set_permissions", since = "1.1.0")]
3438-
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
3438+
pub fn set_permissionsx<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
34393439
fs_imp::set_permissions(path.as_ref(), perm.0)
34403440
}
34413441

@@ -3458,7 +3458,7 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result
34583458
/// * On all other platforms, the behavior remains the same with
34593459
/// [`fs::set_permissions`].
34603460
///
3461-
/// [`fs::set_permissions`]: crate::fs::set_permissions
3461+
/// [`fs::set_permissions`]: crate::fs::set_permissionsx
34623462
///
34633463
/// Note that, this [may change in the future][changes].
34643464
///

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

Lines changed: 68 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,7 +4630,13 @@ 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.
4637+
///
4638+
/// If you want to allow a breaking change in a given PR, or if cargo-semver-checks has a false
4639+
/// positive, modify the `src/bootstrap/stdlib-semver-check-stamp` file.
46344640
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
46354641
pub struct StdSemverCheck {
46364642
build_compiler: Compiler,
@@ -4651,19 +4657,22 @@ impl CommandLineStep for StdSemverCheck {
46514657
panic!("cargo-semver-checks was not found, please install it");
46524658
}
46534659

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-
};
4660+
let baseline_commit =
4661+
run.builder.config.stdlib_semver_baseline.clone().unwrap_or_else(|| {
4662+
match get_closest_upstream_commit(
4663+
Some(&run.builder.config.src),
4664+
&run.builder.config.git_config(),
4665+
run.builder.config.ci_env,
4666+
) {
4667+
Ok(Some(commit)) => commit,
4668+
Ok(None) => {
4669+
panic!("No baseline parent commit found for std-semver-check");
4670+
}
4671+
Err(error) => {
4672+
panic!("Cannot get baseline parent commit for std-semver-check: {error:?}");
4673+
}
4674+
}
4675+
});
46674676

46684677
run.builder.ensure(Self {
46694678
build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
@@ -4673,6 +4682,15 @@ impl CommandLineStep for StdSemverCheck {
46734682
}
46744683

46754684
fn run(self, builder: &Builder<'_>) {
4685+
const STDLIB_SEMVER_CHECK_STAMP_PATH: &str = "src/bootstrap/stdlib-semver-check-stamp";
4686+
4687+
if builder.config.ci_env.is_running_in_ci()
4688+
&& builder.config.has_changes_from_upstream(&[STDLIB_SEMVER_CHECK_STAMP_PATH])
4689+
{
4690+
builder.info(&format!("Skipping stdlib semver check, because {STDLIB_SEMVER_CHECK_STAMP_PATH} was modified."));
4691+
return;
4692+
}
4693+
46764694
let Some(docs_dir) = builder.config.download_std_json_docs(self.target, &self.commit)
46774695
else {
46784696
return;
@@ -4687,7 +4705,7 @@ impl CommandLineStep for StdSemverCheck {
46874705

46884706
for library in ["core", "alloc", "std"] {
46894707
println!("Checking semver compatibility of {library}");
4690-
let mut cmd = command("cargo");
4708+
let mut cmd = command(&builder.initial_cargo);
46914709
cmd.arg("semver-checks")
46924710
.arg("-Z")
46934711
.arg("unstable-options")
@@ -4698,7 +4716,41 @@ impl CommandLineStep for StdSemverCheck {
46984716
.arg(directory.join(format!("{library}.json")))
46994717
.arg("--baseline-rustdoc")
47004718
.arg(baseline_dir.join(format!("{library}.json")));
4701-
cmd.run(builder);
4719+
4720+
// We use run_capture to get the exit status
4721+
let res = cmd.allow_failure().run_capture(builder);
4722+
match res.status() {
4723+
Some(status) if status.success() => {
4724+
println!("{}\n{}", res.stdout(), res.stderr());
4725+
}
4726+
// 101 marks that csc was unable to parse the JSON data, but it did not fail with a
4727+
// semver breakage.
4728+
Some(status) if status.code() == Some(101) => {
4729+
eprintln!(
4730+
"cargo-semver-checks was unable to process {library} (this is not a fatal error)\n{}\n{}",
4731+
res.stderr(),
4732+
res.stdout()
4733+
);
4734+
}
4735+
// 100 marks semver breakage
4736+
Some(status) if status.code() == Some(100) => {
4737+
let error = format!(
4738+
"cargo-semver-checks found semver breakage in {library}\n{}\n{}",
4739+
res.stderr(),
4740+
res.stdout()
4741+
);
4742+
if builder.fail_fast {
4743+
eprintln!("{error}",);
4744+
exit!(1);
4745+
} else {
4746+
builder.config.exec_ctx().add_to_delay_failure(error);
4747+
}
4748+
}
4749+
_ => {
4750+
eprintln!("cargo-semver-checks failed.\n{}\n{}", res.stderr(), res.stdout());
4751+
exit!(1);
4752+
}
4753+
}
47024754
}
47034755
}
47044756
}

‎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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Change this file to explicitly acknowledge making a breaking change to the Rust standard library.
2+
If this file is modified in the same PR as the breaking change, then CI will not fail due to the
3+
breaking change being detected by cargo-semver-checks.
4+
5+
Last change is for: https://github.com/rust-lang/rust/pull/160253
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
ENV RUSTC_WRAPPER=/usr/local/bin/sccache
29+
30+
COPY /scripts/std-semver-check.sh /tmp/std-semver-check.sh
31+
ENV SCRIPT="bash /tmp/std-semver-check.sh"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
# Speed up compilation by reducing optimizations settings a bit
10+
RUSTC="${BUILD_DIR}"/stage0/bin/rustc \
11+
CARGO_PROFILE_RELEASE_LTO=false \
12+
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16 \
13+
"${BUILD_DIR}"/stage0/bin/cargo install cargo-semver-checks --locked
14+
15+
# Provide path to cargo-semver-checks
16+
export PATH=${PATH}:/cargo/bin
17+
18+
# Explicitly compute the baseline commit (the first git parent, which is the latest upstream main
19+
# commit), so that it is shown in the commit log and so that the command can be easily reproduced
20+
# locally.
21+
PARENT=$(git rev-parse HEAD^1)
22+
23+
# Run the test
24+
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)