axbuild 0.4.19

An OS build lib toolkit used by arceos
Documentation
use super::common::{git_stdout, run_git, test_workspace};
use crate::support::git::{
    IncrementalPackageSelection, refs::resolve_since_diff_base, select_incremental_packages,
};

#[test]
fn since_tag_resolves_to_commit() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);
    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let base = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(root.path(), &["tag", "base-tag"]);

    std::fs::write(root.path().join("file.txt"), "head\n").unwrap();
    run_git(root.path(), &["commit", "-am", "head"]);

    assert_eq!(
        resolve_since_diff_base(root.path(), "base-tag").unwrap(),
        base
    );
}

#[test]
fn since_ref_that_is_not_head_ancestor_resolves_to_merge_base() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);
    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let merge_base = git_stdout(root.path(), &["rev-parse", "HEAD"]);

    run_git(root.path(), &["checkout", "-b", "feature"]);
    std::fs::write(root.path().join("feature.txt"), "feature\n").unwrap();
    run_git(root.path(), &["add", "feature.txt"]);
    run_git(root.path(), &["commit", "-m", "feature"]);

    run_git(root.path(), &["checkout", "-b", "main", &merge_base]);
    std::fs::write(root.path().join("main.txt"), "main\n").unwrap();
    run_git(root.path(), &["add", "main.txt"]);
    run_git(root.path(), &["commit", "-m", "main"]);

    run_git(root.path(), &["checkout", "feature"]);

    assert_eq!(
        resolve_since_diff_base(root.path(), "main").unwrap(),
        merge_base
    );
}

#[test]
fn zero_since_on_new_branch_resolves_to_first_unique_parent() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);

    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let base = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/dev", &base],
    );

    run_git(root.path(), &["checkout", "-b", "feature"]);
    std::fs::write(root.path().join("feature.txt"), "feature 1\n").unwrap();
    run_git(root.path(), &["add", "feature.txt"]);
    run_git(root.path(), &["commit", "-m", "feature 1"]);
    std::fs::write(root.path().join("feature.txt"), "feature 2\n").unwrap();
    run_git(root.path(), &["commit", "-am", "feature 2"]);
    let head = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/feature", &head],
    );

    assert_eq!(
        resolve_since_diff_base(root.path(), "0000000000000000000000000000000000000000").unwrap(),
        base
    );
}

#[test]
fn zero_since_ignores_default_branch_tip_after_branch_fork() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);

    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let fork_point = git_stdout(root.path(), &["rev-parse", "HEAD"]);

    run_git(root.path(), &["checkout", "-b", "feature"]);
    std::fs::write(root.path().join("feature.txt"), "feature\n").unwrap();
    run_git(root.path(), &["add", "feature.txt"]);
    run_git(root.path(), &["commit", "-m", "feature"]);
    let feature_head = git_stdout(root.path(), &["rev-parse", "HEAD"]);

    run_git(root.path(), &["checkout", "-b", "dev", &fork_point]);
    std::fs::write(root.path().join("file.txt"), "dev 1\n").unwrap();
    run_git(root.path(), &["commit", "-am", "dev 1"]);
    std::fs::write(root.path().join("file.txt"), "dev 2\n").unwrap();
    run_git(root.path(), &["commit", "-am", "dev 2"]);
    let dev_head = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    assert_ne!(dev_head, fork_point);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/dev", &dev_head],
    );

    run_git(root.path(), &["checkout", "feature"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/feature", &feature_head],
    );

    assert_eq!(
        resolve_since_diff_base(root.path(), "0000000000000000000000000000000000000000").unwrap(),
        fork_point
    );
}

#[test]
fn unresolved_push_before_sha_resolves_like_new_branch_since() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);

    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let base = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/dev", &base],
    );

    run_git(root.path(), &["checkout", "-b", "feature"]);
    std::fs::write(root.path().join("feature.txt"), "feature 1\n").unwrap();
    run_git(root.path(), &["add", "feature.txt"]);
    run_git(root.path(), &["commit", "-m", "feature 1"]);
    std::fs::write(root.path().join("feature.txt"), "feature 2\n").unwrap();
    run_git(root.path(), &["commit", "-am", "feature 2"]);
    let head = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/feature", &head],
    );

    assert_eq!(
        resolve_since_diff_base(root.path(), "1111111111111111111111111111111111111111").unwrap(),
        base
    );
}

#[test]
fn unresolved_push_before_sha_without_remote_refs_returns_error() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);

    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);

    let err = resolve_since_diff_base(root.path(), "1111111111111111111111111111111111111111")
        .unwrap_err();

    assert!(
        format!("{err:#}").contains("no remote refs remain"),
        "unexpected error: {err:#}"
    );
}

#[test]
fn unresolved_named_ref_does_not_use_push_before_sha_fallback() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);

    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let base = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/dev", &base],
    );

    let err = resolve_since_diff_base(root.path(), "missing-branch").unwrap_err();

    assert!(
        format!("{err:#}").contains("failed to resolve `missing-branch` to a commit"),
        "unexpected error: {err:#}"
    );
}

#[test]
fn unresolved_short_sha_does_not_use_push_before_sha_fallback() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);

    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let base = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/dev", &base],
    );

    let err = resolve_since_diff_base(root.path(), "1111111").unwrap_err();

    assert!(
        format!("{err:#}").contains("failed to resolve `1111111` to a commit"),
        "unexpected error: {err:#}"
    );
}

#[test]
fn zero_since_root_manifest_change_uses_inferred_base() {
    let (root, metadata, workspace_packages) = test_workspace();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);
    std::fs::write(
        root.path().join("Cargo.toml"),
        "[workspace]\nmembers = [\"crates/alpha\", \"crates/beta\", \
         \"crates/gamma\"]\n\n[workspace.dependencies]\nalpha = { path = \"crates/alpha\" }\n",
    )
    .unwrap();
    run_git(root.path(), &["add", "."]);
    run_git(root.path(), &["commit", "-m", "base"]);
    let base = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/dev", &base],
    );

    run_git(root.path(), &["checkout", "-b", "feature"]);
    std::fs::write(
        root.path().join("Cargo.toml"),
        "[workspace]\nmembers = [\"crates/alpha\", \"crates/beta\", \
         \"crates/gamma\"]\n\n[workspace.dependencies]\nalpha = { path = \"crates/alpha\", \
         package = \"alpha\" }\n",
    )
    .unwrap();
    run_git(root.path(), &["commit", "-am", "feature"]);
    let head = git_stdout(root.path(), &["rev-parse", "HEAD"]);
    run_git(
        root.path(),
        &["update-ref", "refs/remotes/origin/feature", &head],
    );

    let selected = select_incremental_packages(
        root.path(),
        &metadata,
        &workspace_packages,
        "0000000000000000000000000000000000000000",
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: vec!["alpha".into()],
            affected: vec!["alpha".into(), "beta".into(), "gamma".into()],
        }
    );
}

#[test]
fn zero_since_without_remote_refs_returns_error() {
    let root = tempfile::tempdir().unwrap();
    run_git(root.path(), &["init"]);
    run_git(root.path(), &["config", "user.email", "test@example.com"]);
    run_git(root.path(), &["config", "user.name", "Test User"]);
    std::fs::write(root.path().join("file.txt"), "base\n").unwrap();
    run_git(root.path(), &["add", "file.txt"]);
    run_git(root.path(), &["commit", "-m", "base"]);

    let err = resolve_since_diff_base(root.path(), "0000000000000000000000000000000000000000")
        .unwrap_err();

    assert!(
        format!("{err:#}").contains("no remote refs remain"),
        "unexpected error: {err:#}"
    );
}