├── src
├── App
│ ├── AssemblyInfo.cs
│ ├── FodyWeavers.xml
│ ├── packages.config
│ ├── ReleaseNotesCompiler.CLI.csproj
│ └── Program.cs
├── Compiler
│ ├── FodyWeavers.xml
│ ├── AssemblyInfo.cs
│ ├── IssueExtensions.cs
│ ├── packages.config
│ ├── IGitHubClient.cs
│ ├── ReleaseUpdateRequired.cs
│ ├── MilestoneExtensions.cs
│ ├── DefaultGitHubClient.cs
│ ├── OctokitExtensions.cs
│ ├── ReleaseNotesCompiler.csproj
│ └── ReleaseNotesBuilder.cs
├── .nuget
│ └── packages.config
├── Tests
│ ├── ApprovalTestConfig.cs
│ ├── ReleaseNotesBuilderTests.NoCommitsNoIssues.approved.txt
│ ├── ReleaseNotesBuilderTests.SomeCommitsNoIssues.approved.txt
│ ├── ReleaseNotesBuilderTests.SingularCommitsNoIssues.approved.txt
│ ├── ReleaseNotesBuilderTests.NoCommitsSingularIssues.approved.txt
│ ├── packages.config
│ ├── ReleaseNotesBuilderTests.SomeCommitsSingularIssues.approved.txt
│ ├── ReleaseNotesBuilderTests.SingularCommitsSingularIssues.approved.txt
│ ├── ClipBoardHelper.cs
│ ├── ReleaseNotesBuilderTests.NoCommitsSomeIssues.approved.txt
│ ├── ReleaseNotesBuilderTests.SingularCommitsSomeIssues.approved.txt
│ ├── ReleaseNotesBuilderTests.SomeCommitsSomeIssues.approved.txt
│ ├── ClientBuilder.cs
│ ├── ReleaseNotesBuilderIntegrationTests.cs
│ ├── FakeGitHubClient.cs
│ ├── Helper.cs
│ ├── ReleaseNotesBuilderTests.cs
│ └── ReleaseNotesCompiler.Tests.csproj
├── nuget.config
├── GitHubReleaseNotes.sln
└── GitHubReleaseNotes.sln.DotSettings
├── .gitignore
├── README.md
├── packaging
└── nuget
│ └── releasenotescompiler.cli.nuspec
├── LICENSE
└── .gitattributes
/src/App/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | [assembly: AssemblyCompany("Particular")]
--------------------------------------------------------------------------------
/src/App/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/Compiler/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/.nuget/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Tests/ApprovalTestConfig.cs:
--------------------------------------------------------------------------------
1 | using ApprovalTests.Reporters;
2 |
3 | [assembly: UseReporter(typeof(AllFailingTestsClipboardReporter), typeof(DiffReporter))]
--------------------------------------------------------------------------------
/src/Compiler/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | [assembly: AssemblyTitle("ReleaseNotesCompiler")]
4 | [assembly: AssemblyProduct("ReleaseNotesCompiler")]
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.NoCommitsNoIssues.approved.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Where to get it
5 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.SomeCommitsNoIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [5 commits](https://github.com/TestUser/FakeRepo/commits/1.2.3).
2 |
3 |
4 | ## Where to get it
5 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.SingularCommitsNoIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [1 commit](https://github.com/TestUser/FakeRepo/commits/1.2.3).
2 |
3 |
4 | ## Where to get it
5 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.NoCommitsSingularIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [1 issue](https://github.com/FakeRepo/issues/issues?milestone=0&state=closed) closed.
2 |
3 |
4 | __Bugs__
5 | - [__#1__](http://example.com/1) Issue 1
6 |
7 | ## Where to get it
8 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Compiler/IssueExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler
2 | {
3 | using System.Linq;
4 | using Octokit;
5 |
6 | static class IssueExtensions
7 | {
8 | public static bool IsBug(this Issue issue)
9 | {
10 | return issue.Labels.Any(label => label.Name == "Type: Bug" || label.Name == "Bug");
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.SomeCommitsSingularIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [5 commits](https://github.com/TestUser/FakeRepo/commits/1.2.3) which resulted in [1 issue](https://github.com/FakeRepo/issues/issues?milestone=0&state=closed) being closed.
2 |
3 |
4 | __Bugs__
5 | - [__#1__](http://example.com/1) Issue 1
6 |
7 | ## Where to get it
8 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.SingularCommitsSingularIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [1 commit](https://github.com/TestUser/FakeRepo/commits/1.2.3) which resulted in [1 issue](https://github.com/FakeRepo/issues/issues?milestone=0&state=closed) being closed.
2 |
3 |
4 | __Bugs__
5 | - [__#1__](http://example.com/1) Issue 1
6 |
7 | ## Where to get it
8 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Compiler/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Compiler/IGitHubClient.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler
2 | {
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using Octokit;
6 |
7 | public interface IGitHubClient
8 | {
9 | Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone);
10 | Task> GetIssues(Milestone targetMilestone);
11 | Task> GetMilestones();
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Tests/ClipBoardHelper.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.Tests
2 | {
3 | using System.Threading;
4 | using System.Windows.Forms;
5 |
6 | class ClipBoardHelper
7 | {
8 | public static void SetClipboard(string result)
9 | {
10 | var thread = new Thread(() => Clipboard.SetText(result));
11 | thread.SetApartmentState(ApartmentState.STA);
12 | thread.Start();
13 | thread.Join();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.NoCommitsSomeIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [3 issues](https://github.com/FakeRepo/issues/issues?milestone=0&state=closed) closed.
2 |
3 |
4 | __Bugs__
5 | - [__#1__](http://example.com/1) Issue 1
6 |
7 | __Improvements/Features__
8 | - [__#2__](http://example.com/2) Issue 2
9 | - [__#3__](http://example.com/3) Issue 3
10 |
11 | ## Where to get it
12 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Compiler/ReleaseUpdateRequired.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler
2 | {
3 | public class ReleaseUpdateRequired
4 | {
5 | public string Repository { get; set; }
6 | public string Release { get; set; }
7 | public bool NeedsToBeCreated { get; set; }
8 | public override string ToString()
9 | {
10 | return string.Format("Update required for release {0}(Repo: {1}), NeedsToBeCreated: {2}", Release,Repository, NeedsToBeCreated);
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.SingularCommitsSomeIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [1 commit](https://github.com/TestUser/FakeRepo/commits/1.2.3) which resulted in [3 issues](https://github.com/FakeRepo/issues/issues?milestone=0&state=closed) being closed.
2 |
3 |
4 | __Bugs__
5 | - [__#1__](http://example.com/1) Issue 1
6 |
7 | __Improvements/Features__
8 | - [__#2__](http://example.com/2) Issue 2
9 | - [__#3__](http://example.com/3) Issue 3
10 |
11 | ## Where to get it
12 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.SomeCommitsSomeIssues.approved.txt:
--------------------------------------------------------------------------------
1 | As part of this release we had [5 commits](https://github.com/TestUser/FakeRepo/commits/1.2.3) which resulted in [3 issues](https://github.com/FakeRepo/issues/issues?milestone=0&state=closed) being closed.
2 |
3 |
4 | __Bugs__
5 | - [__#1__](http://example.com/1) Issue 1
6 |
7 | __Improvements/Features__
8 | - [__#2__](http://example.com/2) Issue 2
9 | - [__#3__](http://example.com/3) Issue 3
10 |
11 | ## Where to get it
12 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)
--------------------------------------------------------------------------------
/src/Compiler/MilestoneExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ReleaseNotesCompiler
4 | {
5 | using Octokit;
6 |
7 | static class MilestoneExtensions
8 | {
9 | internal static Version Version(this Milestone ver)
10 | {
11 | var nameWithoutPrerelease = ver.Title.Split('-')[0];
12 | Version parsedVersion;
13 |
14 | if (!System.Version.TryParse(nameWithoutPrerelease, out parsedVersion))
15 | {
16 | return new Version(0, 0);
17 | }
18 |
19 | return parsedVersion;
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/App/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | nugets
2 | build32
3 | binaries
4 | obj
5 | bin
6 | *.vshost.*
7 | .nu
8 | _ReSharper.*
9 | _UpgradeReport.*
10 | *.csproj.user
11 | *.resharper.user
12 | *.resharper
13 | *.suo
14 | *.cache
15 | *~
16 | *.swp
17 | *.user
18 | TestResults
19 | TestResult.xml
20 | results
21 | CommonAssemblyInfo.cs
22 | lib/sqlite/System.Data.SQLite.dll
23 | *.orig
24 | Samples/DataBus/storage
25 | packages
26 | PrecompiledWeb
27 | core-only
28 | Release
29 | Artifacts
30 | LogFiles
31 | csx
32 | *.ncrunchproject
33 | *.ncrunchsolution
34 | _NCrunch_NServiceBus/*
35 | logs
36 | run-git.cmd
37 | src/Chocolatey/Build/*
38 | App_Packages
39 |
--------------------------------------------------------------------------------
/src/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | GitHubReleaseNotes
2 | ====================
3 |
4 | **This project is no longer maintained. Consider using https://github.com/GitTools/GitReleaseManager instead**
5 |
6 | Generates release notes for a milestone in a GitHub repo based on issues associated with the milestone.
7 |
8 | ### Conventions
9 |
10 | * All closed issues/PR's for a milestone will be included.
11 | * Issues/PR's with a label `Type: Bug` will be included in a `Bugs` section
12 | * Issues/PR's not labeled as `Type: Bug` will be included in a `Features/Improvements` section
13 | * Milestones are named `{major.minor.patch}`.
14 | * The version is picked up from the build number (GFV) and that info is used to find the milestone.
15 | * Release notes are generated as markdown.
16 |
--------------------------------------------------------------------------------
/src/Tests/ClientBuilder.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.Tests
2 | {
3 | using Octokit;
4 | using Octokit.Internal;
5 |
6 | public static class ClientBuilder
7 | {
8 | public static GitHubClient Build()
9 | {
10 | var credentialStore = new InMemoryCredentialStore(Helper.Credentials);
11 | var httpClient = new HttpClientAdapter(HttpMessageHandlerFactory.CreateDefault);
12 |
13 | var connection = new Connection(
14 | new ProductHeaderValue("ReleaseNotesCompiler"),
15 | GitHubClient.GitHubApiUrl,
16 | credentialStore,
17 | httpClient,
18 | new SimpleJsonSerializer());
19 |
20 | return new GitHubClient(connection);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packaging/nuget/releasenotescompiler.cli.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | GitHubReleaseNotes
5 | Generates release notes
6 | $version$
7 | NServiceBus Ltd
8 | Particular et al
9 | https://github.com/Particular/GitHubReleaseNotes
10 | Create release notes in markdown given a GH milestone
11 | github release nptes
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderIntegrationTests.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.Tests
2 | {
3 | using System;
4 | using System.Threading.Tasks;
5 | using NUnit.Framework;
6 | using ReleaseNotesCompiler;
7 |
8 | [TestFixture]
9 | public class ReleaseNotesBuilderIntegrationTests
10 | {
11 | [Explicit]
12 | [TestCase("NServiceBus", "5.1.0")]
13 | [TestCase("ServiceControl", "1.0.0-Beta4")]
14 | [TestCase("NServiceBus", "6.0.0")]
15 | public async Task GenerateReleaseNotes(string repo, string version)
16 | {
17 | var gitHubClient = ClientBuilder.Build();
18 |
19 | var releaseNotesBuilder = new ReleaseNotesBuilder(new DefaultGitHubClient(gitHubClient, "Particular", repo), "Particular", repo, version);
20 | var result = await releaseNotesBuilder.BuildReleaseNotes();
21 | Console.WriteLine(result);
22 | ClipBoardHelper.SetClipboard(result);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Particular Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/src/Tests/FakeGitHubClient.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.Tests
2 | {
3 | using System.Collections.Generic;
4 | using System.Collections.ObjectModel;
5 | using System.Threading.Tasks;
6 | using Octokit;
7 | using IGitHubClient = ReleaseNotesCompiler.IGitHubClient;
8 |
9 | public class FakeGitHubClient : IGitHubClient
10 | {
11 | public List Milestones { get; set; }
12 | public List Issues { get; set; }
13 | public int NumberOfCommits { get; set; }
14 |
15 | public FakeGitHubClient()
16 | {
17 | Milestones = new List();
18 | Issues = new List();
19 | }
20 |
21 | public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone)
22 | {
23 | return Task.FromResult(NumberOfCommits);
24 | }
25 |
26 | public Task> GetIssues(Milestone targetMilestone)
27 | {
28 | return Task.FromResult(Issues);
29 | }
30 |
31 | public Task> GetMilestones()
32 | {
33 | return Task.FromResult>(new ReadOnlyCollection(Milestones));
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform CRLF normalization
2 | * text=auto eol=crlf
3 |
4 | # Standard to msysgit
5 | *.doc diff=astextplain
6 | *.DOC diff=astextplain
7 | *.docx diff=astextplain
8 | *.DOCX diff=astextplain
9 | *.dot diff=astextplain
10 | *.DOT diff=astextplain
11 | *.pdf diff=astextplain
12 | *.PDF diff=astextplain
13 | *.rtf diff=astextplain
14 | *.RTF diff=astextplain
15 |
16 | *.exe -text -diff
17 | *.jpg -text -diff
18 | *.png -text -diff
19 | *.gif -text -diff
20 | *.dll -text -diff
21 | *.pdb -text -diff
22 | *.pptx -text -diff
23 | *.xap -text -diff
24 | *.ico -text -diff
25 | *.ttf -text -diff
26 | *.otf -text -diff
27 |
28 | *.cs text diff=csharp
29 | *.config text diff=csharp
30 | *.xml text diff=csharp
31 | *.vb text
32 | *.c text
33 | *.cpp text
34 | *.cxx text
35 | *.h text
36 | *.hxx text
37 | *.py text
38 | *.rb text
39 | *.java text
40 | *.html text
41 | *.htm text
42 | *.css text
43 | *.scss text
44 | *.sass text
45 | *.less text
46 | *.js text
47 | *.lisp text
48 | *.clj text
49 | *.sql text
50 | *.php text
51 | *.lua text
52 | *.m text
53 | *.asm text
54 | *.erl text
55 | *.fs text
56 | *.fsx text
57 | *.hs text
58 |
59 | *.psm1 text
60 | *.ps1 text
61 | *.txt text eol=crlf
62 | *.bat text eol=crlf
63 |
64 | # Custom for Visual Studio
65 | *.csproj merge=union
66 | *.vbproj merge=union
67 | *.fsproj merge=union
68 | *.dbproj merge=union
69 | *.sln text eol=crlf merge=union
70 | *.suo -text -diff
71 | *.snk -text -diff
72 | *.cub -text -diff
73 | *.wixlib -text -diff
74 |
75 |
76 | *.approved.* binary
77 |
--------------------------------------------------------------------------------
/src/Tests/Helper.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.Tests
2 | {
3 | using System;
4 | using System.Net;
5 | using Octokit;
6 |
7 | public static class Helper
8 | {
9 | // From https://github.com/octokit/octokit.net/blob/master/Octokit.Tests.Integration/Helper.cs
10 |
11 | static readonly Lazy _credentialsThunk = new Lazy(() =>
12 | {
13 | var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBUSERNAME");
14 |
15 | var githubToken = Environment.GetEnvironmentVariable("OCTOKIT_OAUTHTOKEN");
16 |
17 | if (githubToken != null)
18 | return new Credentials(githubToken);
19 |
20 | var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBPASSWORD");
21 |
22 | if (githubUsername == null || githubPassword == null)
23 | return Credentials.Anonymous;
24 |
25 | return new Credentials(githubUsername, githubPassword);
26 | });
27 |
28 | public static Credentials Credentials
29 | {
30 | get { return _credentialsThunk.Value; }
31 | }
32 |
33 | public static IWebProxy Proxy
34 | {
35 | get
36 | {
37 | return null;
38 | /*
39 | return new WebProxy(
40 | new System.Uri("http://myproxy:42"),
41 | true,
42 | new string[] {},
43 | new NetworkCredential(@"domain\login", "password"));
44 | */
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Compiler/DefaultGitHubClient.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Octokit;
7 |
8 | public class DefaultGitHubClient : IGitHubClient
9 | {
10 | GitHubClient gitHubClient;
11 | string user;
12 | string repository;
13 |
14 | public DefaultGitHubClient(GitHubClient gitHubClient, string user, string repository)
15 | {
16 | this.gitHubClient = gitHubClient;
17 | this.user = user;
18 | this.repository = repository;
19 | }
20 |
21 | public async Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone)
22 | {
23 | try
24 | {
25 | if (previousMilestone == null)
26 | {
27 | var gitHubClientRepositoryCommitsCompare = await gitHubClient.Repository.Commit.Compare(user, repository, "master", currentMilestone.Title);
28 | return gitHubClientRepositoryCommitsCompare.AheadBy;
29 | }
30 |
31 | var compareResult = await gitHubClient.Repository.Commit.Compare(user, repository, previousMilestone.Title, "master");
32 | return compareResult.AheadBy;
33 | }
34 | catch (NotFoundException)
35 | {
36 | //If there is not tag yet the Compare will return a NotFoundException
37 | //we can safely ignore
38 | return 0;
39 | }
40 | }
41 |
42 | public async Task> GetIssues(Milestone targetMilestone)
43 | {
44 | var allIssues = await gitHubClient.AllIssuesForMilestone(targetMilestone);
45 | return allIssues.Where(x => x.State == ItemState.Closed).ToList();
46 | }
47 |
48 | public Task> GetMilestones()
49 | {
50 | var milestonesClient = gitHubClient.Issue.Milestone;
51 | return milestonesClient.GetAllForRepository(user, repository, new MilestoneRequest
52 | {
53 | State = ItemStateFilter.All
54 | });
55 |
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/Compiler/OctokitExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Octokit;
5 |
6 | namespace ReleaseNotesCompiler
7 | {
8 | public static class OctokitExtensions
9 | {
10 | public static bool IsPullRequest(this Issue issue)
11 | {
12 | return issue.PullRequest != null;
13 | }
14 |
15 | public static async Task> AllIssuesForMilestone(this GitHubClient gitHubClient, Milestone milestone)
16 | {
17 | var closedIssueRequest = new RepositoryIssueRequest
18 | {
19 | Milestone = milestone.Number.ToString(),
20 | State = ItemStateFilter.Closed
21 | };
22 | var openIssueRequest = new RepositoryIssueRequest
23 | {
24 | Milestone = milestone.Number.ToString(),
25 | State = ItemStateFilter.Open
26 | };
27 | var parts = milestone.Url.AbsolutePath.Split('/');
28 | var user = parts[2];
29 | var repository = parts[3];
30 | var closedIssues = await gitHubClient.Issue.GetAllForRepository(user, repository, closedIssueRequest);
31 | var openIssues = await gitHubClient.Issue.GetAllForRepository(user, repository, openIssueRequest);
32 | return openIssues.Union(closedIssues);
33 | }
34 |
35 | public static string HtmlUrl(this Milestone milestone)
36 | {
37 | var parts = milestone.Url.AbsolutePath.Split('/');
38 | var user = parts[2];
39 | var repository = parts[3];
40 | return string.Format("https://github.com/{0}/{1}/issues?milestone={2}&state=closed", user, repository, milestone.Number);
41 | }
42 |
43 | static IEnumerable FixHeaders(IEnumerable lines)
44 | {
45 | var inCode = false;
46 | foreach (var line in lines)
47 | {
48 | if (line.StartsWith("```"))
49 | {
50 | inCode = !inCode;
51 | }
52 | if (!inCode && line.StartsWith("#"))
53 | {
54 | yield return "###" + line;
55 | }
56 | else
57 | {
58 | yield return line;
59 | }
60 | }
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/GitHubReleaseNotes.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReleaseNotesCompiler", "Compiler\ReleaseNotesCompiler.csproj", "{B02A026E-CA3A-48F4-BBA9-EB337B0A2035}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReleaseNotesCompiler.Tests", "Tests\ReleaseNotesCompiler.Tests.csproj", "{FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReleaseNotesCompiler.CLI", "App\ReleaseNotesCompiler.CLI.csproj", "{F1163F09-3D4E-4F95-AF46-24C15AB297FB}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{69196B89-C58C-4705-AF1C-AE6B1042D01D}"
13 | ProjectSection(SolutionItems) = preProject
14 | .nuget\packages.config = .nuget\packages.config
15 | EndProjectSection
16 | EndProject
17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{87E2E61F-5F5D-45F1-8C4A-98E0BF8CA01D}"
18 | ProjectSection(SolutionItems) = preProject
19 | ..\packaging\nuget\releasenotescompiler.cli.nuspec = ..\packaging\nuget\releasenotescompiler.cli.nuspec
20 | EndProjectSection
21 | EndProject
22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CCFB4E86-2A64-4E73-A96E-67D58130C960}"
23 | ProjectSection(SolutionItems) = preProject
24 | ..\README.md = ..\README.md
25 | EndProjectSection
26 | EndProject
27 | Global
28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
29 | Debug|Any CPU = Debug|Any CPU
30 | Release|Any CPU = Release|Any CPU
31 | EndGlobalSection
32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
33 | {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {F1163F09-3D4E-4F95-AF46-24C15AB297FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {F1163F09-3D4E-4F95-AF46-24C15AB297FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {F1163F09-3D4E-4F95-AF46-24C15AB297FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {F1163F09-3D4E-4F95-AF46-24C15AB297FB}.Release|Any CPU.Build.0 = Release|Any CPU
45 | EndGlobalSection
46 | GlobalSection(SolutionProperties) = preSolution
47 | HideSolutionNode = FALSE
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesBuilderTests.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.Tests
2 | {
3 | using System;
4 | using System.Linq;
5 | using ApprovalTests;
6 | using NUnit.Framework;
7 | using Octokit;
8 |
9 | [TestFixture]
10 | public class ReleaseNotesBuilderTests
11 | {
12 | [Test]
13 | public void NoCommitsNoIssues()
14 | {
15 | AcceptTest(0);
16 | }
17 |
18 | [Test]
19 | public void NoCommitsSomeIssues()
20 | {
21 | AcceptTest(0, CreateIssue(1, "Bug"), CreateIssue(2, "Feature"), CreateIssue(3, "Improvement"));
22 | }
23 |
24 | [Test]
25 | public void SomeCommitsNoIssues()
26 | {
27 | AcceptTest(5);
28 | }
29 |
30 | [Test]
31 | public void SomeCommitsSomeIssues()
32 | {
33 | AcceptTest(5, CreateIssue(1, "Bug"), CreateIssue(2, "Feature"), CreateIssue(3, "Improvement"));
34 | }
35 |
36 | [Test]
37 | public void SingularCommitsNoIssues()
38 | {
39 | AcceptTest(1);
40 | }
41 |
42 | [Test]
43 | public void SingularCommitsSomeIssues()
44 | {
45 | AcceptTest(1, CreateIssue(1, "Bug"), CreateIssue(2, "Feature"), CreateIssue(3, "Improvement"));
46 | }
47 |
48 | [Test]
49 | public void SingularCommitsSingularIssues()
50 | {
51 | AcceptTest(1, CreateIssue(1, "Bug"));
52 | }
53 |
54 | [Test]
55 | public void NoCommitsSingularIssues()
56 | {
57 | AcceptTest(0, CreateIssue(1, "Bug"));
58 | }
59 |
60 | [Test]
61 | public void SomeCommitsSingularIssues()
62 | {
63 | AcceptTest(5, CreateIssue(1, "Bug"));
64 | }
65 |
66 | static void AcceptTest(int commits, params Issue[] issues)
67 | {
68 | var fakeClient = new FakeGitHubClient();
69 |
70 | fakeClient.Milestones.Add(CreateMilestone("1.2.3"));
71 |
72 | fakeClient.NumberOfCommits = commits;
73 |
74 | foreach (var issue in issues)
75 | {
76 | fakeClient.Issues.Add(issue);
77 | }
78 |
79 | var builder = new ReleaseNotesBuilder(fakeClient, "TestUser", "FakeRepo", "1.2.3");
80 |
81 | var notes = builder.BuildReleaseNotes().Result;
82 |
83 | Approvals.Verify(notes);
84 | }
85 |
86 |
87 | static Milestone CreateMilestone(string version)
88 | {
89 | return new Milestone(new Uri("https://github.com/Particular/FakeRepo/issues?q=milestone%3A" + version), 0, ItemState.Open, version, String.Empty, null, 0, 0, DateTimeOffset.Now, null, null);
90 | }
91 |
92 | static Issue CreateIssue(int number, params string[] labels)
93 | {
94 | return new Issue(null,
95 | new Uri("http://example.com/" + number),
96 | null,
97 | null,
98 | number,
99 | ItemState.Open,
100 | "Issue " + number,
101 | "Some issue",
102 | null,
103 | null,
104 | labels.Select(x => new Label(null, x, null)).ToArray(),
105 | null,
106 | null,
107 | 0,
108 | null,
109 | null,
110 | DateTimeOffset.Now,
111 | null,
112 | 1,
113 | false,
114 | null);
115 | }
116 | }
117 | }
--------------------------------------------------------------------------------
/src/Compiler/ReleaseNotesCompiler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}
8 | Library
9 | Properties
10 | ReleaseNotesCompiler
11 | ReleaseNotesCompiler
12 | v4.6
13 | 512
14 |
15 |
16 | ..\
17 | true
18 |
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | ..\packages\Octokit.0.22.0\lib\net45\Octokit.dll
40 | True
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/Tests/ReleaseNotesCompiler.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}
8 | Library
9 | Properties
10 | ReleaseNotesCompiler.Tests
11 | ReleaseNotesCompiler.Tests
12 | v4.6
13 | 512
14 | ..\
15 | true
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | full
29 | false
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | true
35 |
36 |
37 |
38 | ..\packages\ApprovalTests.3.0.13\lib\net40\ApprovalTests.dll
39 | True
40 |
41 |
42 | ..\packages\ApprovalUtilities.3.0.13\lib\net45\ApprovalUtilities.dll
43 | True
44 |
45 |
46 | ..\packages\ApprovalUtilities.3.0.13\lib\net45\ApprovalUtilities.Net45.dll
47 | True
48 |
49 |
50 | ..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll
51 | True
52 |
53 |
54 | ..\packages\Octokit.0.22.0\lib\net45\Octokit.dll
55 | True
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}
79 | ReleaseNotesCompiler
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/Compiler/ReleaseNotesBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Octokit;
8 |
9 | namespace ReleaseNotesCompiler
10 | {
11 | using static System.String;
12 |
13 | public class ReleaseNotesBuilder
14 | {
15 | public ReleaseNotesBuilder(IGitHubClient gitHubClient, string user, string repository, string milestoneTitle)
16 | {
17 | this.gitHubClient = gitHubClient;
18 | this.user = user;
19 | this.repository = repository;
20 | this.milestoneTitle = milestoneTitle;
21 | }
22 |
23 | public async Task BuildReleaseNotes()
24 | {
25 | var milestones = await gitHubClient.GetMilestones();
26 |
27 | var targetMilestone = milestones.FirstOrDefault(x => x.Title == milestoneTitle);
28 |
29 | if (targetMilestone == null)
30 | {
31 | throw new Exception($"Could not find milestone for '{milestoneTitle}'.");
32 | }
33 | var issues = await gitHubClient.GetIssues(targetMilestone);
34 | var stringBuilder = new StringBuilder();
35 | var previousMilestone = GetPreviousMilestone(targetMilestone, milestones);
36 | var numberOfCommits = await gitHubClient.GetNumberOfCommitsBetween(previousMilestone, targetMilestone);
37 |
38 | if (issues.Count > 0)
39 | {
40 | var issuesText = Format(issues.Count == 1 ? "{0} issue" : "{0} issues", issues.Count);
41 |
42 | if (numberOfCommits > 0)
43 | {
44 | var commitsLink = GetCommitsLink(targetMilestone, previousMilestone);
45 | var commitsText = Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits);
46 |
47 | stringBuilder.Append($"As part of this release we had [{commitsText}]({commitsLink}) which resulted in [{issuesText}]({targetMilestone.HtmlUrl()}) being closed.");
48 | }
49 | else
50 | {
51 | stringBuilder.Append($"As part of this release we had [{issuesText}]({targetMilestone.HtmlUrl()}) closed.");
52 | }
53 | }
54 | else if (numberOfCommits > 0)
55 | {
56 | var commitsLink = GetCommitsLink(targetMilestone, previousMilestone);
57 | var commitsText = Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits);
58 | stringBuilder.Append($"As part of this release we had [{commitsText}]({commitsLink}).");
59 | }
60 | stringBuilder.AppendLine();
61 |
62 | stringBuilder.AppendLine(targetMilestone.Description);
63 | stringBuilder.AppendLine();
64 |
65 | AddIssues(stringBuilder, issues);
66 |
67 | await AddFooter(stringBuilder);
68 |
69 | return stringBuilder.ToString();
70 | }
71 |
72 | Milestone GetPreviousMilestone(Milestone targetMilestone, IReadOnlyList milestones)
73 | {
74 | var currentVersion = targetMilestone.Version();
75 | return milestones
76 | .OrderByDescending(m => m.Version())
77 | .Distinct().ToList()
78 | .SkipWhile(x => x.Version() >= currentVersion)
79 | .FirstOrDefault();
80 | }
81 |
82 | string GetCommitsLink(Milestone targetMilestone, Milestone previousMilestone)
83 | {
84 | if (previousMilestone == null)
85 | {
86 | return $"https://github.com/{user}/{repository}/commits/{targetMilestone.Title}";
87 | }
88 | return $"https://github.com/{user}/{repository}/compare/{previousMilestone.Title}...{targetMilestone.Title}";
89 | }
90 |
91 | void AddIssues(StringBuilder builder, List issues)
92 | {
93 | var bugs = issues
94 | .Where(issue => issue.IsBug())
95 | .ToList();
96 |
97 | if (bugs.Any())
98 | {
99 | PrintHeading("Bugs", builder);
100 |
101 | PrintIssue(builder, bugs);
102 |
103 | builder.AppendLine();
104 | }
105 |
106 | var others = issues.Where(issue =>!issue.IsBug())
107 | .ToList();
108 |
109 | if (others.Any())
110 | {
111 | PrintHeading("Improvements/Features", builder);
112 |
113 | PrintIssue(builder, others);
114 |
115 | builder.AppendLine();
116 | }
117 | }
118 |
119 | static async Task AddFooter(StringBuilder stringBuilder)
120 | {
121 | var file = new FileInfo("footer.md");
122 |
123 | if (!file.Exists)
124 | {
125 | file = new FileInfo("footer.txt");
126 | }
127 |
128 | if (!file.Exists)
129 | {
130 | stringBuilder.Append(@"## Where to get it
131 | You can download this release from [nuget](https://www.nuget.org/profiles/nservicebus/)");
132 | return;
133 | }
134 |
135 | using (var reader = file.OpenText())
136 | {
137 | stringBuilder.Append(await reader.ReadToEndAsync());
138 | }
139 | }
140 |
141 | static void PrintHeading(string labelName, StringBuilder builder)
142 | {
143 | builder.AppendFormat($"__{labelName}__\r\n");
144 | }
145 |
146 | static void PrintIssue(StringBuilder builder, List relevantIssues)
147 | {
148 | foreach (var issue in relevantIssues)
149 | {
150 | builder.Append($"- [__#{issue.Number}__]({issue.HtmlUrl}) {issue.Title}\r\n");
151 | }
152 | }
153 |
154 | IGitHubClient gitHubClient;
155 | string user;
156 | string repository;
157 | string milestoneTitle;
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/App/ReleaseNotesCompiler.CLI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F1163F09-3D4E-4F95-AF46-24C15AB297FB}
8 | Exe
9 | Properties
10 | ReleaseNotesCompiler.CLI
11 | ReleaseNotesCompiler.CLI
12 | v4.6
13 | 512
14 |
15 |
16 | ..\
17 | true
18 |
19 |
20 |
21 | AnyCPU
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | AnyCPU
32 | pdbonly
33 | true
34 | bin\Release\
35 | TRACE
36 | prompt
37 | 4
38 |
39 |
40 |
41 | ..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll
42 |
43 |
44 | ..\packages\Octokit.0.22.0\lib\net45\Octokit.dll
45 | True
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | Designer
63 |
64 |
65 |
66 |
67 | {b02a026e-ca3a-48f4-bba9-eb337b0a2035}
68 | ReleaseNotesCompiler
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | ();
92 | var attribute = config.Attribute("ExcludeAssemblies");
93 | if (attribute != null)
94 | foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty))
95 | excludedAssemblies.Add(item);
96 | var element = config.Element("ExcludeAssemblies");
97 | if (element != null)
98 | foreach (var item in element.Value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty))
99 | excludedAssemblies.Add(item);
100 |
101 | var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase));
102 |
103 | foreach (var item in filesToCleanup)
104 | File.Delete(item);
105 | ]]>
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/App/Program.cs:
--------------------------------------------------------------------------------
1 | namespace ReleaseNotesCompiler.CLI
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using CommandLine;
8 | using CommandLine.Text;
9 | using Octokit;
10 | using FileMode = System.IO.FileMode;
11 |
12 | abstract class CommonSubOptions
13 | {
14 | [Option('u', "username", HelpText = "The username to access GitHub with.", Required = true)]
15 | public string Username { get; set; }
16 |
17 | [Option('p', "password", HelpText = "The password to access GitHub with.", Required = true)]
18 | public string Password { get; set; }
19 |
20 | [Option('o', "owner", HelpText = "The owner of the repository.", Required = true)]
21 | public string RepositoryOwner { get; set; }
22 |
23 | [Option('r', "repository", HelpText = "The name of the repository.", Required = true)]
24 | public string RepositoryName { get; set; }
25 |
26 | [Option('m', "milestone", HelpText = "The milestone to use.", Required = true)]
27 | public string Milestone { get; set; }
28 |
29 | public GitHubClient CreateGitHubClient()
30 | {
31 | var creds = new Credentials(Username, Password);
32 | var github = new GitHubClient(new ProductHeaderValue("ReleaseNotesCompiler")) { Credentials = creds };
33 |
34 | return github;
35 | }
36 | }
37 |
38 | class CreateSubOptions : CommonSubOptions
39 | {
40 | [Option('a', "asset", HelpText = "Path to the file to include in the release.", Required = false)]
41 | public string AssetPath { get; set; }
42 |
43 | [Option('t', "targetcommitish", HelpText = "The commit to tag. Can be a branch or SHA. Defaults to repo's default branch.", Required = false)]
44 | public string TargetCommitish { get; set; }
45 | }
46 |
47 | class AttachSubOptions : CommonSubOptions
48 | {
49 | [Option('a', "asset", HelpText = "Path to the file to include in the release.", Required = false)]
50 | public string AssetPath { get; set; }
51 | }
52 |
53 | class PublishSubOptions : CommonSubOptions
54 | {
55 | }
56 |
57 | class Options
58 | {
59 | [VerbOption("create", HelpText = "Creates a draft release notes from a milestone.")]
60 | public CreateSubOptions CreateVerb { get; set; }
61 |
62 | [VerbOption("attach", HelpText = "Attaches an asset to a release.")]
63 | public AttachSubOptions AttachVerb { get; set; }
64 |
65 | [VerbOption("publish", HelpText = "Publishes the release notes and closes the milestone.")]
66 | public PublishSubOptions PublishVerb { get; set; }
67 |
68 | [HelpVerbOption]
69 | public string DoHelpForVerb(string verbName)
70 | {
71 | return HelpText.AutoBuild(this, verbName);
72 | }
73 | }
74 |
75 | class Program
76 | {
77 | static int Main(string[] args)
78 | {
79 | var options = new Options();
80 |
81 | var result = 1;
82 |
83 | if (!Parser.Default.ParseArgumentsStrict(args, options, (verb, subOptions) =>
84 | {
85 | if (verb == "create")
86 | {
87 | result = CreateReleaseAsync((CreateSubOptions)subOptions).Result;
88 | }
89 |
90 | if (verb == "attach")
91 | {
92 | result = AttachToReleaseAsync((AttachSubOptions)subOptions).Result;
93 | }
94 |
95 | if (verb == "publish")
96 | {
97 | result = PublishReleaseAsync((PublishSubOptions)subOptions).Result;
98 | }
99 | }))
100 | {
101 | return 1;
102 | }
103 |
104 | return result;
105 | }
106 |
107 | static async Task CreateReleaseAsync(CreateSubOptions options)
108 | {
109 | try
110 | {
111 | var github = options.CreateGitHubClient();
112 |
113 | await CreateRelease(github, options.RepositoryOwner, options.RepositoryName, options.Milestone, options.TargetCommitish, options.AssetPath);
114 |
115 | return 0;
116 | }
117 | catch (Exception ex)
118 | {
119 | Console.WriteLine(ex);
120 |
121 | return 1;
122 | }
123 | }
124 |
125 | static async Task AttachToReleaseAsync(AttachSubOptions options)
126 | {
127 | try
128 | {
129 | var github = options.CreateGitHubClient();
130 |
131 | await AttachToRelease(github, options.RepositoryOwner, options.RepositoryName, options.Milestone, options.AssetPath);
132 |
133 | return 0;
134 | }
135 | catch (Exception ex)
136 | {
137 | Console.WriteLine(ex);
138 |
139 | return 1;
140 | }
141 | }
142 |
143 | static async Task PublishReleaseAsync(PublishSubOptions options)
144 | {
145 | try
146 | {
147 | var github = options.CreateGitHubClient();
148 |
149 | await CloseMilestone(github, options.RepositoryOwner, options.RepositoryName, options.Milestone);
150 |
151 | await PublishRelease(github, options.RepositoryOwner, options.RepositoryName, options.Milestone);
152 |
153 | return 0;
154 | }
155 | catch (Exception ex)
156 | {
157 | Console.WriteLine(ex);
158 |
159 | return 1;
160 | }
161 | }
162 |
163 | static async Task CreateRelease(GitHubClient github, string owner, string repository, string milestone, string targetCommitish, string asset)
164 | {
165 | var releaseNotesBuilder = new ReleaseNotesBuilder(new DefaultGitHubClient(github, owner, repository), owner, repository, milestone);
166 |
167 | var result = await releaseNotesBuilder.BuildReleaseNotes();
168 |
169 | var releaseUpdate = new NewRelease(milestone)
170 | {
171 | Draft = true,
172 | Body = result,
173 | Name = milestone,
174 | };
175 | if (!string.IsNullOrEmpty(targetCommitish))
176 | releaseUpdate.TargetCommitish = targetCommitish;
177 |
178 | var release = await github.Repository.Release.Create(owner, repository, releaseUpdate);
179 |
180 | if (File.Exists(asset))
181 | {
182 | var upload = new ReleaseAssetUpload { FileName = Path.GetFileName(asset), ContentType = "application/octet-stream", RawData = File.Open(asset, FileMode.Open) };
183 |
184 | await github.Repository.Release.UploadAsset(release, upload);
185 | }
186 | }
187 |
188 | static async Task AttachToRelease(GitHubClient github, string owner, string repository, string milestone, string asset)
189 | {
190 | if (!File.Exists(asset))
191 | return;
192 |
193 | var releases = await github.Repository.Release.GetAll(owner, repository);
194 | var release = releases.FirstOrDefault(r => r.Name == milestone);
195 | if (release == null)
196 | return;
197 |
198 | var upload = new ReleaseAssetUpload { FileName = Path.GetFileName(asset), ContentType = "application/octet-stream", RawData = File.Open(asset, FileMode.Open) };
199 |
200 | await github.Repository.Release.UploadAsset(release, upload);
201 | }
202 |
203 | static async Task CloseMilestone(GitHubClient github, string owner, string repository, string milestoneTitle)
204 | {
205 | var milestoneClient = github.Issue.Milestone;
206 | var openMilestones = await milestoneClient.GetAllForRepository(owner, repository, new MilestoneRequest { State = ItemStateFilter.Open });
207 | var milestone = openMilestones.FirstOrDefault(m => m.Title == milestoneTitle);
208 | if (milestone == null)
209 | return;
210 |
211 | await milestoneClient.Update(owner, repository, milestone.Number, new MilestoneUpdate { State = ItemState.Closed });
212 | }
213 |
214 | static async Task PublishRelease(GitHubClient github, string owner, string repository, string milestone)
215 | {
216 | var releases = await github.Repository.Release.GetAll(owner, repository);
217 | var release = releases.FirstOrDefault(r => r.Name == milestone);
218 | if (release == null)
219 | return;
220 |
221 | var releaseUpdate = new ReleaseUpdate
222 | {
223 | Draft = false
224 | };
225 |
226 | await github.Repository.Release.Edit(owner, repository, release.Id, releaseUpdate);
227 | }
228 | }
229 | }
--------------------------------------------------------------------------------
/src/GitHubReleaseNotes.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 | True
6 | True
7 | False
8 | SOLUTION
9 | DO_NOT_SHOW
10 | ERROR
11 | DO_NOT_SHOW
12 | DO_NOT_SHOW
13 | DO_NOT_SHOW
14 | DO_NOT_SHOW
15 | ERROR
16 | ERROR
17 | ERROR
18 | ERROR
19 | ERROR
20 | DO_NOT_SHOW
21 | DO_NOT_SHOW
22 | DO_NOT_SHOW
23 | ERROR
24 | ERROR
25 | ERROR
26 | ERROR
27 | ERROR
28 | ERROR
29 | ERROR
30 | ERROR
31 | ERROR
32 | ERROR
33 | ERROR
34 | ERROR
35 | ERROR
36 | ERROR
37 | ERROR
38 | ERROR
39 | ERROR
40 | ERROR
41 | ERROR
42 | ERROR
43 | ERROR
44 | DO_NOT_SHOW
45 | DO_NOT_SHOW
46 | ERROR
47 | DO_NOT_SHOW
48 | DO_NOT_SHOW
49 | ERROR
50 | ERROR
51 | ERROR
52 | ERROR
53 | ERROR
54 | ERROR
55 | ERROR
56 | ERROR
57 | ERROR
58 | WARNING
59 | ERROR
60 | ERROR
61 | ERROR
62 | ERROR
63 | ERROR
64 | ERROR
65 | ERROR
66 | ERROR
67 | ERROR
68 | ERROR
69 | ERROR
70 | ERROR
71 | ERROR
72 | ERROR
73 | ERROR
74 | SUGGESTION
75 | ERROR
76 | ERROR
77 | ERROR
78 | ERROR
79 | ERROR
80 | ERROR
81 | ERROR
82 | ERROR
83 | ERROR
84 | ERROR
85 | WARNING
86 | ERROR
87 | ERROR
88 | ERROR
89 | DoHide
90 | DoHide
91 | DoHide
92 | DoHide
93 | DoHide
94 | DoHide
95 | DoHide
96 | DoHide
97 | DoHide
98 | DoHide
99 | DoHide
100 | DoHide
101 | DoHide
102 | DoHide
103 | DoHide
104 | DoHide
105 | DoHide
106 | DoHide
107 | DoHide
108 | ERROR
109 | ERROR
110 | ERROR
111 | ERROR
112 | ERROR
113 | ERROR
114 | ERROR
115 | ERROR
116 | ERROR
117 | ERROR
118 | ERROR
119 | DO_NOT_SHOW
120 | SUGGESTION
121 | WARNING
122 | WARNING
123 | ERROR
124 | ERROR
125 | ERROR
126 | ERROR
127 | ERROR
128 | <?xml version="1.0" encoding="utf-16"?><Profile name="Format My Code Using "Particular" conventions"><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><JsReformatCode>True</JsReformatCode><CssReformatCode>True</CssReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><HtmlReformatCode>True</HtmlReformatCode><CSShortenReferences>True</CSShortenReferences><CSharpFormatDocComments>True</CSharpFormatDocComments><CssAlphabetizeProperties>True</CssAlphabetizeProperties></Profile>
129 | Default: Reformat Code
130 | Format My Code Using "Particular" conventions
131 | False
132 | False
133 | ALWAYS_ADD
134 | ALWAYS_ADD
135 | ALWAYS_ADD
136 | ALWAYS_ADD
137 | ALWAYS_ADD
138 | False
139 | False
140 | False
141 | CHOP_ALWAYS
142 | False
143 | CHOP_ALWAYS
144 | CHOP_ALWAYS
145 | True
146 | True
147 | <?xml version="1.0" encoding="utf-16"?>
148 | <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
149 | <TypePattern Priority="100" DisplayName="Type Pattern">
150 | <TypePattern.Match>
151 | <Or>
152 | <And>
153 | <Kind Is="Interface" />
154 | <Or>
155 | <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
156 | <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
157 | </Or>
158 | </And>
159 | <HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" />
160 | </Or>
161 | </TypePattern.Match>
162 | </TypePattern>
163 | <TypePattern Priority="100" DisplayName="Type Pattern">
164 | <TypePattern.Match>
165 | <And>
166 | <Kind Is="Class" />
167 | <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
168 | </And>
169 | </TypePattern.Match>
170 | <Entry DisplayName="Entry">
171 | <Entry.Match>
172 | <And>
173 | <Kind Is="Method" />
174 | <Or>
175 | <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
176 | <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
177 | <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
178 | <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
179 | </Or>
180 | </And>
181 | </Entry.Match>
182 | </Entry>
183 | <Entry DisplayName="Entry" />
184 | <Entry Priority="100" DisplayName="Entry">
185 | <Entry.Match>
186 | <And>
187 | <Kind Is="Method" />
188 | <HasAttribute Name="NUnit.Framework.TestAttribute" />
189 | </And>
190 | </Entry.Match>
191 | <Entry.SortBy>
192 | <Name />
193 | </Entry.SortBy>
194 | </Entry>
195 | </TypePattern>
196 | <TypePattern DisplayName="Type Pattern">
197 | <Entry Priority="100" DisplayName="Entry">
198 | <Entry.Match>
199 | <And>
200 | <Access Is="Public" />
201 | <Kind Is="Delegate" />
202 | </And>
203 | </Entry.Match>
204 | <Entry.SortBy>
205 | <Name />
206 | </Entry.SortBy>
207 | </Entry>
208 | <Entry Priority="100" DisplayName="Entry">
209 | <Entry.Match>
210 | <And>
211 | <Access Is="Public" />
212 | <Kind Is="Enum" />
213 | </And>
214 | </Entry.Match>
215 | <Entry.SortBy>
216 | <Name />
217 | </Entry.SortBy>
218 | </Entry>
219 | <Entry DisplayName="Entry">
220 | <Entry.Match>
221 | <Kind Is="Constructor" />
222 | </Entry.Match>
223 | <Entry.SortBy>
224 | <Static />
225 | </Entry.SortBy>
226 | </Entry>
227 | <Entry DisplayName="Entry">
228 | <Entry.Match>
229 | <Or>
230 | <Kind Is="Property" />
231 | <Kind Is="Indexer" />
232 | </Or>
233 | </Entry.Match>
234 | </Entry>
235 | <Entry Priority="100" DisplayName="Entry">
236 | <Entry.Match>
237 | <And>
238 | <Kind Is="Member" />
239 | <ImplementsInterface />
240 | </And>
241 | </Entry.Match>
242 | <Entry.SortBy>
243 | <ImplementsInterface Immediate="True" />
244 | </Entry.SortBy>
245 | </Entry>
246 | <Entry DisplayName="Entry" />
247 | <Entry DisplayName="Entry">
248 | <Entry.Match>
249 | <Or>
250 | <Kind Is="Constant" />
251 | <And>
252 | <Kind Is="Field" />
253 | <Static />
254 | </And>
255 | </Or>
256 | </Entry.Match>
257 | <Entry.SortBy>
258 | <Kind Order="Constant Field" />
259 | </Entry.SortBy>
260 | </Entry>
261 | <Entry DisplayName="Entry">
262 | <Entry.Match>
263 | <And>
264 | <Kind Is="Field" />
265 | <Not>
266 | <Static />
267 | </Not>
268 | </And>
269 | </Entry.Match>
270 | <Entry.SortBy>
271 | <Readonly />
272 | <Name />
273 | </Entry.SortBy>
274 | </Entry>
275 | <Entry DisplayName="Entry">
276 | <Entry.Match>
277 | <Kind Is="Type" />
278 | </Entry.Match>
279 | <Entry.SortBy>
280 | <Name />
281 | </Entry.SortBy>
282 | </Entry>
283 | </TypePattern>
284 | </Patterns>
285 | <?xml version="1.0" encoding="utf-8" ?>
286 |
287 | <!--
288 | I. Overall
289 |
290 | I.1 Each pattern can have <Match>....</Match> element. For the given type declaration, the pattern with the match, evaluated to 'true' with the largest weight, will be used
291 | I.2 Each pattern consists of the sequence of <Entry>...</Entry> elements. Type member declarations are distributed between entries
292 | I.3 If pattern has RemoveAllRegions="true" attribute, then all regions will be cleared prior to reordering. Otherwise, only auto-generated regions will be cleared
293 | I.4 The contents of each entry is sorted by given keys (First key is primary, next key is secondary, etc). Then the declarations are grouped and en-regioned by given property
294 |
295 | II. Available match operands
296 |
297 | Each operand may have Weight="..." attribute. This weight will be added to the match weight if the operand is evaluated to 'true'.
298 | The default weight is 1
299 |
300 | II.1 Boolean functions:
301 | II.1.1 <And>....</And>
302 | II.1.2 <Or>....</Or>
303 | II.1.3 <Not>....</Not>
304 |
305 | II.2 Operands
306 | II.2.1 <Kind Is="..."/>. Kinds are: class, struct, interface, enum, delegate, type, constructor, destructor, property, indexer, method, operator, field, constant, event, member
307 | II.2.2 <Name Is="..." [IgnoreCase="true/false"] />. The 'Is' attribute contains regular expression
308 | II.2.3 <HasAttribute CLRName="..." [Inherit="true/false"] />. The 'CLRName' attribute contains regular expression
309 | II.2.4 <Access Is="..."/>. The 'Is' values are: public, protected, internal, protected internal, private
310 | II.2.5 <Static/>
311 | II.2.6 <Abstract/>
312 | II.2.7 <Virtual/>
313 | II.2.8 <Override/>
314 | II.2.9 <Sealed/>
315 | II.2.10 <Readonly/>
316 | II.2.11 <ImplementsInterface CLRName="..."/>. The 'CLRName' attribute contains regular expression
317 | II.2.12 <HandlesEvent />
318 | -->
319 |
320 | <Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns">
321 |
322 | <!--Do not reorder COM interfaces and structs marked by StructLayout attribute-->
323 | <Pattern>
324 | <Match>
325 | <Or Weight="100">
326 | <And>
327 | <Kind Is="interface"/>
328 | <Or>
329 | <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute"/>
330 | <HasAttribute CLRName="System.Runtime.InteropServices.ComImport"/>
331 | </Or>
332 | </And>
333 | <HasAttribute CLRName="System.Runtime.InteropServices.StructLayoutAttribute"/>
334 | </Or>
335 | </Match>
336 | </Pattern>
337 |
338 | <!--Special formatting of NUnit test fixture-->
339 | <Pattern RemoveAllRegions="true">
340 | <Match>
341 | <And Weight="100">
342 | <Kind Is="class"/>
343 | <HasAttribute CLRName="NUnit.Framework.TestFixtureAttribute" Inherit="true"/>
344 | </And>
345 | </Match>
346 |
347 | <!--Setup/Teardow-->
348 | <Entry>
349 | <Match>
350 | <And>
351 | <Kind Is="method"/>
352 | <Or>
353 | <HasAttribute CLRName="NUnit.Framework.SetUpAttribute" Inherit="true"/>
354 | <HasAttribute CLRName="NUnit.Framework.TearDownAttribute" Inherit="true"/>
355 | <HasAttribute CLRName="NUnit.Framework.FixtureSetUpAttribute" Inherit="true"/>
356 | <HasAttribute CLRName="NUnit.Framework.FixtureTearDownAttribute" Inherit="true"/>
357 | </Or>
358 | </And>
359 | </Match>
360 | </Entry>
361 |
362 | <!--All other members-->
363 | <Entry/>
364 |
365 | <!--Test methods-->
366 | <Entry>
367 | <Match>
368 | <And Weight="100">
369 | <Kind Is="method"/>
370 | <HasAttribute CLRName="NUnit.Framework.TestAttribute" Inherit="false"/>
371 | </And>
372 | </Match>
373 | <Sort>
374 | <Name/>
375 | </Sort>
376 | </Entry>
377 | </Pattern>
378 |
379 | <!--Default pattern-->
380 | <Pattern>
381 |
382 | <!--public delegate-->
383 | <Entry>
384 | <Match>
385 | <And Weight="100">
386 | <Access Is="public"/>
387 | <Kind Is="delegate"/>
388 | </And>
389 | </Match>
390 | <Sort>
391 | <Name/>
392 | </Sort>
393 | </Entry>
394 |
395 | <!--public enum-->
396 | <Entry>
397 | <Match>
398 | <And Weight="100">
399 | <Access Is="public"/>
400 | <Kind Is="enum"/>
401 | </And>
402 | </Match>
403 | <Sort>
404 | <Name/>
405 | </Sort>
406 | </Entry>
407 |
408 | <!--Constructors. Place static one first-->
409 | <Entry>
410 | <Match>
411 | <Kind Is="constructor"/>
412 | </Match>
413 | <Sort>
414 | <Static/>
415 | </Sort>
416 | </Entry>
417 |
418 | <!--properties, indexers-->
419 | <Entry>
420 | <Match>
421 | <Or>
422 | <Kind Is="property"/>
423 | <Kind Is="indexer"/>
424 | </Or>
425 | </Match>
426 | </Entry>
427 |
428 | <!--interface implementations-->
429 | <Entry>
430 | <Match>
431 | <And Weight="100">
432 | <Kind Is="member"/>
433 | <ImplementsInterface/>
434 | </And>
435 | </Match>
436 | <Sort>
437 | <ImplementsInterface Immediate="true"/>
438 | </Sort>
439 | </Entry>
440 |
441 | <!--all other members-->
442 | <Entry/>
443 |
444 | <!--static fields and constants-->
445 | <Entry>
446 | <Match>
447 | <Or>
448 | <Kind Is="constant"/>
449 | <And>
450 | <Kind Is="field"/>
451 | <Static/>
452 | </And>
453 | </Or>
454 | </Match>
455 | <Sort>
456 | <Kind Order="constant field"/>
457 | </Sort>
458 | </Entry>
459 |
460 | <!--instance fields-->
461 | <Entry>
462 | <Match>
463 | <And>
464 | <Kind Is="field"/>
465 | <Not>
466 | <Static/>
467 | </Not>
468 | </And>
469 | </Match>
470 | <Sort>
471 | <Readonly/>
472 | <Name/>
473 | </Sort>
474 | </Entry>
475 |
476 | <!--nested types-->
477 | <Entry>
478 | <Match>
479 | <Kind Is="type"/>
480 | </Match>
481 | <Sort>
482 | <Name/>
483 | </Sort>
484 | </Entry>
485 | </Pattern>
486 |
487 | </Patterns>
488 |
489 | CustomLayout
490 | True
491 | True
492 | True
493 | False
494 | True
495 | False
496 | False
497 | False
498 | True
499 | Automatic property
500 | True
501 | False
502 | False
503 | DB
504 | DTC
505 | ID
506 | NSB
507 | SLA
508 | $object$_On$event$
509 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
510 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
511 | <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" />
512 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
513 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
514 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
515 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
516 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
517 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
518 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
519 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
520 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
521 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
522 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
523 | <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
524 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
525 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
526 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
527 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
528 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
529 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
530 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
531 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
532 | $object$_On$event$
533 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
534 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
535 | <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" />
536 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
537 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
538 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
539 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
540 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
541 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
542 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
543 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
544 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
545 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
546 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
547 | <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
548 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
549 | True
550 | True
551 | True
552 | True
553 | True
554 | True
555 | True
556 |
557 |
558 |
559 |
560 | <data />
561 | <data><IncludeFilters /><ExcludeFilters /></data>
--------------------------------------------------------------------------------