コード例 #1
0
    public void GetHeight_Merge()
    {
        var firstCommit = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions {
            AllowEmptyCommit = true
        });
        var anotherBranch = this.LibGit2Repository.CreateBranch("another");
        var secondCommit  = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions {
            AllowEmptyCommit = true
        });

        Commands.Checkout(this.LibGit2Repository, anotherBranch);
        Commit[] branchCommits = new Commit[5];
        for (int i = 1; i <= branchCommits.Length; i++)
        {
            branchCommits[i - 1] = this.LibGit2Repository.Commit($"branch commit #{i}", this.Signer, this.Signer, new CommitOptions {
                AllowEmptyCommit = true
            });
        }

        this.LibGit2Repository.Merge(secondCommit, new Signature("t", "*****@*****.**", DateTimeOffset.Now), new MergeOptions {
            FastForwardStrategy = FastForwardStrategy.NoFastForward
        });
        this.SetContextToHead();

        // While we've created 8 commits, the tallest height is only 7.
        Assert.Equal(7, LibGit2GitExtensions.GetHeight(this.Context));

        // Now stop enumerating early on just one branch of the ancestry -- the number should remain high.
        Assert.Equal(7, LibGit2GitExtensions.GetHeight(this.Context, c => c != secondCommit));

        // This time stop in both branches of history, and verify that we count the taller one.
        Assert.Equal(3, LibGit2GitExtensions.GetHeight(this.Context, c => c != secondCommit && c != branchCommits[2]));
    }
コード例 #2
0
    public void GetIdAsVersion_Roundtrip_WithSubdirectoryVersionFiles()
    {
        var rootVersionExpected = VersionOptions.FromVersion(new Version(1, 0));

        this.Context.VersionFile.SetVersion(this.RepoPath, rootVersionExpected);

        var          subPathVersionExpected = VersionOptions.FromVersion(new Version(1, 1));
        const string subPathRelative        = "a";
        string       subPath = Path.Combine(this.RepoPath, subPathRelative);

        Directory.CreateDirectory(subPath);
        this.Context.VersionFile.SetVersion(subPath, subPathVersionExpected);

        this.InitializeSourceControl();

        Commit  head = this.LibGit2Repository.Head.Commits.First();
        Version rootVersionActual    = this.GetVersion(committish: head.Sha);
        Version subPathVersionActual = this.GetVersion(subPathRelative, head.Sha);

        // Verify that the versions calculated took the path into account.
        Assert.Equal(rootVersionExpected.Version.Version.Minor, rootVersionActual?.Minor);
        Assert.Equal(subPathVersionExpected.Version.Version.Minor, subPathVersionActual?.Minor);

        // Verify that we can find the commit given the version and path.
        Assert.Equal(head, LibGit2GitExtensions.GetCommitFromVersion(this.Context, rootVersionActual));
        this.Context.RepoRelativeProjectDirectory = subPathRelative;
        Assert.Equal(head, LibGit2GitExtensions.GetCommitFromVersion(this.Context, subPathVersionActual));

        // Verify that mismatching path and version results in a null value.
        Assert.Null(LibGit2GitExtensions.GetCommitFromVersion(this.Context, rootVersionActual));
        this.Context.RepoRelativeProjectDirectory = string.Empty;
        Assert.Null(LibGit2GitExtensions.GetCommitFromVersion(this.Context, subPathVersionActual));
    }
コード例 #3
0
    public void GetCommitsFromVersion_WithPathFilters()
    {
        string relativeDirectory = "some-sub-dir";

        var commitsAt121 = new List <Commit>();
        var commitsAt122 = new List <Commit>();
        var commitsAt123 = new List <Commit>();

        var versionData = VersionOptions.FromVersion(new Version("1.2"));

        versionData.PathFilters = new[]
        {
            new FilterPath("./", relativeDirectory),
            new FilterPath(":^/some-sub-dir/ignore.txt", relativeDirectory),
            new FilterPath(":^excluded-dir", relativeDirectory)
        };
        commitsAt121.Add(this.WriteVersionFile(versionData, relativeDirectory));

        // Commit touching excluded path does not affect version height
        var ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt");

        File.WriteAllText(ignoredFilePath, "hello");
        Commands.Stage(this.LibGit2Repository, ignoredFilePath);
        commitsAt121.Add(this.LibGit2Repository.Commit("Add excluded file", this.Signer, this.Signer));

        // Commit touching both excluded and included path does affect height
        var includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt");

        File.WriteAllText(includedFilePath, "hello");
        File.WriteAllText(ignoredFilePath, "changed");
        Commands.Stage(this.LibGit2Repository, includedFilePath);
        Commands.Stage(this.LibGit2Repository, ignoredFilePath);
        commitsAt122.Add(this.LibGit2Repository.Commit("Change both excluded and included file", this.Signer, this.Signer));

        // Commit touching excluded directory does not affect version height
        var fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt");

        Directory.CreateDirectory(Path.GetDirectoryName(fileInExcludedDirPath));
        File.WriteAllText(fileInExcludedDirPath, "hello");
        Commands.Stage(this.LibGit2Repository, fileInExcludedDirPath);
        commitsAt122.Add(this.LibGit2Repository.Commit("Add file to excluded dir", this.Signer, this.Signer));

        // Commit touching project directory affects version height
        File.WriteAllText(includedFilePath, "more changes");
        Commands.Stage(this.LibGit2Repository, includedFilePath);
        commitsAt123.Add(this.LibGit2Repository.Commit("Changed included file", this.Signer, this.Signer));

        this.Context.RepoRelativeProjectDirectory = relativeDirectory;
        Assert.Equal(
            commitsAt121.OrderBy(c => c.Sha),
            LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 2, 1)).OrderBy(c => c.Sha));
        Assert.Equal(
            commitsAt122.OrderBy(c => c.Sha),
            LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 2, 2)).OrderBy(c => c.Sha));
        Assert.Equal(
            commitsAt123.OrderBy(c => c.Sha),
            LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 2, 3)).OrderBy(c => c.Sha));
    }
コード例 #4
0
    public void GetHeight_EmptyRepo()
    {
        this.InitializeSourceControl();

        Branch head = this.LibGit2Repository.Head;

        Assert.Throws <InvalidOperationException>(() => LibGit2GitExtensions.GetHeight(this.Context));
        Assert.Throws <InvalidOperationException>(() => LibGit2GitExtensions.GetHeight(this.Context, c => true));
    }
コード例 #5
0
    private void VerifyCommitsWithVersion(Commit[] commits)
    {
        Requires.NotNull(commits, nameof(commits));

        for (int i = 0; i < commits.Length; i++)
        {
            Version encodedVersion = this.GetVersion(committish: commits[i].Sha);
            Assert.Equal(i + 1, encodedVersion.Build);
            Assert.Equal(commits[i], LibGit2GitExtensions.GetCommitFromVersion(this.Context, encodedVersion));
        }
    }
コード例 #6
0
    public void GetCommitsFromVersion_MatchesOnEitherEndian()
    {
        this.InitializeSourceControl();
        Commit commit = this.WriteVersionFile(new VersionOptions {
            Version = SemanticVersion.Parse("1.2"), GitCommitIdShortAutoMinimum = 4
        });

        Version originalVersion      = new VersionOracle(this.Context).Version;
        Version swappedEndian        = new Version(originalVersion.Major, originalVersion.Minor, originalVersion.Build, BinaryPrimitives.ReverseEndianness((ushort)originalVersion.Revision));
        ushort  twoBytesFromCommitId = checked ((ushort)originalVersion.Revision);

        Assert.Contains(commit, LibGit2GitExtensions.GetCommitsFromVersion(this.Context, originalVersion));
        Assert.Contains(commit, LibGit2GitExtensions.GetCommitsFromVersion(this.Context, swappedEndian));
    }
コード例 #7
0
    public void GetCommitsFromVersion_WithMajorMinorChecks()
    {
        Commit v1_0_50 = this.WriteVersionFile(new VersionOptions {
            Version = SemanticVersion.Parse("1.0.50-preview.{height}")
        });
        Commit v1_1_50 = this.WriteVersionFile(new VersionOptions {
            Version = SemanticVersion.Parse("1.1.50-preview.{height}")
        });

        Assert.Empty(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 0)));
        Assert.Empty(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 0, 49)));
        Assert.Equal(v1_0_50, Assert.Single(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 0, 50))));
        Assert.Equal(v1_1_50, Assert.Single(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 1, 50))));
    }
コード例 #8
0
    [SkippableFact(Skip = "It fails already.")] // Skippable, only run test on specific machine
    public void TestBiggerRepo()
    {
        var testBiggerRepoPath = @"D:\git\NerdBank.GitVersioning";

        Skip.If(!Directory.Exists(testBiggerRepoPath));

        using var largeRepo = new Repository(testBiggerRepoPath);
        foreach (var commit in largeRepo.Head.Commits)
        {
            var version = this.GetVersion("src", commit.Sha);
            this.Logger.WriteLine($"commit {commit.Id} got version {version}");
            using var context = LibGit2Context.Create("src", commit.Sha);
            var backAgain = LibGit2GitExtensions.GetCommitFromVersion(context, version);
            Assert.Equal(commit, backAgain);
        }
    }
コード例 #9
0
    [InlineData(50, -2, true)]  // force many build number collisions. generally revision will still make them unique, but it *might* collide on occasion.
    public void GetIdAsVersion_Roundtrip_UnstableOffset(int startingOffset, int offsetStepChange, bool allowCollisions)
    {
        var versionOptions = new VersionOptions
        {
            Version             = SemanticVersion.Parse("1.2"),
            AssemblyVersion     = null,
            VersionHeightOffset = startingOffset,
        };

        this.WriteVersionFile(versionOptions);

        Commit[]  commits  = new Commit[16]; // create enough that statistically we'll likely hit interesting bits as MSB and LSB
        Version[] versions = new Version[commits.Length];
        for (int i = 0; i < commits.Length; i += 2)
        {
            versionOptions.VersionHeightOffset += offsetStepChange;
            commits[i]  = this.WriteVersionFile(versionOptions);
            versions[i] = this.GetVersion(committish: commits[i].Sha);

            commits[i + 1] = this.LibGit2Repository.Commit($"Commit {i + 1}", this.Signer, this.Signer, new CommitOptions {
                AllowEmptyCommit = true
            });
            versions[i + 1] = this.GetVersion(committish: commits[i + 1].Sha);

            this.Logger.WriteLine($"Commit {commits[i].Id.Sha.Substring(0, 8)} as version: {versions[i]}");
            this.Logger.WriteLine($"Commit {commits[i + 1].Id.Sha.Substring(0, 8)} as version: {versions[i + 1]}");

            // Find the commits we just wrote while they are still at the tip of the branch.
            var matchingCommits = LibGit2GitExtensions.GetCommitsFromVersion(this.Context, versions[i]);
            Assert.Contains(commits[i], matchingCommits);
            matchingCommits = LibGit2GitExtensions.GetCommitsFromVersion(this.Context, versions[i + 1]);
            Assert.Contains(commits[i + 1], matchingCommits);
        }

        // Find all commits (again) now that history has been written.
        for (int i = 0; i < commits.Length; i++)
        {
            var matchingCommits = LibGit2GitExtensions.GetCommitsFromVersion(this.Context, versions[i]).ToList();
            Assert.Contains(commits[i], matchingCommits);
            if (!allowCollisions)
            {
                Assert.Single(matchingCommits);
            }
        }
    }
コード例 #10
0
    public void GetHeight_SinglePath()
    {
        var first = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions {
            AllowEmptyCommit = true
        });
        var second = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions {
            AllowEmptyCommit = true
        });
        var third = this.LibGit2Repository.Commit("Third", this.Signer, this.Signer, new CommitOptions {
            AllowEmptyCommit = true
        });

        this.SetContextToHead();
        Assert.Equal(3, LibGit2GitExtensions.GetHeight(this.Context));
        Assert.Equal(3, LibGit2GitExtensions.GetHeight(this.Context, c => true));

        Assert.Equal(2, LibGit2GitExtensions.GetHeight(this.Context, c => c != first));
        Assert.Equal(1, LibGit2GitExtensions.GetHeight(this.Context, c => c != second));
    }
コード例 #11
0
    public void GetIdAsVersion_Roundtrip(string version, string assemblyVersion, int versionHeightOffset)
    {
        var          semanticVersion          = SemanticVersion.Parse(version);
        const string repoRelativeSubDirectory = "subdir";

        this.WriteVersionFile(
            new VersionOptions
        {
            Version             = semanticVersion,
            AssemblyVersion     = new VersionOptions.AssemblyVersionOptions(new Version(assemblyVersion)),
            VersionHeightOffset = versionHeightOffset,
        },
            repoRelativeSubDirectory);

        Commit[]  commits  = new Commit[16]; // create enough that statistically we'll likely hit interesting bits as MSB and LSB
        Version[] versions = new Version[commits.Length];
        for (int i = 0; i < commits.Length; i++)
        {
            commits[i] = this.LibGit2Repository.Commit($"Commit {i + 1}", this.Signer, this.Signer, new CommitOptions {
                AllowEmptyCommit = true
            });
            versions[i] = this.GetVersion(repoRelativeSubDirectory, commits[i].Sha);
            this.Logger.WriteLine($"Commit {commits[i].Id.Sha.Substring(0, 8)} as version: {versions[i]}");
        }

        this.Context.RepoRelativeProjectDirectory = repoRelativeSubDirectory;
        for (int i = 0; i < commits.Length; i++)
        {
            Assert.Equal(commits[i], LibGit2GitExtensions.GetCommitFromVersion(this.Context, versions[i]));

            // Also verify that we can find it without the revision number.
            // This is important because stable, publicly released NuGet packages
            // that contain no assemblies may only have major.minor.build as their version evidence.
            // But folks who specify a.b.c version numbers don't have any unique version component for the commit at all without the 4th integer.
            if (semanticVersion.Version.Build == -1)
            {
                Assert.Equal(commits[i], LibGit2GitExtensions.GetCommitFromVersion(this.Context, new Version(versions[i].Major, versions[i].Minor, versions[i].Build)));
            }
        }
    }
コード例 #12
0
        private static int OnGetCommitsCommand(string project, bool quiet, string version)
        {
            if (!Version.TryParse(version, out Version parsedVersion))
            {
                Console.Error.WriteLine($"\"{version}\" is not a simple a.b.c[.d] version spec.");
                return((int)ExitCodes.InvalidVersionSpec);
            }

            string searchPath = GetSpecifiedOrCurrentDirectoryPath(project);

            using var context = (LibGit2Context)GitContext.Create(searchPath, writable: true);
            if (!context.IsRepository)
            {
                Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath);
                return((int)ExitCodes.NoGitRepo);
            }

            var candidateCommits = LibGit2GitExtensions.GetCommitsFromVersion(context, parsedVersion);

            PrintCommits(quiet, context, candidateCommits);

            return((int)ExitCodes.OK);
        }
コード例 #13
0
        private static int OnTagCommand(string project, string versionOrRef)
        {
            if (string.IsNullOrEmpty(versionOrRef))
            {
                versionOrRef = DefaultRef;
            }

            string searchPath = GetSpecifiedOrCurrentDirectoryPath(project);

            using var context = (LibGit2Context)GitContext.Create(searchPath, writable: true);
            if (context is null)
            {
                Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath);
                return((int)ExitCodes.NoGitRepo);
            }

            var repository = context.Repository;

            if (!context.TrySelectCommit(versionOrRef))
            {
                if (!Version.TryParse(versionOrRef, out Version parsedVersion))
                {
                    Console.Error.WriteLine($"\"{versionOrRef}\" is not a simple a.b.c[.d] version spec or git reference.");
                    return((int)ExitCodes.InvalidVersionSpec);
                }

                string repoRelativeProjectDir = GetRepoRelativePath(searchPath, repository);
                var    candidateCommits       = LibGit2GitExtensions.GetCommitsFromVersion(context, parsedVersion).ToList();
                if (candidateCommits.Count == 0)
                {
                    Console.Error.WriteLine("No commit with that version found.");
                    return((int)ExitCodes.NoMatchingVersion);
                }
                else if (candidateCommits.Count > 1)
                {
                    PrintCommits(false, context, candidateCommits, includeOptions: true);
                    int selection;
                    do
                    {
                        Console.Write("Enter selection: ");
                    }while (!int.TryParse(Console.ReadLine(), out selection) || selection > candidateCommits.Count || selection < 1);
                    context.TrySelectCommit(candidateCommits[selection - 1].Sha);
                }
                else
                {
                    context.TrySelectCommit(candidateCommits.Single().Sha);
                }
            }

            var oracle = new VersionOracle(context, CloudBuild.Active);

            if (!oracle.VersionFileFound)
            {
                Console.Error.WriteLine("No version.json file found in or above \"{0}\" in commit {1}.", searchPath, context.GitCommitId);
                return((int)ExitCodes.NoVersionJsonFound);
            }

            oracle.PublicRelease = true; // assume a public release so we don't get a redundant -gCOMMITID in the tag name
            string tagName = $"v{oracle.SemVer2}";

            try
            {
                context.ApplyTag(tagName);
            }
            catch (LibGit2Sharp.NameConflictException)
            {
                var  taggedCommit = repository.Tags[tagName].Target as LibGit2Sharp.Commit;
                bool correctTag   = taggedCommit?.Sha == context.GitCommitId;
                Console.Error.WriteLine("The tag {0} is already defined ({1}).", tagName, correctTag ? "to the right commit" : $"expected {context.GitCommitId} but was on {taggedCommit.Sha}");
                return((int)(correctTag ? ExitCodes.OK : ExitCodes.TagConflict));
            }

            Console.WriteLine("{0} tag created at {1}.", tagName, context.GitCommitId);
            Console.WriteLine("Remember to push to a remote: git push origin {0}", tagName);

            return((int)ExitCodes.OK);
        }