fix: better validate for dev_brain and 50k reminder not triggering rebuild
This commit is contained in:
@@ -72,12 +72,13 @@ sources:
|
||||
- project: Registered project name
|
||||
path: src/example.rs
|
||||
symbol: optional_symbol
|
||||
revision: exact-clean-git-revision
|
||||
# Use hash instead of revision when the worktree is dirty or is not Git.
|
||||
revision: full-or-unique-short-clean-git-revision
|
||||
# Use `git rev-parse HEAD`, or a unique lowercase hex prefix of at least 7 characters.
|
||||
# Use hash instead when the worktree is dirty or is not Git.
|
||||
---
|
||||
```
|
||||
|
||||
Each source has exactly one evidence version: `revision` or a lowercase SHA-256 `hash`. Paths are project-relative and may not escape the registered project.
|
||||
Each source has exactly one evidence version: `revision` or a lowercase SHA-256 `hash`. A revision is the current clean commit's full object ID or a unique lowercase hexadecimal prefix of at least 7 characters. Paths are project-relative and may not escape the registered project.
|
||||
|
||||
## Compilation
|
||||
|
||||
@@ -1081,9 +1082,9 @@ fn validate_source(source: &SourceRecord, projects: &[RegisteredProject]) -> Res
|
||||
));
|
||||
}
|
||||
if let Some(revision) = &source.revision {
|
||||
return Ok(
|
||||
git_state(&project.root).is_some_and(|(current, clean)| clean && current == *revision)
|
||||
);
|
||||
return Ok(git_state(&project.root).is_some_and(|(current, clean)| {
|
||||
clean && git_revision_matches(&project.root, revision, ¤t)
|
||||
}));
|
||||
}
|
||||
let expected = source.hash.as_deref().unwrap();
|
||||
if expected.len() != 64
|
||||
@@ -1100,6 +1101,29 @@ fn validate_source(source: &SourceRecord, projects: &[RegisteredProject]) -> Res
|
||||
&& !git_state(&project.root).is_some_and(|(_, clean)| clean))
|
||||
}
|
||||
|
||||
fn git_revision_matches(root: &Path, revision: &str, current: &str) -> bool {
|
||||
if revision == current {
|
||||
return true;
|
||||
}
|
||||
if revision.len() < 7
|
||||
|| revision.len() >= current.len()
|
||||
|| !revision
|
||||
.bytes()
|
||||
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Command::new("git")
|
||||
.args(["-C"])
|
||||
.arg(root)
|
||||
.args(["rev-parse", "--verify"])
|
||||
.arg(format!("{revision}^{{commit}}"))
|
||||
.output()
|
||||
.ok()
|
||||
.filter(|output| output.status.success())
|
||||
.is_some_and(|output| String::from_utf8_lossy(&output.stdout).trim() == current)
|
||||
}
|
||||
|
||||
fn git_state(root: &Path) -> Option<(String, bool)> {
|
||||
let revision = Command::new("git")
|
||||
.args(["-C"])
|
||||
@@ -1560,7 +1584,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clean_git_revisions_become_stale_when_the_worktree_changes() {
|
||||
fn clean_full_and_short_git_revisions_become_stale_when_the_worktree_changes() {
|
||||
let fixture = Fixture::new();
|
||||
for arguments in [
|
||||
vec!["init"],
|
||||
@@ -1586,11 +1610,21 @@ mod tests {
|
||||
);
|
||||
}
|
||||
let revision = git_state(&fixture.project).unwrap().0;
|
||||
assert!(git_revision_matches(
|
||||
&fixture.project,
|
||||
&revision[..7],
|
||||
&revision
|
||||
));
|
||||
assert!(!git_revision_matches(
|
||||
&fixture.project,
|
||||
&revision[..6],
|
||||
&revision
|
||||
));
|
||||
let topic = fixture
|
||||
.topic("verified", &"0".repeat(64), "Revision-backed knowledge.")
|
||||
.replace(
|
||||
&format!("hash: {}", "0".repeat(64)),
|
||||
&format!("revision: {revision}"),
|
||||
&format!("revision: {}", &revision[..7]),
|
||||
);
|
||||
let mut brain = fixture.brain();
|
||||
write_topic(&fixture, &mut brain, &topic).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user