mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-29 23:57:51 +00:00
b485881d50
Some checks are pending
binaries / Build binary artifacts (linux-aarch64-gnu, ubuntu-24.04, aarch64-unknown-linux-gnu) (push) Waiting to run
binaries / Build binary artifacts (linux-aarch64-musl, ubuntu-24.04, aarch64-unknown-linux-musl) (push) Waiting to run
binaries / Build binary artifacts (linux-x86_64-gnu, ubuntu-24.04, x86_64-unknown-linux-gnu) (push) Waiting to run
binaries / Build binary artifacts (linux-x86_64-musl, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Waiting to run
binaries / Build binary artifacts (macos-aarch64, macos-14, aarch64-apple-darwin) (push) Waiting to run
binaries / Build binary artifacts (macos-x86_64, macos-13, x86_64-apple-darwin) (push) Waiting to run
binaries / Build binary artifacts (win-x86_64, windows-2022, x86_64-pc-windows-msvc) (push) Waiting to run
nix / flake check (macos-14) (push) Waiting to run
nix / flake check (ubuntu-latest) (push) Waiting to run
build / build (, macos-13) (push) Waiting to run
build / build (, macos-14) (push) Waiting to run
build / build (, ubuntu-latest) (push) Waiting to run
build / build (, windows-latest) (push) Waiting to run
build / build (--all-features, ubuntu-latest) (push) Waiting to run
build / Build jj-lib without Git support (push) Waiting to run
build / Check protos (push) Waiting to run
build / Check formatting (push) Waiting to run
build / Check that MkDocs can build the docs (push) Waiting to run
build / Check that MkDocs can build the docs with Poetry 1.8 (push) Waiting to run
build / cargo-deny (advisories) (push) Waiting to run
build / cargo-deny (bans licenses sources) (push) Waiting to run
build / Clippy check (push) Waiting to run
Codespell / Codespell (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-latest) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
248 lines
8.6 KiB
Rust
248 lines
8.6 KiB
Rust
// Copyright 2024 The Jujutsu Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use std::fmt::Write as _;
|
|
|
|
use jj_lib::annotate::get_annotation_for_file;
|
|
use jj_lib::backend::CommitId;
|
|
use jj_lib::backend::MergedTreeId;
|
|
use jj_lib::backend::MillisSinceEpoch;
|
|
use jj_lib::backend::Signature;
|
|
use jj_lib::backend::Timestamp;
|
|
use jj_lib::commit::Commit;
|
|
use jj_lib::repo::MutableRepo;
|
|
use jj_lib::repo::Repo;
|
|
use jj_lib::repo_path::RepoPath;
|
|
use jj_lib::settings::UserSettings;
|
|
use testutils::create_tree;
|
|
use testutils::TestRepo;
|
|
|
|
fn create_commit_fn<'a>(
|
|
mut_repo: &'a mut MutableRepo,
|
|
settings: &'a UserSettings,
|
|
) -> impl FnMut(&str, &[&CommitId], MergedTreeId) -> Commit + 'a {
|
|
// stabilize commit IDs for ease of debugging
|
|
let signature = Signature {
|
|
name: "Some One".to_owned(),
|
|
email: "some.one@example.com".to_owned(),
|
|
timestamp: Timestamp {
|
|
timestamp: MillisSinceEpoch(0),
|
|
tz_offset: 0,
|
|
},
|
|
};
|
|
move |description, parent_ids, tree_id| {
|
|
let parent_ids = parent_ids.iter().map(|&id| id.clone()).collect();
|
|
mut_repo
|
|
.new_commit(settings, parent_ids, tree_id)
|
|
.set_author(signature.clone())
|
|
.set_committer(signature.clone())
|
|
.set_description(description)
|
|
.write()
|
|
.unwrap()
|
|
}
|
|
}
|
|
|
|
fn annotate(repo: &dyn Repo, commit: &Commit, file_path: &RepoPath) -> String {
|
|
let annotation = get_annotation_for_file(repo, commit, file_path).unwrap();
|
|
let mut output = String::new();
|
|
for (commit_id, line) in &annotation.file_annotations {
|
|
let commit = repo.store().get_commit(commit_id).unwrap();
|
|
let desc = commit.description().trim_end();
|
|
write!(output, "{desc}: {line}").unwrap();
|
|
}
|
|
output
|
|
}
|
|
|
|
#[test]
|
|
fn test_annotate_linear() {
|
|
let settings = testutils::user_settings();
|
|
let test_repo = TestRepo::init();
|
|
let repo = &test_repo.repo;
|
|
|
|
let root_commit_id = repo.store().root_commit_id();
|
|
let file_path = RepoPath::from_internal_string("file");
|
|
|
|
let mut tx = repo.start_transaction(&settings);
|
|
let mut create_commit = create_commit_fn(tx.repo_mut(), &settings);
|
|
let content1 = "";
|
|
let content2 = "2a\n2b\n";
|
|
let content3 = "2b\n3\n";
|
|
let tree1 = create_tree(repo, &[(file_path, content1)]);
|
|
let tree2 = create_tree(repo, &[(file_path, content2)]);
|
|
let tree3 = create_tree(repo, &[(file_path, content3)]);
|
|
let commit1 = create_commit("commit1", &[root_commit_id], tree1.id());
|
|
let commit2 = create_commit("commit2", &[commit1.id()], tree2.id());
|
|
let commit3 = create_commit("commit3", &[commit2.id()], tree3.id());
|
|
let commit4 = create_commit("commit4", &[commit3.id()], tree3.id()); // empty commit
|
|
drop(create_commit);
|
|
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit1, file_path), @"");
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit2, file_path), @r#"
|
|
commit2: 2a
|
|
commit2: 2b
|
|
"#);
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit3, file_path), @r#"
|
|
commit2: 2b
|
|
commit3: 3
|
|
"#);
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit4, file_path), @r#"
|
|
commit2: 2b
|
|
commit3: 3
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_annotate_merge_simple() {
|
|
let settings = testutils::user_settings();
|
|
let test_repo = TestRepo::init();
|
|
let repo = &test_repo.repo;
|
|
|
|
let root_commit_id = repo.store().root_commit_id();
|
|
let file_path = RepoPath::from_internal_string("file");
|
|
|
|
// 4 "2 1 3"
|
|
// |\
|
|
// | 3 "1 3"
|
|
// | |
|
|
// 2 | "2 1"
|
|
// |/
|
|
// 1 "1"
|
|
let mut tx = repo.start_transaction(&settings);
|
|
let mut create_commit = create_commit_fn(tx.repo_mut(), &settings);
|
|
let content1 = "1\n";
|
|
let content2 = "2\n1\n";
|
|
let content3 = "1\n3\n";
|
|
let content4 = "2\n1\n3\n";
|
|
let tree1 = create_tree(repo, &[(file_path, content1)]);
|
|
let tree2 = create_tree(repo, &[(file_path, content2)]);
|
|
let tree3 = create_tree(repo, &[(file_path, content3)]);
|
|
let tree4 = create_tree(repo, &[(file_path, content4)]);
|
|
let commit1 = create_commit("commit1", &[root_commit_id], tree1.id());
|
|
let commit2 = create_commit("commit2", &[commit1.id()], tree2.id());
|
|
let commit3 = create_commit("commit3", &[commit1.id()], tree3.id());
|
|
let commit4 = create_commit("commit4", &[commit2.id(), commit3.id()], tree4.id());
|
|
drop(create_commit);
|
|
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit4, file_path), @r#"
|
|
commit2: 2
|
|
commit1: 1
|
|
commit3: 3
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_annotate_merge_split() {
|
|
let settings = testutils::user_settings();
|
|
let test_repo = TestRepo::init();
|
|
let repo = &test_repo.repo;
|
|
|
|
let root_commit_id = repo.store().root_commit_id();
|
|
let file_path = RepoPath::from_internal_string("file");
|
|
|
|
// 4 "2 1a 1b 3 4"
|
|
// |\
|
|
// | 3 "1b 3"
|
|
// | |
|
|
// 2 | "2 1a"
|
|
// |/
|
|
// 1 "1a 1b"
|
|
let mut tx = repo.start_transaction(&settings);
|
|
let mut create_commit = create_commit_fn(tx.repo_mut(), &settings);
|
|
let content1 = "1a\n1b\n";
|
|
let content2 = "2\n1a\n";
|
|
let content3 = "1b\n3\n";
|
|
let content4 = "2\n1a\n1b\n3\n4\n";
|
|
let tree1 = create_tree(repo, &[(file_path, content1)]);
|
|
let tree2 = create_tree(repo, &[(file_path, content2)]);
|
|
let tree3 = create_tree(repo, &[(file_path, content3)]);
|
|
let tree4 = create_tree(repo, &[(file_path, content4)]);
|
|
let commit1 = create_commit("commit1", &[root_commit_id], tree1.id());
|
|
let commit2 = create_commit("commit2", &[commit1.id()], tree2.id());
|
|
let commit3 = create_commit("commit3", &[commit1.id()], tree3.id());
|
|
let commit4 = create_commit("commit4", &[commit2.id(), commit3.id()], tree4.id());
|
|
drop(create_commit);
|
|
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit4, file_path), @r#"
|
|
commit2: 2
|
|
commit1: 1a
|
|
commit1: 1b
|
|
commit3: 3
|
|
commit4: 4
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic] // FIXME: shouldn't panic because of duplicated "1"s
|
|
fn test_annotate_merge_dup() {
|
|
let settings = testutils::user_settings();
|
|
let test_repo = TestRepo::init();
|
|
let repo = &test_repo.repo;
|
|
|
|
let root_commit_id = repo.store().root_commit_id();
|
|
let file_path = RepoPath::from_internal_string("file");
|
|
|
|
// 4 "2 1 1 3 4"
|
|
// |\
|
|
// | 3 "1 3"
|
|
// | |
|
|
// 2 | "2 1"
|
|
// |/
|
|
// 1 "1"
|
|
let mut tx = repo.start_transaction(&settings);
|
|
let mut create_commit = create_commit_fn(tx.repo_mut(), &settings);
|
|
let content1 = "1\n";
|
|
let content2 = "2\n1\n";
|
|
let content3 = "1\n3\n";
|
|
let content4 = "2\n1\n1\n3\n4\n";
|
|
let tree1 = create_tree(repo, &[(file_path, content1)]);
|
|
let tree2 = create_tree(repo, &[(file_path, content2)]);
|
|
let tree3 = create_tree(repo, &[(file_path, content3)]);
|
|
let tree4 = create_tree(repo, &[(file_path, content4)]);
|
|
let commit1 = create_commit("commit1", &[root_commit_id], tree1.id());
|
|
let commit2 = create_commit("commit2", &[commit1.id()], tree2.id());
|
|
let commit3 = create_commit("commit3", &[commit1.id()], tree3.id());
|
|
let commit4 = create_commit("commit4", &[commit2.id(), commit3.id()], tree4.id());
|
|
drop(create_commit);
|
|
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit4, file_path), @r#"
|
|
commit2: 2
|
|
commit1: 1
|
|
commit1: 1
|
|
commit3: 3
|
|
commit4: 4
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_annotate_file_directory_transition() {
|
|
let settings = testutils::user_settings();
|
|
let test_repo = TestRepo::init();
|
|
let repo = &test_repo.repo;
|
|
|
|
let root_commit_id = repo.store().root_commit_id();
|
|
let file_path1 = RepoPath::from_internal_string("file/was_dir");
|
|
let file_path2 = RepoPath::from_internal_string("file");
|
|
|
|
let mut tx = repo.start_transaction(&settings);
|
|
let mut create_commit = create_commit_fn(tx.repo_mut(), &settings);
|
|
let tree1 = create_tree(repo, &[(file_path1, "1\n")]);
|
|
let tree2 = create_tree(repo, &[(file_path2, "2\n")]);
|
|
let commit1 = create_commit("commit1", &[root_commit_id], tree1.id());
|
|
let commit2 = create_commit("commit2", &[commit1.id()], tree2.id());
|
|
drop(create_commit);
|
|
|
|
insta::assert_snapshot!(annotate(tx.repo(), &commit2, file_path2), @r#"
|
|
commit2: 2
|
|
"#);
|
|
}
|