Skip to content

Commit c3cfe0d

Browse files
committed
[xtask] Attempt to handle CTS revision moving backwards
1 parent 8ff1eb9 commit c3cfe0d

File tree

3 files changed

+118
-13
lines changed

3 files changed

+118
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

xtask/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ env_logger.workspace = true
1818
regex-lite.workspace = true
1919
log.workspace = true
2020
pico-args.workspace = true
21+
serde_json.workspace = true
2122
xshell.workspace = true

xtask/src/cts.rs

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,19 @@ use regex_lite::{Regex, RegexBuilder};
3636
use std::{ffi::OsString, sync::LazyLock};
3737
use xshell::Shell;
3838

39-
use crate::util::git_version_at_least;
39+
use crate::util::{git_version_at_least, looks_like_git_sha};
4040

4141
/// Path within the repository where the CTS will be checked out.
4242
const CTS_CHECKOUT_PATH: &str = "cts";
4343

44+
/// Path to git's `shallow` file.
45+
const GIT_SHALLOW_PATH: &str = ".git/shallow";
46+
4447
/// Path within the repository to a file containing the git revision of the CTS to check out.
4548
const CTS_REVISION_PATH: &str = "cts_runner/revision.txt";
4649

4750
/// URL of the CTS git repository.
48-
const CTS_GIT_URL: &str = "https://github.com/gpuweb/cts.git";
51+
const CTS_GITHUB_PATH: &str = "gpuweb/cts";
4952

5053
/// Path to default CTS test list.
5154
const CTS_DEFAULT_TEST_LIST: &str = "cts_runner/test.lst";
@@ -56,6 +59,100 @@ struct TestLine {
5659
pub fails_if: Vec<String>,
5760
}
5861

62+
fn have_git_sha(shell: &Shell, sha: &str) -> bool {
63+
shell
64+
.cmd("git")
65+
.args(["cat-file", "commit", sha])
66+
.quiet()
67+
.ignore_stdout()
68+
.ignore_stderr()
69+
.run()
70+
.is_ok()
71+
}
72+
73+
fn maybe_deepen_git_repo(shell: &Shell, desired: &str) -> anyhow::Result<()> {
74+
if shell
75+
.cmd("curl")
76+
.args([
77+
"-f",
78+
"-L",
79+
"-I",
80+
"-H",
81+
"Accept: application/vnd.github+json",
82+
"-H",
83+
"X-GitHub-Api-Version: 2022-11-28",
84+
])
85+
.arg(format!(
86+
"https://api.github.com/repos/{CTS_GITHUB_PATH}/commits/{desired}"
87+
))
88+
.quiet()
89+
.ignore_stdout()
90+
.ignore_stderr()
91+
.run()
92+
.is_err()
93+
{
94+
log::warn!("Not deepening repo because the desired CTS SHA was not found on GitHub.");
95+
return Ok(());
96+
}
97+
98+
if !shell.path_exists(GIT_SHALLOW_PATH) {
99+
log::warn!("Not deepening repo because it is not a shallow clone.");
100+
return Ok(());
101+
}
102+
103+
let shallow = shell
104+
.read_file(GIT_SHALLOW_PATH)
105+
.context(format!(
106+
"Failed to read git shallow SHA from {GIT_SHALLOW_PATH}"
107+
))?
108+
.trim()
109+
.to_string();
110+
111+
if !looks_like_git_sha(&shallow) {
112+
log::warn!(
113+
"Automatic deepening of git repo requires a shallow clone with a single graft point"
114+
);
115+
return Ok(());
116+
}
117+
118+
let output = shell
119+
.cmd("curl")
120+
.args([
121+
"-f",
122+
"-L",
123+
"-H",
124+
"Accept: application/vnd.github+json",
125+
"-H",
126+
"X-GitHub-Api-Version: 2022-11-28",
127+
])
128+
.arg(format!(
129+
"https://api.github.com/repos/{CTS_GITHUB_PATH}/compare/{desired}...{shallow}"
130+
))
131+
.output()
132+
.context("Error calling GitHub API")?;
133+
134+
let gh_json: serde_json::Map<String, serde_json::Value> =
135+
serde_json::from_slice(&output.stdout).context("Failed parsing GitHub API JSON")?;
136+
137+
let Some(deepen_count) = gh_json
138+
.get("total_commits")
139+
.and_then(serde_json::Value::as_u64)
140+
else {
141+
bail!("missing or invalid total_commits");
142+
};
143+
144+
log::info!("Fetching CTS with --deepen {deepen_count}");
145+
146+
shell
147+
.cmd("git")
148+
.args(["fetch", "--deepen", &deepen_count.to_string()])
149+
.quiet()
150+
.run()
151+
.context("Failed to deepen git repo")?;
152+
153+
Ok(())
154+
}
155+
59156
pub fn run_cts(
60157
shell: Shell,
61158
mut args: Arguments,
@@ -142,7 +239,11 @@ pub fn run_cts(
142239
}
143240
let mut cmd = shell
144241
.cmd("git")
145-
.args(["clone", CTS_GIT_URL, CTS_CHECKOUT_PATH])
242+
.args([
243+
"clone",
244+
&format!("https://github.com/{CTS_GITHUB_PATH}.git"),
245+
CTS_CHECKOUT_PATH,
246+
])
146247
.quiet();
147248

148249
if git_version_at_least(&shell, [2, 49, 0])? {
@@ -187,23 +288,25 @@ pub fn run_cts(
187288
}
188289

189290
// If we don't have the CTS commit we want, try to fetch it.
190-
if shell
191-
.cmd("git")
192-
.args(["cat-file", "commit", &cts_revision])
193-
.quiet()
194-
.ignore_stdout()
195-
.ignore_stderr()
196-
.run()
197-
.is_err()
198-
{
199-
log::info!("Fetching CTS");
291+
if !have_git_sha(&shell, &cts_revision) {
292+
log::info!("Desired SHA not found, fetching CTS");
200293
shell
201294
.cmd("git")
202295
.args(["fetch", "--quiet"])
203296
.quiet()
204297
.run()
205298
.context("Failed to fetch CTS")?;
206299
}
300+
301+
// If we still don't have the commit we want, maybe we need more history.
302+
if !have_git_sha(&shell, &cts_revision) {
303+
log::info!("Desired SHA still not found, checking if missing from shallow clone");
304+
maybe_deepen_git_repo(&shell, &cts_revision)?;
305+
}
306+
307+
if !have_git_sha(&shell, &cts_revision) {
308+
bail!("Unable to obtain the desired CTS revision {cts_revision}");
309+
}
207310
} else {
208311
shell.change_dir(CTS_CHECKOUT_PATH);
209312
}

0 commit comments

Comments
 (0)