aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci-check-only.yml2
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--.run/src/bin/ci.py37
-rw-r--r--mingling_ci/src/cmd/cmd_git_unlock.rs29
4 files changed, 46 insertions, 24 deletions
diff --git a/.github/workflows/ci-check-only.yml b/.github/workflows/ci-check-only.yml
index dc97c81..548026d 100644
--- a/.github/workflows/ci-check-only.yml
+++ b/.github/workflows/ci-check-only.yml
@@ -61,7 +61,7 @@ jobs:
- name: Unlock workspace (idempotency check)
if: always()
- run: cargo ci git-unlock
+ run: cargo ci git-unlock --show-diff
- name: Fail when the check failed
if: steps.check.outcome == 'failure'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d4892c3..56667d4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -61,7 +61,7 @@ jobs:
- name: Unlock workspace (idempotency check)
if: always()
- run: cargo ci git-unlock
+ run: cargo ci git-unlock --show-diff
- name: Fail when the check failed
if: steps.check.outcome == 'failure'
diff --git a/.run/src/bin/ci.py b/.run/src/bin/ci.py
index ced6566..6234a19 100644
--- a/.run/src/bin/ci.py
+++ b/.run/src/bin/ci.py
@@ -14,20 +14,21 @@ import subprocess
import sys
from pathlib import Path
-# The pipeline steps, in execution order.
-STEPS = [
- "git-lock",
- "report-clean",
- "build-check",
- "clippy-check",
- "test-all",
- "example-check",
- "docs-check",
- "example-refresh",
- "docsify-refresh",
- "features-refresh",
- # Idempotency check: exits non-zero if CI contaminated the workspace.
- "git-unlock",
+# The pipeline steps, in execution order, as (command, args) pairs.
+STEPS: list[tuple[str, list[str]]] = [
+ ("git-lock", []),
+ ("report-clean", []),
+ ("build-check", []),
+ ("clippy-check", []),
+ ("test-all", []),
+ ("example-check", []),
+ ("docs-check", []),
+ ("example-refresh", []),
+ ("docsify-refresh", []),
+ ("features-refresh", []),
+ # Idempotency check: exits non-zero if CI contaminated the workspace, and
+ # prints the diff of the contamination before restoring.
+ ("git-unlock", ["--show-diff"]),
]
@@ -57,12 +58,12 @@ def main() -> int:
except OSError:
pass
- for step in STEPS:
- print(f"==> cargo ci {step}")
- result = subprocess.run(["cargo", "ci", step], check=False)
+ for command, args in STEPS:
+ print(f"==> cargo ci {' '.join([command, *args])}")
+ result = subprocess.run(["cargo", "ci", command, *args], check=False)
if result.returncode != 0:
print(
- f"error: step `{step}` failed with exit code {result.returncode}",
+ f"error: step `{command}` failed with exit code {result.returncode}",
file=sys.stderr,
)
return result.returncode
diff --git a/mingling_ci/src/cmd/cmd_git_unlock.rs b/mingling_ci/src/cmd/cmd_git_unlock.rs
index 6d7389d..41efefc 100644
--- a/mingling_ci/src/cmd/cmd_git_unlock.rs
+++ b/mingling_ci/src/cmd/cmd_git_unlock.rs
@@ -1,12 +1,13 @@
use mingling::{
Grouped, RenderResult, Routable,
- macros::{buffer, command, r_println, renderer},
+ macros::{arg, buffer, command, r_println, renderer},
+ picker::{EntryPicker, value::Flag},
res::ResExitCode,
};
-use crate::Next;
use crate::git::{LOCK_FILE, TEMP_COMMIT_MARK, head_message, run_git, worktree_clean};
use crate::res::{CargoError, MessagePrinter};
+use crate::{Entry, Next};
/// Undoes a CI temporary commit created by [`crate::cmd::cmd_git_lock`].
///
@@ -21,9 +22,13 @@ use crate::res::{CargoError, MessagePrinter};
///
/// When the working tree is dirty (e.g. CI left tracked changes behind) the
/// restore still runs, but the command reports a non-zero exit code so the
-/// caller knows the CI phase contaminated the repository.
+/// caller knows the CI phase contaminated the repository. With `--show-diff`
+/// the diff of those changes is printed before they are discarded.
#[command(node = "git-unlock")]
-pub fn git_unlock() -> Next {
+// `#[command]` rewrites an owned first param into the entry type, so the args
+// must be passed by value even though the body only reads them.
+#[allow(clippy::needless_pass_by_value)]
+pub fn git_unlock(args: Entry) -> Next {
let head = head_message().unwrap_or_default();
if !head.contains(TEMP_COMMIT_MARK) {
return ErrorGitUnlock(format!("HEAD is not a CI temporary commit: `{head}`")).to_chain();
@@ -37,6 +42,10 @@ pub fn git_unlock() -> Next {
let based_on_dirty =
std::fs::read_to_string(LOCK_FILE).is_ok_and(|content| content.trim() == "true");
+ if dirty && *args.pick(&arg![show_diff: Flag]).unwrap() {
+ show_diff();
+ }
+
if let Err(e) = undo_ci_phase(based_on_dirty) {
return ErrorGitUnlock(e).to_chain();
}
@@ -44,6 +53,18 @@ pub fn git_unlock() -> Next {
ResultGitUnlock { dirty }.to_chain()
}
+/// Prints the tracked changes the CI run left behind, before the restore
+/// discards them. Untracked files are not shown (they are removed by clean).
+fn show_diff() {
+ let Ok(diff) = run_git(["diff", "HEAD"]) else {
+ return;
+ };
+ if diff.is_empty() {
+ return;
+ }
+ println!("{diff}");
+}
+
/// Restores the workspace, keeping the user's pre-lock changes.
///
/// With a base `TEMP` commit (`true`) the marker commit is dropped by a hard