about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2025-04-10 12:11:24 +0200
committerJakub Beránek <berykubik@gmail.com>2025-04-20 09:35:42 +0200
commit40058519bae2c4921e5a1cf5db42c0e9861b156f (patch)
tree726e3e98997ddefec473924ccf46cd537e1f5597 /src/bootstrap
parente9f3e3abda4ad922f09707702057bd13fc7bbd4a (diff)
Use `--author-date-order` when looking up upstream commits to support subtree synces
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/src/core/config/tests.rs71
-rw-r--r--src/bootstrap/src/utils/tests/git.rs10
2 files changed, 79 insertions, 2 deletions
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 04e328c8b1b..96ac8a6d52f 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -858,6 +858,7 @@ fn test_local_changes_in_previous_upstream() {
         ctx.create_branch("feature");
         ctx.modify("d");
         ctx.commit();
+
         assert_eq!(
             ctx.check_modifications(&["a"], CiEnv::None),
             PathFreshness::LastModifiedUpstream { upstream: sha }
@@ -914,3 +915,73 @@ fn test_local_changes_negative_path() {
         );
     });
 }
+
+#[test]
+fn test_local_changes_subtree_that_used_bors() {
+    // Here we simulate a very specific situation related to subtrees.
+    // When you have merge commits locally, we should ignore them w.r.t. the artifact download
+    // logic.
+    // The upstream search code currently uses a simple heuristic:
+    // - Find commits by bors (or in general an author with the merge commit e-mail)
+    // - Find the newest such commit
+    // This should make it work even for subtrees that:
+    // - Used bors in the past (so they have bors merge commits in their history).
+    // - Use Josh to merge rustc into the subtree, in a way that the rustc history is the second
+    // parent, not the first one.
+    //
+    // In addition, when searching for modified files, we cannot simply start from HEAD, because
+    // in this situation git wouldn't find the right commit.
+    //
+    // This test checks that this specific scenario will resolve to the right rustc commit, both
+    // when finding a modified file and when finding a non-existent file (which essentially means
+    // that we just lookup the most recent upstream commit).
+    //
+    // See https://github.com/rust-lang/rust/issues/101907#issuecomment-2697671282 for more details.
+    git_test(|ctx| {
+        ctx.create_upstream_merge(&["a"]);
+
+        // Start unrelated subtree history
+        ctx.run_git(&["switch", "--orphan", "subtree"]);
+        ctx.modify("bar");
+        ctx.commit();
+        // Now we need to emulate old bors commits in the subtree.
+        // Git only has a resolution of one second, which is a problem, since our git logic orders
+        // merge commits by their date.
+        // To avoid sleeping in the test, we modify the commit date to be forcefully in the past.
+        ctx.create_upstream_merge(&["subtree/a"]);
+        ctx.run_git(&["commit", "--amend", "--date", "Wed Feb 16 14:00 2011 +0100", "--no-edit"]);
+
+        // Merge the subtree history into rustc
+        ctx.switch_to_branch("main");
+        ctx.run_git(&["merge", "subtree", "--allow-unrelated"]);
+
+        // Create a rustc commit that modifies a path that we're interested in (`x`)
+        let upstream_1 = ctx.create_upstream_merge(&["x"]);
+        // Create another bors commit
+        let upstream_2 = ctx.create_upstream_merge(&["a"]);
+
+        ctx.switch_to_branch("subtree");
+
+        // Create a subtree branch
+        ctx.create_branch("subtree-pr");
+        ctx.modify("baz");
+        ctx.commit();
+        // We merge rustc into this branch (simulating a "subtree pull")
+        ctx.merge("main", "committer <committer@foo.bar>");
+
+        // And then merge that branch into the subtree (simulating a situation right before a
+        // "subtree push")
+        ctx.switch_to_branch("subtree");
+        ctx.merge("subtree-pr", "committer <committer@foo.bar>");
+
+        // And we want to check that we resolve to the right commits.
+        assert_eq!(
+            ctx.check_modifications(&["x"], CiEnv::None),
+            PathFreshness::LastModifiedUpstream { upstream: upstream_1 }
+        );
+        assert_eq!(
+            ctx.check_modifications(&["nonexistent"], CiEnv::None),
+            PathFreshness::LastModifiedUpstream { upstream: upstream_2 }
+        );
+    });
+}
diff --git a/src/bootstrap/src/utils/tests/git.rs b/src/bootstrap/src/utils/tests/git.rs
index 735dafb3f29..99e0793af46 100644
--- a/src/bootstrap/src/utils/tests/git.rs
+++ b/src/bootstrap/src/utils/tests/git.rs
@@ -53,12 +53,14 @@ impl GitCtx {
         modified_files: &[&str],
         author: &str,
     ) -> String {
+        let current_branch = self.get_current_branch();
+
         self.create_branch(branch);
         for file in modified_files {
             self.modify(file);
         }
         self.commit();
-        self.switch_to_branch("main");
+        self.switch_to_branch(&current_branch);
         self.merge(branch, author);
         self.run_git(&["branch", "-d", branch]);
         self.get_current_commit()
@@ -68,12 +70,16 @@ impl GitCtx {
         self.run_git(&["rev-parse", "HEAD"])
     }
 
+    pub fn get_current_branch(&self) -> String {
+        self.run_git(&["rev-parse", "--abbrev-ref", "HEAD"])
+    }
+
     pub fn merge(&self, branch: &str, author: &str) {
         self.run_git(&["merge", "--no-commit", "--no-ff", branch]);
         self.run_git(&[
             "commit".to_string(),
             "-m".to_string(),
-            "Merge of {branch}".to_string(),
+            format!("Merge of {branch} into {}", self.get_current_branch()),
             "--author".to_string(),
             author.to_string(),
         ]);