예제 #1
0
        public void ShouldWriteAllVersionsToProjectFiles()
        {
            var tempDir = TempDir.Create();

            TempCsProject.Create(Path.Join(tempDir, "project1"), "1.1.1");
            TempCsProject.Create(Path.Join(tempDir, "project2"), "1.1.1");

            var projects = Projects.Discover(tempDir);

            projects.WriteVersion(new Version(2, 0, 0));

            var updated = Projects.Discover(tempDir);

            updated.Version.ShouldBe(Version.Parse("2.0.0"));
        }
예제 #2
0
        public void WriteVersion(Version nextVersion)
        {
            var doc = new XmlDocument {
                PreserveWhitespace = true
            };

            try
            {
                doc.Load(ProjectFile);
            }
            catch (Exception)
            {
                throw new InvalidOperationException($"Project {ProjectFile} is not a valid csproj file. Please make sure that you have a valid csproj file in place!");
            }

            var versionElement = doc.SelectSingleNode("/Project/PropertyGroup/Version");

            versionElement.InnerText = nextVersion.ToString();

            doc.Save(ProjectFile);
        }
예제 #3
0
        public Version NextVersion(Version version, bool ignoreInsignificant = false)
        {
            switch (_versionImpact)
            {
            case VersionImpact.Patch:
                return(new Version(version.Major, version.Minor, version.Patch + 1));

            case VersionImpact.Minor:
                return(new Version(version.Major, version.Minor + 1, 0));

            case VersionImpact.Major:
                return(new Version(version.Major + 1, 0, 0));

            case VersionImpact.None:
                var buildVersion = ignoreInsignificant ? version.Patch : version.Patch + 1;
                return(new Version(version.Major, version.Minor, buildVersion));

            default:
                throw new InvalidOperationException($"Version impact of {_versionImpact} cannot be handled");
            }
        }
예제 #4
0
 public string BuildVersionTagLink(Version version)
 {
     return($"https://{_organization}@dev.azure.com/{_organization}/{_repository}/releases/tag/v{version}");
 }
예제 #5
0
 public static Tag SelectVersionTag(this Repository repository, Version version)
 {
     return(repository.Tags.SingleOrDefault(t => t.FriendlyName == $"v{version}"));
 }
예제 #6
0
        public Version Versionize(bool dryrun                       = false,
                                  bool skipDirtyCheck               = false,
                                  bool skipCommit                   = false,
                                  string releaseVersion             = null,
                                  bool ignoreInsignificant          = false,
                                  bool includeAllCommitsInChangelog = false,
                                  string releaseCommitMessageSuffix = null)
        {
            var workingDirectory = _directory.FullName;

            using (var repo = new Repository(workingDirectory))
            {
                var isDirty = repo.RetrieveStatus(new StatusOptions()).IsDirty;

                if (!skipDirtyCheck && isDirty)
                {
                    Exit($"Repository {workingDirectory} is dirty. Please commit your changes.", 1);
                }

                var projects = Projects.Discover(workingDirectory);

                if (projects.IsEmpty())
                {
                    Exit($"Could not find any projects files in {workingDirectory} that have a <Version> defined in their csproj file.", 1);
                }

                if (projects.HasInconsistentVersioning())
                {
                    Exit($"Some projects in {workingDirectory} have an inconsistent <Version> defined in their csproj file. Please update all versions to be consistent or remove the <Version> elements from projects that should not be versioned", 1);
                }

                Information($"Discovered {projects.GetProjectFiles().Count()} versionable projects");
                foreach (var project in projects.GetProjectFiles())
                {
                    Information($"  * {project}");
                }

                var versionTag       = repo.SelectVersionTag(projects.Version);
                var commitsInVersion = repo.GetCommitsSinceLastVersion(versionTag);

                var conventionalCommits = ConventionalCommitParser.Parse(commitsInVersion);

                var versionIncrement = VersionIncrementStrategy.CreateFrom(conventionalCommits);

                var nextVersion = versionTag == null ? projects.Version : versionIncrement.NextVersion(projects.Version, ignoreInsignificant);

                if (ignoreInsignificant && nextVersion == projects.Version)
                {
                    Exit($"Version was not affected by commits since last release ({projects.Version}), since you specified to ignore insignificant changes, no action will be performed.", 0);
                }

                if (!string.IsNullOrWhiteSpace(releaseVersion))
                {
                    try
                    {
                        nextVersion = Version.Parse(releaseVersion);
                    }
                    catch (Exception)
                    {
                        Exit($"Could not parse the specified release version {releaseVersion} as valid version", 1);
                    }
                }

                var versionTime = DateTimeOffset.Now;

                // Commit changelog and version source
                if (!dryrun && (nextVersion != projects.Version))
                {
                    projects.WriteVersion(nextVersion);

                    foreach (var projectFile in projects.GetProjectFiles())
                    {
                        Commands.Stage(repo, projectFile);
                    }
                }

                Step($"bumping version from {projects.Version} to {nextVersion} in projects");

                var changelog = Changelog.Discover(workingDirectory);

                if (!dryrun)
                {
                    var changelogLinkBuilder = ChangelogLinkBuilderFactory.CreateFor(repo);
                    changelog.Write(nextVersion, versionTime, changelogLinkBuilder, conventionalCommits, includeAllCommitsInChangelog);
                }

                Step("updated CHANGELOG.md");

                if (!dryrun && !skipCommit)
                {
                    Commands.Stage(repo, changelog.FilePath);

                    foreach (var projectFile in projects.GetProjectFiles())
                    {
                        Commands.Stage(repo, projectFile);
                    }
                }

                if (!dryrun && !skipCommit)
                {
                    var author    = repo.Config.BuildSignature(versionTime);
                    var committer = author;

                    // TODO: Check if tag exists before commit
                    var releaseCommitMessage = $"chore(release): {nextVersion} {releaseCommitMessageSuffix}".TrimEnd();
                    var versionCommit        = repo.Commit(releaseCommitMessage, author, committer);
                    Step("committed changes in projects and CHANGELOG.md");

                    repo.Tags.Add($"v{nextVersion}", versionCommit, author, $"{nextVersion}");
                    Step($"tagged release as {nextVersion}");

                    Information("");
                    Information("i Run `git push --follow-tags origin master` to push all changes including tags");
                }
                else if (skipCommit)
                {
                    Information("");
                    Information($"i Commit and tagging of release was skipped. Tag this release as `v{nextVersion}` to make versionize detect the release");
                }

                return(nextVersion);
            }
        }
예제 #7
0
 private Project(string projectFile, Version version)
 {
     ProjectFile = projectFile;
     Version     = version;
 }
예제 #8
0
        public void Write(Version version, DateTimeOffset versionTime, IChangelogLinkBuilder linkBuilder, IEnumerable <ConventionalCommit> commits,
                          bool includeAllCommitsInChangelog = false)
        {
            var versionTagLink = string.IsNullOrWhiteSpace(linkBuilder.BuildVersionTagLink(version)) ? version.ToString() : $"[{version}]({linkBuilder.BuildVersionTagLink(version)})";

            var markdown = $"<a name=\"{version}\"></a>";

            markdown += "\n";
            markdown += $"## {versionTagLink} ({versionTime.Year}-{versionTime.Month}-{versionTime.Day})";
            markdown += "\n";
            markdown += "\n";

            var bugFixes = BuildBlock("Bug Fixes", linkBuilder, commits.Where(commit => commit.IsFix));

            if (!string.IsNullOrWhiteSpace(bugFixes))
            {
                markdown += bugFixes;
                markdown += "\n";
            }

            var features = BuildBlock("Features", linkBuilder, commits.Where(commit => commit.IsFeature));

            if (!string.IsNullOrWhiteSpace(features))
            {
                markdown += features;
                markdown += "\n";
            }

            var breaking = BuildBlock("Breaking Changes", linkBuilder, commits.Where(commit => commit.IsBreakingChange));

            if (!string.IsNullOrWhiteSpace(breaking))
            {
                markdown += breaking;
                markdown += "\n";
            }

            if (includeAllCommitsInChangelog)
            {
                var other = BuildBlock("Other", linkBuilder, commits.Where(commit => !commit.IsFix && !commit.IsFeature && !commit.IsBreakingChange));

                if (!string.IsNullOrWhiteSpace(other))
                {
                    markdown += other;
                    markdown += "\n";
                }
            }

            if (File.Exists(FilePath))
            {
                var contents = File.ReadAllText(FilePath);

                var firstReleaseHeadlineIdx = contents.IndexOf("<a name=\"", StringComparison.Ordinal);

                if (firstReleaseHeadlineIdx >= 0)
                {
                    markdown = contents.Insert(firstReleaseHeadlineIdx, markdown);
                }
                else
                {
                    markdown = contents + "\n\n" + markdown;
                }

                File.WriteAllText(FilePath, markdown);
            }
            else
            {
                File.WriteAllText(FilePath, Preamble + "\n" + markdown);
            }
        }