-
Notifications
You must be signed in to change notification settings - Fork 3
by_commit_with_notes v2 #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -151,6 +151,42 @@ That means Limmat won't re-run tests unless the actual repository contents | |
| change - for example changes to the commit message won't invalidate cache | ||
| results. | ||
|
|
||
| For fine-grained cache control, you can use `cache = "by_commit_with_notes"`. | ||
| This creates cache keys based on both the commit hash and git notes attached | ||
| to the commit under the `refs/notes/limmat` ref. This allows you to | ||
| invalidate the cache for specific commits by adding or modifying notes: | ||
|
|
||
| ```bash | ||
| # This will invalidate the cache for this commit | ||
| git notes --ref=limmat add -m "force rebuild" abc1234 | ||
|
|
||
| # Different note content = different cache key | ||
| git notes --ref=limmat add -m "test with flag X" abc1234 --force | ||
| ``` | ||
|
|
||
| Your test scripts can access the exact notes content that was used for the cache key: | ||
|
|
||
| ```bash | ||
| #!/bin/bash | ||
| # Example test script using git notes for configuration | ||
|
|
||
| if [[ -n "$LIMMAT_NOTES_OBJECT" ]]; then | ||
| # Get the exact notes content used for cache key generation | ||
| notes_content=$(git cat-file -p "$LIMMAT_NOTES_OBJECT") | ||
| echo "Test configuration from notes: $notes_content" | ||
|
|
||
| # Parse test parameters from notes | ||
| if echo "$notes_content" | grep -q "rebuild"; then | ||
| echo "Force rebuild requested" | ||
| make clean | ||
| fi | ||
| else | ||
| echo "No notes attached to this commit, using defaults" | ||
| fi | ||
|
|
||
| make test | ||
| ``` | ||
|
|
||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to integrate it into |
||
| If the test is terminated by a signal, it isn't considered to have produced a | ||
| result: instead of "success" or "failure" it's an "error". Errors aren't cached. | ||
|
|
||
|
|
@@ -323,6 +359,7 @@ These environment variables are passed to your job. | |
| | `LIMMAT_ORIGIN` | Path of the main repository worktree (i.e. `--repo`). | | ||
| | `LIMMAT_COMMIT` | Hash of the commit to be tested. | | ||
| | `LIMMAT_CONFIG` | Path of the config file. | | ||
| | `LIMMAT_NOTES_OBJECT` | Git object hash of the notes content used for cache key generation (when using `cache = "by_commit_with_notes"`). Empty if no notes exist. | | ||
| | `LIMMAT_RESOURCE_<resource_name>_<n>` | Values for [resources](#resources) used by the test. | | ||
| | `LIMMAT_RESOURCE_<resource_name>` | If the test only uses one of a resource, shorthand for `LIMMAT_RESOURCE_<resource_name>_0` | | ||
| | `LIMMAT_ARTIFACTS_<job_name>` | If the test depends on `job_name`, this directory contains that job's [artifacts](#artifacts). | | ||
|
|
@@ -376,6 +413,13 @@ make -j defconfig | |
| make -j16 vmlinux O=$LIMMAT_ARTIFACTS | ||
| """ | ||
|
|
||
| # Run stress tests that can be configured via git notes | ||
| [[tests]] | ||
| name = "stress_test" | ||
| cache = "by_commit_with_notes" | ||
| command = "stress_test.sh" | ||
| depends_on = ["kbuild"] | ||
|
|
||
| # Check the locally-built kernel boots in a QEMU VM. | ||
| [[tests]] | ||
| name = "boot_qemu" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,6 +94,7 @@ pub struct Test { | |
| /// willing to wait when you terminate this program. | ||
| shutdown_grace_period_s: u64, | ||
| #[serde(default = "default_cache_policy")] | ||
| /// Controls when test results are cached. "by_commit" (default) caches by commit hash. "by_tree" caches by tree hash (ignores commit message changes). "by_commit_with_notes" caches by commit hash plus git notes under refs/notes/limmat. "no_caching" disables caching. | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document on the enum |
||
| cache: CachePolicy, | ||
| #[serde(default)] | ||
| depends_on: Vec<String>, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -172,6 +172,7 @@ impl Worktree for PersistentWorktree { | |
| pub struct Commit { | ||
| pub hash: CommitHash, | ||
| pub tree: TreeHash, | ||
| pub limmat_notes_object: Option<Hash>, | ||
| } | ||
|
|
||
| impl Commit { | ||
|
|
@@ -180,6 +181,7 @@ impl Commit { | |
| Self { | ||
| hash: CommitHash::new("080b8ecbad3e34e55c5a035af80100f73b742a8d"), | ||
| tree: TreeHash::new("6366d790125291272542a6b40f6fd3400e080821"), | ||
| limmat_notes_object: None, | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -457,6 +459,65 @@ pub trait Worktree: Debug + Sync { | |
| }) | ||
| } | ||
|
|
||
| async fn get_notes_object_hash( | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document. Make notes ref configurable. |
||
| &self, | ||
| commit_hash: &CommitHash, | ||
| ) -> anyhow::Result<Option<Hash>> { | ||
| debug!( | ||
| "Looking for git notes for commit {}", | ||
| commit_hash.as_ref() as &str | ||
| ); | ||
| let output = self | ||
| .git(["notes", "--ref=limmat", "list"]) | ||
| .await | ||
| .arg(commit_hash.as_ref() as &str) | ||
| .output() | ||
| .await | ||
| .context("failed to run 'git notes list'")?; | ||
|
|
||
| debug!("git notes list exit code: {:?}", output.status.code()); | ||
| debug!( | ||
| "git notes list stdout: {:?}", | ||
| String::from_utf8_lossy(&output.stdout) | ||
| ); | ||
| debug!( | ||
| "git notes list stderr: {:?}", | ||
| String::from_utf8_lossy(&output.stderr) | ||
| ); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove most or all of the debug logs in here. |
||
|
|
||
| // Exit code 1 means no notes found, which is fine | ||
| if output.status.code() == Some(1) { | ||
| debug!("No notes found for commit {}", commit_hash.as_ref() as &str); | ||
| return Ok(None); | ||
| } | ||
|
|
||
| if !output.status.success() { | ||
| // Other error - treat as no notes to be safe | ||
| debug!( | ||
| "git notes list failed with code {:?}, treating as no notes", | ||
| output.status.code() | ||
| ); | ||
| return Ok(None); | ||
| } | ||
|
|
||
| let notes_output = String::from_utf8_lossy(&output.stdout); | ||
| let notes_object_hash = notes_output.trim(); | ||
| if notes_object_hash.is_empty() { | ||
| debug!( | ||
| "Empty notes output for commit {}", | ||
| commit_hash.as_ref() as &str | ||
| ); | ||
| return Ok(None); | ||
| } | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's treat empty output as an error here too |
||
|
|
||
| debug!( | ||
| "Found notes object hash {} for commit {}", | ||
| notes_object_hash, | ||
| commit_hash.as_ref() as &str | ||
| ); | ||
| Ok(Some(Hash::new(notes_object_hash.to_string()))) | ||
| } | ||
|
|
||
| // None means we successfully looked it up but it didn't exist. | ||
| async fn rev_parse<S>(&self, rev_spec: S) -> anyhow::Result<Option<Commit>> | ||
| where | ||
|
|
@@ -486,9 +547,14 @@ pub trait Worktree: Debug + Sync { | |
| String::from_utf8_lossy(&output.stderr) | ||
| ); | ||
| } | ||
|
|
||
| let commit_hash = CommitHash::new(parts[0]); | ||
| let limmat_notes_object = self.get_notes_object_hash(&commit_hash).await?; | ||
|
|
||
| Ok(Some(Commit { | ||
| hash: CommitHash::new(parts[0]), | ||
| hash: commit_hash, | ||
| tree: TreeHash::new(parts[1]), | ||
| limmat_notes_object, | ||
| })) | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rework the docs.