├── .gitignore
├── .travis.yml
├── LICENSE
├── NuGet.config
├── build
├── build.sh
└── test.sh
├── readme.md
└── src
├── SemanticRelease.CommitAnalyzer.Tests
├── CommitMessageParserTests.cs
├── FileSystemGitRepositoryTests.cs
├── InMemoryGitRepositoryTests.cs
├── ProjectReleaserTests.cs
├── SemanticRelease.CommitAnalyzer.Tests.csproj
└── VersionCalculatorTests.cs
├── SemanticRelease.CommitAnalyzer
├── CommitMessageParser.cs
├── DefaultCommitAnalyzer.cs
├── DefaultPreConditions.cs
├── DotnetCoreBuildTools.cs
├── DotnetProjectParser.cs
├── GitHubSourcePublisher.cs
├── InMemoryGitRepository.cs
├── OnDiskGitRepository.cs
├── ProjectReleaser.cs
├── SemanticRelease.CommitAnalyzer.csproj
└── VersionCalculator.cs
├── SemanticRelease.Core
├── Program.cs
├── SemanticRelease.Core.csproj
└── cli
│ ├── CurrentVersionCli.cs
│ ├── PublishCli.cs
│ ├── ReleaseCli.cs
│ ├── SemanticReleaseEntry.cs
│ └── ToolCliBase.cs
├── SemanticRelease.Extensibility
├── CommitStatusEventArgs.cs
├── ICommitAnalyzer.cs
├── IPostReleaseAction.cs
├── IPreConditionVerifier.cs
├── IProjectManager.cs
├── IProjectReleaseStrategy.cs
├── IReleaseVerifier.cs
├── ISourcePublisher.cs
├── ISourceRepositoryProvider.cs
├── IVersionCalculator.cs
├── Model
│ ├── NoOpReleaseException.cs
│ ├── Release.cs
│ ├── ReleaseCommit.cs
│ ├── ReleaseRepository.cs
│ └── SemanticReleaseVersion.cs
├── ReleaseType.cs
└── SemanticRelease.Extensibility.csproj
├── SemanticRelease.GlobalTool
├── Program.cs
└── SemanticRelease.GlobalTool.csproj
├── SemanticRelease.Tool
├── Program.cs
└── SemanticRelease.Tool.csproj
└── dotnet-semantic-release.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.*~
3 | project.lock.json
4 | .DS_Store
5 | *.pyc
6 |
7 | # Visual Studio Code
8 | .vscode
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | [Pp]ackages/
22 | [Rr]eports/
23 | x64/
24 | x86/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | msbuild.log
29 | msbuild.err
30 | msbuild.wrn
31 | coverage.info
32 | coverage.xml
33 |
34 | # Visual Studio 2015
35 | .vs/
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | solution: src/dotnet-semantic-release.sln
3 | mono: none
4 | dotnet: 2.1.500
5 | install:
6 | - mkdir packages
7 | - dotnet restore src
8 | script:
9 | - ./build/test.sh $(pwd)
10 | - ./build/build.sh $(pwd)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 axlj45
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/build/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | WORKING_DIR=$1
4 | SRC_DIR=$WORKING_DIR/src
5 | PKG_DIR=$WORKING_DIR/packages
6 |
7 | mkdir -p $PKG_DIR
8 | rm -rf $PKG_DIR/*.nupkg
9 |
10 | dotnet pack --configuration=release $SRC_DIR/SemanticRelease.Extensibility/*.csproj
11 | dotnet pack --configuration=release $SRC_DIR/SemanticRelease.CommitAnalyzer/*.csproj
12 | dotnet pack --configuration=release $SRC_DIR/SemanticRelease.Core/*.csproj
13 | dotnet build --configuration=release $SRC_DIR/SemanticRelease.Tool/*.csproj
14 | cp $SRC_DIR/**/bin/release/*.nupkg $PKG_DIR
15 |
16 | dotnet build --configuration=release $SRC_DIR/SemanticRelease.GlobalTool/*.csproj
17 | cp $SRC_DIR/SemanticRelease.GlobalTool/bin/release/*.nupkg $PKG_DIR
--------------------------------------------------------------------------------
/build/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | WORKING_DIR=$1
4 |
5 | for project in $(find $WORKING_DIR -name *.Tests.csproj); do
6 | dotnet test $project /p:CollectCoverage=true /p:CoverletOutputFormat=lcov;
7 | done
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Dotnet Semantic Release
2 |
3 | Inspired by the [Semantic Release][0] module for NodeJS, the intent is to completely remove manual intervention from the versioning process by automating the [Semantic Versioning][1] specification during build/release time.
4 |
5 | **Note**: This package is still in a very early phase of development. Pull requests are welcome.
6 |
7 | [](https://travis-ci.org/axlj45/dotnet-semantic-release)
8 |
9 | ## Usage
10 |
11 | ### Global Tool
12 |
13 | ```sh
14 | # Install tool
15 | dotnet tool install --global SemanticRelease.GlobalTool
16 |
17 | # View help
18 | semantic-release --help
19 |
20 | # Version and tag application
21 | semantic-release release --project-path
22 | ```
23 |
24 | ### Dotnet CLI Tool
25 |
26 | Add the following to your `.csproj` file:
27 |
28 | ```xml
29 |
30 |
31 |
32 | ```
33 |
34 | ```sh
35 | # Navigate to the *.csproj location
36 | cd
37 |
38 | # Version and tag application
39 | dotnet-semanticrelease release
40 | ```
41 |
42 | ### Standardizing commit messages
43 |
44 | [Commitzen][2] is a great NodeJS tool that prompts developers at the time of commit for information regarding commit scope, description, issue id, etc. It uses this information to form a commit message that follows a consistent format and makes it easy for tools like this to intepret.
45 |
46 | dotnet-semantic-release currently relies on the `cz-convential-changelog` library for parsing commit messages.
47 |
48 | To use it, install the latest version of NodeJS, NPM, and Conventional changelog library.
49 |
50 | ```sh
51 | # Install commitizen
52 | npm install -g commitizen
53 |
54 | # Install conventional-changelog library
55 | npm install -g cz-conventional-changelog
56 |
57 | # Set the default changelog library
58 | echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
59 | ```
60 |
61 | From here on out, execute `npx git-cz` to perform commits.
62 |
63 | ## How does it work?
64 |
65 | The tool checks for keywords inside commit messages to identify if the changes that occured should cause a version bump.
66 |
67 | For example:
68 |
69 | * `feat`: will bump the *minor* version number (ie. 1.**4**.3 would become 1.**5**.0).
70 | * `fix`: will bump the patch version (ie. 1.27.**0** becomes 1.27.**1**).
71 | * `Breaking Change`: will cause the major version to increment (ie. **2**.4.1 would become **3**.0.0).
72 |
73 |
74 | ## What happens when I "release"?
75 |
76 | * Locate the nearest `.csproj` file and read the `Version`. If `Version` doesn't exis, try to read `PackageVersion`.
77 | * Verify that the current branch is the configured release branch, it has a remote source, and the current branch is up to date with the remote source
78 | * Calculate the next version
79 | * Update the `Version` and `PackageVersion` (if applicable)
80 | * Tag the current branch
81 |
82 | ## Limitations
83 |
84 | Here are a list of current limitations that will be fixed/implemented in future release of the library. The list is in no particular order.
85 |
86 | * Automatic changelog generation not implemented yet
87 | * Extensibility model is unstable
88 | * Only GIT is supported
89 | * Tags are not automatically committed
90 | * `Version` and `PackageVersion` are considered synonymous when locating an existing version.
91 | * `VersionPrefix` and `VersionSuffix` are not considered
92 |
93 |
94 | [0]:https://github.com/semantic-release/semantic-release
95 | [1]:https://semver.org/
96 | [2]:https://github.com/commitizen/cz-cli
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer.Tests/CommitMessageParserTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using SemanticRelease.Extensibility;
4 | using SemanticRelease.Extensibility.Model;
5 | using Xunit;
6 |
7 | namespace SemanticRelease.CommitAnalyzer.Tests
8 | {
9 | public class CommitMessageParserTests
10 | {
11 | [Fact]
12 | public void NonVersionableChangesYieldsNoRelease()
13 | {
14 | var commits = new List();
15 | commits.Add(GetNonVersionableChange());
16 |
17 | var parser = new CommitMessageParser(commits);
18 | var result = parser.GetReleaseType();
19 |
20 | Assert.Equal(ReleaseType.NONE, result);
21 | }
22 |
23 | [Fact]
24 | public void FixYieldsPatchRelease()
25 | {
26 | var commits = new List();
27 | commits.Add(GetPatchCommit());
28 |
29 | var parser = new CommitMessageParser(commits);
30 | var result = parser.GetReleaseType();
31 |
32 | Assert.Equal(ReleaseType.PATCH, result);
33 | }
34 |
35 | [Fact]
36 | public void PeformanceYieldsPatchRelease()
37 | {
38 | var commits = new List();
39 | commits.Add(GetCommit("perf"));
40 |
41 | var parser = new CommitMessageParser(commits);
42 | var result = parser.GetReleaseType();
43 |
44 | Assert.Equal(ReleaseType.PATCH, result);
45 | }
46 |
47 | [Fact]
48 | public void SecurityYieldsPatchRelease()
49 | {
50 | var commits = new List();
51 | commits.Add(GetCommit("security"));
52 |
53 | var parser = new CommitMessageParser(commits);
54 | var result = parser.GetReleaseType();
55 |
56 | Assert.Equal(ReleaseType.PATCH, result);
57 | }
58 |
59 | [Fact]
60 | public void FeatureYieldsMinorRelease()
61 | {
62 | var commits = new List();
63 | commits.Add(GetFeatureCommit());
64 |
65 | var parser = new CommitMessageParser(commits);
66 | var result = parser.GetReleaseType();
67 |
68 | Assert.Equal(ReleaseType.MINOR, result);
69 | }
70 |
71 | [Fact]
72 | public void BreakingChangeYieldsMajorRelease()
73 | {
74 | var commits = new List();
75 | commits.Add(GetBreakingPatchCommit());
76 |
77 | var parser = new CommitMessageParser(commits);
78 | var result = parser.GetReleaseType();
79 |
80 | Assert.Equal(ReleaseType.MAJOR, result);
81 | }
82 |
83 | [Fact]
84 | public void MinorReleaseCommitTakesPrecedenceOverPatch()
85 | {
86 | var commits = new List();
87 | commits.Add(GetFeatureCommit());
88 | commits.Add(GetPatchCommit());
89 |
90 | var parser = new CommitMessageParser(commits);
91 | var result = parser.GetReleaseType();
92 |
93 | Assert.Equal(ReleaseType.MINOR, result);
94 | }
95 |
96 | [Fact]
97 | public void MajorReleaseCommitTakesPrecedenceOverMinor()
98 | {
99 | var commits = new List();
100 | commits.Add(GetFeatureCommit());
101 | commits.Add(GetBreakingFeatureCommit());
102 |
103 | var parser = new CommitMessageParser(commits);
104 | var result = parser.GetReleaseType();
105 |
106 | Assert.Equal(ReleaseType.MAJOR, result);
107 | }
108 |
109 |
110 |
111 | private ReleaseCommit GetPatchCommit()
112 | {
113 | return GetCommit("fix");
114 | }
115 |
116 | private ReleaseCommit GetFeatureCommit()
117 | {
118 | return GetCommit("feat");
119 | }
120 |
121 | private ReleaseCommit GetBreakingFeatureCommit()
122 | {
123 | return GetCommit("feat", true);
124 | }
125 |
126 | private ReleaseCommit GetBreakingPatchCommit()
127 | {
128 | return GetCommit("fix", true);
129 | }
130 |
131 | private ReleaseCommit GetNonVersionableChange()
132 | {
133 | return GetCommit("chore");
134 | }
135 |
136 | private ReleaseCommit GetNonVersionableBreakingChange()
137 | {
138 | return GetCommit("chore", true);
139 | }
140 |
141 | private ReleaseCommit GetCommit(string commitType, bool isBreaking = false, string msg = "Standard message")
142 | {
143 | string commitMsg = $"{commitType}: ${msg}";
144 |
145 | if (isBreaking)
146 | {
147 | commitMsg += Environment.NewLine;
148 | commitMsg += "BREAKING: A breaking change occurred.";
149 | }
150 |
151 | return new ReleaseCommit(0, "DEADBEEF", commitMsg);
152 | }
153 | }
154 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer.Tests/FileSystemGitRepositoryTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 | using System.IO.Abstractions.TestingHelpers;
3 |
4 | namespace SemanticRelease.CommitAnalyzer.Tests
5 | {
6 | public class FileSystemGitRepositoryTests
7 | {
8 | [Fact]
9 | public void CannotInitializeBadFileSystemGitRepository()
10 | {
11 | var emptyFileSystem = new MockFileSystem();
12 | Assert.Throws(() => new OnDiskGitRepository("trunk", "./", emptyFileSystem));
13 | }
14 |
15 | [Fact(Skip = "Not ready yet...")]
16 | public void CanInitializeFileSystemGitRepository()
17 | {
18 | var repository = new OnDiskGitRepository("trunk", "./", new MockFileSystem());
19 |
20 | Assert.Equal("InMemory", repository.RepositoryPath);
21 | Assert.Equal("trunk", repository.ReleaseBranch);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer.Tests/InMemoryGitRepositoryTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace SemanticRelease.CommitAnalyzer.Tests
5 | {
6 | public class InMemoryGitRepositoryTests
7 | {
8 | [Fact]
9 | public void CanInitializeInMemoryGitRepository()
10 | {
11 | var repository = new InMemoryGitRepository("trunk");
12 |
13 | Assert.Equal("InMemory", repository.RepositoryPath);
14 | Assert.Equal("trunk", repository.ReleaseBranch);
15 | Assert.NotNull(repository.RepositoryRef);
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer.Tests/ProjectReleaserTests.cs:
--------------------------------------------------------------------------------
1 | using System.IO.Abstractions.TestingHelpers;
2 | using LibGit2Sharp;
3 | using Moq;
4 | using SemanticRelease.Extensibility;
5 | using Xunit;
6 |
7 | namespace SemanticRelease.CommitAnalyzer.Tests
8 | {
9 | public class ProjectReleaserTests
10 | {
11 | private MockFileSystem _fileSystem { get; }
12 |
13 | public ProjectReleaserTests()
14 | {
15 | _fileSystem = new MockFileSystem();
16 | _fileSystem.AddDirectory("/home/projects/semantic_release/src");
17 | }
18 |
19 | [Fact]
20 | public void ProjectCanRelease()
21 | {
22 | string repositoryPath = "/home/projects/semantic_release";
23 | string projectPath = "/home/projects/semantic_release/src";
24 |
25 | var projectManager = new Mock();
26 | projectManager.SetupGet(o => o.ProjectPath).Returns(projectPath);
27 |
28 | var repo = new Mock>();
29 | repo.SetupGet(o => o.RepositoryPath).Returns(repositoryPath);
30 |
31 | var repository = new Repository();
32 |
33 | repo.SetupGet(o => o.RepositoryRef).Returns(repository);
34 |
35 | var releaser = new ProjectReleaser(projectManager.Object, repo.Object, _fileSystem);
36 |
37 | // releaser.PrepareForRelease();
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer.Tests/SemanticRelease.CommitAnalyzer.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | false
6 | A. Leonard
7 |
8 |
9 |
10 |
11 |
12 | runtime; build; native; contentfiles; analyzers
13 | all
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer.Tests/VersionCalculatorTests.cs:
--------------------------------------------------------------------------------
1 | using SemanticRelease.Extensibility;
2 | using SemanticRelease.Extensibility.Model;
3 | using Xunit;
4 |
5 | namespace SemanticRelease.CommitAnalyzer.Tests
6 | {
7 | public class VersionCalculatorTests
8 | {
9 | IVersionCalculator systemUnderTest = new VersionCalculator();
10 |
11 | [Fact]
12 | public void MajorReleaseShouldIncrementMajorVersion()
13 | {
14 | var lastRelease = new Release("1.0.0", "DEADBEEF");
15 |
16 | var nextVersion = systemUnderTest.GetNextVersion(lastRelease, ReleaseType.MAJOR);
17 |
18 | Assert.Equal("2.0.0", nextVersion.ToString());
19 | }
20 |
21 | [Fact]
22 | public void MinorReleaseShouldIncrementMinorVersion()
23 | {
24 | var lastRelease = new Release("1.0.0", "DEADBEEF");
25 |
26 | var nextVersion = systemUnderTest.GetNextVersion(lastRelease, ReleaseType.MINOR);
27 |
28 | Assert.Equal("1.1.0", nextVersion.ToString());
29 | }
30 |
31 |
32 | [Fact]
33 | public void PatchReleaseShouldIncrementPatchVersion()
34 | {
35 | var lastRelease = new Release("1.0.0", "DEADBEEF");
36 |
37 | var nextVersion = systemUnderTest.GetNextVersion(lastRelease, ReleaseType.PATCH);
38 |
39 | Assert.Equal("1.0.1", nextVersion.ToString());
40 | }
41 |
42 | [Fact]
43 | public void NoReleaseShouldThrowExeption()
44 | {
45 | var lastRelease = new Release("1.0.0", "DEADBEEF");
46 |
47 | Assert.Throws(() => systemUnderTest.GetNextVersion(lastRelease, ReleaseType.NONE));
48 | }
49 |
50 | [Fact]
51 | public void VersionShouldDefaultToOneO()
52 | {
53 | Release lastRelease = null;
54 |
55 | var nextVersion = systemUnderTest.GetNextVersion(lastRelease, ReleaseType.MAJOR);
56 |
57 | Assert.Equal("1.0.0", nextVersion.ToString());
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/CommitMessageParser.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Runtime.CompilerServices;
3 | using System.Text.RegularExpressions;
4 | using SemanticRelease.Extensibility;
5 | using SemanticRelease.Extensibility.Model;
6 |
7 | [assembly: InternalsVisibleTo("SemanticRelease.CommitAnalyzer.Tests")]
8 | namespace SemanticRelease.CommitAnalyzer
9 | {
10 | internal class CommitMessageParser
11 | {
12 | private readonly IEnumerable _commitsSinceRelease;
13 |
14 | public CommitMessageParser(IEnumerable commitsSinceRelease)
15 | {
16 | _commitsSinceRelease = commitsSinceRelease;
17 | }
18 |
19 | public ReleaseType GetReleaseType()
20 | {
21 | var releaseType = ReleaseType.NONE;
22 |
23 | var multiLineIgnoreCase = RegexOptions.IgnoreCase | RegexOptions.Singleline;
24 |
25 | var majorRelease = new Regex("(BREAKING)", RegexOptions.Singleline);
26 | var minorRelease = new Regex(@"(feat:|feature:|feat\(.*\))", multiLineIgnoreCase);
27 | var patchRelease = new Regex(@"(fix|perf|security)(\(.*\))?:", multiLineIgnoreCase);
28 |
29 | foreach (var commit in _commitsSinceRelease)
30 | {
31 | if (majorRelease.IsMatch(commit.Message))
32 | {
33 | releaseType = ReleaseType.MAJOR;
34 | break;
35 | }
36 |
37 | if (minorRelease.IsMatch(commit.Message) || releaseType == ReleaseType.MINOR)
38 | {
39 | releaseType = ReleaseType.MINOR;
40 | continue;
41 | }
42 |
43 | if (patchRelease.IsMatch(commit.Message))
44 | {
45 | releaseType = ReleaseType.PATCH;
46 | }
47 | }
48 |
49 | return releaseType;
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/DefaultCommitAnalyzer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using SemanticRelease.Extensibility;
5 | using SemanticRelease.Extensibility.Model;
6 | using LibGit2Sharp;
7 | using SemanticVersion = SemVer.Version;
8 |
9 | namespace SemanticRelease.CommitAnalyzer
10 | {
11 | public class DefaultCommitAnalyzer : ICommitAnalyzer
12 | {
13 | private ISourceRepositoryProvider _repository;
14 | private readonly IRepository _repoReference;
15 | private readonly VersionCalculator _versionCalculator;
16 |
17 | public event EventHandler CommitEvent;
18 |
19 | public DefaultCommitAnalyzer(ISourceRepositoryProvider repositoryProvider)
20 | {
21 | this._repository = repositoryProvider;
22 |
23 | var repoRef = _repository.RepositoryRef as ReleaseRepository;
24 | this._repoReference = repoRef.GetRepositoryReference();
25 |
26 | this._versionCalculator = new VersionCalculator();
27 | }
28 |
29 | public Release CalculateNextRelease()
30 | {
31 | var lastRelease = GetLastRelease();
32 |
33 | var msg = "This is the first release.";
34 |
35 | SendEvent($"Last Release: {lastRelease?.Version.ToString() ?? msg}");
36 |
37 | var commitsSinceRelease = CommitsSinceLastRelease(lastRelease).ToList();
38 |
39 | var releaseType = new CommitMessageParser(commitsSinceRelease).GetReleaseType();
40 |
41 | SendEvent($"Release type: {releaseType}");
42 |
43 | var nextVersion = _versionCalculator.GetNextVersion(lastRelease, releaseType);
44 |
45 | SendEvent($"Next version: {nextVersion}");
46 |
47 | return new Release(nextVersion.ToString(), null);
48 | }
49 |
50 | private void SendEvent(string message)
51 | {
52 | CommitEvent?.Invoke(this, new CommitStatusEventArgs(message));
53 | }
54 |
55 | private IEnumerable CommitsSinceLastRelease(Release lastRelease)
56 | {
57 | var lastReleaseCommit = _repoReference.Commits.FirstOrDefault(o => o.Sha.Equals(lastRelease?.Sha));
58 | int index = 0;
59 |
60 | foreach (var commit in _repoReference.Commits)
61 | {
62 | if (commit.Sha.Equals(lastReleaseCommit?.Sha)) break;
63 |
64 | yield return new ReleaseCommit(index++, commit.Sha, commit.Message);
65 | }
66 | }
67 |
68 | public Release GetLastRelease()
69 | {
70 | var lastRelease = _repoReference.Tags.Where(o =>
71 | {
72 | try
73 | {
74 | var version = new SemanticVersion(o.FriendlyName);
75 | return string.IsNullOrEmpty(version.PreRelease);
76 | }
77 | catch
78 | {
79 | return false;
80 | }
81 | })
82 | .Select(o => new { Commit = o, Version = new SemanticVersion(o.FriendlyName) })
83 | .OrderByDescending(o => o.Version)
84 | .Select(o => new Release(o.Version.ToString(), o.Commit.PeeledTarget.Sha))
85 | .FirstOrDefault();
86 |
87 | return lastRelease;
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/DefaultPreConditions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SemanticRelease.Extensibility;
3 | using LibGit2Sharp;
4 | using SemanticRelease.Extensibility.Model;
5 |
6 | namespace SemanticRelease.CommitAnalyzer
7 | {
8 | public class DefaultPreConditions : IPreConditionVerifier
9 | {
10 | private readonly ISourceRepositoryProvider _repository;
11 |
12 | public DefaultPreConditions(ISourceRepositoryProvider repositoryProvider)
13 | {
14 | this._repository = repositoryProvider;
15 | }
16 |
17 | public void Verify(bool detachedHead)
18 | {
19 | var repoRef = _repository.RepositoryRef as ReleaseRepository;
20 |
21 | var repo = repoRef.GetRepositoryReference();
22 |
23 | if (!detachedHead && !repo.Head.FriendlyName.Equals(_repository.ReleaseBranch))
24 | {
25 | throw new Exception($"Wrong Branch: {repo.Head.FriendlyName} must be {_repository.ReleaseBranch} to deploy");
26 | }
27 |
28 | if (!detachedHead && !repo.Head.IsTracking)
29 | {
30 | throw new Exception("No remote found for current branch.");
31 | }
32 |
33 | if (!repo.Head.IsCurrentRepositoryHead)
34 | {
35 | throw new Exception("Local repository is not in sync with remote repository.");
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/DotnetCoreBuildTools.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using Microsoft.Build.Evaluation;
6 | using Microsoft.Build.Utilities;
7 |
8 | namespace SemanticRelease.CommitAnalyzer
9 | {
10 | // Pulled from https://daveaglick.com/posts/running-a-design-time-build-with-msbuild-apis
11 | public static class DotnetCoreBuildTools
12 | {
13 | public static string GetCoreBasePath(string projectPath)
14 | {
15 | // Ensure that we set the DOTNET_CLI_UI_LANGUAGE environment variable to "en-US" before
16 | // running 'dotnet --info'. Otherwise, we may get localized results.
17 |
18 | string originalCliLanguage = Environment.GetEnvironmentVariable("DOTNET_CLI_UI_LANGUAGE");
19 | Environment.SetEnvironmentVariable("DOTNET_CLI_UI_LANGUAGE", "en-US");
20 |
21 | try
22 | {
23 | // Create the process info
24 | ProcessStartInfo startInfo = new ProcessStartInfo("dotnet", "--info")
25 | {
26 | // global.json may change the version, so need to set working directory
27 | WorkingDirectory = Path.GetDirectoryName(projectPath),
28 | CreateNoWindow = true,
29 | UseShellExecute = false,
30 | RedirectStandardOutput = true,
31 | RedirectStandardError = true
32 | };
33 |
34 | // Execute the process
35 | using (Process process = Process.Start(startInfo))
36 | {
37 | List lines = new List();
38 | process.OutputDataReceived += (_, e) =>
39 | {
40 | if (!string.IsNullOrWhiteSpace(e.Data))
41 | {
42 | lines.Add(e.Data);
43 | }
44 | };
45 | process.BeginOutputReadLine();
46 | process.WaitForExit();
47 | return ParseCoreBasePath(lines);
48 | }
49 | }
50 | finally
51 | {
52 | Environment.SetEnvironmentVariable("DOTNET_CLI_UI_LANGUAGE", originalCliLanguage);
53 | }
54 | }
55 |
56 | public static string ParseCoreBasePath(List lines)
57 | {
58 | if (lines == null || lines.Count == 0)
59 | {
60 | throw new Exception("Could not get results from `dotnet --info` call");
61 | }
62 |
63 | foreach (string line in lines)
64 | {
65 | int colonIndex = line.IndexOf(':');
66 | if (colonIndex >= 0
67 | && line.Substring(0, colonIndex).Trim().Equals("Base Path", StringComparison.OrdinalIgnoreCase))
68 | {
69 | return line.Substring(colonIndex + 1).Trim();
70 | }
71 | }
72 |
73 | throw new Exception("Could not locate base path in `dotnet --info` results");
74 | }
75 |
76 | public static Dictionary GetCoreGlobalProperties(string projectPath, string toolsPath)
77 | {
78 | string solutionDir = Path.GetDirectoryName(projectPath);
79 | string extensionsPath = toolsPath;
80 | string sdksPath = Path.Combine(toolsPath, "Sdks");
81 | string roslynTargetsPath = Path.Combine(toolsPath, "Roslyn");
82 |
83 | return new Dictionary
84 | {
85 | { "SolutionDir", solutionDir },
86 | { "MSBuildExtensionsPath", extensionsPath },
87 | { "MSBuildSDKsPath", sdksPath },
88 | { "RoslynTargetsPath", roslynTargetsPath }
89 | };
90 | }
91 |
92 |
93 | public static Project GetCoreProject(string projectPath)
94 | {
95 | string toolsPath = GetCoreBasePath(projectPath);
96 | Dictionary globalProperties = GetCoreGlobalProperties(projectPath, toolsPath);
97 | ProjectCollection projectCollection = new ProjectCollection(globalProperties);
98 | projectCollection.AddToolset(new Toolset(ToolLocationHelper.CurrentToolsVersion, toolsPath, projectCollection, string.Empty));
99 |
100 | Environment.SetEnvironmentVariable("MSBuildExtensionsPath", globalProperties["MSBuildExtensionsPath"]);
101 | Environment.SetEnvironmentVariable("MSBuildSDKsPath", globalProperties["MSBuildSDKsPath"]);
102 |
103 | Project project = projectCollection.LoadProject(projectPath);
104 | return project;
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/DotnetProjectParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO.Abstractions;
3 | using System.Linq;
4 | using Microsoft.Build.Evaluation;
5 | using SemanticRelease.Extensibility;
6 |
7 | namespace SemanticRelease.CommitAnalyzer
8 | {
9 | public class DotnetProjectParser : IProjectManager
10 | {
11 | public string ProjectPath { get; }
12 | private readonly Project _project;
13 | private string _version;
14 |
15 | private PathBase Path { get; }
16 | private DirectoryBase Directory { get; }
17 |
18 | public DotnetProjectParser(string projectPath, IFileSystem fileSystem)
19 | {
20 | Path = fileSystem.Path;
21 | Directory = fileSystem.Directory;
22 |
23 | var workingDir = Path.GetDirectoryName(projectPath) + "/";
24 | ProjectPath = FindProjPath(projectPath);
25 | _project = DotnetCoreBuildTools.GetCoreProject(ProjectPath);
26 | }
27 |
28 | public string GetVersion()
29 | {
30 | var props = _project.Xml.PropertyGroups.First(); // Need to make sure no other property groups exist with version in them.
31 |
32 | var version = props.Properties.Where(o => o.Name.Equals("Version")).FirstOrDefault();
33 | var packageVer = props.Properties.FirstOrDefault(o => o.Name.Equals("PackageVersion"));
34 |
35 | return version?.Value ?? packageVer?.Value ?? string.Empty;
36 | }
37 |
38 | public void SetVersion(string version)
39 | {
40 | _version = version;
41 |
42 | var props = _project.Xml.PropertyGroups.First(); // Need to make sure no other property groups exist with version in them.
43 | props.SetProperty("Version", _version);
44 |
45 | var packageVer = props.Properties.FirstOrDefault(o => o.Name.Equals("PackageVersion"));
46 | if (!string.IsNullOrEmpty(packageVer?.Name)) props.SetProperty(packageVer.Name, _version);
47 |
48 | _project.Save();
49 | }
50 |
51 | private string FindProjPath(string currentDir, int maxDepth = 3, int currentDepth = 0)
52 | {
53 | try
54 | {
55 | currentDepth++;
56 |
57 | if (currentDepth > maxDepth) throw new Exception();
58 |
59 | var project = Directory.EnumerateFiles(currentDir, "*.csproj").FirstOrDefault();
60 |
61 | if (string.IsNullOrEmpty(project))
62 | return FindProjPath(Directory.GetParent(currentDir).FullName, maxDepth, currentDepth);
63 | else
64 | return project;
65 | }
66 | catch (Exception)
67 | {
68 | throw new Exception("Unable to locate dotnet project path.");
69 | }
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/GitHubSourcePublisher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using LibGit2Sharp;
4 | using LibGit2Sharp.Handlers;
5 | using SemanticRelease.Extensibility;
6 | using SemanticRelease.Extensibility.Model;
7 |
8 | namespace SemanticRelease.CommitAnalyzer
9 | {
10 | public class GitHubSourcePublisher : ISourcePublisher
11 | {
12 | private readonly ReleaseRepository _repoRef;
13 | private readonly IRepository repo;
14 |
15 | public GitHubSourcePublisher(ISourceRepositoryProvider repositoryProvider)
16 | {
17 | _repoRef = repositoryProvider.RepositoryRef as ReleaseRepository;
18 | this.repo = _repoRef.GetRepositoryReference();
19 | }
20 |
21 | public void Push()
22 | {
23 | var currentBranch = repo.Head.FriendlyName;
24 | var releaseBranch = _repoRef.ReleaseBranch;
25 |
26 | if (!string.Equals(releaseBranch, currentBranch))
27 | throw new NoOpReleaseException($"Current branch '{currentBranch}' does not match release branch: {releaseBranch}");
28 |
29 | var options = GetPushOptions();
30 | repo.Network.Push(repo.Head, options);
31 | }
32 |
33 | public void Push(string tagToPush)
34 | {
35 | Push();
36 | var options = GetPushOptions();
37 |
38 | var selectedTag = repo
39 | .Tags
40 | .FirstOrDefault(o => o.FriendlyName.Equals(tagToPush, StringComparison.CurrentCultureIgnoreCase))
41 | ?.CanonicalName;
42 |
43 | if (string.IsNullOrEmpty(selectedTag))
44 | throw new Exception($"Cannot push {tagToPush}, tag not found.");
45 |
46 | var origin = repo.Network.Remotes["origin"];
47 |
48 | repo.Network.Push(origin, selectedTag, options);
49 | }
50 |
51 | private PushOptions GetPushOptions()
52 | {
53 | var options = new PushOptions();
54 | options.CredentialsProvider = GetCredentialsHandler();
55 | return options;
56 | }
57 |
58 | private CredentialsHandler GetCredentialsHandler()
59 | {
60 | string user = Environment.GetEnvironmentVariable("GH_USER");
61 | string token = Environment.GetEnvironmentVariable("GH_TOKEN");
62 | var handler = new CredentialsHandler(
63 | (url, usernameFromUrl, types) => new UsernamePasswordCredentials()
64 | {
65 | Username = usernameFromUrl ?? user,
66 | Password = token
67 | });
68 | return handler;
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/InMemoryGitRepository.cs:
--------------------------------------------------------------------------------
1 | using LibGit2Sharp;
2 | using SemanticRelease.Extensibility;
3 | using SemanticRelease.Extensibility.Model;
4 |
5 | namespace SemanticRelease.CommitAnalyzer
6 | {
7 | public class InMemoryGitRepository : ISourceRepositoryProvider
8 | {
9 | private readonly ReleaseRepository _repository;
10 |
11 | public string ReleaseBranch => _repository.ReleaseBranch;
12 |
13 | public string RepositoryPath => _repository.RepositoryPath;
14 |
15 | public IRepository RepositoryRef => (IRepository)_repository.GetRepositoryReference();
16 |
17 | object ISourceRepositoryProvider.RepositoryRef => _repository.GetRepositoryReference();
18 |
19 | public InMemoryGitRepository(string releaseBranch)
20 | {
21 | var repoRef = new Repository();
22 |
23 | _repository = new ReleaseRepository("InMemory", releaseBranch, repoRef);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/OnDiskGitRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO.Abstractions;
3 | using System.Linq;
4 | using LibGit2Sharp;
5 | using SemanticRelease.Extensibility;
6 | using SemanticRelease.Extensibility.Model;
7 |
8 | namespace SemanticRelease.CommitAnalyzer
9 | {
10 | public class OnDiskGitRepository : ISourceRepositoryProvider
11 | {
12 | private readonly ReleaseRepository _repository;
13 |
14 | public IRepository RepositoryRef => _repository?.GetRepositoryReference();
15 |
16 | public string ReleaseBranch => _repository?.ReleaseBranch;
17 |
18 | public string RepositoryPath => _repository?.RepositoryPath;
19 |
20 | object ISourceRepositoryProvider.RepositoryRef => _repository;
21 |
22 | private DirectoryBase Directory { get; }
23 |
24 | public OnDiskGitRepository(string repoPath, string releaseBranch, IFileSystem fileSystem)
25 | {
26 | Directory = fileSystem.Directory;
27 |
28 | var gitPath = FindGitPath(repoPath);
29 | var repoRef = new Repository(gitPath);
30 |
31 | _repository = new ReleaseRepository(gitPath, releaseBranch, repoRef);
32 | }
33 |
34 | private string FindGitPath(string currentPath, int maxDepth = 4, int currentDepth = 0)
35 | {
36 | try
37 | {
38 | currentDepth++;
39 |
40 | if (currentDepth > maxDepth) throw new Exception();
41 |
42 | var dir = Directory.EnumerateDirectories(currentPath, ".git").FirstOrDefault();
43 |
44 | if (string.IsNullOrEmpty(dir))
45 | return FindGitPath(Directory.GetParent(currentPath).FullName, maxDepth, currentDepth);
46 | else
47 | return dir;
48 | }
49 | catch (Exception ex)
50 | {
51 | throw new System.IO.FileNotFoundException("Unable to locate git repository for project.", ex);
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/ProjectReleaser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO.Abstractions;
3 | using LibGit2Sharp;
4 | using SemanticRelease.Extensibility;
5 |
6 | namespace SemanticRelease.CommitAnalyzer
7 | {
8 | public class ProjectReleaser : IProjectReleaseStrategy
9 | {
10 | private readonly ISourceRepositoryProvider _gitRepo;
11 | private readonly IProjectManager _project;
12 |
13 | private DirectoryBase Directory { get; }
14 | private PathBase Path { get; }
15 |
16 | public ProjectReleaser(
17 | IProjectManager project,
18 | ISourceRepositoryProvider repo,
19 | IFileSystem fileSystem)
20 | {
21 | Directory = fileSystem.Directory;
22 | Path = fileSystem.Path;
23 |
24 | _project = project;
25 | _gitRepo = (ISourceRepositoryProvider)repo;
26 | }
27 |
28 | public void PrepareForRelease()
29 | {
30 | var repo = _gitRepo.RepositoryRef;
31 |
32 | int workDirLength = Directory.GetParent(_gitRepo.RepositoryPath).FullName.Length;
33 | string workingPath = Path.GetFullPath(_project.ProjectPath).Substring(workDirLength + 1);
34 |
35 | repo.Index.Add(workingPath);
36 | var signature = new Signature("jenkins", "jenkins", DateTimeOffset.UtcNow);
37 | var vCommit = repo.Commit($"chore(release): Releasing {_project.GetVersion()}", signature, signature);
38 | var vTag = repo.ApplyTag(_project.GetVersion());
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/SemanticRelease.CommitAnalyzer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | SemanticRelease.CommitAnalyzer
5 | SemanticRelease.CommitAnalyzer
6 | 2.2.0
7 |
8 |
9 |
10 | A. Leonard
11 | https://github.com/axlj45/dotnet-semantic-release/blob/trunk/LICENSE
12 | false
13 | Version package per semantic version specification.
14 | semantic-versioning semantic-release
15 | git
16 | https://github.com/axlj45/dotnet-semantic-release
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/SemanticRelease.CommitAnalyzer/VersionCalculator.cs:
--------------------------------------------------------------------------------
1 | using SemanticRelease.Extensibility;
2 | using SemanticRelease.Extensibility.Model;
3 | using SemanticVersion = SemVer.Version;
4 |
5 | namespace SemanticRelease.CommitAnalyzer
6 | {
7 | internal class VersionCalculator : IVersionCalculator
8 | {
9 |
10 | public SemanticReleaseVersion GetNextVersion(Release lastRelease, ReleaseType releaseType)
11 | {
12 | var lastVersion = lastRelease?.Version;
13 |
14 | if (lastVersion == null) return new SemanticReleaseVersion("1.0.0");
15 |
16 | var testVersion = new SemanticVersion(lastVersion);
17 |
18 | int nextMajor = testVersion.Major;
19 | int nextMinor = testVersion.Minor;
20 | int nextPatch = testVersion.Patch;
21 |
22 | switch (releaseType)
23 | {
24 | case ReleaseType.MAJOR:
25 | nextMajor += 1;
26 | nextMinor = 0;
27 | nextPatch = 0;
28 | break;
29 |
30 | case ReleaseType.MINOR:
31 | nextMinor += 1;
32 | nextPatch = 0;
33 | break;
34 |
35 | case ReleaseType.PATCH:
36 | nextPatch += 1;
37 | break;
38 |
39 | default:
40 | throw new NoOpReleaseException(lastVersion);
41 | }
42 |
43 | var newVersion = new SemanticVersion($"{nextMajor}.{nextMinor}.{nextPatch}");
44 |
45 | return new SemanticReleaseVersion(newVersion.ToString());
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/Program.cs:
--------------------------------------------------------------------------------
1 | using McMaster.Extensions.CommandLineUtils;
2 | using SemanticRelease.Core.CLI;
3 |
4 | namespace SemanticRelease.Core
5 | {
6 | [Command(Description = "Semantic Release")]
7 | public class Program
8 | {
9 | public static int Main(string[] args) => CommandLineApplication.Execute(args);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/SemanticRelease.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | 2.2.0
5 | SemanticRelease.Core
6 | SemanticRelease.Core
7 |
8 |
9 |
10 | A. Leonard
11 | https://github.com/axlj45/dotnet-semantic-release/blob/trunk/LICENSE
12 | false
13 | Core libraries for the Semantic Release Tool and Global Tool
14 | semantic-versioning semantic-release
15 | git
16 | https://github.com/axlj45/dotnet-semantic-release
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/cli/CurrentVersionCli.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SemanticRelease.CommitAnalyzer;
3 | using McMaster.Extensions.CommandLineUtils;
4 | using System.IO.Abstractions;
5 |
6 | namespace SemanticRelease.Core.CLI
7 | {
8 | [Command(Description = "Get version of target project")]
9 | public class CurrentVersionCli : ToolCliBase
10 | {
11 | private readonly FileSystem _fileSystem;
12 |
13 | private SemanticReleaseEntry Parent { get; set; }
14 |
15 | public CurrentVersionCli()
16 | {
17 | _fileSystem = new FileSystem();
18 | }
19 |
20 | protected override int OnExecute(CommandLineApplication app)
21 | {
22 | var targetProject = TargetProject ?? Parent.TargetProject;
23 |
24 | var project = new DotnetProjectParser(targetProject ?? System.Environment.CurrentDirectory, _fileSystem);
25 |
26 | Console.WriteLine(project.GetVersion());
27 |
28 | return 0;
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/cli/PublishCli.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO.Abstractions;
3 | using McMaster.Extensions.CommandLineUtils;
4 | using SemanticRelease.CommitAnalyzer;
5 | using SemanticRelease.Core.CLI;
6 |
7 | namespace SemanticRelease.Core.CLI
8 | {
9 | [Command(Description = "Create new version and prepare for release")]
10 | public class PublishCli : ToolCliBase
11 | {
12 | private readonly FileSystem _fileSystem;
13 |
14 | private SemanticReleaseEntry Parent { get; set; }
15 |
16 |
17 | public PublishCli()
18 | {
19 | _fileSystem = new FileSystem();
20 | }
21 |
22 | protected override int OnExecute(CommandLineApplication app)
23 | {
24 | var workingDir = TargetProject ?? Parent.TargetProject ?? System.Environment.CurrentDirectory;
25 | var releaseBranch = ReleaseBranch ?? Parent.ReleaseBranch ?? "trunk";
26 |
27 | try
28 | {
29 | var repository = new OnDiskGitRepository(workingDir, releaseBranch, _fileSystem);
30 |
31 | var publisher = new GitHubSourcePublisher(repository);
32 | var commitAnalyzer = new DefaultCommitAnalyzer(repository);
33 |
34 | var lastRelease = commitAnalyzer.GetLastRelease();
35 |
36 | publisher.Push(lastRelease.Version);
37 | }
38 | catch (Exception ex)
39 | {
40 | Console.WriteLine(ex.Message);
41 | return 1;
42 | }
43 |
44 | return 0;
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/cli/ReleaseCli.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SemanticRelease.CommitAnalyzer;
3 | using SemanticRelease.Extensibility.Model;
4 | using McMaster.Extensions.CommandLineUtils;
5 | using SemanticRelease.Extensibility;
6 | using System.IO.Abstractions;
7 |
8 | namespace SemanticRelease.Core.CLI
9 | {
10 | [Command(Description = "Create new version and prepare for release")]
11 | public class ReleaseCli : ToolCliBase
12 | {
13 | private readonly FileSystem _fileSystem;
14 |
15 | private SemanticReleaseEntry Parent { get; set; }
16 |
17 | [Option("-f|--fail-on-no-release", Description = "Return non-zero exit code when no release is required.")]
18 | public bool ThrowOnNoOp { get; set; }
19 |
20 | [Option("-d|--detached-head", Description = "Work with a detached HEAD (for example, when building on Azure pipelines)")]
21 | public bool DetachedHead { get; set; }
22 |
23 | public ReleaseCli()
24 | {
25 | _fileSystem = new FileSystem();
26 | }
27 |
28 | protected override int OnExecute(CommandLineApplication app)
29 | {
30 | var workingDir = TargetProject ?? Parent.TargetProject ?? System.Environment.CurrentDirectory;
31 | var releaseBranch = ReleaseBranch ?? Parent.ReleaseBranch ?? "trunk";
32 |
33 | try
34 | {
35 | var repository = new OnDiskGitRepository(workingDir, releaseBranch, _fileSystem);
36 |
37 | var preconditions = new DefaultPreConditions(repository);
38 | preconditions.Verify(DetachedHead);
39 |
40 | var commitAnalyzer = new DefaultCommitAnalyzer(repository);
41 | commitAnalyzer.CommitEvent += OnCommitEvent;
42 | var nextRelease = commitAnalyzer.CalculateNextRelease();
43 |
44 | var project = new DotnetProjectParser(workingDir, _fileSystem);
45 | project.SetVersion(nextRelease.Version);
46 |
47 | var releaser = new ProjectReleaser(project, repository, _fileSystem);
48 | releaser.PrepareForRelease();
49 | }
50 | catch (NoOpReleaseException ex)
51 | {
52 | Console.WriteLine($"There have been no releasable commits since v{ex.LastVersion}");
53 | return ThrowOnNoOp ? 1 : 0;
54 | }
55 | catch (Exception ex)
56 | {
57 | Console.WriteLine(ex.Message);
58 | return 1;
59 | }
60 |
61 | return 0;
62 | }
63 |
64 | private void OnCommitEvent(object sender, CommitStatusEventArgs e)
65 | {
66 | Console.WriteLine(e.Message);
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/cli/SemanticReleaseEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using SemanticRelease.CommitAnalyzer;
4 | using McMaster.Extensions.CommandLineUtils;
5 |
6 | namespace SemanticRelease.Core.CLI
7 | {
8 | [Command("semantic-release", Description = "Semantic Release")]
9 | [VersionOptionFromMember("--version", MemberName = nameof(GetVersion))]
10 | [Subcommand("release", typeof(ReleaseCli))]
11 | [Subcommand("project-version", typeof(CurrentVersionCli))]
12 | [Subcommand("publish", typeof(PublishCli))]
13 | public class SemanticReleaseEntry : ToolCliBase
14 | {
15 | private static string GetVersion()
16 | => Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion;
17 |
18 | protected override int OnExecute(CommandLineApplication app)
19 | {
20 | base.OnExecute(app);
21 | return 0;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Core/cli/ToolCliBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using McMaster.Extensions.CommandLineUtils;
5 |
6 | namespace SemanticRelease.Core.CLI
7 | {
8 | [HelpOption("--help")]
9 | public class ToolCliBase
10 | {
11 | [Option("-p|--project-path ", Description = "The directory that contains the csproj project to release.")]
12 | [FileOrDirectoryExists]
13 | public string TargetProject { get; set; }
14 |
15 | [Option("-b|--release-branch ", Description = "Branch that is permitted to perform a release. Default is 'trunk'")]
16 | public string ReleaseBranch { get; set; }
17 |
18 | protected virtual int OnExecute(CommandLineApplication app)
19 | {
20 | app.ShowHelp();
21 | return 0;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/CommitStatusEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SemanticRelease.Extensibility
4 | {
5 | public class CommitStatusEventArgs : EventArgs
6 | {
7 | public string Message { get; }
8 |
9 | public CommitStatusEventArgs(string message)
10 | {
11 | this.Message = message;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/ICommitAnalyzer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SemanticRelease.Extensibility.Model;
3 |
4 | namespace SemanticRelease.Extensibility
5 | {
6 | public interface ICommitAnalyzer
7 | {
8 | Release CalculateNextRelease();
9 |
10 | event EventHandler CommitEvent;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/IPostReleaseAction.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public interface IPostReleaseAction
4 | {
5 |
6 | }
7 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/IPreConditionVerifier.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public interface IPreConditionVerifier
4 | {
5 | void Verify(bool detachedHead);
6 | }
7 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/IProjectManager.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public interface IProjectManager
4 | {
5 | string ProjectPath { get; }
6 | string GetVersion();
7 | void SetVersion(string version);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/IProjectReleaseStrategy.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public interface IProjectReleaseStrategy
4 | {
5 | void PrepareForRelease();
6 | }
7 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/IReleaseVerifier.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public interface IReleaseVerifier
4 | {
5 |
6 | }
7 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/ISourcePublisher.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public interface ISourcePublisher
4 | {
5 | void Push();
6 | void Push(string tagToPush);
7 | }
8 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/ISourceRepositoryProvider.cs:
--------------------------------------------------------------------------------
1 | using SemanticRelease.Extensibility.Model;
2 |
3 | namespace SemanticRelease.Extensibility
4 | {
5 | public interface ISourceRepositoryProvider
6 | {
7 | string ReleaseBranch { get; }
8 | string RepositoryPath { get; }
9 |
10 | object RepositoryRef { get; }
11 | }
12 |
13 | public interface ISourceRepositoryProvider : ISourceRepositoryProvider
14 | {
15 | new T RepositoryRef { get; }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/IVersionCalculator.cs:
--------------------------------------------------------------------------------
1 | using SemanticRelease.Extensibility.Model;
2 |
3 | namespace SemanticRelease.Extensibility
4 | {
5 | public interface IVersionCalculator
6 | {
7 | SemanticReleaseVersion GetNextVersion(Release lastRelease, ReleaseType releaseType);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/Model/NoOpReleaseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace SemanticRelease.Extensibility.Model
5 | {
6 | [Serializable]
7 | public class NoOpReleaseException : Exception
8 | {
9 | public string LastVersion { get; }
10 |
11 | public NoOpReleaseException(string lastVersion) : base()
12 | {
13 | LastVersion = lastVersion;
14 | }
15 | public NoOpReleaseException(string lastVersion, string message) : base(message)
16 | {
17 | LastVersion = lastVersion;
18 | }
19 |
20 | public NoOpReleaseException(string lastVersion, string message, Exception inner)
21 | : base(message, inner)
22 | {
23 | LastVersion = lastVersion;
24 | }
25 | protected NoOpReleaseException(
26 | SerializationInfo info,
27 | StreamingContext context) : base(info, context) { }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/Model/Release.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SemanticRelease.Extensibility.Model
4 | {
5 | public class Release
6 | {
7 | public Release(string version, string sha) : this(version, sha, null)
8 | { }
9 |
10 | public Release(string version, string sha, IEnumerable commitsSinceLastRelease)
11 | {
12 | this.Version = version;
13 | this.Sha = sha;
14 | this.CommitsSinceLastRelease = commitsSinceLastRelease;
15 | }
16 |
17 | public string Version { get; private set; }
18 | public string Sha { get; private set; }
19 | public IEnumerable CommitsSinceLastRelease { get; private set; }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/Model/ReleaseCommit.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility.Model
2 | {
3 | public class ReleaseCommit
4 | {
5 | public ReleaseCommit(int index, string sha, string message)
6 | {
7 | this.Sha = sha;
8 | this.Index = index;
9 | this.Message = message;
10 | }
11 |
12 | public int Index { get; }
13 | public string Sha { get; }
14 | public string Message { get; }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/Model/ReleaseRepository.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility.Model
2 | {
3 | public abstract class AbstractReleaseRepository
4 | {
5 | public virtual string ReleaseBranch { get; }
6 | public virtual string RepositoryPath { get; }
7 | protected virtual object RepositoryRef { get; }
8 |
9 | protected AbstractReleaseRepository(string repositoryPath, string releaseBranchName, object repositoryReference)
10 | {
11 | this.RepositoryPath = repositoryPath;
12 | this.ReleaseBranch = releaseBranchName;
13 | this.RepositoryRef = repositoryReference;
14 | }
15 | }
16 | public class ReleaseRepository : AbstractReleaseRepository
17 | {
18 |
19 | public ReleaseRepository(string repositoryPath, string releaseBranchName, T repositoryReference)
20 | : base(repositoryPath, releaseBranchName, repositoryReference) { }
21 |
22 | public T GetRepositoryReference()
23 | {
24 | return (T)RepositoryRef;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/Model/SemanticReleaseVersion.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility.Model
2 | {
3 | public class SemanticReleaseVersion
4 | {
5 | public string Version { get; }
6 |
7 | public SemanticReleaseVersion(string version)
8 | {
9 | this.Version = version;
10 | }
11 |
12 | public override string ToString() => this.Version;
13 | }
14 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/ReleaseType.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticRelease.Extensibility
2 | {
3 | public enum ReleaseType
4 | {
5 | MAJOR = 6,
6 | PREMAJOR = 3,
7 | MINOR = 5,
8 | PREMINOR = 2,
9 | PATCH = 4,
10 | PREPATCH = 1,
11 | NONE = 0
12 | }
13 | }
--------------------------------------------------------------------------------
/src/SemanticRelease.Extensibility/SemanticRelease.Extensibility.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | 2.2.0
5 | SemanticRelease.Extensibility
6 | SemanticRelease.Extensibility
7 |
8 |
9 |
10 | A. Leonard
11 | https://github.com/axlj45/dotnet-semantic-release/blob/trunk/LICENSE
12 | false
13 | Library for extending dotnet-semanticrelease.
14 | semantic-versioning semantic-release
15 | git
16 | https://github.com/axlj45/dotnet-semantic-release
17 |
18 |
--------------------------------------------------------------------------------
/src/SemanticRelease.GlobalTool/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SemanticRelease.GlobalTool
4 | {
5 | class Program
6 | {
7 | static int Main(string[] args) => SemanticRelease.Core.Program.Main(args);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SemanticRelease.GlobalTool/SemanticRelease.GlobalTool.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | Exe
5 | semantic-release
6 | SemanticRelease.GlobalTool
7 | SemanticRelease.GlobalTool
8 | 2.3.0
9 | 2.3.0
10 | True
11 | True
12 |
13 |
14 |
15 |
16 | A. Leonard
17 | https://github.com/axlj45/dotnet-semantic-release/blob/trunk/LICENSE
18 | false
19 | Version package per semantic version specification.
20 | semantic-versioning semantic-release
21 | git
22 | https://github.com/axlj45/dotnet-semantic-release
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/SemanticRelease.Tool/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SemanticRelease.Tool
4 | {
5 | class Program
6 | {
7 | static int Main(string[] args) => SemanticRelease.Core.Program.Main(args);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SemanticRelease.Tool/SemanticRelease.Tool.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | Exe
5 | SemanticRelease.Tool
6 | dotnet-semanticrelease
7 | 2.3.0
8 | True
9 |
10 |
11 | A. Leonard
12 | https://github.com/axlj45/dotnet-semantic-release/blob/trunk/LICENSE
13 | false
14 | Version package per semantic version specification.
15 | semantic-versioning semantic-release
16 | git
17 | https://github.com/axlj45/dotnet-semantic-release
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/dotnet-semantic-release.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticRelease.CommitAnalyzer", "SemanticRelease.CommitAnalyzer\SemanticRelease.CommitAnalyzer.csproj", "{55AE256E-F66A-4309-9A15-6B9405F1246A}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticRelease.Extensibility", "SemanticRelease.Extensibility\SemanticRelease.Extensibility.csproj", "{CBBC497D-FB07-4882-B7DC-3B7EAC014573}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticRelease.Core", "SemanticRelease.Core\SemanticRelease.Core.csproj", "{0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticRelease.GlobalTool", "SemanticRelease.GlobalTool\SemanticRelease.GlobalTool.csproj", "{A06BE319-8084-43A0-9C97-F7532E2482C7}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticRelease.Tool", "SemanticRelease.Tool\SemanticRelease.Tool.csproj", "{91D21FC5-8F14-4F30-AA16-6F46D2B449AD}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SemanticRelease.CommitAnalyzer.Tests", "SemanticRelease.CommitAnalyzer.Tests\SemanticRelease.CommitAnalyzer.Tests.csproj", "{4EC641CE-6626-491F-A481-6FF7D29858AD}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Debug|x64 = Debug|x64
22 | Debug|x86 = Debug|x86
23 | Release|Any CPU = Release|Any CPU
24 | Release|x64 = Release|x64
25 | Release|x86 = Release|x86
26 | EndGlobalSection
27 | GlobalSection(SolutionProperties) = preSolution
28 | HideSolutionNode = FALSE
29 | EndGlobalSection
30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Debug|x64.ActiveCfg = Debug|Any CPU
34 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Debug|x64.Build.0 = Debug|Any CPU
35 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Debug|x86.ActiveCfg = Debug|Any CPU
36 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Debug|x86.Build.0 = Debug|Any CPU
37 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Release|Any CPU.Build.0 = Release|Any CPU
39 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Release|x64.ActiveCfg = Release|Any CPU
40 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Release|x64.Build.0 = Release|Any CPU
41 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Release|x86.ActiveCfg = Release|Any CPU
42 | {11FFB322-FEB1-4C28-B991-A3DD75C8AE0E}.Release|x86.Build.0 = Release|Any CPU
43 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Debug|x64.ActiveCfg = Debug|Any CPU
46 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Debug|x64.Build.0 = Debug|Any CPU
47 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Debug|x86.ActiveCfg = Debug|Any CPU
48 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Debug|x86.Build.0 = Debug|Any CPU
49 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Release|Any CPU.Build.0 = Release|Any CPU
51 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Release|x64.ActiveCfg = Release|Any CPU
52 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Release|x64.Build.0 = Release|Any CPU
53 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Release|x86.ActiveCfg = Release|Any CPU
54 | {55AE256E-F66A-4309-9A15-6B9405F1246A}.Release|x86.Build.0 = Release|Any CPU
55 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Debug|Any CPU.Build.0 = Debug|Any CPU
57 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Debug|x64.ActiveCfg = Debug|Any CPU
58 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Debug|x64.Build.0 = Debug|Any CPU
59 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Debug|x86.ActiveCfg = Debug|Any CPU
60 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Debug|x86.Build.0 = Debug|Any CPU
61 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Release|Any CPU.ActiveCfg = Release|Any CPU
62 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Release|Any CPU.Build.0 = Release|Any CPU
63 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Release|x64.ActiveCfg = Release|Any CPU
64 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Release|x64.Build.0 = Release|Any CPU
65 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Release|x86.ActiveCfg = Release|Any CPU
66 | {CBBC497D-FB07-4882-B7DC-3B7EAC014573}.Release|x86.Build.0 = Release|Any CPU
67 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
68 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
69 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Debug|x64.ActiveCfg = Debug|Any CPU
70 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Debug|x64.Build.0 = Debug|Any CPU
71 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Debug|x86.ActiveCfg = Debug|Any CPU
72 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Debug|x86.Build.0 = Debug|Any CPU
73 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
74 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Release|Any CPU.Build.0 = Release|Any CPU
75 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Release|x64.ActiveCfg = Release|Any CPU
76 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Release|x64.Build.0 = Release|Any CPU
77 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Release|x86.ActiveCfg = Release|Any CPU
78 | {0C2E13AE-2B5C-42A9-94FD-F6CEC07A41B0}.Release|x86.Build.0 = Release|Any CPU
79 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
80 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
81 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Debug|x64.ActiveCfg = Debug|Any CPU
82 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Debug|x64.Build.0 = Debug|Any CPU
83 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Debug|x86.ActiveCfg = Debug|Any CPU
84 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Debug|x86.Build.0 = Debug|Any CPU
85 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
86 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Release|Any CPU.Build.0 = Release|Any CPU
87 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Release|x64.ActiveCfg = Release|Any CPU
88 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Release|x64.Build.0 = Release|Any CPU
89 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Release|x86.ActiveCfg = Release|Any CPU
90 | {A06BE319-8084-43A0-9C97-F7532E2482C7}.Release|x86.Build.0 = Release|Any CPU
91 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
92 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
93 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Debug|x64.ActiveCfg = Debug|Any CPU
94 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Debug|x64.Build.0 = Debug|Any CPU
95 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Debug|x86.ActiveCfg = Debug|Any CPU
96 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Debug|x86.Build.0 = Debug|Any CPU
97 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
98 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Release|Any CPU.Build.0 = Release|Any CPU
99 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Release|x64.ActiveCfg = Release|Any CPU
100 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Release|x64.Build.0 = Release|Any CPU
101 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Release|x86.ActiveCfg = Release|Any CPU
102 | {91D21FC5-8F14-4F30-AA16-6F46D2B449AD}.Release|x86.Build.0 = Release|Any CPU
103 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
104 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
105 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Debug|x64.ActiveCfg = Debug|Any CPU
106 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Debug|x64.Build.0 = Debug|Any CPU
107 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Debug|x86.ActiveCfg = Debug|Any CPU
108 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Debug|x86.Build.0 = Debug|Any CPU
109 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
110 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Release|Any CPU.Build.0 = Release|Any CPU
111 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Release|x64.ActiveCfg = Release|Any CPU
112 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Release|x64.Build.0 = Release|Any CPU
113 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Release|x86.ActiveCfg = Release|Any CPU
114 | {4EC641CE-6626-491F-A481-6FF7D29858AD}.Release|x86.Build.0 = Release|Any CPU
115 | EndGlobalSection
116 | EndGlobal
117 |
--------------------------------------------------------------------------------