├── .config └── dotnet-tools.json ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ └── build.yml ├── .markdownlint.json ├── .vscode └── settings.json ├── 47dc2ec9-b548-41ac-a2e9-4fd238472b8e.cake ├── COMMITTERS.md ├── CONTRIBUTING.md ├── CREDITS.md ├── GitReleaseManager.yaml ├── LICENSE ├── README.md ├── build.ps1 ├── build.sh ├── cake.config ├── config.wyam ├── docs └── input │ ├── _Bottom.cshtml │ ├── assets │ ├── css │ │ └── override.less │ └── img │ │ └── favicon.ico │ └── docs │ ├── advanced.md │ ├── commands │ ├── add-assets.md │ ├── close.md │ ├── create.md │ ├── discard.md │ ├── export.md │ ├── index.cshtml │ ├── init.md │ ├── label.md │ ├── open.md │ ├── publish.md │ └── show-config.md │ ├── configuration │ ├── create-configuration.md │ ├── default-configuration.md │ ├── exclude-issues.md │ ├── export-configuration.md │ ├── include-issues.md │ ├── index.cshtml │ ├── label-aliases.md │ └── template-configuration.md │ ├── credits │ ├── icon.md │ ├── index.cshtml │ └── particular.md │ ├── images │ ├── example-export.png │ ├── example-release-notes.png │ └── grm-usage.png │ ├── index.md │ ├── installation │ ├── chocolatey.md │ ├── dotnettool.md │ ├── index.cshtml │ └── nuget.md │ ├── logging │ ├── index.cshtml │ └── logging.md │ └── why-grm.md ├── gitversion.yml ├── icons ├── package_icon.png ├── package_icon.svg └── package_icon_no_credit.png ├── nuspec ├── chocolatey │ ├── GitReleaseManager.Portable.nuspec │ ├── LICENSE.TXT │ ├── VERIFICATION.TXT │ ├── chocolateyInstall.ps1 │ └── chocolateyUninstall.ps1 └── nuget │ └── GitReleaseManager.nuspec ├── recipe.cake ├── src ├── .editorconfig ├── CustomDictionary.xml ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── GitReleaseManager.Cli │ ├── GitReleaseManager.Cli.csproj │ ├── GlobalSuppressions.cs │ ├── Logging │ │ └── LogConfiguration.cs │ └── Program.cs ├── GitReleaseManager.Core.Tests │ ├── .editorconfig │ ├── Commands │ │ ├── AddAssetsCommandTests.cs │ │ ├── CloseCommandTests.cs │ │ ├── CreateCommandTests.cs │ │ ├── DiscardCommandTests.cs │ │ ├── ExportCommandTests.cs │ │ ├── InitCommandTests.cs │ │ ├── LabelCommandTests.cs │ │ ├── OpenCommandTests.cs │ │ ├── PublishCommandTests.cs │ │ └── ShowConfigCommandTests.cs │ ├── EnsureTests.cs │ ├── GitReleaseManager.Core.Tests.csproj │ ├── Provider │ │ └── GitHubProviderTests.cs │ ├── Templates │ │ └── TemplateLoaderTests.cs │ └── VcsServiceTests.cs ├── GitReleaseManager.Core │ ├── Attributes │ │ └── SampleAttribute.cs │ ├── AutoMapperConfiguration.cs │ ├── Commands │ │ ├── AddAssetsCommand.cs │ │ ├── CloseCommand.cs │ │ ├── CreateCommand.cs │ │ ├── DiscardCommand.cs │ │ ├── ExportCommand.cs │ │ ├── ICommand.cs │ │ ├── InitCommand.cs │ │ ├── LabelCommand.cs │ │ ├── OpenCommand.cs │ │ ├── PublishCommand.cs │ │ └── ShowConfigCommand.cs │ ├── Configuration │ │ ├── CloseConfig.cs │ │ ├── CommentSerialization │ │ │ ├── CommentGatheringTypeInspector.cs │ │ │ ├── CommentsObjectDescriptor.cs │ │ │ └── CommentsObjectGraphVisitor.cs │ │ ├── Config.cs │ │ ├── ConfigSerializer.cs │ │ ├── ConfigurationProvider.cs │ │ ├── CreateConfig.cs │ │ ├── ExportConfig.cs │ │ ├── LabelAlias.cs │ │ └── LabelConfig.cs │ ├── Ensure.cs │ ├── Exceptions │ │ ├── ApiException.cs │ │ ├── ForbiddenException.cs │ │ ├── InvalidIssuesException.cs │ │ └── NotFoundException.cs │ ├── Extensions │ │ ├── JsonExtensions.cs │ │ ├── MilestoneExtensions.cs │ │ ├── OctokitExtensions.cs │ │ └── StringExtensions.cs │ ├── GitReleaseManager.Core.csproj │ ├── GlobalSuppressions.cs │ ├── Helpers │ │ ├── FileSystem.cs │ │ └── IFileSystem.cs │ ├── IVcsService.cs │ ├── MappingProfiles │ │ ├── GitHubProfile.cs │ │ └── GitLabProfile.cs │ ├── Model │ │ ├── Issue.cs │ │ ├── IssueComment.cs │ │ ├── ItemState.cs │ │ ├── ItemStateFilter.cs │ │ ├── Label.cs │ │ ├── Milestone.cs │ │ ├── RateLimit.cs │ │ ├── Release.cs │ │ ├── ReleaseAsset.cs │ │ ├── ReleaseAssetUpload.cs │ │ ├── User.cs │ │ └── VcsProvider.cs │ ├── Options │ │ ├── AddAssetSubOptions.cs │ │ ├── BaseSubOptions.cs │ │ ├── BaseVcsSubOptions.cs │ │ ├── CloseSubOptions.cs │ │ ├── CreateSubOptions.cs │ │ ├── DiscardSubOptions.cs │ │ ├── ExportSubOptions.cs │ │ ├── InitSubOptions.cs │ │ ├── LabelSubOptions.cs │ │ ├── MainOptions.cs │ │ ├── OpenSubOptions.cs │ │ ├── PublishSubOptions.cs │ │ └── ShowConfigSubOptions.cs │ ├── Provider │ │ ├── GitHubProvider.cs │ │ ├── GitLabProvider.cs │ │ └── IVcsProvider.cs │ ├── ReleaseNotes │ │ ├── IReleaseNotesBuilder.cs │ │ ├── IReleaseNotesExporter.cs │ │ ├── ReleaseNotesBuilder.cs │ │ └── ReleaseNotesExporter.cs │ ├── Templates │ │ ├── ReleaseTemplates.tt │ │ ├── TemplateFactory.cs │ │ ├── TemplateKind.cs │ │ ├── TemplateLoader.cs │ │ ├── contributors │ │ │ ├── contributor-details.sbn │ │ │ ├── contributors.sbn │ │ │ ├── create │ │ │ │ └── footer.sbn │ │ │ ├── index.sbn │ │ │ ├── issue-details.sbn │ │ │ ├── issue-note.sbn │ │ │ ├── issues.sbn │ │ │ ├── milestone.sbn │ │ │ └── release-info.sbn │ │ ├── default │ │ │ ├── create │ │ │ │ └── footer.sbn │ │ │ ├── index.sbn │ │ │ ├── issue-details.sbn │ │ │ ├── issue-note.sbn │ │ │ ├── issues.sbn │ │ │ ├── milestone.sbn │ │ │ └── release-info.sbn │ │ └── no_issues │ │ │ ├── create │ │ │ └── footer.sbn │ │ │ ├── index.sbn │ │ │ ├── issues.sbn │ │ │ ├── milestone.sbn │ │ │ └── release-info.sbn │ └── VcsService.cs ├── GitReleaseManager.IntegrationTests │ ├── .editorconfig │ ├── ClientBuilder.cs │ ├── ClipBoardHelper.cs │ ├── GitHubProviderIntegrationTests.cs │ ├── GitLabProviderIntegrationTests.cs │ ├── GitReleaseManager.IntegrationTests.csproj │ ├── Helper.cs │ └── ReleaseNotesBuilderIntegrationTests.cs ├── GitReleaseManager.Tests │ ├── .editorconfig │ ├── ApprovalTestConfig.cs │ ├── ConfigurationTests.cs │ ├── Extensions │ │ └── StringExtensionsTests.cs │ ├── GitReleaseManager.Tests.csproj │ ├── Helper.cs │ ├── ReleaseNotesBuilderTests.CorrectlyExcludeIssues.approved.txt │ ├── ReleaseNotesBuilderTests.CorrectlyExcludeIssuesWhenBothIncludeAndExcludeLabelIsSet.approved.txt │ ├── ReleaseNotesBuilderTests.CorrectlyUseFooterWhenEnabled.approved.txt │ ├── ReleaseNotesBuilderTests.CorrectlyUseFooterWithMilestoneWhenEnabled.approved.txt │ ├── ReleaseNotesBuilderTests.NoCommitsNoIssues.approved.txt │ ├── ReleaseNotesBuilderTests.NoCommitsSingularIssues.approved.txt │ ├── ReleaseNotesBuilderTests.NoCommitsSomeIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SingularCommitsNoIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SingularCommitsSingularIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SingularCommitsSomeIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SingularCommitsWithHeaderLabelAlias.approved.txt │ ├── ReleaseNotesBuilderTests.SingularCommitsWithMilestoneDescription.approved.txt │ ├── ReleaseNotesBuilderTests.SomeCommits.approved.txt │ ├── ReleaseNotesBuilderTests.SomeCommitsNoIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SomeCommitsSingularIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SomeCommitsSomeIssues.approved.txt │ ├── ReleaseNotesBuilderTests.SomeCommitsWithPluralizedLabelAlias.approved.txt │ ├── ReleaseNotesBuilderTests.SomeCommitsWithoutPluralizedLabelAlias.approved.txt │ ├── ReleaseNotesBuilderTests.cs │ ├── ReleaseNotesExporterTests.NoReleases.approved.txt │ ├── ReleaseNotesExporterTests.SingleRelease.approved.txt │ ├── ReleaseNotesExporterTests.SingleReleaseExcludeCreatedDateInTitle.approved.txt │ ├── ReleaseNotesExporterTests.SingleReleaseExcludeRegexRemoval.approved.txt │ ├── ReleaseNotesExporterTests.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ └── VcsServiceMock.cs ├── GitReleaseManager.Tool │ └── GitReleaseManager.Tool.csproj ├── GitReleaseManager.sln ├── GitReleaseManager.sln.DotSettings ├── GlobalSuppressions.cs └── stylecop.json └── tests └── integration ├── buildData.cake ├── expected ├── releasenotes-with-token.md └── releasenotes-with-username-password.md ├── tests.cake ├── utilities.cake └── xunit.cake /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "1.3.0", 7 | "commands": [ 8 | "dotnet-cake" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://EditorConfig.org 3 | 4 | root = true 5 | 6 | # Keep this file simple, only basic formatting should be 7 | # defined here. 8 | # Code styles should be defined in src/.editorconfig 9 | 10 | [*] 11 | charset = utf-8 # Just for consistency 12 | # Indentation and spacing 13 | indent_size = 4 14 | indent_style = space 15 | tab_width = 4 16 | 17 | # New line preferences 18 | end_of_line = unset 19 | insert_final_newline = false 20 | trim_trailing_whitespace = true 21 | 22 | [*.sh] 23 | end_of_line = lf 24 | 25 | [*.sln] 26 | # Visual studio defaults 27 | end_of_line = crlf 28 | insert_final_newline = true 29 | indent_style = tab 30 | 31 | [*.csproj] 32 | # Visual studio defaults 33 | end_of_line = crlf 34 | insert_final_newline = true 35 | indent_style = space 36 | tab_width = 4 37 | indent_size = 4 38 | 39 | [*.md] 40 | trim_trailing_whitespace = false 41 | insert_final_newline = true # Conflicts with markdownlint when false 42 | indent_size = 2 # Incorrect indentation happens when this is not 2 43 | 44 | [*.{yml,yaml}] 45 | indent_size = 2 # Incorrect indentation happens when this is not 2 46 | 47 | [*.ps1] 48 | end_of_line = crlf 49 | charset = utf-8-bom 50 | indent_style = space 51 | indent_size = 2 52 | 53 | [*.js] 54 | indent_style = tab 55 | indent_size = 2 56 | 57 | [*.{bat,cmd}] 58 | end_of_line = crlf 59 | charset = latin1 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report a bug 3 | about: Create a bug report to help us improve 4 | title: "REPLACE THIS TEXT WITH A GENERAL SUMMARY OF THE ISSUE" 5 | labels: Bug, Investigating 6 | assignees: "" 7 | --- 8 | 9 | ## Description 10 | 11 | 12 | 13 | ## Expected Behavior 14 | 15 | 16 | ## Actual Behavior 17 | 18 | 19 | ## Possible Fix 20 | 21 | 22 | ## Steps to Reproduce 23 | 24 | 25 | 26 | ## Context 27 | 28 | 29 | ## Your Environment 30 | 31 | 32 | 33 | - Version Used: 34 | - Edition Used (.NET Core, .NET Framework): 35 | - Operating System and version (Windows 10, Ubuntu 18.04): 36 | - Link to your project: 37 | - Link to your CI build (if appropriate): 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Gitter Community Chat 4 | url: https://gitter.im/GitTools/GitReleaseManager 5 | about: Please ask and answer questions here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggest a new feature 3 | about: Suggest a new feature to implement 4 | title: "REPLACE THIS TEXT WITH A GENERAL SUMMARY OF THE FEATURE" 5 | labels: Feature, Investigating 6 | assignees: "" 7 | --- 8 | 9 | ## Detailed Description 10 | 11 | 12 | ## Context 13 | 14 | 15 | 16 | ## Possible Implementation 17 | 18 | 19 | ## Your Environment 20 | 21 | - Version Used: 22 | - Edition Used (.NET Core, .NET Framework): 23 | - Operating System and version (Windows 10, Ubuntu 18.04): 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Related Issue 7 | 8 | 9 | 10 | 11 | 12 | ## Motivation and Context 13 | 14 | 15 | ## How Has This Been Tested? 16 | 17 | 18 | 19 | 20 | ## Screenshots (if appropriate): 21 | 22 | ## Checklist: 23 | 24 | 25 | 26 | - [ ] My code follows the code style of this project. 27 | - [ ] My change requires a change to the documentation. 28 | - [ ] I have updated the documentation accordingly. 29 | - [ ] I have read the **CONTRIBUTING** document. 30 | - [ ] I have added tests to cover my changes. 31 | - [ ] All new and existing tests passed. 32 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | labels: 6 | - "Build" 7 | schedule: 8 | interval: daily 9 | - package-ecosystem: nuget 10 | directory: "/src" 11 | labels: 12 | - "Build" 13 | groups: 14 | analyzers: 15 | patterns: 16 | - "*Analyzers" 17 | serilog: 18 | patterns: 19 | - "Serilog.*" 20 | tests: 21 | patterns: 22 | - "NUnit.*" 23 | - "Microsoft.NET.Test.Sdk" 24 | - "NSubstitute" 25 | - "coverlet.msbuild" 26 | schedule: 27 | interval: daily 28 | open-pull-requests-limit: 10 29 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - develop 8 | - "feature/**" 9 | - "release/**" 10 | - "hotfix/**" 11 | tags: 12 | - "*" 13 | pull_request: 14 | 15 | jobs: 16 | build: 17 | runs-on: ${{ matrix.os }} 18 | strategy: 19 | matrix: 20 | os: [ windows-2022 ] 21 | 22 | env: 23 | GITTOOLS_GITHUB_TOKEN: ${{ secrets.NUGET_GITHUB_TOKEN }} 24 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} 25 | NUGET_SOURCE: https://api.nuget.org/v3/index.json 26 | CHOCOLATEY_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }} 27 | CHOCOLATEY_SOURCE: https://push.chocolatey.org/ 28 | TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 29 | TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} 30 | TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} 31 | TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} 32 | COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} 33 | CODECOV_REPO_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} 34 | GPR_USER: gittools-bot 35 | GPR_PASSWORD: ${{ secrets.NUGET_GITHUB_TOKEN }} 36 | steps: 37 | - name: Checkout the repository 38 | uses: actions/checkout@v4 39 | 40 | - name: Fetch all tags and branches 41 | run: git fetch --prune --unshallow 42 | 43 | - name: Install .NET SDK 2.1.x, 3.1.x, 5.0.x, 8.0.x, and 9.0.x 44 | uses: actions/setup-dotnet@v4 45 | with: 46 | dotnet-version: | 47 | 2.1.x 48 | 3.1.x 49 | 5.0.x 50 | 8.0.x 51 | 9.0.x 52 | 53 | - name: Cache Tools 54 | uses: actions/cache@v4 55 | with: 56 | path: tools 57 | key: ${{ runner.os }}-tools-${{ hashFiles('recipe.cake') }} 58 | 59 | - name: Build project 60 | uses: cake-build/cake-action@v3 61 | with: 62 | script-path: recipe.cake 63 | target: CI 64 | verbosity: Normal 65 | cake-version: tool-manifest 66 | 67 | - name: Upload Issues-Report 68 | uses: actions/upload-artifact@v4 69 | with: 70 | if-no-files-found: warn 71 | name: ${{ matrix.os }} issues 72 | path: BuildArtifacts/report.html 73 | 74 | - name: Upload Packages 75 | uses: actions/upload-artifact@v4 76 | if: runner.os == 'Windows' 77 | with: 78 | if-no-files-found: warn 79 | name: package 80 | path: BuildArtifacts/Packages/**/* -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD026": false 3 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.rulers": [80], 3 | "cSpell.words": [ 4 | "Usings", 5 | "addasset", 6 | "buildartifacts", 7 | "choco", 8 | "gitreleasemanager", 9 | "nupkg", 10 | "psake", 11 | "readonly", 12 | "releasenotes", 13 | "showconfig" 14 | ], 15 | "omnisharp.enableEditorConfigSupport": true, 16 | "omnisharp.enableRoslynAnalyzers": true 17 | } -------------------------------------------------------------------------------- /47dc2ec9-b548-41ac-a2e9-4fd238472b8e.cake: -------------------------------------------------------------------------------- 1 | #tool dotnet:?package=GitVersion.Tool&version=5.6.7 -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | GitReleaseManager has been the thoughts and work of the following people: 2 | 3 | ## Committers & Contributors 4 | 5 | ### Committers 6 | 7 | These are the committers to GitTools/GitReleaseManager repository: 8 | 9 | - [Gary Ewan Park](https://github.com/gep13) - Creater of GitReleaseManager, committer, vision, direction 10 | - [Kim Nordmo](https://github.com/AdmiringWorm) - Committer, vision direction 11 | 12 | ### Contributors 13 | 14 | - [Particular Software](http://www.particular.net/) created the original [GitHubReleaseNotes](https://github.com/Particular/GitHubReleaseNotes) project, which GitReleaseManager is based on. 15 | 16 | #### Other Contributors 17 | 18 | - [GitReleaseManager](https://github.com/GitTools/GitReleaseManager/graphs/contributors) 19 | 20 | ## Frameworks 21 | 22 | GitReleaseManager uses the following awesome frameworks (in no particular order): 23 | 24 | - [Octokit.net](https://github.com/octokit/octokit.net) 25 | - [YamlDotNet](http://aaubry.net/pages/yamldotnet.html) 26 | 27 | GitReleaseManager is built, with the following fantastic frameworks and services (in no particular order): 28 | 29 | - [Cake](https://github.com/cake-build/cake) 30 | - [NuGet.exe](https://www.nuget.org/) 31 | - [AppVeyor](http://www.appveyor.com/) 32 | 33 | GitReleaseManager is tested and analyzed with the following rockstar frameworks (in no particular order): 34 | 35 | - [FxCop]() 36 | - [StyleCop](http://stylecop.codeplex.com/) 37 | - [InspectCode](https://confluence.jetbrains.com/display/NETCOM/Introducing+InspectCode) 38 | - [DupFinder](https://confluence.jetbrains.com/display/NETCOM/Introducing+dupFinder) 39 | - [Coveralls](https://coveralls.io/) 40 | - [NUnit](http://www.nunit.org/) 41 | - [OpenCover](https://github.com/opencover/opencover) 42 | 43 | We would like to credit other super sweet tools/frameworks that aid in the development of GitReleaseManager: 44 | 45 | - [ReSharper](https://www.jetbrains.com/resharper/) 46 | - [NuGet Framework](https://www.nuget.org/) 47 | -------------------------------------------------------------------------------- /GitReleaseManager.yaml: -------------------------------------------------------------------------------- 1 | issue-labels-include: 2 | - Breaking change 3 | - Feature 4 | - Bug 5 | - Improvement 6 | - Documentation 7 | - security 8 | issue-labels-exclude: 9 | - Build 10 | - Internal Refactoring 11 | issue-labels-alias: 12 | - name: Documentation 13 | header: Documentation 14 | plural: Documentation 15 | - name: security 16 | header: Security 17 | plural: Security 18 | create: 19 | include-sha-section: true 20 | sha-section-heading: "SHA256 Hashes of the release artifacts" 21 | sha-section-line-format: "- `{1}\t{0}`" 22 | include-contributors: true 23 | close: 24 | use-issue-comments: true 25 | set-due-date: true 26 | issue-comment: |- 27 | :tada: This issue has been resolved in version {milestone} :tada: 28 | 29 | The release is available on: 30 | 31 | - [GitHub Release](https://github.com/{owner}/{repository}/releases/tag/{milestone}) 32 | - [NuGet Package](https://www.nuget.org/packages/gitreleasemanager/{milestone}) 33 | - [Chocolatey Package](https://chocolatey.org/packages/gitreleasemanager.portable/{milestone}) 34 | - [.Net Global Tool](https://www.nuget.org/packages/GitReleaseManager.Tool/{milestone}) 35 | 36 | Your **[GitReleaseManager](https://github.com/GitTools/GitReleaseManager)** bot :package::rocket: -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 - Present - GitTools Contributors 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. -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | $SCRIPT_NAME = "recipe.cake" 2 | 3 | Write-Host "Restoring .NET Core tools" 4 | dotnet tool restore 5 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 6 | 7 | Write-Host "Bootstrapping Cake" 8 | dotnet cake $SCRIPT_NAME --bootstrap 9 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 10 | 11 | Write-Host "Running Build" 12 | dotnet cake $SCRIPT_NAME @args 13 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCRIPT_NAME="recipe.cake" 3 | 4 | echo "Restoring .NET Core tools" 5 | dotnet tool restore 6 | 7 | echo "Bootstrapping Cake" 8 | dotnet cake $SCRIPT_NAME --bootstrap 9 | 10 | echo "Running Build" 11 | dotnet cake $SCRIPT_NAME "$@" -------------------------------------------------------------------------------- /cake.config: -------------------------------------------------------------------------------- 1 | ; This is the default configuration file for Cake. 2 | ; This file was downloaded from https://github.com/cake-build/resources 3 | 4 | [Nuget] 5 | Source=https://api.nuget.org/v3/index.json 6 | 7 | [Paths] 8 | Tools=./tools 9 | Addins=./tools/Addins 10 | Modules=./tools/Modules -------------------------------------------------------------------------------- /config.wyam: -------------------------------------------------------------------------------- 1 | Pipelines["RenderPages"].Replace("WriteMetadata", new Headings(2)); -------------------------------------------------------------------------------- /docs/input/_Bottom.cshtml: -------------------------------------------------------------------------------- 1 |
2 | GitHub 3 |
4 | 9 | 10 | -------------------------------------------------------------------------------- /docs/input/assets/css/override.less: -------------------------------------------------------------------------------- 1 | @font-family-sans-serif: "Roboto", Helvetica, Arial, sans-serif; 2 | 3 | /* For Gitter and GitHub */ 4 | .bottom-footer { 5 | margin-bottom: 40px !important; // Make room for Gitter and GitHub buttons 6 | } 7 | 8 | .gitter-open-chat-button { 9 | background-color: #3c8dbc; 10 | font-family: @font-family-sans-serif; 11 | letter-spacing: normal; 12 | right: 90px; 13 | } 14 | 15 | .gitter-open-chat-button:focus, .gitter-open-chat-button:hover, 16 | .github-button:focus, .github-button:hover, 17 | { 18 | background-color: #4EABDD; 19 | color: #fff; 20 | } 21 | 22 | .gitter-chat-embed { 23 | top: 49px; 24 | border-top: 1px solid #000; 25 | z-index: 10000; 26 | } 27 | 28 | .github-button { 29 | z-index: 100; 30 | position: fixed; 31 | bottom: 0px; 32 | right: 240px; 33 | padding: 1em 3em; 34 | background-color: #367fa9; 35 | border: 0; 36 | border-top-left-radius: 0.5em; 37 | border-top-right-radius: 0.5em; 38 | font-family: sans-serif; 39 | font-size: 9pt; 40 | text-transform: uppercase; 41 | text-align: center; 42 | text-decoration: none; 43 | cursor: pointer; 44 | cursor: hand; 45 | -webkit-transition: all .3s ease; 46 | transition: all .3s ease; 47 | color: #fff; 48 | a, a:active, a:hover, a:focus { 49 | color: #fff; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docs/input/assets/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitTools/GitReleaseManager/1550105c8da911a83f396bd3199e0b7b613ecbb8/docs/input/assets/img/favicon.ico -------------------------------------------------------------------------------- /docs/input/docs/commands/add-assets.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 30 3 | Title: Add Assets 4 | --- 5 | 6 | Once a draft set of release notes has been created, it is possible to add 7 | additional assets to the release using the addasset command. 8 | 9 | ## **Required Parameters** 10 | 11 | - `--token`: The access token to access GitHub with. 12 | - `-o, --owner`: The owner of the repository. 13 | - `-r, --repository`: The name of the repository. 14 | - `-t, --tagName`: The name of the release (Typically this is the generated 15 | SemVer Version Number). 16 | - `-a, --assets`: Path(s) to the file(s) to include in the release. This is a 17 | comma separated list of files to include 18 | 19 | ## **Optional Parameters** 20 | 21 | - `-d, -targetDirectory`: The directory on which GitReleaseManager should be 22 | executed. Defaults to current directory. 23 | - `-l, -logFilePath`: Path to where log file should be created. Defaults to 24 | logging to console. 25 | 26 | ## **Examples** 27 | 28 | ```bash 29 | gitreleasemanager.exe addasset -t 0.1.0 -u bob --token fsdfsf67657sdf5s7d5f -r repo -a c:\buildartifacts\setup.exe,c:\buildartifacts\setup.nupkg 30 | 31 | gitreleasemanager.exe create --tagName 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo --assets c:\buildartifacts\setup.exe,c:\buildartifacts\setup.nupkg 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/input/docs/commands/close.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 40 3 | Title: Close 4 | --- 5 | 6 | Out of the box, publishing a release on GitHub does not close the milestone 7 | associated with the release. This command, when executed, closes the specified 8 | milestone. 9 | 10 | ## **Required Parameters** 11 | 12 | - `--token`: The access token to access GitHub with. 13 | - `-o, --owner`: The owner of the repository. 14 | - `-r, --repository`: The name of the repository. 15 | - `-m, --milestone`: The milestone to use. 16 | 17 | ## **Optional Parameters** 18 | 19 | - `-d, --targetDirectory`: The directory on which GitReleaseManager should be 20 | executed. Defaults to current directory. 21 | - `-l, --logFilePath`: Path to where log file should be created. Defaults to 22 | logging to console. 23 | 24 | ## **Examples** 25 | 26 | ```bash 27 | gitreleasemanager.exe close -m 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 28 | 29 | gitreleasemanager.exe close --milestone 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/input/docs/commands/create.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 10 3 | Title: Create 4 | --- 5 | 6 | This is the main command of GitReleaseManager and it is used to create a draft 7 | set of release notes based on a milestone, which has been set up in GitHub. 8 | 9 | There are three modes of operation when creating a Release. GitReleaseManager can 10 | take as an input the name of the milestone to generate the release notes from. 11 | Or, it can take as an input the name of a file which contains the release notes 12 | to include in the Release. 13 | Or, it can create a release that doesn't contain any release notes, i.e. it is empty. 14 | 15 | ## **Required Parameters** 16 | 17 | - `--token`: The access token to access GitHub with. 18 | - `-o, --owner`: The owner of the repository. 19 | - `-r, --repository`: The name of the repository. 20 | 21 | ## **Optional Parameters** 22 | 23 | - `-m, --milestone`: The milestone to use. 24 | - `-n, --name`: The name of the release (Typically this is the generated SemVer 25 | Version Number). 26 | - `-i, --inputFilePath`: The path to the file to be used as the content of the 27 | release notes. 28 | - `-e, --pre`: Creates the release as a pre-release. 29 | - `-a, --assets`: Path(s) to the file(s) to include in the release. This is a 30 | comma separated list of files to include 31 | - `-c, --targetcommitish`: The commit to tag. Can be a branch or SHA. Defaults 32 | to repository's default branch. 33 | - `-d, --targetDirectory`: The directory on which GitReleaseManager should be 34 | executed. Defaults to current directory. 35 | - `-l, --logFilePath`: Path to where log file should be created. Defaults to 36 | logging to console. 37 | - `-t, --template`: The path to the file to be used as the template for the 38 | release notes. 39 | - `--allowEmpty`: Allow the creation of an empty set of release notes. In this 40 | mode, milestone and input file path will be ignored. 41 | 42 | ## **Template** 43 | 44 | GitReleaseManager uses the [Scriban](https://github.com/lunet-io/scriban) 45 | library to parse and render release notes. For more information on how you can 46 | create your own template, please check the Scriban 47 | [documentation](https://github.com/lunet-io/scriban/tree/master/doc). 48 | 49 | ## **Examples** 50 | 51 | Use GitReleaseManager to create a Release, generating the release notes based on 52 | Milestone: 53 | 54 | ```bash 55 | gitreleasemanager.exe create -m 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 56 | 57 | gitreleasemanager.exe create --milestone 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 58 | ``` 59 | 60 | Use GitReleaseManager to create a Release, taking the release notes as an input parameter: 61 | 62 | ```bash 63 | gitreleasemanager.exe create -i c:\temp\releasenotes.md -n 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 64 | 65 | gitreleasemanager.exe create --inputFilePath c:\temp\releasenotes.md --name 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 66 | ``` 67 | 68 | Use GitReleaseManager to create an empty release: 69 | 70 | ```bash 71 | gitreleasemanager.exe create -n 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo --allowEmpty 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/input/docs/commands/discard.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 20 3 | Title: Discard 4 | --- 5 | 6 | After creating a draft release, it might be necessary to also discard it. This 7 | could be for a number of reasons, which don't need to be detailed here, but 8 | if/when required, this command will discard a draft release. 9 | 10 | :::{.alert .alert-info} 11 | **NOTE:** 12 | The command will only work for releases that are in the draft state. It won't 13 | delete a published release. 14 | ::: 15 | 16 | ## **Required Parameters** 17 | 18 | - `--token`: The access token to access GitHub with. 19 | - `-o, --owner`: The owner of the repository. 20 | - `-r, --repository`: The name of the repository. 21 | - `-m, --milestone`: The name of the release (Typically this is the generated 22 | SemVer Version Number). 23 | 24 | ## **Optional Parameters** 25 | 26 | - `-d, -targetDirectory`: The directory on which GitReleaseManager should be 27 | executed. Defaults to current directory. 28 | - `-l, -logFilePath`: Path to where log file should be created. Defaults to 29 | logging to console. 30 | 31 | ## **Examples** 32 | 33 | ```bash 34 | gitreleasemanager.exe discard -m 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 35 | 36 | gitreleasemanager.exe discard --milestone 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/input/docs/commands/export.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 70 3 | Title: Export 4 | --- 5 | 6 | This command will export all the release notes for a given repository on GitHub. 7 | The generated file will be in Markdown format, and the contents of the exported 8 | file is configurable using the GitReleaseManager configuration file, per repository. 9 | 10 | There are two modes of operation when exporting Release Notes. GitReleaseManager 11 | can either export all Release Notes, or can export only a specific Release, 12 | using the tagName parameter. 13 | 14 | ## **Required Parameters** 15 | 16 | - `--token`: The access token to access GitHub with. 17 | - `-o, --owner`: The owner of the repository. 18 | - `-r, --repository`: The name of the repository. 19 | - `-f, --fileOutputPath`: Path to the file export releases. 20 | 21 | ## **Optional Parameters** 22 | 23 | - `-t, --tagName`: The name of the release (Typically this is the generated 24 | SemVer Version Number). 25 | - `-d, --targetDirectory`: The directory on which GitReleaseManager should be 26 | executed. Defaults to current directory. 27 | - `-l, --logFilePath`: Path to where log file should be created. Defaults to 28 | logging to console. 29 | 30 | ## **Examples** 31 | 32 | Use GitReleaseManager to export all Release Notes: 33 | 34 | ```bash 35 | gitreleasemanager.exe export --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo -f c:\temp\releases.md 36 | 37 | gitreleasemanager.exe export --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo --fileOutputPath c:\temp\releases.md 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/input/docs/commands/index.cshtml: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 50 3 | Description: How to use the various commands exposed by GitReleaseManager 4 | --- 5 |

@Html.Raw(Model.String(DocsKeys.Description))

6 | 7 | @Html.Partial("_ChildPages") -------------------------------------------------------------------------------- /docs/input/docs/commands/init.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 80 3 | Title: Init 4 | --- 5 | 6 | The Init command is used to create a GitReleaseManager configuration file which 7 | controls the configurable options of GitReleaseManager 8 | 9 | ## **Optional Parameters** 10 | 11 | - `-d, --targetDirectory`: The directory on which GitReleaseManager should be 12 | executed. Defaults to current directory. 13 | - `-l, --logFilePath`: Path to where log file should be created. Defaults to 14 | logging to console. 15 | - `--templates`: Extract all embedded resource templates to disk. Defaults to false. 16 | (_Will not overwrite existing files_). 17 | 18 | ## **Examples** 19 | 20 | Create a new GitReleaseManager configuration file in the current working directory: 21 | 22 | ```bash 23 | gitreleasemanager.exe init 24 | ``` 25 | 26 | Create a new GitReleaseManager configuration file in a specific directory: 27 | 28 | ```bash 29 | gitreleasemanager.exe init -d c:\temp 30 | 31 | gitreleasemanager.exe init --targetDirectory c:\temp 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/input/docs/commands/label.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 100 3 | Title: Label 4 | --- 5 | 6 | When first setting up a repository, it is nice to be able to configure a set of 7 | default labels, so that you can have some consistency across your various 8 | projects. While GitHub, and other Source Control systems provide a set of 9 | default labels, they are not always exactly what you want. This command will 10 | remove all the current labels configured within a repository, and create a new 11 | set of them. 12 | 13 | :::{.alert .alert-info} 14 | **NOTE:** 15 | 16 | The available list of labels that are created is currently hard-coded into 17 | GitReleaseManager, it is not possible to configure them. This will come in a 18 | later version. 19 | ::: 20 | 21 | ## **Required Parameters** 22 | 23 | - `--token`: The access token to access GitHub with. 24 | - `-o, --owner`: The owner of the repository. 25 | - `-r, --repository`: The name of the repository. 26 | 27 | ## **Optional Parameters** 28 | 29 | - `-d, -targetDirectory`: The directory on which GitReleaseManager should be 30 | executed. Defaults to current directory. 31 | - `-l, -logFilePath`: Path to where log file should be created. Defaults to 32 | logging to console. 33 | 34 | ## **Examples** 35 | 36 | ```bash 37 | gitreleasemanager.exe label --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 38 | 39 | gitreleasemanager.exe label --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/input/docs/commands/open.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 50 3 | Title: Open 4 | --- 5 | 6 | Depending on the workflow that is being followed, closing on a milestone is 7 | something that is typically done once a release has been published. However, it 8 | might also be necessary to revert closing of a milestone. There are several 9 | reasons _why_ this might be necessary, which aren't really important to go into 10 | here, but this command allow you to open a closed milestone. 11 | 12 | :::{.alert .alert-info} 13 | **NOTE:** 14 | 15 | This command will _only_ work against a currently closed milestone. No action 16 | will be taken against a milestone that is already open. 17 | ::: 18 | 19 | ## **Required Parameters** 20 | 21 | - `--token`: The access token to access GitHub with. 22 | - `-o, --owner`: The owner of the repository. 23 | - `-r, --repository`: The name of the repository. 24 | - `-m, --milestone`: The milestone to use. 25 | 26 | ## **Optional Parameters** 27 | 28 | - `-d, --targetDirectory`: The directory on which GitReleaseManager should be 29 | executed. Defaults to current directory. 30 | - `-l, --logFilePath`: Path to where log file should be created. Defaults to 31 | logging to console. 32 | 33 | ## **Examples** 34 | 35 | ```bash 36 | gitreleasemanager.exe open -m 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 37 | 38 | gitreleasemanager.exe open --milestone 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/input/docs/commands/publish.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 60 3 | Title: Publish 4 | --- 5 | 6 | While it would be possible to automatically publish a set of release notes in a 7 | single command, it is envisioned that some manual intervention is required to 8 | ensure that all release notes are valid, and any additional information is added 9 | to the release, prior to publishing. As a result, a second command is required 10 | to actually publish a release. 11 | 12 | ## **Required Parameters** 13 | 14 | - `--token`: The access token to access GitHub with. 15 | - `-o, --owner`: The owner of the repository. 16 | - `-r, --repository`: The name of the repository. 17 | - `-t, --tagName`: The name of the release (Typically this is the generated 18 | SemVer Version Number). 19 | 20 | ## **Optional Parameters** 21 | 22 | - `-d, -targetDirectory`: The directory on which GitReleaseManager should be 23 | executed. Defaults to current directory. 24 | - `-l, -logFilePath`: Path to where log file should be created. Defaults to 25 | logging to console. 26 | 27 | ## **Examples** 28 | 29 | ```bash 30 | gitreleasemanager.exe publish -t 0.1.0 --token fsdfsf67657sdf5s7d5f -o repoOwner -r repo 31 | 32 | gitreleasemanager.exe publish --tagName 0.1.0 --token fsdfsf67657sdf5s7d5f --owner repoOwner --repository repo 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/input/docs/commands/show-config.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 90 3 | Title: Show Config 4 | --- 5 | 6 | The showconfig command is used to display the current configuration for 7 | GitReleaseManager when executed against a specific directory. 8 | 9 | ## **Optional Parameters** 10 | 11 | - `-d, --targetDirectory`: The directory on which GitReleaseManager should be 12 | executed. Defaults to current directory. 13 | - `-l, --logFilePath`: Path to where log file should be created. Defaults to 14 | logging to console. 15 | 16 | ## **Examples** 17 | 18 | Show the configuration for the current working directory: 19 | 20 | ```bash 21 | gitreleasemanager.exe showconfig 22 | ``` 23 | 24 | Show the configuration for a specific directory: 25 | 26 | ```bash 27 | gitreleasemanager.exe showconfig -d c:\temp 28 | 29 | gitreleasemanager.exe showconfig --targetDirectory c:\temp 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/input/docs/configuration/create-configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 20 3 | Title: Example of Create Configuration 4 | --- 5 | 6 | When creating a release, it is possible to control the look and feel of the 7 | release notes, using settings within the GitReleaseManager configuration file. 8 | 9 | Out of the box, GitReleaseManager creates a simple list of Issues included 10 | within a milestone, split into the labels that have been configured. However, 11 | it is possible to include additional information in the form of a footer, which 12 | provides additional information, for example, where an installation of the 13 | release can be located. 14 | 15 | Take for example the GitReleaseManager configuration file which is used by the 16 | [Chocolatey GUI](https://github.com/chocolatey/ChocolateyGUI) project: 17 | 18 | :::{.alert .alert-warning} 19 | Configuring the footer is no longer recommended. Going forward the recommendation 20 | is to configure the footer using separate template files. 21 | Please see [Template Configuration](template-configuration#editing-the-templates) 22 | for more information. 23 | ::: 24 | 25 | ```yaml 26 | create: 27 | include-footer: true 28 | footer-heading: Where to get it 29 | footer-content: You can download this release from [chocolatey.org](https://chocolatey.org/packages/chocolateyGUI/{milestone}) 30 | footer-includes-milestone: true 31 | milestone-replace-text: "{milestone}" 32 | ``` 33 | 34 | This would result in the following 35 | [release notes](https://github.com/chocolatey/ChocolateyGUI/releases/tag/0.13.1) 36 | being generated: 37 | 38 | ![Example Release Notes](../images/example-release-notes.png){.img-responsive} 39 | 40 | :::{.alert .alert-info} 41 | The generated URL for the link to Chocolatey.org includes the milestone number. 42 | The complete URL is https://chocolatey.org/packages/chocolateyGUI/0.13.1. This 43 | was achieved by using a regular expression replacement of the 44 | [footer-content](default-configuration), using the 45 | [milestone-replace-text](default-configuration) property as the text to replace 46 | with the actual milestone. 47 | 48 | This approach can be used for any project, this example simply shows what is 49 | done in the Chocolatey GUI project. 50 | ::: 51 | -------------------------------------------------------------------------------- /docs/input/docs/configuration/exclude-issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 50 3 | Title: Issues to exclude 4 | --- 5 | 6 | From time to time, you may want to include issues within a milestone, however, 7 | you don't want any information about these issues to appear in the release notes 8 | that are generated for that milestone. For example, let's say you were doing 9 | some internal refactoring work. This information is not required for the end 10 | user, but you as the administrator would want to know when that work was done. 11 | GitReleaseManager caters for this requirement using the issue-labels-exclude 12 | section of the GitReleaseManager configuration file. 13 | 14 | Out of the box, GitReleaseManager is configured to exclude issues that are 15 | tagged with the following labels: 16 | 17 | ```yaml 18 | issue-labels-exclude: 19 | - Build 20 | ``` 21 | 22 | :::{.alert .alert-info} 23 | You can add as many issue labels into this section as required. Any issue, 24 | included within a milestone that contains a label specified within this list 25 | will NOT be included within the generated release notes. 26 | ::: 27 | 28 | :::{.alert .alert-warning} 29 | All issues assigned to a milestone have to have a label which matches to one 30 | listed in the include to exclude sections of the GitReleaseManager configuration 31 | file or the default configuration. 32 | ::: 33 | -------------------------------------------------------------------------------- /docs/input/docs/configuration/export-configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 30 3 | Title: Example of Export Configuration 4 | --- 5 | 6 | Once you have created a number of releases, you might want to export all of the 7 | release notes into a single file. This is especially useful if you want to 8 | embed all the release notes within your application. To cater for this, 9 | GitReleaseManager includes the export command. The format of the resulting file 10 | can be configured via a number of parameters. 11 | 12 | Out of the box, GitReleaseManager exports all the release notes for a given 13 | project, exactly as these release notes appear within GitHub. However, there 14 | are certain things that you might want to add, or remove, for the exported file. 15 | 16 | Take for example the GitReleaseManager configuration file which is used by the 17 | [Chocolatey GUI](https://github.com/chocolatey/ChocolateyGUI) project: 18 | 19 | ```yaml 20 | export: 21 | include-created-date-in-title: true 22 | created-date-string-format: MMMM dd, yyyy 23 | perform-regex-removal: true 24 | regex-text: '### Where to get it(\r\n)*You can .*\)' 25 | multiline-regex: true 26 | ``` 27 | 28 | This results in a file which looks like this: 29 | 30 | ![Example Exported Release Notes](../images/example-export.png) 31 | 32 | :::{.alert .alert-info} 33 | The important things to note in the above image are that a created date has been 34 | added for each release, via the include-created-date-in-title parameter (and it 35 | is possible to configure the DateTime format string that is used). And also, 36 | the "Where to get it" section has not been included. Since we are including the 37 | release notes within the Chocolatey GUI application, the user already has it 38 | installed, so they don't need to know where to get it. 39 | 40 | Assumes that you can create the necessary regular expression, any text can be 41 | removed from the exported set of release notes. 42 | 43 | This approach can be used for any project, this example simply shows what is 44 | done in the Chocolatey GUI project. 45 | ::: 46 | -------------------------------------------------------------------------------- /docs/input/docs/configuration/include-issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 40 3 | Title: Issues to include 4 | --- 5 | 6 | In order to include an issue within the release notes that are generated by 7 | GitReleaseManager, each issue within a milestone has to be labelled with one of 8 | a set of pre-defined labels. 9 | 10 | Out of the box, GitReleaseManager is configured to include issues that are 11 | tagged with one of the following labels: 12 | 13 | ```yaml 14 | issue-labels-include: 15 | - Bug 16 | - Feature 17 | - Improvement 18 | ``` 19 | 20 | :::{.alert .alert-info} 21 | You can add as many issue labels into this section as required. Any issue, 22 | included within a milestone that contains a label specified within this list 23 | will be included within the generated release notes. 24 | ::: 25 | 26 | :::{.alert .alert-warning} 27 | All issues assigned to a milestone have to have a label which matches to one 28 | listed in the include to exclude sections of the GitReleaseManager configuration 29 | file or the default configuration. 30 | ::: 31 | -------------------------------------------------------------------------------- /docs/input/docs/configuration/index.cshtml: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 40 3 | Description: How to use configure GitReleaseManager 4 | --- 5 |

@Html.Raw(Model.String(DocsKeys.Description))

6 | 7 | @Html.Partial("_ChildPages") -------------------------------------------------------------------------------- /docs/input/docs/configuration/label-aliases.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 60 3 | Title: Label Aliases 4 | --- 5 | 6 | When there are more than one issue associated with a particular label, 7 | GitReleaseManager will attempt to pluralize the label name. For example, `Bugs` 8 | instead of `Bug`. However, there are times when this basic pluralization will 9 | not work. For example, `Documentation` will be pluralized as `Documentations` 10 | which doesn't really make sense. In these situations, it is possible to 11 | override the automatic title. 12 | 13 | This is possible for both the singular and plural cases. 14 | 15 | Here is an example of how to configure two label aliases. The title `Foo` will 16 | be used instead of `Bug`, and `Baz` instead of `Improvement`. If each label 17 | contains more than one feature, `Bar` and `Qux` will be used instead in the 18 | release notes. 19 | 20 | ```yaml 21 | issue-labels-alias: 22 | - name: Bug 23 | header: Foo 24 | plural: Bar 25 | 26 | - name: Improvement 27 | header: Baz 28 | plural: Qux 29 | ``` 30 | 31 | :::{.alert .alert-info} 32 | You can add as many label aliases as required. 33 | ::: 34 | -------------------------------------------------------------------------------- /docs/input/docs/credits/icon.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 20 3 | Title: Icon 4 | --- 5 | 6 | [Pull-request](https://thenounproject.com/term/pull-request/116189/) designed by 7 | [Richard Slater](https://thenounproject.com/richard.slater/) from 8 | [The Noun Project](https://thenounproject.com/). 9 | -------------------------------------------------------------------------------- /docs/input/docs/credits/index.cshtml: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 60 3 | Description: Credits 4 | --- 5 |

@Html.Raw(Model.String(DocsKeys.Description))

6 | 7 | @Html.Partial("_ChildPages") -------------------------------------------------------------------------------- /docs/input/docs/credits/particular.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 10 3 | Title: Particular Software 4 | --- 5 | 6 | Full original credit has to go to the people at 7 | [Particular Software](http://www.particular.net/), without whom this project 8 | would not have been possible. They originally created the 9 | [GitHubReleaseNotes](https://github.com/Particular/GitHubReleaseNotes) project, 10 | which GitReleaseManager is based on, and draws a lot of inspiration from. 11 | 12 | Where GitHubReleaseNotes uses a set of fixed configuration, based on 13 | Particular's internal usage requirements, GitReleaseManager attempts to be fully 14 | configurable, so that the end user can decide what should be done when creating 15 | and exporting Release Notes on GitHub. Huge thanks to the people at Particular 16 | for their support in helping me create this project. For more information about 17 | what has changed between GitHubReleaseNotes and GitReleaseManager, see this 18 | [issue](https://github.com/GitTools/GitReleaseManager/issues/24). 19 | 20 | In addition, a large thank you has to go to again 21 | [Particular Software](http://www.particular.net/) and the contributors behind 22 | the [GitVersion](https://github.com/ParticularLabs/GitVersion) Project. 23 | GitReleaseManager draws on the work done in that project in terms of 24 | initializing and using a YAML configuration file to allow setting of 25 | configuration properties at run-time. 26 | -------------------------------------------------------------------------------- /docs/input/docs/images/example-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitTools/GitReleaseManager/1550105c8da911a83f396bd3199e0b7b613ecbb8/docs/input/docs/images/example-export.png -------------------------------------------------------------------------------- /docs/input/docs/images/example-release-notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitTools/GitReleaseManager/1550105c8da911a83f396bd3199e0b7b613ecbb8/docs/input/docs/images/example-release-notes.png -------------------------------------------------------------------------------- /docs/input/docs/images/grm-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitTools/GitReleaseManager/1550105c8da911a83f396bd3199e0b7b613ecbb8/docs/input/docs/images/grm-usage.png -------------------------------------------------------------------------------- /docs/input/docs/index.md: -------------------------------------------------------------------------------- 1 | # What is GitReleaseManager? 2 | 3 | GitReleaseManager is a tool that will help create a set of release notes for 4 | your application/product. It does this using the collection of issues which 5 | are stored on the GitHub Issue Tracker for your application/product. 6 | 7 | By inspecting the issues that have been assigned to a particular milestone, 8 | GitReleaseManager creates a set of release notes, in markdown format, which are 9 | then used to create a Release on GitHub. 10 | 11 | In addition to creating a Release, GitReleaseManager can be used to publish a 12 | release, close a milestone, and also to export the complete set of release notes 13 | for your application/product. -------------------------------------------------------------------------------- /docs/input/docs/installation/chocolatey.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 10 3 | Title: Via Chocolatey 4 | --- 5 | 6 | It is possible to install the portable version of GitReleaseManager using Chocolatey. Simply execute the following installation command: 7 | 8 | ```bash 9 | choco install gitreleasemanager.portable 10 | ``` 11 | 12 | :::{.alert .alert-info} 13 | Depending on which version of Chocolatey you are using, you may be required to 14 | confirm the installation of the application. You can avoid this prompt using 15 | the following command: 16 | 17 | `choco install gitreleasemanager.portable -y` 18 | ::: 19 | 20 | Once installed, GitReleaseManager should be immediately available on the command 21 | line. You can either use: 22 | 23 | ```bash 24 | gitreleasemanager 25 | ``` 26 | 27 | or: 28 | 29 | ```bash 30 | grm 31 | ``` 32 | 33 | Which should then output something similar to the following: 34 | 35 | ![GitReleaseManager Usage](../images/grm-usage.png) 36 | -------------------------------------------------------------------------------- /docs/input/docs/installation/dotnettool.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 30 3 | Title: Via .Net Global Tool 4 | --- 5 | 6 | It is possible to install GitReleaseManager as a .Net Global Tool. Simply 7 | execute the following command: 8 | 9 | ```bash 10 | dotnet tool install --global GitReleaseManager.Tool 11 | ``` 12 | 13 | :::{.alert .alert-warning} 14 | This will require that .Net Core is installed on the machine which you are 15 | trying to install the .Net Global Tool. 16 | ::: 17 | 18 | Once installed, GitReleaseManager should be immediately available on the command 19 | line. You can call: 20 | 21 | ```bash 22 | dotnet-gitreleasemanager 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/input/docs/installation/index.cshtml: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 30 3 | Description: How to install GitReleaseManager 4 | --- 5 |

@Html.Raw(Model.String(DocsKeys.Description))

6 | 7 | @Html.Partial("_ChildPages") -------------------------------------------------------------------------------- /docs/input/docs/installation/nuget.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 20 3 | Title: Via NuGet 4 | --- 5 | 6 | It is possible to install GitReleaseManager as a Solution Level package in 7 | Visual Studio using NuGet. Simply execute the following installation command: 8 | 9 | ```bash 10 | Install-Package GitReleaseManager 11 | ``` 12 | 13 | This will add the GitReleaseManager into the packages folder for your Solution, 14 | which can then be consumed within your build process. 15 | -------------------------------------------------------------------------------- /docs/input/docs/logging/index.cshtml: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 50 3 | Description: How to log the output from GitReleaseManager 4 | --- 5 |

@Html.Raw(Model.String(DocsKeys.Description))

6 | 7 | @Html.Partial("_ChildPages") -------------------------------------------------------------------------------- /docs/input/docs/logging/logging.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 10 3 | Title: Configure Logging 4 | --- 5 | 6 | It is possible to view all the output from GitReleaseManager, either in the 7 | console window, or by writing out to a file. 8 | 9 | By default, all command output is written to the console window, however, it is 10 | possible to specify a text file where command output should be written to. 11 | 12 | ## **Examples** 13 | 14 | Enable logging to a file located in c:\temp\log.txt using the following command: 15 | 16 | ```bash 17 | gitreleasemanager.cli.exe init -l c:\temp\log.txt 18 | 19 | gitreleasemanager.cli.exe init -logFilePath c:\temp\log.txt 20 | ``` 21 | 22 | :::{.alert .alert-info} 23 | Assuming you simply wanted to **pipe** the output from GitReleaseManager to a 24 | file, when executing directly from the command line, it is not required to use 25 | the -l parameter. The log messages written to the console window, would simply 26 | be piped to the output file. 27 | ::: 28 | -------------------------------------------------------------------------------- /docs/input/docs/why-grm.md: -------------------------------------------------------------------------------- 1 | --- 2 | Order: 10 3 | Title: Why would I want to use GitReleaseManager 4 | --- 5 | 6 | There are a number of reasons that you would want to incorporate 7 | GitReleaseManager into your workflow. 8 | 9 | :::{.alert .alert-info} 10 | GitReleaseManager works best when included within an automated Build Process, 11 | using something like Cake, etc. However, it can also be 12 | used as a standalone tool, running directly at the command line. 13 | ::: 14 | 15 | Here are a few examples: 16 | 17 | ## Create Milestone Release Notes 18 | 19 | Assuming that you are already using the concept of milestones in GitHub, once a 20 | milestone is completed, and you have a number of closed issues, you can use the 21 | [create command](commands/create) to generate a draft set of release notes, 22 | which includes all the closed issues (assuming that they match the 23 | [set of labels](configuration/include-issues) which are configured to be 24 | included. 25 | 26 | ## Publish Release 27 | 28 | Even if you don't want to use GitReleaseManager to create the release notes on 29 | GitHub, you may still want the ability to Publish a Release (which has the 30 | result of creating a tag in your repository). This can be done using the 31 | [publish command](commands/publish). 32 | 33 | :::{.alert .alert-info} 34 | Publishing a Release also closes the associated Milestone for the Release. 35 | ::: 36 | 37 | ## Add Asset to Release 38 | 39 | As part of your Release process, you may want to include assets into the GitHub 40 | Release. This could be the final MSI package for your application, or a NuGet 41 | package. GitReleaseManager allows you to do this in two ways. The first is 42 | using the [create command](commands/create), which includes the ability to add 43 | an asset at the time of Release creation. However, at the time of Release 44 | creation, you might not have all the assets that you want to add. As a result, 45 | there is a separate [add asset](commands/add-assets) command that you can use to 46 | add an asset to an existing Release. 47 | 48 | ## Close Milestone 49 | 50 | When working directly in GitHub, publishing a Release doesn't close the 51 | associated milestone. When using the GitReleaseManager's 52 | [publish command](commands/publish) the associated milestone is also closed. 53 | However, you can also use the [close command](commands/close) directly if you 54 | are not using the publish workflow as part of your process. 55 | 56 | ## Export Release Notes 57 | 58 | When working on a project, you might want to include all the Release Notes 59 | within the application itself, let's say in the About dialog. 60 | GitReleaseManager's [export command](commands/export) makes it really simple to 61 | export the entire history of your application/product, by creating a markdown 62 | file with all the information contained in the releases section of GitHub. 63 | -------------------------------------------------------------------------------- /gitversion.yml: -------------------------------------------------------------------------------- 1 | next-version: 0.14.0 -------------------------------------------------------------------------------- /icons/package_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitTools/GitReleaseManager/1550105c8da911a83f396bd3199e0b7b613ecbb8/icons/package_icon.png -------------------------------------------------------------------------------- /icons/package_icon_no_credit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitTools/GitReleaseManager/1550105c8da911a83f396bd3199e0b7b613ecbb8/icons/package_icon_no_credit.png -------------------------------------------------------------------------------- /nuspec/chocolatey/GitReleaseManager.Portable.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | gitreleasemanager.portable 7 | GitReleaseManager 8 | $version$ 9 | GitTools Contributors 10 | gep13 11 | https://github.com/GitTools/GitReleaseManager/blob/develop/LICENSE 12 | https://github.com/GitTools/GitReleaseManager 13 | https://cdn.jsdelivr.net/gh/GitTools/GitReleaseManager@e61a984ddd300e36c9d88ca45696d2f93b631839/icons/package_icon.svg 14 | false 15 | Tool for creating and exporting releases for software applications from online Version Control Systems 16 | Tool for creating and exporting releases for software applications 17 | Copyright (c) 2015 - Present - GitTools Contributors 18 | en-GB 19 | github release notes create export 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /nuspec/chocolatey/LICENSE.TXT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 - Present - GitTools Contributors 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. -------------------------------------------------------------------------------- /nuspec/chocolatey/VERIFICATION.TXT: -------------------------------------------------------------------------------- 1 | VERIFICATION 2 | Verification is intended to assist the Chocolatey moderators and community in verifying that this package's contents are trustworthy. 3 | 4 | This package is owned and updated by the members of the GitTools Organisation on GitHub: 5 | 6 | https://github.com/GitTools 7 | 8 | The files contained within this Chocolatey Package are the same as those that are hosted on our releases page: 9 | 10 | https://github.com/GitTools/GitReleaseManager/releases 11 | 12 | If you have any concerns about the contents of this package, please raise an issue here: 13 | 14 | https://github.com/GitTools/GitReleaseManager/releases -------------------------------------------------------------------------------- /nuspec/chocolatey/chocolateyInstall.ps1: -------------------------------------------------------------------------------- 1 | Generate-BinFile "grm" "$packageFolder\Tools\GitReleaseManager.exe" -------------------------------------------------------------------------------- /nuspec/chocolatey/chocolateyUninstall.ps1: -------------------------------------------------------------------------------- 1 | Remove-BinFile "grm" "$packageFolder\Tools\GitReleaseManager.exe" -------------------------------------------------------------------------------- /nuspec/nuget/GitReleaseManager.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | GitReleaseManager 7 | GitReleaseManager 8 | $version$ 9 | GitTools Contributors 10 | gep13 11 | MIT 12 | https://github.com/GitTools/GitReleaseManager 13 | 14 | package_icon.png 15 | false 16 | Tool for creating and exporting releases for software applications from online Version Control Systems 17 | Tool for creating and exporting releases for software applications 18 | Copyright (c) 2015 - Present - GitTools Contributors 19 | en-GB 20 | github release notes create export 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /recipe.cake: -------------------------------------------------------------------------------- 1 | #load nuget:?package=Cake.Recipe&version=3.1.1 2 | #tool dotnet:?package=dotnet-t4&version=2.2.1 3 | #addin nuget:?package=Cake.Git&version=1.0.0 4 | #addin nuget:?package=Cake.Twitter&version=1.1.1 5 | 6 | Environment.SetVariableNames(githubTokenVariable: "GITTOOLS_GITHUB_TOKEN"); 7 | 8 | var standardNotificationMessage = "A new version, {0} of {1} has just been released. Get it from Chocolatey, NuGet, or as a .Net Global Tool."; 9 | 10 | BuildParameters.SetParameters(context: Context, 11 | buildSystem: BuildSystem, 12 | sourceDirectoryPath: "./src", 13 | title: "GitReleaseManager", 14 | repositoryOwner: "GitTools", 15 | repositoryName: "GitReleaseManager", 16 | appVeyorAccountName: "GitTools", 17 | shouldRunDotNetCorePack: true, 18 | shouldRunIntegrationTests: true, 19 | integrationTestScriptPath: "./tests/integration/tests.cake", 20 | twitterMessage: standardNotificationMessage, 21 | preferredBuildProviderType: BuildProviderType.GitHubActions, 22 | gitterMessage: "@/all " + standardNotificationMessage, 23 | shouldRunCodecov: false, 24 | shouldGenerateDocumentation: false); 25 | 26 | BuildParameters.PackageSources.Add(new PackageSourceData(Context, "GPR", "https://nuget.pkg.github.com/GitTools/index.json", FeedType.NuGet, false)); 27 | 28 | BuildParameters.PrintParameters(Context); 29 | 30 | ToolSettings.SetToolSettings(context: Context, 31 | testCoverageFilter: "+[GitReleaseManager*]* -[GitReleaseManager.Core.Tests*]* -[GitReleaseManager.Tests*]*", 32 | testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", 33 | testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs", 34 | kuduSyncIgnore: ".git;CNAME;_git2"); 35 | 36 | BuildParameters.Tasks.DotNetCoreBuildTask.Does((context) => 37 | { 38 | var buildDir = BuildParameters.Paths.Directories.PublishedApplications; 39 | 40 | var grmExecutable = context.GetFiles(buildDir + "/GitReleaseManager.Tool/**/*.exe").First(); 41 | 42 | context.Information("Registering Built GRM executable... {0}", grmExecutable.FullPath); 43 | context.Tools.RegisterFile(grmExecutable); 44 | }); 45 | 46 | BuildParameters.Tasks.CreateReleaseNotesTask 47 | .IsDependentOn(BuildParameters.Tasks.DotNetCoreBuildTask); // We need to be sure that the executable exist, and have been registered before using it 48 | 49 | Task("Transform-TextTemplates") 50 | .IsDependeeOf(BuildParameters.Tasks.DotNetCoreBuildTask.Task.Name) 51 | .Does(() => 52 | { 53 | var templates = GetFiles("src/**/*.tt"); 54 | 55 | foreach (var template in templates) 56 | { 57 | TransformTemplate(template); 58 | } 59 | }); 60 | 61 | ((CakeTask)BuildParameters.Tasks.ExportReleaseNotesTask.Task).ErrorHandler = null; 62 | ((CakeTask)BuildParameters.Tasks.PublishGitHubReleaseTask.Task).ErrorHandler = null; 63 | BuildParameters.Tasks.PublishPreReleasePackagesTask.IsDependentOn(BuildParameters.Tasks.PublishGitHubReleaseTask); 64 | BuildParameters.Tasks.PublishReleasePackagesTask.IsDependentOn(BuildParameters.Tasks.PublishGitHubReleaseTask); 65 | 66 | Build.RunDotNetCore(); -------------------------------------------------------------------------------- /src/CustomDictionary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cli 8 | commitish 9 | Git 10 | Octokit 11 | Prerelease 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8.0 4 | 5 | GitTools Contributors 6 | https://github.com/GitTools/GitReleaseManager 7 | false 8 | github release notes create export 9 | Copyright (c) 2015 - Present - GitTools Contributors 10 | MIT 11 | package_icon.png 12 | https://github.com/GitTools/GitReleaseManager/releases 13 | git 14 | https://github.com/GitTools/GitReleaseManager.git 15 | 16 | pdbonly 17 | true 18 | $(NoWarn);CS1591;CA1707;Serilog004 19 | AllEnabledByDefault 20 | 21 | 22 | 23 | 24 | CustomDictionary.xml 25 | 26 | 27 | 28 | 29 | 30 | 31 | all 32 | runtime; build; native; contentfiles; analyzers; buildtransitive 33 | 34 | 35 | 36 | all 37 | runtime; build; native; contentfiles; analyzers; buildtransitive 38 | 39 | 40 | runtime; build; native; contentfiles; analyzers; buildtransitive 41 | all 42 | 43 | 44 | All 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | true 10 | true 11 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | $(NoWarn);NU1507 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | GitReleaseManager 5 | net8.0 6 | true 7 | true 8 | win-x64 9 | GitReleaseManager.Cli 10 | Create release notes in markdown given a milestone 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | all 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/GitReleaseManager.Cli/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Code Analysis results, point to "Suppress Message", and click 8 | // "In Suppression File". 9 | // You do not need to add suppressions to this file manually. 10 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Wrong Usage", "DF0037:Marks undisposed objects assinged to a property, originated from a method invocation.", Justification = "Cleanup happens at the end of the application.", Scope = "member", Target = "~M:GitReleaseManager.Cli.Program.ConfigureLogging(GitReleaseManager.Cli.Options.BaseSubOptions)")] -------------------------------------------------------------------------------- /src/GitReleaseManager.Cli/Logging/LogConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text; 3 | using Destructurama; 4 | using GitReleaseManager.Core.Options; 5 | using Octokit; 6 | using Serilog; 7 | using Serilog.Events; 8 | using Serilog.Sinks.SystemConsole.Themes; 9 | 10 | namespace GitReleaseManager.Cli.Logging 11 | { 12 | public static class LogConfiguration 13 | { 14 | private const string CONSOLE_FULL_TEMPLATE = "[{Level:u3}] " + CONSOLE_INFO_TEMPLATE; 15 | private const string CONSOLE_INFO_TEMPLATE = "{Message:l}{NewLine}{Exception}"; 16 | private const string FILE_TEMPLATE = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"; 17 | private static readonly ConsoleTheme _consoleTheme = AnsiConsoleTheme.Code; 18 | 19 | public static void ConfigureLogging(BaseSubOptions options) 20 | { 21 | var config = new LoggerConfiguration() 22 | .MinimumLevel.Verbose() 23 | .Destructure.UsingAttributes() 24 | .Destructure.ByTransforming(asset => new { asset.FileName, asset.ContentType }); 25 | 26 | CreateDebugLogger(config); 27 | CreateConsoleInformationLogger(config, CONSOLE_INFO_TEMPLATE, _consoleTheme); 28 | CreateConsoleFullLogger(config, CONSOLE_FULL_TEMPLATE, _consoleTheme, options); 29 | 30 | if (!string.IsNullOrEmpty(options.LogFilePath)) 31 | { 32 | CreateFileLogger(config, options.LogFilePath, FILE_TEMPLATE); 33 | } 34 | 35 | Log.Logger = config.CreateLogger(); 36 | } 37 | 38 | private static void CreateConsoleFullLogger(LoggerConfiguration config, string consoleTemplate, ConsoleTheme consoleTheme, BaseSubOptions options) 39 | { 40 | config.WriteTo.Logger((config) => config 41 | .Filter.ByExcluding((logEvent) => logEvent.Level == LogEventLevel.Information) 42 | .Filter.ByExcluding((logEvent) => !options.Debug && logEvent.Level == LogEventLevel.Debug) 43 | .Filter.ByExcluding((logEvent) => !options.Verbose && logEvent.Level == LogEventLevel.Verbose) 44 | .WriteTo.Console( 45 | outputTemplate: consoleTemplate, 46 | standardErrorFromLevel: options.IsCISystem ? LogEventLevel.Error : LogEventLevel.Warning, 47 | theme: consoleTheme)); 48 | } 49 | 50 | private static void CreateConsoleInformationLogger(LoggerConfiguration config, string consoleTemplate, ConsoleTheme consoleTheme) 51 | { 52 | config.WriteTo.Logger((config) => config 53 | .Filter.ByIncludingOnly((logEvent) => logEvent.Level == LogEventLevel.Information) 54 | .WriteTo.Console( 55 | outputTemplate: consoleTemplate, 56 | theme: consoleTheme)); 57 | } 58 | 59 | private static void CreateFileLogger(LoggerConfiguration config, string logFilePath, string logTemplate) 60 | { 61 | config.WriteTo.File(logFilePath, outputTemplate: logTemplate, encoding: new UTF8Encoding(false)); 62 | } 63 | 64 | [Conditional("DEBUG")] 65 | private static void CreateDebugLogger(LoggerConfiguration config) 66 | { 67 | config.WriteTo.Debug(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = false 2 | 3 | [*.cs] 4 | dotnet_naming_rule.async_method_should_have_async_suffix.severity = none -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/AddAssetsCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using GitReleaseManager.Core.Commands; 4 | using GitReleaseManager.Core.Options; 5 | using NSubstitute; 6 | using NUnit.Framework; 7 | using Serilog; 8 | using Shouldly; 9 | 10 | namespace GitReleaseManager.Core.Tests.Commands 11 | { 12 | [TestFixture] 13 | public class AddAssetsCommandTests 14 | { 15 | private IVcsService _vcsService; 16 | private ILogger _logger; 17 | private AddAssetsCommand _command; 18 | 19 | [SetUp] 20 | public void Setup() 21 | { 22 | _vcsService = Substitute.For(); 23 | _logger = Substitute.For(); 24 | _command = new AddAssetsCommand(_vcsService, _logger); 25 | } 26 | 27 | [Test] 28 | public async Task Should_Execute_Command() 29 | { 30 | var options = new AddAssetSubOptions 31 | { 32 | RepositoryOwner = "owner", 33 | RepositoryName = "repository", 34 | TagName = "0.1.0", 35 | AssetPaths = new List(), 36 | }; 37 | 38 | _vcsService.AddAssetsAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.AssetPaths). 39 | Returns(Task.CompletedTask); 40 | 41 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 42 | result.ShouldBe(0); 43 | 44 | await _vcsService.Received(1).AddAssetsAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.AssetPaths).ConfigureAwait(false); 45 | _logger.Received(1).Information(Arg.Any()); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/CloseCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Commands; 3 | using GitReleaseManager.Core.Options; 4 | using NSubstitute; 5 | using NUnit.Framework; 6 | using Serilog; 7 | using Shouldly; 8 | 9 | namespace GitReleaseManager.Core.Tests.Commands 10 | { 11 | [TestFixture] 12 | public class CloseCommandTests 13 | { 14 | private IVcsService _vcsService; 15 | private ILogger _logger; 16 | private CloseCommand _command; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _vcsService = Substitute.For(); 22 | _logger = Substitute.For(); 23 | _command = new CloseCommand(_vcsService, _logger); 24 | } 25 | 26 | [Test] 27 | public async Task Should_Execute_Command() 28 | { 29 | var options = new CloseSubOptions 30 | { 31 | RepositoryOwner = "owner", 32 | RepositoryName = "repository", 33 | Milestone = "0.1.0", 34 | }; 35 | 36 | _vcsService.CloseMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone) 37 | .Returns(Task.CompletedTask); 38 | 39 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 40 | result.ShouldBe(0); 41 | 42 | await _vcsService.Received(1).CloseMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false); 43 | _logger.Received(1).Information(Arg.Any(), options.Milestone); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/DiscardCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Commands; 3 | using GitReleaseManager.Core.Options; 4 | using NSubstitute; 5 | using NUnit.Framework; 6 | using Serilog; 7 | using Shouldly; 8 | 9 | namespace GitReleaseManager.Core.Tests.Commands 10 | { 11 | [TestFixture] 12 | public class DiscardCommandTests 13 | { 14 | private IVcsService _vcsService; 15 | private ILogger _logger; 16 | private DiscardCommand _command; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _vcsService = Substitute.For(); 22 | _logger = Substitute.For(); 23 | _command = new DiscardCommand(_vcsService, _logger); 24 | } 25 | 26 | [Test] 27 | public async Task Should_Execute_Command() 28 | { 29 | var options = new DiscardSubOptions 30 | { 31 | RepositoryOwner = "owner", 32 | RepositoryName = "repository", 33 | Milestone = "0.1.0", 34 | }; 35 | 36 | _vcsService.DiscardReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone) 37 | .Returns(Task.CompletedTask); 38 | 39 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 40 | result.ShouldBe(0); 41 | 42 | await _vcsService.Received(1).DiscardReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false); 43 | _logger.Received(1).Information(Arg.Any(), options.Milestone); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/ExportCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using GitReleaseManager.Core.Commands; 4 | using GitReleaseManager.Core.Options; 5 | using NSubstitute; 6 | using NUnit.Framework; 7 | using Serilog; 8 | using Shouldly; 9 | 10 | namespace GitReleaseManager.Core.Tests.Commands 11 | { 12 | [TestFixture] 13 | public class ExportCommandTests 14 | { 15 | private IVcsService _vcsService; 16 | private ILogger _logger; 17 | private ExportCommand _command; 18 | private string _fileOutputPath; 19 | 20 | [SetUp] 21 | public void Setup() 22 | { 23 | _vcsService = Substitute.For(); 24 | _logger = Substitute.For(); 25 | _command = new ExportCommand(_vcsService, _logger); 26 | _fileOutputPath = Path.Combine(Path.GetTempPath(), "ReleaseExport.txt"); 27 | } 28 | 29 | [Test] 30 | [NonParallelizable] 31 | public async Task Should_Execute_Command() 32 | { 33 | var options = new ExportSubOptions 34 | { 35 | RepositoryOwner = "owner", 36 | RepositoryName = "repository", 37 | TagName = "0.1.0", 38 | FileOutputPath = _fileOutputPath, 39 | }; 40 | 41 | var releaseText = "releaseText"; 42 | 43 | _vcsService.ExportReleasesAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.SkipPrereleases) 44 | .Returns(releaseText); 45 | 46 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 47 | result.ShouldBe(0); 48 | 49 | var exportFileExists = File.Exists(_fileOutputPath); 50 | exportFileExists.ShouldBeTrue(); 51 | 52 | var exportFileContent = File.ReadAllText(_fileOutputPath); 53 | exportFileContent.ShouldBe(releaseText); 54 | 55 | await _vcsService.Received(1).ExportReleasesAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.SkipPrereleases).ConfigureAwait(false); 56 | _logger.Received(1).Information(Arg.Any(), options.TagName); 57 | 58 | if (exportFileExists) 59 | { 60 | File.Delete(_fileOutputPath); 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/LabelCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Commands; 3 | using GitReleaseManager.Core.Options; 4 | using NSubstitute; 5 | using NUnit.Framework; 6 | using Serilog; 7 | using Shouldly; 8 | 9 | namespace GitReleaseManager.Core.Tests.Commands 10 | { 11 | [TestFixture] 12 | public class LabelCommandTests 13 | { 14 | private IVcsService _vcsService; 15 | private ILogger _logger; 16 | private LabelCommand _command; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _vcsService = Substitute.For(); 22 | _logger = Substitute.For(); 23 | _command = new LabelCommand(_vcsService, _logger); 24 | } 25 | 26 | [Test] 27 | public async Task Should_Execute_Command() 28 | { 29 | var options = new LabelSubOptions 30 | { 31 | RepositoryOwner = "owner", 32 | RepositoryName = "repository", 33 | }; 34 | 35 | _vcsService.CreateLabelsAsync(options.RepositoryOwner, options.RepositoryName) 36 | .Returns(Task.CompletedTask); 37 | 38 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 39 | result.ShouldBe(0); 40 | 41 | await _vcsService.Received(1).CreateLabelsAsync(options.RepositoryOwner, options.RepositoryName).ConfigureAwait(false); 42 | _logger.Received(1).Information(Arg.Any()); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/OpenCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Commands; 3 | using GitReleaseManager.Core.Options; 4 | using NSubstitute; 5 | using NUnit.Framework; 6 | using Serilog; 7 | using Shouldly; 8 | 9 | namespace GitReleaseManager.Core.Tests.Commands 10 | { 11 | [TestFixture] 12 | public class OpenCommandTests 13 | { 14 | private IVcsService _vcsService; 15 | private ILogger _logger; 16 | private OpenCommand _command; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _vcsService = Substitute.For(); 22 | _logger = Substitute.For(); 23 | _command = new OpenCommand(_vcsService, _logger); 24 | } 25 | 26 | [Test] 27 | public async Task Should_Execute_Command() 28 | { 29 | var options = new OpenSubOptions 30 | { 31 | RepositoryOwner = "owner", 32 | RepositoryName = "repository", 33 | Milestone = "0.1.0", 34 | }; 35 | 36 | _vcsService.OpenMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone) 37 | .Returns(Task.CompletedTask); 38 | 39 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 40 | result.ShouldBe(0); 41 | 42 | await _vcsService.Received(1).OpenMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false); 43 | _logger.Received(1).Information(Arg.Any(), options.Milestone); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/PublishCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Commands; 3 | using GitReleaseManager.Core.Options; 4 | using NSubstitute; 5 | using NUnit.Framework; 6 | using Serilog; 7 | using Shouldly; 8 | 9 | namespace GitReleaseManager.Core.Tests.Commands 10 | { 11 | [TestFixture] 12 | public class PublishCommandTests 13 | { 14 | private IVcsService _vcsService; 15 | private ILogger _logger; 16 | private PublishCommand _command; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _vcsService = Substitute.For(); 22 | _logger = Substitute.For(); 23 | _command = new PublishCommand(_vcsService, _logger); 24 | } 25 | 26 | [Test] 27 | public async Task Should_Execute_Command() 28 | { 29 | var options = new PublishSubOptions 30 | { 31 | RepositoryOwner = "owner", 32 | RepositoryName = "repository", 33 | TagName = "0.1.0", 34 | }; 35 | 36 | _vcsService.PublishReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.TagName) 37 | .Returns(Task.CompletedTask); 38 | 39 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 40 | result.ShouldBe(0); 41 | 42 | await _vcsService.Received(1).PublishReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.TagName).ConfigureAwait(false); 43 | _logger.Received(1).Information(Arg.Any(), options.TagName); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/Commands/ShowConfigCommandTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using GitReleaseManager.Core.Commands; 4 | using GitReleaseManager.Core.Configuration; 5 | using GitReleaseManager.Core.Helpers; 6 | using GitReleaseManager.Core.Options; 7 | using NSubstitute; 8 | using NUnit.Framework; 9 | using Serilog; 10 | using Shouldly; 11 | 12 | namespace GitReleaseManager.Core.Tests.Commands 13 | { 14 | [TestFixture] 15 | public class ShowConfigCommandTests 16 | { 17 | private IFileSystem _fileSystem; 18 | private ILogger _logger; 19 | private ShowConfigCommand _command; 20 | 21 | [SetUp] 22 | public void Setup() 23 | { 24 | _fileSystem = Substitute.For(); 25 | _logger = Substitute.For(); 26 | 27 | var currentDirectory = Environment.CurrentDirectory; 28 | var configuration = ConfigurationProvider.Provide(currentDirectory, _fileSystem); 29 | _command = new ShowConfigCommand(_logger, configuration); 30 | } 31 | 32 | [Test] 33 | public async Task Should_Execute_Command() 34 | { 35 | var options = new ShowConfigSubOptions(); 36 | 37 | var result = await _command.ExecuteAsync(options).ConfigureAwait(false); 38 | result.ShouldBe(0); 39 | 40 | _logger.Received(1).Information(Arg.Any(), Arg.Any()); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/EnsureTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using NUnit.Framework; 4 | using Shouldly; 5 | 6 | namespace GitReleaseManager.Core.Tests 7 | { 8 | [TestFixture] 9 | public class EnsureTests 10 | { 11 | [Test] 12 | public void Should_Throw_Exception_When_String_Is_Null() 13 | { 14 | var paramName = "str"; 15 | 16 | var ex = Should.Throw(() => Ensure.IsNotNullOrWhiteSpace(null, paramName)); 17 | ex.ParamName.ShouldBe(paramName); 18 | } 19 | 20 | [TestCase("")] 21 | [TestCase(" ")] 22 | public void Should_Throw_Exception_When_String_Is_Whitespace(string str) 23 | { 24 | var paramName = nameof(str); 25 | 26 | var ex = Should.Throw(() => Ensure.IsNotNullOrWhiteSpace(str, paramName)); 27 | ex.Message.ShouldContain("Value cannot be empty or white-space."); 28 | ex.ParamName.ShouldBe(paramName); 29 | } 30 | 31 | [Test] 32 | public void Should_Throw_Exception_When_File_Not_Exists() 33 | { 34 | var tempPath = Path.GetTempPath(); 35 | var tempFile = "TempFile.txt"; 36 | 37 | var path = Path.Combine(tempPath, tempFile); 38 | var message = "File does not exist"; 39 | 40 | var ex = Should.Throw(() => Ensure.FileExists(path, message)); 41 | ex.Message.ShouldBe(message); 42 | ex.FileName.ShouldBe(tempFile); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core.Tests/GitReleaseManager.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0;net9.0 4 | GitReleaseManager.Core.Tests 5 | Test Project for GitReleaseManager.Core 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | all 23 | 24 | 25 | 26 | 27 | 28 | all 29 | runtime; build; native; contentfiles; analyzers 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Attributes/SampleAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GitReleaseManager.Core.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 6 | public sealed class SampleAttribute : Attribute 7 | { 8 | public SampleAttribute(object value) 9 | { 10 | Value = value; 11 | } 12 | 13 | public object Value { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/AutoMapperConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Serilog; 3 | 4 | namespace GitReleaseManager.Core 5 | { 6 | public static class AutoMapperConfiguration 7 | { 8 | private static readonly ILogger _logger = Log.ForContext(typeof(AutoMapperConfiguration)); 9 | 10 | public static IMapper Configure() 11 | { 12 | _logger.Debug("Creating mapper configuration"); 13 | var config = new MapperConfiguration(cfg => 14 | { 15 | cfg.AddMaps(new[] { typeof(AutoMapperConfiguration) }); 16 | }); 17 | 18 | var mapper = config.CreateMapper(); 19 | 20 | _logger.Debug("Finished creating mapper configuration"); 21 | 22 | return mapper; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/AddAssetsCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | using Serilog; 4 | 5 | namespace GitReleaseManager.Core.Commands 6 | { 7 | public class AddAssetsCommand : ICommand 8 | { 9 | private readonly IVcsService _vcsService; 10 | private readonly ILogger _logger; 11 | 12 | public AddAssetsCommand(IVcsService vcsService, ILogger logger) 13 | { 14 | _vcsService = vcsService; 15 | _logger = logger; 16 | } 17 | 18 | public async Task ExecuteAsync(AddAssetSubOptions options) 19 | { 20 | var vcsOptions = options as BaseVcsOptions; 21 | 22 | if (vcsOptions?.Provider == Model.VcsProvider.GitLab) 23 | { 24 | _logger.Error("The 'addasset' command is currently not supported when targeting GitLab."); 25 | return 1; 26 | } 27 | 28 | _logger.Information("Uploading assets"); 29 | await _vcsService.AddAssetsAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.AssetPaths).ConfigureAwait(false); 30 | 31 | return 0; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/CloseCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | using Serilog; 4 | 5 | namespace GitReleaseManager.Core.Commands 6 | { 7 | public class CloseCommand : ICommand 8 | { 9 | private readonly IVcsService _vcsService; 10 | private readonly ILogger _logger; 11 | 12 | public CloseCommand(IVcsService vcsService, ILogger logger) 13 | { 14 | _vcsService = vcsService; 15 | _logger = logger; 16 | } 17 | 18 | public async Task ExecuteAsync(CloseSubOptions options) 19 | { 20 | _logger.Information("Closing milestone {Milestone}", options.Milestone); 21 | await _vcsService.CloseMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false); 22 | 23 | return 0; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/CreateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using GitReleaseManager.Core.Model; 4 | using GitReleaseManager.Core.Options; 5 | using Serilog; 6 | 7 | namespace GitReleaseManager.Core.Commands 8 | { 9 | public class CreateCommand : ICommand 10 | { 11 | private readonly IVcsService _vcsService; 12 | private readonly ILogger _logger; 13 | 14 | public CreateCommand(IVcsService vcsService, ILogger logger) 15 | { 16 | _vcsService = vcsService; 17 | _logger = logger; 18 | } 19 | 20 | public async Task ExecuteAsync(CreateSubOptions options) 21 | { 22 | _logger.Information("Creating release..."); 23 | 24 | Release release; 25 | 26 | if (options.AllowEmpty) 27 | { 28 | _logger.Verbose("The AllowEmpty option has been passed, so an empty release will now be created"); 29 | release = await _vcsService.CreateEmptyReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.Name, options.TargetCommitish, options.Prerelease).ConfigureAwait(false); 30 | } 31 | else if (!string.IsNullOrEmpty(options.Milestone)) 32 | { 33 | if (!string.IsNullOrWhiteSpace(options.InputFilePath)) 34 | { 35 | throw new InvalidOperationException("Both a milestone and an input file path have been specified. Only one of these arguments may be used at the same time when creating a release!"); 36 | } 37 | 38 | _logger.Verbose("Milestone {Milestone} was specified", options.Milestone); 39 | var releaseName = options.Name; 40 | 41 | if (string.IsNullOrWhiteSpace(releaseName)) 42 | { 43 | _logger.Verbose("No Release Name was specified, using {Milestone}.", options.Milestone); 44 | releaseName = options.Milestone; 45 | } 46 | 47 | release = await _vcsService.CreateReleaseFromMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone, releaseName, options.TargetCommitish, options.AssetPaths, options.Prerelease, options.Template).ConfigureAwait(false); 48 | } 49 | else 50 | { 51 | _logger.Verbose("No milestone was specified, switching to release creating from input file"); 52 | release = await _vcsService.CreateReleaseFromInputFileAsync(options.RepositoryOwner, options.RepositoryName, options.Name, options.InputFilePath, options.TargetCommitish, options.AssetPaths, options.Prerelease).ConfigureAwait(false); 53 | } 54 | 55 | _logger.Information("Drafted release is available at:\n{HtmlUrl}", release.HtmlUrl); 56 | _logger.Verbose("Body:\n{Body}", release.Body); 57 | 58 | return 0; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/DiscardCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | using Serilog; 4 | 5 | namespace GitReleaseManager.Core.Commands 6 | { 7 | public class DiscardCommand : ICommand 8 | { 9 | private readonly IVcsService _vcsService; 10 | private readonly ILogger _logger; 11 | 12 | public DiscardCommand(IVcsService vcsService, ILogger logger) 13 | { 14 | _vcsService = vcsService; 15 | _logger = logger; 16 | } 17 | 18 | public async Task ExecuteAsync(DiscardSubOptions options) 19 | { 20 | _logger.Information("Discarding release {Milestone}", options.Milestone); 21 | await _vcsService.DiscardReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false); 22 | 23 | return 0; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/ExportCommand.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using GitReleaseManager.Core.Options; 4 | using Serilog; 5 | 6 | namespace GitReleaseManager.Core.Commands 7 | { 8 | public class ExportCommand : ICommand 9 | { 10 | private readonly IVcsService _vcsService; 11 | private readonly ILogger _logger; 12 | 13 | public ExportCommand(IVcsService vcsService, ILogger logger) 14 | { 15 | _vcsService = vcsService; 16 | _logger = logger; 17 | } 18 | 19 | public async Task ExecuteAsync(ExportSubOptions options) 20 | { 21 | if (string.IsNullOrWhiteSpace(options.TagName)) 22 | { 23 | _logger.Information("Exporting all releases."); 24 | } 25 | else 26 | { 27 | _logger.Information("Exporting release {TagName}.", options.TagName); 28 | } 29 | 30 | var releasesContent = await _vcsService.ExportReleasesAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.SkipPrereleases).ConfigureAwait(false); 31 | 32 | using (var sw = new StreamWriter(File.Open(options.FileOutputPath, FileMode.OpenOrCreate))) 33 | { 34 | sw.Write(releasesContent); 35 | } 36 | 37 | return 0; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/ICommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | 4 | namespace GitReleaseManager.Core.Commands 5 | { 6 | public interface ICommand 7 | where TOptions : BaseSubOptions 8 | { 9 | Task ExecuteAsync(TOptions options); 10 | } 11 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/InitCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using GitReleaseManager.Core.Configuration; 5 | using GitReleaseManager.Core.Helpers; 6 | using GitReleaseManager.Core.Options; 7 | using GitReleaseManager.Core.Templates; 8 | using Serilog; 9 | 10 | namespace GitReleaseManager.Core.Commands 11 | { 12 | public class InitCommand : ICommand 13 | { 14 | private readonly IFileSystem _fileSystem; 15 | private readonly ILogger _logger; 16 | 17 | public InitCommand(IFileSystem fileSystem, ILogger logger) 18 | { 19 | _fileSystem = fileSystem; 20 | _logger = logger; 21 | } 22 | 23 | public Task ExecuteAsync(InitSubOptions options) 24 | { 25 | var directory = options.TargetDirectory ?? Environment.CurrentDirectory; 26 | 27 | if (!options.ExtractTemplates) 28 | { 29 | _logger.Information("Creating sample configuration file"); 30 | ConfigurationProvider.WriteSample(directory, _fileSystem); 31 | } 32 | else 33 | { 34 | _logger.Information("Extracting Embedded templates"); 35 | 36 | var templates = ReleaseTemplates.GetExportTemplates(); 37 | var config = ConfigurationProvider.Provide(directory, _fileSystem); 38 | var templatesDirectory = new DirectoryInfo(_fileSystem.ResolvePath(config.TemplatesDirectory)); 39 | 40 | if (!templatesDirectory.Exists) 41 | { 42 | templatesDirectory.Create(); 43 | } 44 | 45 | foreach (var template in templates) 46 | { 47 | var fullFilePath = Path.Combine(templatesDirectory.FullName, template.Key); 48 | var templateDir = Path.GetDirectoryName(fullFilePath); 49 | if (!Directory.Exists(templateDir)) 50 | { 51 | Directory.CreateDirectory(templateDir); 52 | } 53 | else if (File.Exists(fullFilePath)) 54 | { 55 | _logger.Warning("File '{FilePath}' already exist. Skipping file.", template.Key); 56 | continue; 57 | } 58 | 59 | _logger.Information("Creating new file '{FilePath}'!", template.Key); 60 | _fileSystem.WriteAllText(fullFilePath, template.Value); 61 | } 62 | 63 | _logger.Information("All embedded templates has been extracted!"); 64 | } 65 | 66 | return Task.FromResult(0); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/LabelCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | using Serilog; 4 | 5 | namespace GitReleaseManager.Core.Commands 6 | { 7 | public class LabelCommand : ICommand 8 | { 9 | private readonly IVcsService _vcsService; 10 | private readonly ILogger _logger; 11 | 12 | public LabelCommand(IVcsService vcsService, ILogger logger) 13 | { 14 | _vcsService = vcsService; 15 | _logger = logger; 16 | } 17 | 18 | public async Task ExecuteAsync(LabelSubOptions options) 19 | { 20 | var vcsOptions = options as BaseVcsOptions; 21 | 22 | if (vcsOptions?.Provider == Model.VcsProvider.GitLab) 23 | { 24 | _logger.Error("The label command is currently not supported when targeting GitLab."); 25 | return 1; 26 | } 27 | 28 | _logger.Information("Creating standard labels"); 29 | await _vcsService.CreateLabelsAsync(options.RepositoryOwner, options.RepositoryName).ConfigureAwait(false); 30 | 31 | return 0; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/OpenCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | using Serilog; 4 | 5 | namespace GitReleaseManager.Core.Commands 6 | { 7 | public class OpenCommand : ICommand 8 | { 9 | private readonly IVcsService _vcsService; 10 | private readonly ILogger _logger; 11 | 12 | public OpenCommand(IVcsService vcsService, ILogger logger) 13 | { 14 | _vcsService = vcsService; 15 | _logger = logger; 16 | } 17 | 18 | public async Task ExecuteAsync(OpenSubOptions options) 19 | { 20 | _logger.Information("Opening milestone {Milestone}", options.Milestone); 21 | await _vcsService.OpenMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false); 22 | 23 | return 0; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/PublishCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Options; 3 | using Serilog; 4 | 5 | namespace GitReleaseManager.Core.Commands 6 | { 7 | public class PublishCommand : ICommand 8 | { 9 | private readonly IVcsService _vcsService; 10 | private readonly ILogger _logger; 11 | 12 | public PublishCommand(IVcsService vcsService, ILogger logger) 13 | { 14 | _vcsService = vcsService; 15 | _logger = logger; 16 | } 17 | 18 | public async Task ExecuteAsync(PublishSubOptions options) 19 | { 20 | _logger.Information("Publish release {TagName}", options.TagName); 21 | await _vcsService.PublishReleaseAsync(options.RepositoryOwner, options.RepositoryName, options.TagName).ConfigureAwait(false); 22 | 23 | return 0; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Commands/ShowConfigCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GitReleaseManager.Core.Configuration; 3 | using GitReleaseManager.Core.Options; 4 | using Serilog; 5 | 6 | namespace GitReleaseManager.Core.Commands 7 | { 8 | public class ShowConfigCommand : ICommand 9 | { 10 | private readonly ILogger _logger; 11 | private readonly Config _config; 12 | 13 | public ShowConfigCommand(ILogger logger, Config config) 14 | { 15 | _logger = logger; 16 | _config = config; 17 | } 18 | 19 | public Task ExecuteAsync(ShowConfigSubOptions options) 20 | { 21 | var configuration = ConfigurationProvider.GetEffectiveConfigAsString(_config); 22 | _logger.Information("{Configuration}", configuration); 23 | 24 | return Task.FromResult(0); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/CloseConfig.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using GitReleaseManager.Core.Attributes; 3 | using YamlDotNet.Serialization; 4 | 5 | namespace GitReleaseManager.Core.Configuration 6 | { 7 | /// 8 | /// Class for holding configuration values used during milestone closing. This class cannot be inherited. 9 | /// 10 | public sealed class CloseConfig 11 | { 12 | /// 13 | /// Gets or sets a value indicating whether adding issue comments is enabled or not. 14 | /// 15 | [Description("Whether to add comments to issues closed and with the published milestone release.")] 16 | [YamlMember(Alias = "use-issue-comments")] 17 | public bool IssueComments { get; set; } 18 | 19 | /// 20 | /// Gets or sets the issue comment format to use when commenting on issues. 21 | /// 22 | [Sample(":tada: This issue has been resolved in version {milestone} :tada:\n\nThe release is available on:\n\n- [NuGet package(@{milestone})](https://nuget.org/packages/{repository}/{milestone})\n- [GitHub release](https://github.com/{owner}/{repository}/releases/tag/{milestone})\n\nYour **[GitReleaseManager](https://github.com/GitTools/GitReleaseManager)** bot :package::rocket:")] 23 | [YamlMember(Alias = "issue-comment", ScalarStyle = YamlDotNet.Core.ScalarStyle.Literal)] 24 | public string IssueCommentFormat { get; set; } 25 | 26 | /// 27 | /// Gets or sets a value indicating whether the due date should be set when closing the milestone. 28 | /// 29 | [Description("Whether to set the due date when closing the milestone.")] 30 | [YamlMember(Alias = "set-due-date")] 31 | public bool SetDueDate { get; set; } 32 | } 33 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/CommentSerialization/CommentGatheringTypeInspector.cs: -------------------------------------------------------------------------------- 1 | // All of the classes in this file have been aquired from 2 | // https://dotnetfiddle.net/8M6iIE which was mentioned 3 | // on the YamlDotNet repository here: https://github.com/aaubry/YamlDotNet/issues/444#issuecomment-546709672 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.ComponentModel; 8 | using System.Linq; 9 | using YamlDotNet.Core; 10 | using YamlDotNet.Serialization; 11 | using YamlDotNet.Serialization.TypeInspectors; 12 | 13 | namespace GitReleaseManager.Core.Configuration.CommentSerialization 14 | { 15 | public sealed class CommentGatheringTypeInspector : TypeInspectorSkeleton 16 | { 17 | private readonly ITypeInspector _innerTypeDescriptor; 18 | 19 | public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor) 20 | { 21 | _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor)); 22 | } 23 | 24 | public override IEnumerable GetProperties(Type type, object container) 25 | { 26 | return _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d)); 27 | } 28 | 29 | private sealed class CommentsPropertyDescriptor : IPropertyDescriptor 30 | { 31 | private readonly IPropertyDescriptor _baseDescriptor; 32 | 33 | public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor) 34 | { 35 | _baseDescriptor = baseDescriptor; 36 | Name = baseDescriptor.Name; 37 | } 38 | 39 | public string Name { get; set; } 40 | 41 | public Type Type => _baseDescriptor.Type; 42 | 43 | public Type TypeOverride 44 | { 45 | get => _baseDescriptor.TypeOverride; 46 | set => _baseDescriptor.TypeOverride = value; 47 | } 48 | 49 | public bool CanWrite => _baseDescriptor.CanWrite; 50 | 51 | public int Order { get; set; } 52 | 53 | public ScalarStyle ScalarStyle 54 | { 55 | get => _baseDescriptor.ScalarStyle; 56 | set => _baseDescriptor.ScalarStyle = value; 57 | } 58 | 59 | public T GetCustomAttribute() 60 | where T : Attribute 61 | { 62 | return _baseDescriptor.GetCustomAttribute(); 63 | } 64 | 65 | public IObjectDescriptor Read(object target) 66 | { 67 | var description = _baseDescriptor.GetCustomAttribute(); 68 | return description != null 69 | ? new CommentsObjectDescriptor(_baseDescriptor.Read(target), description.Description) 70 | : _baseDescriptor.Read(target); 71 | } 72 | 73 | public void Write(object target, object value) 74 | { 75 | _baseDescriptor.Write(target, value); 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/CommentSerialization/CommentsObjectDescriptor.cs: -------------------------------------------------------------------------------- 1 | // All of the classes in this file have been aquired from 2 | // https://dotnetfiddle.net/8M6iIE which was mentioned 3 | // on the YamlDotNet repository here: https://github.com/aaubry/YamlDotNet/issues/444#issuecomment-546709672 4 | 5 | using System; 6 | using YamlDotNet.Core; 7 | using YamlDotNet.Serialization; 8 | 9 | namespace GitReleaseManager.Core.Configuration.CommentSerialization 10 | { 11 | public sealed class CommentsObjectDescriptor : IObjectDescriptor 12 | { 13 | private readonly IObjectDescriptor _innerDescriptor; 14 | 15 | public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment) 16 | { 17 | _innerDescriptor = innerDescriptor; 18 | Comment = comment; 19 | } 20 | 21 | public string Comment { get; private set; } 22 | 23 | public object Value => _innerDescriptor.Value; 24 | 25 | public Type Type => _innerDescriptor.Type; 26 | 27 | public Type StaticType => _innerDescriptor.StaticType; 28 | 29 | public ScalarStyle ScalarStyle => _innerDescriptor.ScalarStyle; 30 | } 31 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/CommentSerialization/CommentsObjectGraphVisitor.cs: -------------------------------------------------------------------------------- 1 | // All of the classes in this file have been aquired from 2 | // https://dotnetfiddle.net/8M6iIE which was mentioned 3 | // on the YamlDotNet repository here: https://github.com/aaubry/YamlDotNet/issues/444#issuecomment-546709672 4 | 5 | using YamlDotNet.Core; 6 | using YamlDotNet.Core.Events; 7 | using YamlDotNet.Serialization; 8 | using YamlDotNet.Serialization.ObjectGraphVisitors; 9 | 10 | namespace GitReleaseManager.Core.Configuration.CommentSerialization 11 | { 12 | public sealed class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor 13 | { 14 | public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) 15 | : base(nextVisitor) 16 | { 17 | } 18 | 19 | public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) 20 | { 21 | if (value is CommentsObjectDescriptor commentsDescriptor && commentsDescriptor.Comment != null) 22 | { 23 | context?.Emit(new Comment(commentsDescriptor.Comment, false)); 24 | } 25 | 26 | return base.EnterMapping(key, value, context); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/CreateConfig.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using GitReleaseManager.Core.Attributes; 3 | using YamlDotNet.Serialization; 4 | 5 | namespace GitReleaseManager.Core.Configuration 6 | { 7 | public class CreateConfig 8 | { 9 | [Description("Enable generation of footer content in the release notes. Extract the recommended templates by running 'init --templates' and edit the footer.sbn file to provide the wanted footer content.")] 10 | [Sample(true)] 11 | [YamlMember(Alias = "include-footer")] 12 | public bool IncludeFooter { get; set; } 13 | 14 | [YamlMember(Alias = "footer-heading", DefaultValuesHandling = DefaultValuesHandling.OmitNull)] 15 | public string FooterHeading { get; set; } 16 | 17 | [YamlMember(Alias = "footer-content", DefaultValuesHandling = DefaultValuesHandling.OmitNull)] 18 | public string FooterContent { get; set; } 19 | 20 | [YamlMember(Alias = "footer-includes-milestone", DefaultValuesHandling = DefaultValuesHandling.OmitDefaults)] 21 | public bool FooterIncludesMilestone { get; set; } 22 | 23 | [YamlMember(Alias = "milestone-replace-text", DefaultValuesHandling = DefaultValuesHandling.OmitNull)] 24 | public string MilestoneReplaceText { get; set; } 25 | 26 | [YamlMember(Alias = "include-sha-section")] 27 | public bool IncludeShaSection { get; set; } 28 | 29 | [YamlMember(Alias = "sha-section-heading")] 30 | public string ShaSectionHeading { get; set; } 31 | 32 | [YamlMember(Alias = "sha-section-line-format")] 33 | public string ShaSectionLineFormat { get; set; } 34 | 35 | [YamlMember(Alias = "allow-update-to-published")] 36 | public bool AllowUpdateToPublishedRelease { get; set; } 37 | 38 | [YamlMember(Alias = "allow-milestone-without-issues")] 39 | public bool AllowMilestonesWithoutIssues { get; set; } 40 | 41 | [YamlMember(Alias = "include-contributors")] 42 | public bool IncludeContributors { get; set; } 43 | } 44 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/ExportConfig.cs: -------------------------------------------------------------------------------- 1 | using GitReleaseManager.Core.Attributes; 2 | using YamlDotNet.Serialization; 3 | 4 | namespace GitReleaseManager.Core.Configuration 5 | { 6 | public class ExportConfig 7 | { 8 | [YamlMember(Alias = "include-created-date-in-title")] 9 | public bool IncludeCreatedDateInTitle { get; set; } 10 | 11 | [Sample("MMMM dd, yyyy")] 12 | [YamlMember(Alias = "created-date-string-format")] 13 | public string CreatedDateStringFormat { get; set; } 14 | 15 | [YamlMember(Alias = "perform-regex-removal")] 16 | public bool PerformRegexRemoval { get; set; } 17 | 18 | [Sample("### Where to get it(\\r\\n)*You can .*\\.")] 19 | [YamlMember(Alias = "regex-text")] 20 | public string RegexText { get; set; } 21 | 22 | [YamlMember(Alias = "multiline-regex")] 23 | public bool IsMultilineRegex { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/LabelAlias.cs: -------------------------------------------------------------------------------- 1 | namespace GitReleaseManager.Core.Configuration 2 | { 3 | public class LabelAlias 4 | { 5 | public string Name { get; set; } 6 | 7 | public string Header { get; set; } 8 | 9 | public string Plural { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Configuration/LabelConfig.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Serialization; 2 | 3 | namespace GitReleaseManager.Core.Configuration 4 | { 5 | public class LabelConfig 6 | { 7 | [YamlMember(Alias = "name")] 8 | public string Name { get; set; } 9 | 10 | [YamlMember(Alias = "description")] 11 | public string Description { get; set; } 12 | 13 | [YamlMember(Alias = "color")] 14 | public string Color { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Ensure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace GitReleaseManager.Core 5 | { 6 | /// 7 | /// Provides static methods that help a constructor or method to verify correct arguments and 8 | /// state. 9 | /// 10 | public static class Ensure 11 | { 12 | /// 13 | /// Checks whether a specified string is not null, empty, or consists only 14 | /// of white-space characters. 15 | /// 16 | /// The string to test. 17 | /// The name of the parameter that caused the exception. 18 | /// str is 19 | /// null. 20 | /// str is 21 | /// whitespace. 22 | public static void IsNotNullOrWhiteSpace(string str, string paramName) 23 | { 24 | if (str == null) 25 | { 26 | throw new ArgumentNullException(paramName); 27 | } 28 | 29 | if (string.IsNullOrWhiteSpace(str)) 30 | { 31 | throw new ArgumentException("Value cannot be empty or white-space.", paramName); 32 | } 33 | } 34 | 35 | /// 36 | /// Checks if a file exists. 37 | /// 38 | /// The path to test. 39 | /// A message that describes the error. 40 | /// File does not exist. 41 | public static void FileExists(string path, string message) 42 | { 43 | if (!File.Exists(path)) 44 | { 45 | var fileName = Path.GetFileName(path); 46 | throw new FileNotFoundException(message, fileName); 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Exceptions/ApiException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GitReleaseManager.Core.Exceptions 5 | { 6 | [Serializable] 7 | public class ApiException : Exception 8 | { 9 | public ApiException() 10 | { 11 | } 12 | 13 | public ApiException(string message) 14 | : base(message) 15 | { 16 | } 17 | 18 | public ApiException(string message, Exception inner) 19 | : base(message, inner) 20 | { 21 | } 22 | 23 | protected ApiException(SerializationInfo info, StreamingContext context) 24 | : base(info, context) 25 | { 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Exceptions/ForbiddenException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GitReleaseManager.Core.Exceptions 5 | { 6 | [Serializable] 7 | public class ForbiddenException : Exception 8 | { 9 | public ForbiddenException() 10 | { 11 | } 12 | 13 | public ForbiddenException(string message) 14 | : base(message) 15 | { 16 | } 17 | 18 | public ForbiddenException(string message, Exception inner) 19 | : base(message, inner) 20 | { 21 | } 22 | 23 | protected ForbiddenException(SerializationInfo info, StreamingContext context) 24 | : base(info, context) 25 | { 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Exceptions/InvalidIssuesException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace GitReleaseManager.Core.Exceptions 5 | { 6 | [Serializable] 7 | public class InvalidIssuesException : Exception 8 | { 9 | public InvalidIssuesException() 10 | { 11 | } 12 | 13 | public InvalidIssuesException(List errors) 14 | : base(string.Join(Environment.NewLine, errors)) 15 | { 16 | Errors = errors; 17 | } 18 | 19 | public InvalidIssuesException(List errors, string message) 20 | : base(message) 21 | { 22 | Errors = errors; 23 | } 24 | 25 | public InvalidIssuesException(List errors, string message, Exception inner) 26 | : base(message, inner) 27 | { 28 | Errors = errors; 29 | } 30 | 31 | public List Errors { get; set; } 32 | 33 | protected InvalidIssuesException( 34 | System.Runtime.Serialization.SerializationInfo info, 35 | System.Runtime.Serialization.StreamingContext context) 36 | : base(info, context) 37 | { 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Exceptions/NotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GitReleaseManager.Core.Exceptions 5 | { 6 | [Serializable] 7 | public class NotFoundException : Exception 8 | { 9 | public NotFoundException() 10 | { 11 | } 12 | 13 | public NotFoundException(string message) 14 | : base(message) 15 | { 16 | } 17 | 18 | public NotFoundException(string message, Exception inner) 19 | : base(message, inner) 20 | { 21 | } 22 | 23 | protected NotFoundException(SerializationInfo info, StreamingContext context) 24 | : base(info, context) 25 | { 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Extensions/JsonExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.Json; 5 | 6 | namespace GitReleaseManager.Core.Extensions 7 | { 8 | internal static class JsonExtensions 9 | { 10 | /// 11 | /// Get a JsonElement from a path. Each level in the path is seperated by a dot. 12 | /// 13 | /// The parent Json element. 14 | /// The path of the desired child element. 15 | /// The child element. 16 | public static JsonElement GetJsonElement(this JsonElement jsonElement, string path) 17 | { 18 | if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined) 19 | { 20 | return default(JsonElement); 21 | } 22 | 23 | string[] segments = path.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); 24 | 25 | foreach (var segment in segments) 26 | { 27 | if (int.TryParse(segment, out var index) && jsonElement.ValueKind == JsonValueKind.Array) 28 | { 29 | jsonElement = jsonElement.EnumerateArray().ElementAtOrDefault(index); 30 | if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined) 31 | { 32 | return default(JsonElement); 33 | } 34 | 35 | continue; 36 | } 37 | 38 | jsonElement = jsonElement.TryGetProperty(segment, out var value) ? value : default; 39 | 40 | if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined) 41 | { 42 | return default(JsonElement); 43 | } 44 | } 45 | 46 | return jsonElement; 47 | } 48 | 49 | /// 50 | /// Get the first JsonElement matching a path from the provided list of paths. 51 | /// 52 | /// The parent Json element. 53 | /// The path of the desired child element. 54 | /// The child element. 55 | public static JsonElement GetFirstJsonElement(this JsonElement jsonElement, IEnumerable paths) 56 | { 57 | if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined) 58 | { 59 | return default(JsonElement); 60 | } 61 | 62 | var element = default(JsonElement); 63 | 64 | foreach (var path in paths) 65 | { 66 | element = jsonElement.GetJsonElement(path); 67 | 68 | if (element.ValueKind is JsonValueKind.Null || element.ValueKind is JsonValueKind.Undefined) 69 | { 70 | continue; 71 | } 72 | 73 | break; 74 | } 75 | 76 | return element; 77 | } 78 | 79 | public static string GetJsonElementValue(this JsonElement jsonElement) => jsonElement.ValueKind != JsonValueKind.Null && 80 | jsonElement.ValueKind != JsonValueKind.Undefined 81 | ? jsonElement.ToString() 82 | : default; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Extensions/MilestoneExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Serilog; 3 | 4 | namespace GitReleaseManager.Core.Extensions 5 | { 6 | public static class MilestoneExtensions 7 | { 8 | public static readonly ILogger _logger = Log.ForContext(typeof(MilestoneExtensions)); 9 | 10 | public static Version Version(this Octokit.Milestone ver) 11 | { 12 | if (ver is null) 13 | { 14 | throw new ArgumentNullException(nameof(ver)); 15 | } 16 | 17 | var nameWithoutPrerelease = ver.Title.Split('-')[0]; 18 | if (nameWithoutPrerelease.StartsWith("v", StringComparison.OrdinalIgnoreCase)) 19 | { 20 | _logger.Debug("Removing version prefix from {Name}.", ver.Title); 21 | nameWithoutPrerelease = nameWithoutPrerelease.Remove(0, 1); 22 | } 23 | 24 | if (!System.Version.TryParse(nameWithoutPrerelease, out Version parsedVersion)) 25 | { 26 | _logger.Warning("No valid version was found on {Title}.", ver.Title); 27 | return new Version(0, 0); 28 | } 29 | 30 | return parsedVersion; 31 | } 32 | 33 | public static Version Version(this NGitLab.Models.Milestone ver) 34 | { 35 | if (ver is null) 36 | { 37 | throw new ArgumentNullException(nameof(ver)); 38 | } 39 | 40 | var nameWithoutPrerelease = ver.Title.Split('-')[0]; 41 | if (nameWithoutPrerelease.StartsWith("v", StringComparison.OrdinalIgnoreCase)) 42 | { 43 | _logger.Debug("Removing version prefix from {Name}", ver.Title); 44 | nameWithoutPrerelease = nameWithoutPrerelease.Remove(0, 1); 45 | } 46 | 47 | if (!System.Version.TryParse(nameWithoutPrerelease, out Version parsedVersion)) 48 | { 49 | _logger.Warning("No valid version was found on {Title}", ver.Title); 50 | return new Version(0, 0); 51 | } 52 | 53 | return parsedVersion; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Extensions/OctokitExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Octokit; 7 | using Serilog; 8 | 9 | namespace GitReleaseManager.Core.Extensions 10 | { 11 | public static class OctokitExtensions 12 | { 13 | private static readonly ILogger _logger = Log.ForContext(typeof(OctokitExtensions)); 14 | 15 | public static bool IsPullRequest(this Issue issue) 16 | { 17 | if (issue is null) 18 | { 19 | throw new ArgumentNullException(nameof(issue)); 20 | } 21 | 22 | return !(issue.PullRequest is null); 23 | } 24 | 25 | public static Task> AllIssuesForMilestone(this IGitHubClient gitHubClient, Milestone milestone) 26 | { 27 | if (gitHubClient is null) 28 | { 29 | throw new ArgumentNullException(nameof(gitHubClient)); 30 | } 31 | 32 | if (milestone is null) 33 | { 34 | throw new ArgumentNullException(nameof(milestone)); 35 | } 36 | 37 | return AllIssuesForMilestoneInternalAsync(gitHubClient, milestone); 38 | } 39 | 40 | public static Uri HtmlUrl(this Milestone milestone) 41 | { 42 | if (milestone is null) 43 | { 44 | throw new ArgumentNullException(nameof(milestone)); 45 | } 46 | 47 | var parts = milestone.Url.Split('/'); 48 | var user = parts[2]; 49 | var repository = parts[3]; 50 | 51 | return new Uri(string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/issues?milestone={2}&state=closed", user, repository, milestone.Number)); 52 | } 53 | 54 | private static async Task> AllIssuesForMilestoneInternalAsync(IGitHubClient gitHubClient, Milestone milestone) 55 | { 56 | var closedIssueRequest = new RepositoryIssueRequest 57 | { 58 | Milestone = milestone.Number.ToString(CultureInfo.InvariantCulture), 59 | State = ItemStateFilter.Closed, 60 | }; 61 | 62 | var openIssueRequest = new RepositoryIssueRequest 63 | { 64 | Milestone = milestone.Number.ToString(CultureInfo.InvariantCulture), 65 | State = ItemStateFilter.Open, 66 | }; 67 | 68 | var parts = milestone.Url.Split('/'); 69 | var user = parts[4]; 70 | var repository = parts[5]; 71 | 72 | _logger.Verbose("Finding closed issues for milestone {Milestone} on {Owner}/{Repository}", milestone.Title, user, repository); 73 | var closedIssues = await gitHubClient.Issue.GetAllForRepository(user, repository, closedIssueRequest).ConfigureAwait(false); 74 | _logger.Verbose("Finding open issues for milestone {Milestone} on {Owner}/{Repository}", milestone.Title, user, repository); 75 | var openIssues = await gitHubClient.Issue.GetAllForRepository(user, repository, openIssueRequest).ConfigureAwait(false); 76 | 77 | return openIssues.Union(closedIssues); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("GitReleaseManager.Tests")] 6 | 7 | namespace GitReleaseManager.Core.Extensions 8 | { 9 | internal static class StringExtensions 10 | { 11 | public static string ReplaceMilestoneTitle(this string source, string milestoneKey, string milestoneTitle) 12 | { 13 | #pragma warning disable SA1001 // Commas should be spaced correctly 14 | var dict = new Dictionary 15 | { 16 | { milestoneKey.Trim('{','}'), milestoneTitle }, 17 | }; 18 | #pragma warning restore SA1001 // Commas should be spaced correctly 19 | 20 | return source.ReplaceTemplate(dict); 21 | } 22 | 23 | public static string ReplaceTemplate(this string source, object values) 24 | { 25 | IDictionary pairs; 26 | 27 | if (values is IDictionary dict) 28 | { 29 | pairs = new Dictionary(dict, StringComparer.OrdinalIgnoreCase); 30 | } 31 | else 32 | { 33 | var type = values.GetType(); 34 | var properties = type.GetProperties(); 35 | pairs = properties.ToDictionary(x => x.Name, x => x.GetValue(values), StringComparer.OrdinalIgnoreCase); 36 | } 37 | 38 | var sb = new StringBuilder(); 39 | int i, prevI = 0; 40 | while ((i = source.IndexOf('{', prevI)) >= 0) 41 | { 42 | sb.Append(source.Substring(prevI, i - prevI)); 43 | prevI = i + 1; 44 | if ((i = source.IndexOf('}', prevI)) > prevI) 45 | { 46 | var name = source.Substring(prevI, i - prevI); 47 | if (pairs.ContainsKey(name)) 48 | { 49 | sb.Append(pairs[name]); 50 | } 51 | 52 | prevI = ++i; 53 | } 54 | } 55 | 56 | if (source.Length > prevI) 57 | { 58 | sb.Append(source.Substring(prevI, source.Length - prevI)); 59 | } 60 | 61 | return sb.ToString(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/GitReleaseManager.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net8.0;net9.0 7 | GitReleaseManager.Core 8 | Create release notes in markdown given a milestone 9 | false 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | all 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | True 36 | True 37 | ReleaseTemplates.tt 38 | 39 | 40 | 41 | 42 | TextTemplatingFileGenerator 43 | ReleaseTemplates.g.cs 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Code Analysis results, point to "Suppress Message", and click 8 | // "In Suppression File". 9 | // You do not need to add suppressions to this file manually. 10 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly", Justification = "This was in relation to the Information Version Number generated by GitVersion, which we want to leave as is.")] 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "GitReleaseManager.Core.Helpers", Justification = "Still being worked on")] 12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Wrong Usage", "DF0033:Marks undisposed objects assinged to a property, originated from a method invocation.", Justification = "This is being handled later in the code", Scope = "member", Target = "~M:GitReleaseManager.Core.GitHubProvider.AddAssets(System.String,System.String,System.String,System.Collections.Generic.IList{System.String})~System.Threading.Tasks.Task")] -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Helpers/FileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using GitReleaseManager.Core.Options; 5 | 6 | namespace GitReleaseManager.Core.Helpers 7 | { 8 | public class FileSystem : IFileSystem 9 | { 10 | private readonly BaseSubOptions options; 11 | 12 | public FileSystem(BaseSubOptions options) 13 | { 14 | this.options = options; 15 | } 16 | 17 | public void Copy(string @source, string destination, bool overwrite) 18 | { 19 | File.Copy(@source, destination, overwrite); 20 | } 21 | 22 | public void Move(string @source, string destination) 23 | { 24 | File.Move(@source, destination); 25 | } 26 | 27 | public bool Exists(string file) 28 | { 29 | return File.Exists(file); 30 | } 31 | 32 | public void Delete(string path) 33 | { 34 | File.Delete(path); 35 | } 36 | 37 | public string ResolvePath(string path) 38 | { 39 | if (Path.IsPathRooted(path)) 40 | { 41 | return path; 42 | } 43 | 44 | return Path.Combine(options.TargetDirectory ?? Environment.CurrentDirectory, path); 45 | } 46 | 47 | public string ReadAllText(string path) 48 | { 49 | return File.ReadAllText(path); 50 | } 51 | 52 | public void WriteAllText(string file, string fileContents) 53 | { 54 | File.WriteAllText(file, fileContents); 55 | } 56 | 57 | public IEnumerable DirectoryGetFiles(string directory, string searchPattern, SearchOption searchOption) 58 | { 59 | return Directory.GetFiles(directory, searchPattern, searchOption); 60 | } 61 | 62 | public Stream OpenWrite(string path) 63 | { 64 | return File.OpenWrite(path); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Helpers/IFileSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace GitReleaseManager.Core.Helpers 5 | { 6 | public interface IFileSystem 7 | { 8 | void Copy(string source, string destination, bool overwrite); 9 | 10 | void Move(string source, string destination); 11 | 12 | bool Exists(string file); 13 | 14 | void Delete(string path); 15 | 16 | string ReadAllText(string path); 17 | 18 | string ResolvePath(string path); 19 | 20 | void WriteAllText(string file, string fileContents); 21 | 22 | IEnumerable DirectoryGetFiles(string directory, string searchPattern, SearchOption searchOption); 23 | 24 | Stream OpenWrite(string path); 25 | } 26 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/IVcsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using GitReleaseManager.Core.Model; 4 | 5 | namespace GitReleaseManager.Core 6 | { 7 | public interface IVcsService 8 | { 9 | Task CreateEmptyReleaseAsync(string owner, string repository, string name, string targetCommitish, bool prerelease); 10 | 11 | Task CreateReleaseFromMilestoneAsync(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease, string templateFilePath); 12 | 13 | Task CreateReleaseFromInputFileAsync(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease); 14 | 15 | Task DiscardReleaseAsync(string owner, string repository, string tagName); 16 | 17 | Task AddAssetsAsync(string owner, string repository, string tagName, IList assets); 18 | 19 | Task ExportReleasesAsync(string owner, string repository, string tagName, bool skipPrereleases); 20 | 21 | Task CloseMilestoneAsync(string owner, string repository, string milestoneTitle); 22 | 23 | Task OpenMilestoneAsync(string owner, string repository, string milestoneTitle); 24 | 25 | Task PublishReleaseAsync(string owner, string repository, string tagName); 26 | 27 | Task CreateLabelsAsync(string owner, string repository); 28 | } 29 | } -------------------------------------------------------------------------------- /src/GitReleaseManager.Core/Model/Issue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GitReleaseManager.Core.Model 4 | { 5 | public sealed class Issue 6 | { 7 | public string Title { get; set; } 8 | 9 | public long InternalNumber { get; set; } 10 | 11 | public int PublicNumber { get; set; } 12 | 13 | public string HtmlUrl { get; set; } 14 | 15 | public IReadOnlyList