Merge pull request #828 from mikepenz/develop

dev -> main
This commit is contained in:
Mike Penz
2022-07-26 17:39:08 +02:00
committed by GitHub
18 changed files with 1104 additions and 241 deletions
+75 -3
View File
@@ -28,6 +28,7 @@
<a href="#full-sample-%EF%B8%8F">Sample 🖥️</a> &bull; <a href="#full-sample-%EF%B8%8F">Sample 🖥️</a> &bull;
<a href="#customization-%EF%B8%8F">Customization 🖍️</a> &bull; <a href="#customization-%EF%B8%8F">Customization 🖍️</a> &bull;
<a href="#contribute-">Contribute 🧬</a> &bull; <a href="#contribute-">Contribute 🧬</a> &bull;
<a href="#local-testing-">Local Testing 🧪</a> &bull;
<a href="#license">License 📓</a> <a href="#license">License 📓</a>
</p> </p>
@@ -86,6 +87,11 @@ A full set list of possible output values for this action.
| `outputs.categorized_prs` | Count of PRs which were successfully categorized as part of the action. | | `outputs.categorized_prs` | Count of PRs which were successfully categorized as part of the action. |
| `outputs.open_prs` | Count of open PRs. Only fetched if `includeOpen` is enabled. | | `outputs.open_prs` | Count of open PRs. Only fetched if `includeOpen` is enabled. |
| `outputs.uncategorized_prs` | Count of PRs which were not categorized as part of the action. | | `outputs.uncategorized_prs` | Count of PRs which were not categorized as part of the action. |
| `outputs.changed_files` | Count of changed files in this release. |
| `outputs.additions` | Count of code additions in this release (lines). |
| `outputs.deletions` | Count of code deletions in this release (lines). |
| `outputs.changes` | Total count of changes in this release (lines). |
| `outputs.commits` | Count of commits which have been added in this release. |
## Full Sample 🖥️ ## Full Sample 🖥️
@@ -291,8 +297,9 @@ Table of supported placeholders allowed to be used in the `pr_template` configur
| `${{MILESTONE}}` | Milestone this PR was part of, as assigned on GitHub | | `${{MILESTONE}}` | Milestone this PR was part of, as assigned on GitHub |
| `${{BODY}}` | Description/Body of the pull request as specified on GitHub | | `${{BODY}}` | Description/Body of the pull request as specified on GitHub |
| `${{ASSIGNEES}}` | Login names of assigned GitHub users, joined by `,` | | `${{ASSIGNEES}}` | Login names of assigned GitHub users, joined by `,` |
| `${{REVIEWERS}}` | GitHub Login names of specified reviewers, joined by `,` | | `${{REVIEWERS}}` | GitHub Login names of specified reviewers, joined by `,`. Requires `fetchReviewers` to be enabled. |
| `${{APPROVERS}}` | GitHub Login names of users who approved the PR, joined by `,` | | `${{APPROVERS}}` | GitHub Login names of users who approved the PR, joined by `,` |
| `${{DAYS_SINCE}}` | Days between the 2 releases. Requires `fetchReleaseInformation` to be enabled. |
### Template placeholders ### Template placeholders
@@ -307,14 +314,20 @@ Table of supported placeholders allowed to be used in the `template` and `empty_
| `${{OWNER}}` | Describes the owner of the repository the changelog was generated for | x | | `${{OWNER}}` | Describes the owner of the repository the changelog was generated for | x |
| `${{REPO}}` | The repository name of the repo the changelog was generated for | x | | `${{REPO}}` | The repository name of the repo the changelog was generated for | x |
| `${{FROM_TAG}}` | Defines the 'start' from where the changelog did consider merged pull requests | x | | `${{FROM_TAG}}` | Defines the 'start' from where the changelog did consider merged pull requests | x |
| `${{FROM_TAG_DATE}}` | Defines the date at which the 'start' tag was created | x |
| `${{TO_TAG}}` | Defines until which tag the changelog did consider merged pull requests | x | | `${{TO_TAG}}` | Defines until which tag the changelog did consider merged pull requests | x |
| `${{TO_TAG_DATE}}` | Defines the date at which the 'until' tag was created | x |
| `${{RELEASE_DIFF}}` | Introduces a link to the full diff between from tag and to tag releases | x | | `${{RELEASE_DIFF}}` | Introduces a link to the full diff between from tag and to tag releases | x |
| `${{CHANGED_FILES}}` | The count of changed files. | |
| `${{ADDITIONS}}` | The count of code additions (lines). | |
| `${{DELETIONS}}` | The count of code deletions (lines). | |
| `${{CHANGES}}` | The count of total changes (lines). | |
| `${{COMMITS}}` | The count of commits in this release. | |
| `${{CATEGORIZED_COUNT}}` | The count of PRs which were categorized | | | `${{CATEGORIZED_COUNT}}` | The count of PRs which were categorized | |
| `${{UNCATEGORIZED_COUNT}}` | The count of PRs and changes which were not categorized. No label overlapping with category labels | | | `${{UNCATEGORIZED_COUNT}}` | The count of PRs and changes which were not categorized. No label overlapping with category labels | |
| `${{OPEN_COUNT}}` | The count of open PRs. Will only be fetched if `includeOpen` is configured. | | | `${{OPEN_COUNT}}` | The count of open PRs. Will only be fetched if `includeOpen` is configured. | |
| `${{IGNORED_COUNT}}` | The count of PRs and changes which were specifically ignored from the changelog. | | | `${{IGNORED_COUNT}}` | The count of PRs and changes which were specifically ignored from the changelog. | |
### Configuration Specification ### Configuration Specification
Table of descriptions for the `configuration.json` options to configure the resulting release notes / changelog. Table of descriptions for the `configuration.json` options to configure the resulting release notes / changelog.
@@ -377,6 +390,65 @@ It's suggested to export the token to your path before running the tests so that
export GITHUB_TOKEN=your_personal_github_pat export GITHUB_TOKEN=your_personal_github_pat
``` ```
## Local Testing 🧪
This GitHub action is fully developed in Typescript and can be run locally via npm. Doing so is a great way to test the action and/or your custom configurations locally, without the need to push and re-run GitHub actions over and over again.
To run this action locally, first make sure you provide a `GITHUB_TOKEN` with enough permissions to access the repository.
```
# GitHub token for the action
export GITHUB_TOKEN=your_read_only_github_token
```
Afterwards run the testcases with:
```bash
npm test -- custom.test.ts
```
<details><summary><b>custom.test.ts</b></summary>
<p>
```typescript
import {resolveConfiguration} from '../src/utils'
import {ReleaseNotesBuilder} from '../src/releaseNotesBuilder'
jest.setTimeout(180000)
it('Test custom changelog builder', async () => {
const configuration = resolveConfiguration(
'',
'configs_test/configuration_approvers.json'
)
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
'1.5.0', // fromTag
'2.0.0', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
true, // enable to fetch reviewers
false, // commitMode
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(``)
})
```
</p>
</details>
Additionally it is possible to do full debugging including the option of breakpoints via (for example) Visual Code.
Open the project in Visual code -> open the terminal -> use the `+` and start a new `JavaScript Debug Terminal`. Afterwards run the tests as described above.
## Developed By ## Developed By
* Mike Penz * Mike Penz
@@ -404,7 +476,7 @@ export GITHUB_TOKEN=your_personal_github_pat
All patches and changes applied to the original source are licensed under the Apache 2.0 license. All patches and changes applied to the original source are licensed under the Apache 2.0 license.
Copyright 2021 Mike Penz Copyright 2022 Mike Penz
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
+31 -21
View File
@@ -14,18 +14,19 @@ it('Should have empty changelog (tags)', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.0.1', fromTag: { name: 'v0.0.1' },
toTag: 'v0.0.2', toTag: { name: 'v0.0.2' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
const changeLog = await releaseNotes.pull() const changeLog = await releaseNotes.pull()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual(null) expect(changeLog).toStrictEqual("- no changes")
}) })
it('Should match generated changelog (tags)', async () => { it('Should match generated changelog (tags)', async () => {
@@ -33,11 +34,12 @@ it('Should match generated changelog (tags)', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.0.1', fromTag: { name: 'v0.0.1'},
toTag: 'v0.0.3', toTag: { name: 'v0.0.3' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -60,11 +62,12 @@ it('Should match generated changelog (refs)', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3', fromTag: { name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3' },
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa', toTag: { name: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -95,11 +98,12 @@ it('Should match generated changelog and replace all occurrences (refs)', async
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3', fromTag: { name: '5ec7a2d86fe9f43fdd38d5e254a1117c8a51b4c3' },
toTag: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa', toTag: { name: 'fa3788c8c4b3373ef8424ce3eb008a5cd07cc5aa' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -132,11 +136,12 @@ it('Should match ordered ASC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -156,11 +161,12 @@ it('Should match ordered DESC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -180,11 +186,12 @@ it('Should match ordered by title ASC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -204,11 +211,12 @@ it('Should match ordered by title DESC', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v0.3.0', fromTag: { name: 'v0.3.0' },
toTag: 'v0.5.0', toTag: { name: 'v0.5.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -228,11 +236,12 @@ it('Should ignore PRs not merged into develop branch', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v1.3.1', fromTag: { name: 'v1.3.1' },
toTag: 'v1.4.0', toTag: { name: 'v1.4.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -250,11 +259,12 @@ it('Should ignore PRs not merged into main branch', async () => {
const releaseNotes = new ReleaseNotes(octokit, { const releaseNotes = new ReleaseNotes(octokit, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v1.3.1', fromTag: { name: 'v1.3.1' },
toTag: 'v1.4.0', toTag: { name: 'v1.4.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
+76 -5
View File
@@ -17,6 +17,7 @@ it('Should match generated changelog (unspecified fromTag)', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -45,6 +46,7 @@ it('Should match generated changelog (unspecified tags)', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -70,6 +72,7 @@ it('Should use empty placeholder', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -96,6 +99,7 @@ it('Should fill empty placeholders', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -103,7 +107,7 @@ it('Should fill empty placeholders', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`mikepenz\nrelease-changelog-builder-action\nv0.0.2\nv0.0.3` `mikepenz\nrelease-changelog-builder-action\nv0.0.2\nv0.0.3\nhttps://github.com/mikepenz/release-changelog-builder-action/compare/v0.0.2...v0.0.3`
) )
}) })
@@ -124,6 +128,7 @@ it('Should fill `template` placeholders', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -131,7 +136,7 @@ it('Should fill `template` placeholders', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🧪 Tests\n\n- [CI] Specify Test Case\n - PR: #10\n\n\n\n\nmikepenz\nrelease-changelog-builder-action\nv0.0.1\nv0.0.3\n1\n0\n0` `## 🧪 Tests\n\n- [CI] Specify Test Case\n - PR: #10\n\n\n\n\nmikepenz\nrelease-changelog-builder-action\nv0.0.1\nv0.0.3\nhttps://github.com/mikepenz/release-changelog-builder-action/compare/v0.0.1...v0.0.3\n1\n0\n0\n19\n14827\n444\n15271\n3`
) )
}) })
@@ -152,6 +157,7 @@ it('Should fill `template` placeholders, ignore', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -159,7 +165,7 @@ it('Should fill `template` placeholders, ignore', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🚀 Features\n\n- Enhance sorting by using proper semver\n - PR: #51\n\n## 🧪 Tests\n\n- Improve test cases\n - PR: #49\n\n\n- Bump @types/node from 14.11.8 to 14.11.10\n - PR: #47\n- Adjust code to move fromTag resolving to main.ts\n - PR: #48\n- dev -> main\n - PR: #52\n- Update package.json to updated description\n - PR: #53\n- dev -> main\n - PR: #54\n\n- New additional placeholders for \`template\` and \`empty_template\`\n - PR: #50\n\nmikepenz\nrelease-changelog-builder-action\nv0.9.1\nv0.9.5\n2\n5\n1` `## 🚀 Features\n\n- Enhance sorting by using proper semver\n - PR: #51\n\n## 🧪 Tests\n\n- Improve test cases\n - PR: #49\n\n\n- Bump @types/node from 14.11.8 to 14.11.10\n - PR: #47\n- Adjust code to move fromTag resolving to main.ts\n - PR: #48\n- dev -> main\n - PR: #52\n- Update package.json to updated description\n - PR: #53\n- dev -> main\n - PR: #54\n\n- New additional placeholders for \`template\` and \`empty_template\`\n - PR: #50\n\nmikepenz\nrelease-changelog-builder-action\nv0.9.1\nv0.9.5\nhttps://github.com/mikepenz/release-changelog-builder-action/compare/v0.9.1...v0.9.5\n2\n5\n1\n16\n2931\n450\n3381\n26`
) )
}) })
@@ -180,6 +186,7 @@ it('Uncategorized category', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, false,
configuration configuration
) )
@@ -208,6 +215,7 @@ it('Verify commit based changelog', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
true, true,
configuration configuration
) )
@@ -236,6 +244,7 @@ it('Verify commit based changelog, with emoji categorisation', async () => {
false, false,
false, false,
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
true, true,
configuration configuration
) )
@@ -264,6 +273,7 @@ it('Verify default inclusion of open PRs', async () => {
false, // failOnError false, // failOnError
false, // ignorePrePrelease false, // ignorePrePrelease
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // commitMode false, // commitMode
configuration // configuration configuration // configuration
) )
@@ -292,6 +302,7 @@ it('Verify custom categorisation of open PRs', async () => {
false, // failOnError false, // failOnError
false, // ignorePrePrelease false, // ignorePrePrelease
false, // enable to fetch reviewers false, // enable to fetch reviewers
false, // enable to fetch tag release information
false, // commitMode false, // commitMode
configuration // configuration configuration // configuration
) )
@@ -303,7 +314,7 @@ it('Verify custom categorisation of open PRs', async () => {
) )
}) })
it('Verify reviewers who approved are fetched', async () => { it('Verify reviewers who approved are fetched and also release information', async () => {
const configuration = resolveConfiguration( const configuration = resolveConfiguration(
'', '',
'configs_test/configuration_approvers.json' 'configs_test/configuration_approvers.json'
@@ -320,6 +331,7 @@ it('Verify reviewers who approved are fetched', async () => {
false, // failOnError false, // failOnError
false, // ignorePrePrelease false, // ignorePrePrelease
true, // enable to fetch reviewers true, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // commitMode false, // commitMode
configuration // configuration configuration // configuration
) )
@@ -327,6 +339,65 @@ it('Verify reviewers who approved are fetched', async () => {
const changeLog = await releaseNotesBuilder.build() const changeLog = await releaseNotesBuilder.build()
console.log(changeLog) console.log(changeLog)
expect(changeLog).toStrictEqual( expect(changeLog).toStrictEqual(
`## 🚀 Features\n\n- A feature to be going to v2 (nr3) -- (#3) [merged] --- \n- New feature to keep open (nr5) -- (#7) [open] --- gabrielpopa\n\n` `## 🚀 Features\n\n- A feature to be going to v2 (nr3) -- (#3) [merged] --- \n- New feature to keep open (nr5) -- (#7) [open] --- gabrielpopa\n\n\n\n0`
) )
}) })
it('Fetch release information', async () => {
const configuration = resolveConfiguration(
'',
'configs_test/configuration_approvers.json'
)
configuration.template = "${{FROM_TAG}}-${{FROM_TAG_DATE}}\n${{TO_TAG}}-${{TO_TAG_DATE}}\n${{DAYS_SINCE}}"
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
'2.0.0', // fromTag
'3.0.0-a01', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // commitMode
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(
`2.0.0-2022-04-08T07:52:40.000Z\n3.0.0-a01-2022-07-26T14:28:36.000Z\n109`
)
})
it('Fetch release information for non existing tag / release', async () => {
const configuration = resolveConfiguration(
'',
'configs_test/configuration_approvers.json'
)
configuration.template = "${{FROM_TAG}}-${{FROM_TAG_DATE}}\n${{TO_TAG}}-${{TO_TAG_DATE}}\n${{DAYS_SINCE}}"
const releaseNotesBuilder = new ReleaseNotesBuilder(
null, // baseUrl
null, // token
'.', // repoPath
'mikepenz', // user
'release-changelog-builder-action-playground', // repo
'2.0.0', // fromTag
'3.0.1', // toTag
true, // includeOpen
false, // failOnError
false, // ignorePrePrelease
false, // enable to fetch reviewers
true, // enable to fetch tag release information
false, // commitMode
configuration // configuration
)
const changeLog = await releaseNotesBuilder.build()
console.log(changeLog)
expect(changeLog).toStrictEqual(`- no changes`)
})
+55 -41
View File
@@ -2,6 +2,7 @@ import {buildChangelog} from '../src/transform'
import {PullRequestInfo} from '../src/pullRequests' import {PullRequestInfo} from '../src/pullRequests'
import moment from 'moment' import moment from 'moment'
import { DefaultConfiguration, Configuration } from '../src/configuration'; import { DefaultConfiguration, Configuration } from '../src/configuration';
import { DefaultDiffInfo } from '../src/commits';
jest.setTimeout(180000) jest.setTimeout(180000)
@@ -130,14 +131,15 @@ it('Extract label from title, combined regex', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -159,14 +161,15 @@ it('Extract label from title and body, combined regex', async () => {
let prs = Array.from(mergedPullRequests) let prs = Array.from(mergedPullRequests)
prs.push(pullRequestWithLabelInBody) prs.push(pullRequestWithLabelInBody)
const resultChangelog = buildChangelog(prs, { const resultChangelog = buildChangelog(DefaultDiffInfo, prs, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -190,14 +193,15 @@ it('Extract label from title, split regex', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -221,14 +225,15 @@ it('Extract label from title, match', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -247,14 +252,15 @@ it('Extract label from title, match multiple', async () => {
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -274,14 +280,15 @@ it('Extract label from title, match multiple, custon non matching label', async
} }
] ]
const resultChangelog = buildChangelog(mergedPullRequests, { const resultChangelog = buildChangelog(DefaultDiffInfo, mergedPullRequests, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration configuration
}) })
@@ -388,14 +395,15 @@ it('Match multiple labels exhaustive for category', async () => {
} }
] ]
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -413,14 +421,15 @@ it('Deduplicate duplicated PRs', async () => {
method: 'match' method: 'match'
} }
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -439,14 +448,15 @@ it('Deduplicate duplicated PRs DESC', async () => {
method: 'match' method: 'match'
} }
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -471,14 +481,15 @@ it('Use empty_content for empty category', async () => {
} }
] ]
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
@@ -493,14 +504,15 @@ it('Commit SHA-1 in commitMode', async () => {
customConfig.sort = "DESC" customConfig.sort = "DESC"
customConfig.pr_template = "${{MERGE_SHA}}" customConfig.pr_template = "${{MERGE_SHA}}"
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: true, commitMode: true,
configuration: customConfig configuration: customConfig
}) })
@@ -512,22 +524,23 @@ it('Commit SHA-1 in commitMode', async () => {
it('Release Diff', async () => { it('Release Diff', async () => {
const customConfig = Object.assign({}, DefaultConfiguration) const customConfig = Object.assign({}, DefaultConfiguration)
customConfig.template = "${{RELEASE_DIFF}}" customConfig.template = "${{RELEASE_DIFF}}\n${{DAYS_SINCE}}"
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'release-changelog-builder-action', repo: 'release-changelog-builder-action',
fromTag: 'v2.8.0', fromTag: { name: 'v2.8.0' },
toTag: 'v2.8.1', toTag: { name: 'v2.8.1' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: true,
commitMode: true, commitMode: true,
configuration: customConfig configuration: customConfig
}) })
expect(resultChangelog).toStrictEqual( expect(resultChangelog).toStrictEqual(
`https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1` `https://github.com/mikepenz/release-changelog-builder-action/compare/v2.8.0...v2.8.1\n`
) )
}) })
@@ -553,14 +566,15 @@ it('Use exclude labels to not include a PR within a category.', async () => {
} }
] ]
const resultChangelog = buildChangelog(pullRequestsWithLabels, { const resultChangelog = buildChangelog(DefaultDiffInfo, pullRequestsWithLabels, {
owner: 'mikepenz', owner: 'mikepenz',
repo: 'test-repo', repo: 'test-repo',
fromTag: '1.0.0', fromTag: { name: '1.0.0' },
toTag: '2.0.0', toTag: { name: '2.0.0' },
includeOpen: false, includeOpen: false,
failOnError: false, failOnError: false,
fetchReviewers: false, fetchReviewers: false,
fetchReleaseInformation: false,
commitMode: false, commitMode: false,
configuration: customConfig configuration: customConfig
}) })
+3
View File
@@ -29,6 +29,9 @@ inputs:
fetchReviewers: fetchReviewers:
description: 'Will enable fetching the users/reviewers who approved the PR' description: 'Will enable fetching the users/reviewers who approved the PR'
default: "false" default: "false"
fetchReleaseInformation:
description: 'Will enable fetching release information for the tags. E.g. creation date'
default: "false"
commitMode: commitMode:
description: 'Enables a `light` commit based mode. This mode generates changelogs based on the commits. Please note that this is not officially supported, and lacks a lot of features only possible with PRs.' description: 'Enables a `light` commit based mode. This mode generates changelogs based on the commits. Please note that this is not officially supported, and lacks a lot of features only possible with PRs.'
default: "false" default: "false"
+1 -1
View File
@@ -1,4 +1,4 @@
{ {
"template": "${{CHANGELOG}}", "template": "${{CHANGELOG}}\n\n${{DAYS_SINCE}}",
"pr_template": "- ${{TITLE}} -- (#${{NUMBER}}) [${{STATUS}}] ${{REVIEWERS}} --- ${{APPROVERS}}" "pr_template": "- ${{TITLE}} -- (#${{NUMBER}}) [${{STATUS}}] ${{REVIEWERS}} --- ${{APPROVERS}}"
} }
@@ -1,6 +1,6 @@
{ {
"template": "${{CHANGELOG}}\n${{UNCATEGORIZED}}\n${{IGNORED}}\n${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}\n${{CATEGORIZED_COUNT}}\n${{UNCATEGORIZED_COUNT}}\n${{IGNORED_COUNT}}", "template": "${{CHANGELOG}}\n${{UNCATEGORIZED}}\n${{IGNORED}}\n${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}\n${{RELEASE_DIFF}}\n${{CATEGORIZED_COUNT}}\n${{UNCATEGORIZED_COUNT}}\n${{IGNORED_COUNT}}\n${{CHANGED_FILES}}\n${{ADDITIONS}}\n${{DELETIONS}}\n${{CHANGES}}\n${{COMMITS}}",
"empty_template": "${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}", "empty_template": "${{OWNER}}\n${{REPO}}\n${{FROM_TAG}}\n${{TO_TAG}}\n${{RELEASE_DIFF}}",
"max_pull_requests": 1000, "max_pull_requests": 1000,
"max_back_track_time_days": 1000 "max_back_track_time_days": 1000
} }
Generated Vendored
+171 -55
View File
@@ -42,21 +42,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.filterCommits = exports.Commits = void 0; exports.filterCommits = exports.Commits = exports.DefaultDiffInfo = void 0;
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const moment_1 = __importDefault(__nccwpck_require__(9623)); const moment_1 = __importDefault(__nccwpck_require__(9623));
exports.DefaultDiffInfo = {
changedFiles: 0,
additions: 0,
deletions: 0,
changes: 0,
commits: 0,
commitInfo: []
};
class Commits { class Commits {
constructor(octokit) { constructor(octokit) {
this.octokit = octokit; this.octokit = octokit;
} }
getDiff(owner, repo, base, head) { getDiff(owner, repo, base, head) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const commits = yield this.getDiffRemote(owner, repo, base, head); const diff = yield this.getDiffRemote(owner, repo, base, head);
return this.sortCommits(commits); diff.commitInfo = this.sortCommits(diff.commitInfo);
return diff;
}); });
} }
getDiffRemote(owner, repo, base, head) { getDiffRemote(owner, repo, base, head) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let changedFilesCount = 0;
let additionCount = 0;
let deletionCount = 0;
let changeCount = 0;
let commitCount = 0;
// Fetch comparisons recursively until we don't find any commits // Fetch comparisons recursively until we don't find any commits
// This is because the GitHub API limits the number of commits returned in a single response. // This is because the GitHub API limits the number of commits returned in a single response.
let commits = []; let commits = [];
@@ -72,23 +87,40 @@ class Commits {
if (compareResult.data.total_commits === 0) { if (compareResult.data.total_commits === 0) {
break; break;
} }
changedFilesCount += (_b = (_a = compareResult.data.files) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
const files = compareResult.data.files;
if (files !== undefined) {
for (const file of files) {
additionCount += file.additions;
deletionCount += file.deletions;
changeCount += file.changes;
}
}
commitCount += compareResult.data.commits.length;
commits = compareResult.data.commits.concat(commits); commits = compareResult.data.commits.concat(commits);
compareHead = `${commits[0].sha}^`; compareHead = `${commits[0].sha}^`;
} }
core.info(`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`); core.info(`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`);
return commits return {
.filter(commit => commit.sha) changedFiles: changedFilesCount,
.map(commit => { additions: additionCount,
var _a, _b; deletions: deletionCount,
return ({ changes: changeCount,
sha: commit.sha || '', commits: commitCount,
summary: commit.commit.message.split('\n')[0], commitInfo: commits
message: commit.commit.message, .filter(commit => commit.sha)
date: (0, moment_1.default)((_a = commit.commit.committer) === null || _a === void 0 ? void 0 : _a.date), .map(commit => {
author: ((_b = commit.commit.author) === null || _b === void 0 ? void 0 : _b.name) || '', var _a, _b;
prNumber: undefined return ({
}); sha: commit.sha || '',
}); summary: commit.commit.message.split('\n')[0],
message: commit.commit.message,
date: (0, moment_1.default)((_a = commit.commit.committer) === null || _a === void 0 ? void 0 : _a.date),
author: ((_b = commit.commit.author) === null || _b === void 0 ? void 0 : _b.name) || '',
prNumber: undefined
});
})
};
}); });
} }
sortCommits(commits) { sortCommits(commits) {
@@ -275,6 +307,16 @@ class GitCommandManager {
return revListOutput.stdout.trim(); return revListOutput.stdout.trim();
}); });
} }
tagCreation(tagName) {
return __awaiter(this, void 0, void 0, function* () {
const creationDate = yield this.execGit([
'for-each-ref',
'--format="%(creatordate:rfc)"',
`refs/tags/${tagName}`
]);
return creationDate.stdout.trim().replace(/"/g, '');
});
}
static createCommandManager(workingDirectory) { static createCommandManager(workingDirectory) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const result = new GitCommandManager(); const result = new GitCommandManager();
@@ -385,8 +427,9 @@ function run() {
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true'; const ignorePreReleases = core.getInput('ignorePreReleases') === 'true';
const failOnError = core.getInput('failOnError') === 'true'; const failOnError = core.getInput('failOnError') === 'true';
const fetchReviewers = core.getInput('fetchReviewers') === 'true'; const fetchReviewers = core.getInput('fetchReviewers') === 'true';
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true';
const commitMode = core.getInput('commitMode') === 'true'; const commitMode = core.getInput('commitMode') === 'true';
const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, fetchReviewers, commitMode, configuration).build(); const result = yield new releaseNotesBuilder_1.ReleaseNotesBuilder(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen, failOnError, ignorePreReleases, fetchReviewers, fetchReleaseInformation, commitMode, configuration).build();
core.setOutput('changelog', result); core.setOutput('changelog', result);
// write the result in changelog to file if possible // write the result in changelog to file if possible
const outputFile = core.getInput('outputFile'); const outputFile = core.getInput('outputFile');
@@ -718,9 +761,12 @@ class ReleaseNotes {
pull() { pull() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let mergedPullRequests; let mergedPullRequests;
let diffInfo;
if (!this.options.commitMode) { if (!this.options.commitMode) {
core.startGroup(`🚀 Load pull requests`); core.startGroup(`🚀 Load pull requests`);
mergedPullRequests = yield this.getMergedPullRequests(this.octokit); const [info, prs] = yield this.getMergedPullRequests(this.octokit);
mergedPullRequests = prs;
diffInfo = info;
// define the included PRs within this release as output // define the included PRs within this release as output
core.setOutput('pull_requests', mergedPullRequests core.setOutput('pull_requests', mergedPullRequests
.map(pr => { .map(pr => {
@@ -732,15 +778,23 @@ class ReleaseNotes {
else { else {
core.startGroup(`🚀 Load commit history`); core.startGroup(`🚀 Load commit history`);
core.info(`⚠️ Executing experimental commit mode`); core.info(`⚠️ Executing experimental commit mode`);
mergedPullRequests = yield this.generateCommitPRs(this.octokit); const [info, prs] = yield this.generateCommitPRs(this.octokit);
mergedPullRequests = prs;
diffInfo = info;
core.endGroup(); core.endGroup();
} }
core.setOutput('changed_files', diffInfo.changedFiles);
core.setOutput('additions', diffInfo.additions);
core.setOutput('deletions', diffInfo.deletions);
core.setOutput('changes', diffInfo.changes);
core.setOutput('commits', diffInfo.commits);
if (mergedPullRequests.length === 0) { if (mergedPullRequests.length === 0) {
core.warning(`⚠️ No pull requests found`); core.warning(`⚠️ No pull requests found`);
return null; return (0, transform_1.fillAdditionalPlaceholders)(this.options.configuration.empty_template ||
configuration_1.DefaultConfiguration.empty_template, this.options);
} }
core.startGroup('📦 Build changelog'); core.startGroup('📦 Build changelog');
const resultChangelog = (0, transform_1.buildChangelog)(mergedPullRequests, this.options); const resultChangelog = (0, transform_1.buildChangelog)(diffInfo, mergedPullRequests, this.options);
core.endGroup(); core.endGroup();
return resultChangelog; return resultChangelog;
}); });
@@ -748,29 +802,30 @@ class ReleaseNotes {
getCommitHistory(octokit) { getCommitHistory(octokit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { owner, repo, fromTag, toTag, failOnError } = this.options; const { owner, repo, fromTag, toTag, failOnError } = this.options;
core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`); core.info(`️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`);
const commitsApi = new commits_1.Commits(octokit); const commitsApi = new commits_1.Commits(octokit);
let commits; let diffInfo;
try { try {
commits = yield commitsApi.getDiff(owner, repo, fromTag, toTag); diffInfo = yield commitsApi.getDiff(owner, repo, fromTag.name, toTag.name);
} }
catch (error) { catch (error) {
(0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError); (0, utils_1.failOrError)(`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, failOnError);
return []; return commits_1.DefaultDiffInfo;
} }
if (commits.length === 0) { if (diffInfo.commitInfo.length === 0) {
core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`); core.warning(`⚠️ No commits found between - ${fromTag.name}...${toTag.name}`);
return []; return commits_1.DefaultDiffInfo;
} }
return commits; return diffInfo;
}); });
} }
getMergedPullRequests(octokit) { getMergedPullRequests(octokit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { owner, repo, includeOpen, fetchReviewers, configuration } = this.options; const { owner, repo, includeOpen, fetchReviewers, configuration } = this.options;
const commits = yield this.getCommitHistory(octokit); const diffInfo = yield this.getCommitHistory(octokit);
const commits = diffInfo.commitInfo;
if (commits.length === 0) { if (commits.length === 0) {
return []; return [diffInfo, []];
} }
const firstCommit = commits[0]; const firstCommit = commits[0];
const lastCommit = commits[commits.length - 1]; const lastCommit = commits[commits.length - 1];
@@ -832,20 +887,24 @@ class ReleaseNotes {
} }
} }
} }
return finalPrs; else {
core.debug(`️ Fetching reviewers was disabled`);
}
return [diffInfo, finalPrs];
}); });
} }
generateCommitPRs(octokit) { generateCommitPRs(octokit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { owner, repo, configuration } = this.options; const { owner, repo, configuration } = this.options;
const commits = yield this.getCommitHistory(octokit); const diffInfo = yield this.getCommitHistory(octokit);
const commits = diffInfo.commitInfo;
if (commits.length === 0) { if (commits.length === 0) {
return []; return [diffInfo, []];
} }
const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches || const prCommits = (0, commits_1.filterCommits)(commits, configuration.exclude_merge_branches ||
configuration_1.DefaultConfiguration.exclude_merge_branches); configuration_1.DefaultConfiguration.exclude_merge_branches);
core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`); core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`);
return prCommits.map(function (commit) { const prs = prCommits.map(function (commit) {
return { return {
number: 0, number: 0,
title: commit.summary, title: commit.summary,
@@ -865,6 +924,7 @@ class ReleaseNotes {
status: 'merged' status: 'merged'
}; };
}); });
return [diffInfo, prs];
}); });
} }
} }
@@ -918,9 +978,8 @@ const rest_1 = __nccwpck_require__(5375);
const releaseNotes_1 = __nccwpck_require__(5882); const releaseNotes_1 = __nccwpck_require__(5882);
const tags_1 = __nccwpck_require__(7532); const tags_1 = __nccwpck_require__(7532);
const utils_1 = __nccwpck_require__(918); const utils_1 = __nccwpck_require__(918);
const transform_1 = __nccwpck_require__(1644);
class ReleaseNotesBuilder { class ReleaseNotesBuilder {
constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, commitMode, configuration) { constructor(baseUrl, token, repositoryPath, owner, repo, fromTag, toTag, includeOpen = false, failOnError, ignorePreReleases, fetchReviewers = false, fetchReleaseInformation = false, commitMode, configuration) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.token = token; this.token = token;
this.repositoryPath = repositoryPath; this.repositoryPath = repositoryPath;
@@ -932,11 +991,11 @@ class ReleaseNotesBuilder {
this.failOnError = failOnError; this.failOnError = failOnError;
this.ignorePreReleases = ignorePreReleases; this.ignorePreReleases = ignorePreReleases;
this.fetchReviewers = fetchReviewers; this.fetchReviewers = fetchReviewers;
this.fetchReleaseInformation = fetchReleaseInformation;
this.commitMode = commitMode; this.commitMode = commitMode;
this.configuration = configuration; this.configuration = configuration;
} }
build() { build() {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (!this.owner) { if (!this.owner) {
(0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'owner'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'owner'`, this.failOnError);
@@ -965,40 +1024,46 @@ class ReleaseNotesBuilder {
const tagsApi = new tags_1.Tags(octokit); const tagsApi = new tags_1.Tags(octokit);
const tagRange = yield tagsApi.retrieveRange(this.repositoryPath, this.owner, this.repo, this.fromTag, this.toTag, this.ignorePreReleases, this.configuration.max_tags_to_fetch || const tagRange = yield tagsApi.retrieveRange(this.repositoryPath, this.owner, this.repo, this.fromTag, this.toTag, this.ignorePreReleases, this.configuration.max_tags_to_fetch ||
configuration_1.DefaultConfiguration.max_tags_to_fetch, this.configuration.tag_resolver || configuration_1.DefaultConfiguration.tag_resolver); configuration_1.DefaultConfiguration.max_tags_to_fetch, this.configuration.tag_resolver || configuration_1.DefaultConfiguration.tag_resolver);
const thisTag = (_a = tagRange.to) === null || _a === void 0 ? void 0 : _a.name; let thisTag = tagRange.to;
if (!thisTag) { if (!thisTag) {
(0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError); (0, utils_1.failOrError)(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError);
return null; return null;
} }
else { else {
this.toTag = thisTag; core.setOutput('toTag', thisTag.name);
core.setOutput('toTag', thisTag); core.debug(`Resolved 'toTag' as ${thisTag.name}`);
core.debug(`Resolved 'toTag' as ${thisTag}`);
} }
const previousTag = (_b = tagRange.from) === null || _b === void 0 ? void 0 : _b.name; let previousTag = tagRange.from;
if (previousTag == null) { if (previousTag == null) {
(0, utils_1.failOrError)(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError); (0, utils_1.failOrError)(`💥 Unable to retrieve previous tag given ${this.toTag}`, this.failOnError);
return null; return null;
} }
this.fromTag = previousTag; core.setOutput('fromTag', previousTag.name);
core.setOutput('fromTag', previousTag); core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`);
core.debug(`fromTag resolved via previousTag as: ${previousTag}`); if (this.fetchReleaseInformation) {
// load release information from the GitHub API
core.info(`️ Fetching release information was enabled`);
thisTag = yield tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, thisTag);
previousTag = yield tagsApi.fillTagInformation(this.repositoryPath, this.owner, this.repo, previousTag);
}
else {
core.debug(`️ Fetching release information was disabled`);
}
core.endGroup(); core.endGroup();
const options = { const options = {
owner: this.owner, owner: this.owner,
repo: this.repo, repo: this.repo,
fromTag: this.fromTag, fromTag: previousTag,
toTag: this.toTag, toTag: thisTag,
includeOpen: this.includeOpen, includeOpen: this.includeOpen,
failOnError: this.failOnError, failOnError: this.failOnError,
fetchReviewers: this.fetchReviewers, fetchReviewers: this.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation,
commitMode: this.commitMode, commitMode: this.commitMode,
configuration: this.configuration configuration: this.configuration
}; };
const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options); const releaseNotes = new releaseNotes_1.ReleaseNotes(octokit, options);
return ((yield releaseNotes.pull()) || return yield releaseNotes.pull();
(0, transform_1.fillAdditionalPlaceholders)(this.configuration.empty_template ||
configuration_1.DefaultConfiguration.empty_template, options));
}); });
} }
} }
@@ -1051,6 +1116,9 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
}; };
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.sortTags = exports.filterTags = exports.Tags = void 0; exports.sortTags = exports.filterTags = exports.Tags = void 0;
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
@@ -1059,6 +1127,7 @@ const semver = __importStar(__nccwpck_require__(1383));
const semver_1 = __nccwpck_require__(1383); const semver_1 = __nccwpck_require__(1383);
const gitHelper_1 = __nccwpck_require__(353); const gitHelper_1 = __nccwpck_require__(353);
const transform_1 = __nccwpck_require__(1644); const transform_1 = __nccwpck_require__(1644);
const moment_1 = __importDefault(__nccwpck_require__(9623));
class Tags { class Tags {
constructor(octokit) { constructor(octokit) {
this.octokit = octokit; this.octokit = octokit;
@@ -1100,6 +1169,35 @@ class Tags {
return tagsInfo; return tagsInfo;
}); });
} }
fillTagInformation(repositoryPath, owner, repo, tagInfo) {
return __awaiter(this, void 0, void 0, function* () {
const options = this.octokit.repos.getReleaseByTag.endpoint.merge({
owner,
repo,
tag: tagInfo.name
});
try {
const response = yield this.octokit.request(options);
const release = response.data;
tagInfo.date = (0, moment_1.default)(release.created_at);
core.info(`️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`);
}
catch (error) {
core.info(`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`);
const gitHelper = yield (0, gitHelper_1.createCommandManager)(repositoryPath);
const creationTimeString = yield gitHelper.tagCreation(tagInfo.name);
const creationTime = (0, moment_1.default)(creationTimeString);
if (creationTimeString !== null && creationTime.isValid()) {
tagInfo.date = creationTime;
core.info(`️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}`);
}
else {
core.info(`⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'`);
}
}
return tagInfo;
});
}
findPredecessorTag(sortedTags, repositoryPath, tag, ignorePreReleases) { findPredecessorTag(sortedTags, repositoryPath, tag, ignorePreReleases) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const tags = sortedTags; const tags = sortedTags;
@@ -1364,7 +1462,7 @@ exports.validateTransformer = exports.fillAdditionalPlaceholders = exports.build
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const configuration_1 = __nccwpck_require__(5527); const configuration_1 = __nccwpck_require__(5527);
const pullRequests_1 = __nccwpck_require__(4217); const pullRequests_1 = __nccwpck_require__(4217);
function buildChangelog(prs, options) { function buildChangelog(diffInfo, prs, options) {
// sort to target order // sort to target order
const config = options.configuration; const config = options.configuration;
const sort = config.sort || configuration_1.DefaultConfiguration.sort; const sort = config.sort || configuration_1.DefaultConfiguration.sort;
@@ -1546,18 +1644,36 @@ function buildChangelog(prs, options) {
transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString()); transformedChangelog = transformedChangelog.replace(/\${{UNCATEGORIZED_COUNT}}/g, uncategorizedPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString()); transformedChangelog = transformedChangelog.replace(/\${{OPEN_COUNT}}/g, openPrs.length.toString());
transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString()); transformedChangelog = transformedChangelog.replace(/\${{IGNORED_COUNT}}/g, ignoredPrs.length.toString());
// code change placeholders
transformedChangelog = transformedChangelog.replace(/\${{CHANGED_FILES}}/g, diffInfo.changedFiles.toString());
transformedChangelog = transformedChangelog.replace(/\${{ADDITIONS}}/g, diffInfo.additions.toString());
transformedChangelog = transformedChangelog.replace(/\${{DELETIONS}}/g, diffInfo.deletions.toString());
transformedChangelog = transformedChangelog.replace(/\${{CHANGES}}/g, diffInfo.changes.toString());
transformedChangelog = transformedChangelog.replace(/\${{COMMITS}}/g, diffInfo.commits.toString());
transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options); transformedChangelog = fillAdditionalPlaceholders(transformedChangelog, options);
core.info(`️ Filled template`); core.info(`️ Filled template`);
return transformedChangelog; return transformedChangelog;
} }
exports.buildChangelog = buildChangelog; exports.buildChangelog = buildChangelog;
function fillAdditionalPlaceholders(text, options) { function fillAdditionalPlaceholders(text, options) {
var _a, _b;
let transformed = text; let transformed = text;
// repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner); transformed = transformed.replace(/\${{OWNER}}/g, options.owner);
transformed = transformed.replace(/\${{REPO}}/g, options.repo); transformed = transformed.replace(/\${{REPO}}/g, options.repo);
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag); transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name);
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag); transformed = transformed.replace(/\${{FROM_TAG_DATE}}/g, ((_a = options.fromTag.date) === null || _a === void 0 ? void 0 : _a.toISOString()) || '');
transformed = transformed.replace(/\${{RELEASE_DIFF}}/g, `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag}...${options.toTag}`); transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag.name);
transformed = transformed.replace(/\${{TO_TAG_DATE}}/g, ((_b = options.toTag.date) === null || _b === void 0 ? void 0 : _b.toISOString()) || '');
const fromDate = options.fromTag.date;
const toDate = options.toTag.date;
if (fromDate !== undefined && toDate !== undefined) {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, toDate.diff(fromDate, 'days').toString() || '');
}
else {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, '');
}
transformed = transformed.replace(/\${{RELEASE_DIFF}}/g, `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`);
return transformed; return transformed;
} }
exports.fillAdditionalPlaceholders = fillAdditionalPlaceholders; exports.fillAdditionalPlaceholders = fillAdditionalPlaceholders;
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+438 -40
View File
@@ -17,15 +17,15 @@
"moment": "^2.29.4", "moment": "^2.29.4",
"semver": "^7.3.7", "semver": "^7.3.7",
"tunnel": "^0.0.6", "tunnel": "^0.0.6",
"webpack": "^5.73.0" "webpack": "^5.74.0"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^28.1.6", "@types/jest": "^28.1.6",
"@types/node": "^18.0.6", "@types/node": "^18.6.1",
"@typescript-eslint/parser": "^5.30.7", "@typescript-eslint/parser": "^5.31.0",
"@vercel/ncc": "^0.34.0", "@vercel/ncc": "^0.34.0",
"eslint": "^8.20.0", "eslint": "^8.20.0",
"eslint-plugin-github": "^4.3.6", "eslint-plugin-github": "^4.3.7",
"eslint-plugin-jest": "^26.6.0", "eslint-plugin-jest": "^26.6.0",
"jest": "^28.1.3", "jest": "^28.1.3",
"jest-circus": "^28.1.3", "jest-circus": "^28.1.3",
@@ -592,6 +592,31 @@
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
}, },
"node_modules/@babel/runtime": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/runtime-corejs3": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz",
"integrity": "sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==",
"dev": true,
"dependencies": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.18.6", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz",
@@ -1569,9 +1594,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.0.6", "version": "18.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.1.tgz",
"integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==" "integrity": "sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg=="
}, },
"node_modules/@types/prettier": { "node_modules/@types/prettier": {
"version": "2.6.3", "version": "2.6.3",
@@ -1639,14 +1664,14 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "5.30.7", "version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.7.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz",
"integrity": "sha512-Rg5xwznHWWSy7v2o0cdho6n+xLhK2gntImp0rJroVVFkcYFYQ8C8UJTSuTw/3CnExBmPjycjmUJkxVmjXsld6A==", "integrity": "sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "5.30.7", "@typescript-eslint/scope-manager": "5.31.0",
"@typescript-eslint/types": "5.30.7", "@typescript-eslint/types": "5.31.0",
"@typescript-eslint/typescript-estree": "5.30.7", "@typescript-eslint/typescript-estree": "5.31.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -1665,6 +1690,80 @@
} }
} }
}, },
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz",
"integrity": "sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.31.0",
"@typescript-eslint/visitor-keys": "5.31.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz",
"integrity": "sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz",
"integrity": "sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.31.0",
"@typescript-eslint/visitor-keys": "5.31.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz",
"integrity": "sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.31.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "5.30.7", "version": "5.30.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.7.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.7.tgz",
@@ -2082,6 +2181,19 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true "dev": true
}, },
"node_modules/aria-query": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
"integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.10.2",
"@babel/runtime-corejs3": "^7.10.2"
},
"engines": {
"node": ">=6.0"
}
},
"node_modules/array-includes": { "node_modules/array-includes": {
"version": "3.1.5", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
@@ -2128,6 +2240,27 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
"dev": true
},
"node_modules/axe-core": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
"integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
"integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
"dev": true
},
"node_modules/babel-jest": { "node_modules/babel-jest": {
"version": "28.1.3", "version": "28.1.3",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz",
@@ -2461,6 +2594,17 @@
"safe-buffer": "~5.1.1" "safe-buffer": "~5.1.1"
} }
}, },
"node_modules/core-js-pure": {
"version": "3.24.0",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.0.tgz",
"integrity": "sha512-uzMmW8cRh7uYw4JQtzqvGWRyC2T5+4zipQLQdi2FmiRqP83k3d6F3stv2iAlNhOs6cXN401FCD5TL0vvleuHgA==",
"dev": true,
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -2475,6 +2619,12 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
"dev": true
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -2869,9 +3019,9 @@
} }
}, },
"node_modules/eslint-plugin-github": { "node_modules/eslint-plugin-github": {
"version": "4.3.6", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.3.6.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.3.7.tgz",
"integrity": "sha512-W4l9CV1DdSaWYZXWiuH/v0bh3c55iFyyhw2EgIwdAeRxogn7svsI5MLBRA9YZ0cdQyekWMZUfAHEeFhDpOyzWg==", "integrity": "sha512-tYZdXvAEz4JCMrC4NHIUoJTsLUvydCxff5OqB5hgU0vQbLmMkw6VOipN2KNe+T06pEhAWs1KBEwyq9cmMWRe7A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/eslint-plugin": "^5.1.0",
@@ -2882,9 +3032,11 @@
"eslint-plugin-filenames": "^1.3.2", "eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-i18n-text": "^1.0.1", "eslint-plugin-i18n-text": "^1.0.1",
"eslint-plugin-import": "^2.25.2", "eslint-plugin-import": "^2.25.2",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-no-only-tests": "^2.6.0", "eslint-plugin-no-only-tests": "^2.6.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-rule-documentation": ">=1.0.0", "eslint-rule-documentation": ">=1.0.0",
"jsx-ast-utils": "^3.3.2",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"svg-element-attributes": "^1.3.1" "svg-element-attributes": "^1.3.1"
}, },
@@ -2982,6 +3134,48 @@
} }
} }
}, },
"node_modules/eslint-plugin-jsx-a11y": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz",
"integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.18.9",
"aria-query": "^4.2.2",
"array-includes": "^3.1.5",
"ast-types-flow": "^0.0.7",
"axe-core": "^4.4.3",
"axobject-query": "^2.2.0",
"damerau-levenshtein": "^1.0.8",
"emoji-regex": "^9.2.2",
"has": "^1.0.3",
"jsx-ast-utils": "^3.3.2",
"language-tags": "^1.0.5",
"minimatch": "^3.1.2",
"semver": "^6.3.0"
},
"engines": {
"node": ">=4.0"
},
"peerDependencies": {
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-no-only-tests": { "node_modules/eslint-plugin-no-only-tests": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-2.6.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-2.6.0.tgz",
@@ -4619,6 +4813,19 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/jsx-ast-utils": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz",
"integrity": "sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==",
"dev": true,
"dependencies": {
"array-includes": "^3.1.5",
"object.assign": "^4.1.2"
},
"engines": {
"node": ">=4.0"
}
},
"node_modules/kleur": { "node_modules/kleur": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@@ -4628,6 +4835,21 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/language-subtag-registry": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
"integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
"dev": true
},
"node_modules/language-tags": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
"integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
"dev": true,
"dependencies": {
"language-subtag-registry": "~0.3.2"
}
},
"node_modules/leven": { "node_modules/leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -5351,6 +5573,12 @@
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"dev": true "dev": true
}, },
"node_modules/regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
"dev": true
},
"node_modules/regexp.prototype.flags": { "node_modules/regexp.prototype.flags": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@@ -6195,20 +6423,20 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
}, },
"node_modules/webpack": { "node_modules/webpack": {
"version": "5.73.0", "version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
"dependencies": { "dependencies": {
"@types/eslint-scope": "^3.7.3", "@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51", "@types/estree": "^0.0.51",
"@webassemblyjs/ast": "1.11.1", "@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1",
"acorn": "^8.4.1", "acorn": "^8.7.1",
"acorn-import-assertions": "^1.7.6", "acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5", "browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2", "chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.9.3", "enhanced-resolve": "^5.10.0",
"es-module-lexer": "^0.9.0", "es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1", "eslint-scope": "5.1.1",
"events": "^3.2.0", "events": "^3.2.0",
@@ -6221,7 +6449,7 @@
"schema-utils": "^3.1.0", "schema-utils": "^3.1.0",
"tapable": "^2.1.1", "tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3", "terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1", "watchpack": "^2.4.0",
"webpack-sources": "^3.2.3" "webpack-sources": "^3.2.3"
}, },
"bin": { "bin": {
@@ -6836,6 +7064,25 @@
"@babel/helper-plugin-utils": "^7.18.6" "@babel/helper-plugin-utils": "^7.18.6"
} }
}, },
"@babel/runtime": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"@babel/runtime-corejs3": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz",
"integrity": "sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==",
"dev": true,
"requires": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
}
},
"@babel/template": { "@babel/template": {
"version": "7.18.6", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz",
@@ -7653,9 +7900,9 @@
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "18.0.6", "version": "18.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.1.tgz",
"integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==" "integrity": "sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg=="
}, },
"@types/prettier": { "@types/prettier": {
"version": "2.6.3", "version": "2.6.3",
@@ -7707,15 +7954,58 @@
} }
}, },
"@typescript-eslint/parser": { "@typescript-eslint/parser": {
"version": "5.30.7", "version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.7.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz",
"integrity": "sha512-Rg5xwznHWWSy7v2o0cdho6n+xLhK2gntImp0rJroVVFkcYFYQ8C8UJTSuTw/3CnExBmPjycjmUJkxVmjXsld6A==", "integrity": "sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/scope-manager": "5.30.7", "@typescript-eslint/scope-manager": "5.31.0",
"@typescript-eslint/types": "5.30.7", "@typescript-eslint/types": "5.31.0",
"@typescript-eslint/typescript-estree": "5.30.7", "@typescript-eslint/typescript-estree": "5.31.0",
"debug": "^4.3.4" "debug": "^4.3.4"
},
"dependencies": {
"@typescript-eslint/scope-manager": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz",
"integrity": "sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.31.0",
"@typescript-eslint/visitor-keys": "5.31.0"
}
},
"@typescript-eslint/types": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz",
"integrity": "sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz",
"integrity": "sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.31.0",
"@typescript-eslint/visitor-keys": "5.31.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz",
"integrity": "sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.31.0",
"eslint-visitor-keys": "^3.3.0"
}
}
} }
}, },
"@typescript-eslint/scope-manager": { "@typescript-eslint/scope-manager": {
@@ -8032,6 +8322,16 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true "dev": true
}, },
"aria-query": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
"integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.10.2",
"@babel/runtime-corejs3": "^7.10.2"
}
},
"array-includes": { "array-includes": {
"version": "3.1.5", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
@@ -8063,6 +8363,24 @@
"es-shim-unscopables": "^1.0.0" "es-shim-unscopables": "^1.0.0"
} }
}, },
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
"dev": true
},
"axe-core": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
"integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==",
"dev": true
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
"integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
"dev": true
},
"babel-jest": { "babel-jest": {
"version": "28.1.3", "version": "28.1.3",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz",
@@ -8315,6 +8633,12 @@
"safe-buffer": "~5.1.1" "safe-buffer": "~5.1.1"
} }
}, },
"core-js-pure": {
"version": "3.24.0",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.0.tgz",
"integrity": "sha512-uzMmW8cRh7uYw4JQtzqvGWRyC2T5+4zipQLQdi2FmiRqP83k3d6F3stv2iAlNhOs6cXN401FCD5TL0vvleuHgA==",
"dev": true
},
"cross-spawn": { "cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -8326,6 +8650,12 @@
"which": "^2.0.1" "which": "^2.0.1"
} }
}, },
"damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
"dev": true
},
"debug": { "debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -8632,9 +8962,9 @@
} }
}, },
"eslint-plugin-github": { "eslint-plugin-github": {
"version": "4.3.6", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.3.6.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.3.7.tgz",
"integrity": "sha512-W4l9CV1DdSaWYZXWiuH/v0bh3c55iFyyhw2EgIwdAeRxogn7svsI5MLBRA9YZ0cdQyekWMZUfAHEeFhDpOyzWg==", "integrity": "sha512-tYZdXvAEz4JCMrC4NHIUoJTsLUvydCxff5OqB5hgU0vQbLmMkw6VOipN2KNe+T06pEhAWs1KBEwyq9cmMWRe7A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/eslint-plugin": "^5.1.0",
@@ -8645,9 +8975,11 @@
"eslint-plugin-filenames": "^1.3.2", "eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-i18n-text": "^1.0.1", "eslint-plugin-i18n-text": "^1.0.1",
"eslint-plugin-import": "^2.25.2", "eslint-plugin-import": "^2.25.2",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-no-only-tests": "^2.6.0", "eslint-plugin-no-only-tests": "^2.6.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-rule-documentation": ">=1.0.0", "eslint-rule-documentation": ">=1.0.0",
"jsx-ast-utils": "^3.3.2",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"svg-element-attributes": "^1.3.1" "svg-element-attributes": "^1.3.1"
} }
@@ -8715,6 +9047,41 @@
"@typescript-eslint/utils": "^5.10.0" "@typescript-eslint/utils": "^5.10.0"
} }
}, },
"eslint-plugin-jsx-a11y": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz",
"integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==",
"dev": true,
"requires": {
"@babel/runtime": "^7.18.9",
"aria-query": "^4.2.2",
"array-includes": "^3.1.5",
"ast-types-flow": "^0.0.7",
"axe-core": "^4.4.3",
"axobject-query": "^2.2.0",
"damerau-levenshtein": "^1.0.8",
"emoji-regex": "^9.2.2",
"has": "^1.0.3",
"jsx-ast-utils": "^3.3.2",
"language-tags": "^1.0.5",
"minimatch": "^3.1.2",
"semver": "^6.3.0"
},
"dependencies": {
"emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"eslint-plugin-no-only-tests": { "eslint-plugin-no-only-tests": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-2.6.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-2.6.0.tgz",
@@ -9909,12 +10276,37 @@
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"dev": true "dev": true
}, },
"jsx-ast-utils": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz",
"integrity": "sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==",
"dev": true,
"requires": {
"array-includes": "^3.1.5",
"object.assign": "^4.1.2"
}
},
"kleur": { "kleur": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true "dev": true
}, },
"language-subtag-registry": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
"integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
"dev": true
},
"language-tags": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
"integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
"dev": true,
"requires": {
"language-subtag-registry": "~0.3.2"
}
},
"leven": { "leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -10444,6 +10836,12 @@
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"dev": true "dev": true
}, },
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
"dev": true
},
"regexp.prototype.flags": { "regexp.prototype.flags": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@@ -11024,20 +11422,20 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
}, },
"webpack": { "webpack": {
"version": "5.73.0", "version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
"requires": { "requires": {
"@types/eslint-scope": "^3.7.3", "@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51", "@types/estree": "^0.0.51",
"@webassemblyjs/ast": "1.11.1", "@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1",
"acorn": "^8.4.1", "acorn": "^8.7.1",
"acorn-import-assertions": "^1.7.6", "acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5", "browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2", "chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.9.3", "enhanced-resolve": "^5.10.0",
"es-module-lexer": "^0.9.0", "es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1", "eslint-scope": "5.1.1",
"events": "^3.2.0", "events": "^3.2.0",
@@ -11050,7 +11448,7 @@
"schema-utils": "^3.1.0", "schema-utils": "^3.1.0",
"tapable": "^2.1.1", "tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3", "terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1", "watchpack": "^2.4.0",
"webpack-sources": "^3.2.3" "webpack-sources": "^3.2.3"
}, },
"dependencies": { "dependencies": {
+4 -4
View File
@@ -40,15 +40,15 @@
"moment": "^2.29.4", "moment": "^2.29.4",
"semver": "^7.3.7", "semver": "^7.3.7",
"tunnel": "^0.0.6", "tunnel": "^0.0.6",
"webpack": "^5.73.0" "webpack": "^5.74.0"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^28.1.6", "@types/jest": "^28.1.6",
"@types/node": "^18.0.6", "@types/node": "^18.6.1",
"@typescript-eslint/parser": "^5.30.7", "@typescript-eslint/parser": "^5.31.0",
"@vercel/ncc": "^0.34.0", "@vercel/ncc": "^0.34.0",
"eslint": "^8.20.0", "eslint": "^8.20.0",
"eslint-plugin-github": "^4.3.6", "eslint-plugin-github": "^4.3.7",
"eslint-plugin-jest": "^26.6.0", "eslint-plugin-jest": "^26.6.0",
"jest": "^28.1.3", "jest": "^28.1.3",
"jest-circus": "^28.1.3", "jest-circus": "^28.1.3",
+56 -19
View File
@@ -2,6 +2,24 @@ import * as core from '@actions/core'
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest' import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
import moment from 'moment' import moment from 'moment'
export interface DiffInfo {
changedFiles: number
additions: number
deletions: number
changes: number
commits: number
commitInfo: CommitInfo[]
}
export const DefaultDiffInfo: DiffInfo = {
changedFiles: 0,
additions: 0,
deletions: 0,
changes: 0,
commits: 0,
commitInfo: []
}
export interface CommitInfo { export interface CommitInfo {
sha: string sha: string
summary: string summary: string
@@ -18,14 +36,10 @@ export class Commits {
repo: string, repo: string,
base: string, base: string,
head: string head: string
): Promise<CommitInfo[]> { ): Promise<DiffInfo> {
const commits: CommitInfo[] = await this.getDiffRemote( const diff: DiffInfo = await this.getDiffRemote(owner, repo, base, head)
owner, diff.commitInfo = this.sortCommits(diff.commitInfo)
repo, return diff
base,
head
)
return this.sortCommits(commits)
} }
private async getDiffRemote( private async getDiffRemote(
@@ -33,7 +47,13 @@ export class Commits {
repo: string, repo: string,
base: string, base: string,
head: string head: string
): Promise<CommitInfo[]> { ): Promise<DiffInfo> {
let changedFilesCount = 0
let additionCount = 0
let deletionCount = 0
let changeCount = 0
let commitCount = 0
// Fetch comparisons recursively until we don't find any commits // Fetch comparisons recursively until we don't find any commits
// This is because the GitHub API limits the number of commits returned in a single response. // This is because the GitHub API limits the number of commits returned in a single response.
let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] = let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] =
@@ -50,6 +70,16 @@ export class Commits {
if (compareResult.data.total_commits === 0) { if (compareResult.data.total_commits === 0) {
break break
} }
changedFilesCount += compareResult.data.files?.length ?? 0
const files = compareResult.data.files
if (files !== undefined) {
for (const file of files) {
additionCount += file.additions
deletionCount += file.deletions
changeCount += file.changes
}
}
commitCount += compareResult.data.commits.length
commits = compareResult.data.commits.concat(commits) commits = compareResult.data.commits.concat(commits)
compareHead = `${commits[0].sha}^` compareHead = `${commits[0].sha}^`
} }
@@ -58,16 +88,23 @@ export class Commits {
`️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}` `️ Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`
) )
return commits return {
.filter(commit => commit.sha) changedFiles: changedFilesCount,
.map(commit => ({ additions: additionCount,
sha: commit.sha || '', deletions: deletionCount,
summary: commit.commit.message.split('\n')[0], changes: changeCount,
message: commit.commit.message, commits: commitCount,
date: moment(commit.commit.committer?.date), commitInfo: commits
author: commit.commit.author?.name || '', .filter(commit => commit.sha)
prNumber: undefined .map(commit => ({
})) sha: commit.sha || '',
summary: commit.commit.message.split('\n')[0],
message: commit.commit.message,
date: moment(commit.commit.committer?.date),
author: commit.commit.author?.name || '',
prNumber: undefined
}))
}
} }
private sortCommits(commits: CommitInfo[]): CommitInfo[] { private sortCommits(commits: CommitInfo[]): CommitInfo[] {
+9
View File
@@ -44,6 +44,15 @@ class GitCommandManager {
return revListOutput.stdout.trim() return revListOutput.stdout.trim()
} }
async tagCreation(tagName: string): Promise<string> {
const creationDate = await this.execGit([
'for-each-ref',
'--format="%(creatordate:rfc)"',
`refs/tags/${tagName}`
])
return creationDate.stdout.trim().replace(/"/g, '')
}
static async createCommandManager( static async createCommandManager(
workingDirectory: string workingDirectory: string
): Promise<GitCommandManager> { ): Promise<GitCommandManager> {
+3
View File
@@ -36,6 +36,8 @@ async function run(): Promise<void> {
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true' const ignorePreReleases = core.getInput('ignorePreReleases') === 'true'
const failOnError = core.getInput('failOnError') === 'true' const failOnError = core.getInput('failOnError') === 'true'
const fetchReviewers = core.getInput('fetchReviewers') === 'true' const fetchReviewers = core.getInput('fetchReviewers') === 'true'
const fetchReleaseInformation =
core.getInput('fetchReleaseInformation') === 'true'
const commitMode = core.getInput('commitMode') === 'true' const commitMode = core.getInput('commitMode') === 'true'
const result = await new ReleaseNotesBuilder( const result = await new ReleaseNotesBuilder(
@@ -50,6 +52,7 @@ async function run(): Promise<void> {
failOnError, failOnError,
ignorePreReleases, ignorePreReleases,
fetchReviewers, fetchReviewers,
fetchReleaseInformation,
commitMode, commitMode,
configuration configuration
).build() ).build()
+57 -26
View File
@@ -1,19 +1,21 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import {CommitInfo, Commits, filterCommits} from './commits' import {Commits, filterCommits, DiffInfo, DefaultDiffInfo} from './commits'
import {Configuration, DefaultConfiguration} from './configuration' import {Configuration, DefaultConfiguration} from './configuration'
import {PullRequestInfo, PullRequests} from './pullRequests' import {PullRequestInfo, PullRequests} from './pullRequests'
import {Octokit} from '@octokit/rest' import {Octokit} from '@octokit/rest'
import {buildChangelog} from './transform' import {buildChangelog, fillAdditionalPlaceholders} from './transform'
import {failOrError} from './utils' import {failOrError} from './utils'
import {TagInfo} from './tags'
export interface ReleaseNotesOptions { export interface ReleaseNotesOptions {
owner: string // the owner of the repository owner: string // the owner of the repository
repo: string // the repository repo: string // the repository
fromTag: string // the tag/ref to start from fromTag: TagInfo // the tag/ref to start from
toTag: string // the tag/ref up to toTag: TagInfo // the tag/ref up to
includeOpen: boolean // defines if we should also fetch open pull requests includeOpen: boolean // defines if we should also fetch open pull requests
failOnError: boolean // defines if we should fail the action in case of an error failOnError: boolean // defines if we should fail the action in case of an error
fetchReviewers: boolean // defines if the action should fetch the reviewers for PRs - approved reviewers are not included in the default PR listing fetchReviewers: boolean // defines if the action should fetch the reviewers for PRs - approved reviewers are not included in the default PR listing
fetchReleaseInformation: boolean // defines if the action should fetch the release information for the from and to tag - e.g. the creation date for the associated release
commitMode: boolean // defines if we use the alternative commit based mode. note: this is only partially supported commitMode: boolean // defines if we use the alternative commit based mode. note: this is only partially supported
configuration: Configuration // the configuration as defined in `configuration.ts` configuration: Configuration // the configuration as defined in `configuration.ts`
} }
@@ -21,11 +23,15 @@ export interface ReleaseNotesOptions {
export class ReleaseNotes { export class ReleaseNotes {
constructor(private octokit: Octokit, private options: ReleaseNotesOptions) {} constructor(private octokit: Octokit, private options: ReleaseNotesOptions) {}
async pull(): Promise<string | null> { async pull(): Promise<string> {
let mergedPullRequests: PullRequestInfo[] let mergedPullRequests: PullRequestInfo[]
let diffInfo: DiffInfo
if (!this.options.commitMode) { if (!this.options.commitMode) {
core.startGroup(`🚀 Load pull requests`) core.startGroup(`🚀 Load pull requests`)
mergedPullRequests = await this.getMergedPullRequests(this.octokit)
const [info, prs] = await this.getMergedPullRequests(this.octokit)
mergedPullRequests = prs
diffInfo = info
// define the included PRs within this release as output // define the included PRs within this release as output
core.setOutput( core.setOutput(
@@ -41,53 +47,74 @@ export class ReleaseNotes {
} else { } else {
core.startGroup(`🚀 Load commit history`) core.startGroup(`🚀 Load commit history`)
core.info(`⚠️ Executing experimental commit mode`) core.info(`⚠️ Executing experimental commit mode`)
mergedPullRequests = await this.generateCommitPRs(this.octokit) const [info, prs] = await this.generateCommitPRs(this.octokit)
mergedPullRequests = prs
diffInfo = info
core.endGroup() core.endGroup()
} }
core.setOutput('changed_files', diffInfo.changedFiles)
core.setOutput('additions', diffInfo.additions)
core.setOutput('deletions', diffInfo.deletions)
core.setOutput('changes', diffInfo.changes)
core.setOutput('commits', diffInfo.commits)
if (mergedPullRequests.length === 0) { if (mergedPullRequests.length === 0) {
core.warning(`⚠️ No pull requests found`) core.warning(`⚠️ No pull requests found`)
return null return fillAdditionalPlaceholders(
this.options.configuration.empty_template ||
DefaultConfiguration.empty_template,
this.options
)
} }
core.startGroup('📦 Build changelog') core.startGroup('📦 Build changelog')
const resultChangelog = buildChangelog(mergedPullRequests, this.options) const resultChangelog = buildChangelog(
diffInfo,
mergedPullRequests,
this.options
)
core.endGroup() core.endGroup()
return resultChangelog return resultChangelog
} }
private async getCommitHistory(octokit: Octokit): Promise<CommitInfo[]> { private async getCommitHistory(octokit: Octokit): Promise<DiffInfo> {
const {owner, repo, fromTag, toTag, failOnError} = this.options const {owner, repo, fromTag, toTag, failOnError} = this.options
core.info(`️ Comparing ${owner}/${repo} - '${fromTag}...${toTag}'`) core.info(
`️ Comparing ${owner}/${repo} - '${fromTag.name}...${toTag.name}'`
)
const commitsApi = new Commits(octokit) const commitsApi = new Commits(octokit)
let commits: CommitInfo[] let diffInfo: DiffInfo
try { try {
commits = await commitsApi.getDiff(owner, repo, fromTag, toTag) diffInfo = await commitsApi.getDiff(owner, repo, fromTag.name, toTag.name)
} catch (error) { } catch (error) {
failOrError( failOrError(
`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`, `💥 Failed to retrieve - Invalid tag? - Because of: ${error}`,
failOnError failOnError
) )
return [] return DefaultDiffInfo
} }
if (commits.length === 0) { if (diffInfo.commitInfo.length === 0) {
core.warning(`⚠️ No commits found between - ${fromTag}...${toTag}`) core.warning(
return [] `⚠️ No commits found between - ${fromTag.name}...${toTag.name}`
)
return DefaultDiffInfo
} }
return commits return diffInfo
} }
private async getMergedPullRequests( private async getMergedPullRequests(
octokit: Octokit octokit: Octokit
): Promise<PullRequestInfo[]> { ): Promise<[DiffInfo, PullRequestInfo[]]> {
const {owner, repo, includeOpen, fetchReviewers, configuration} = const {owner, repo, includeOpen, fetchReviewers, configuration} =
this.options this.options
const commits = await this.getCommitHistory(octokit) const diffInfo = await this.getCommitHistory(octokit)
const commits = diffInfo.commitInfo
if (commits.length === 0) { if (commits.length === 0) {
return [] return [diffInfo, []]
} }
const firstCommit = commits[0] const firstCommit = commits[0]
@@ -191,19 +218,22 @@ export class ReleaseNotes {
) )
} }
} }
} else {
core.debug(`️ Fetching reviewers was disabled`)
} }
return finalPrs return [diffInfo, finalPrs]
} }
private async generateCommitPRs( private async generateCommitPRs(
octokit: Octokit octokit: Octokit
): Promise<PullRequestInfo[]> { ): Promise<[DiffInfo, PullRequestInfo[]]> {
const {owner, repo, configuration} = this.options const {owner, repo, configuration} = this.options
const commits = await this.getCommitHistory(octokit) const diffInfo = await this.getCommitHistory(octokit)
const commits = diffInfo.commitInfo
if (commits.length === 0) { if (commits.length === 0) {
return [] return [diffInfo, []]
} }
const prCommits = filterCommits( const prCommits = filterCommits(
@@ -214,7 +244,7 @@ export class ReleaseNotes {
core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`) core.info(`️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`)
return prCommits.map(function (commit): PullRequestInfo { const prs = prCommits.map(function (commit): PullRequestInfo {
return { return {
number: 0, number: 0,
title: commit.summary, title: commit.summary,
@@ -234,5 +264,6 @@ export class ReleaseNotes {
status: 'merged' status: 'merged'
} }
}) })
return [diffInfo, prs]
} }
} }
+31 -19
View File
@@ -4,7 +4,6 @@ import {Octokit} from '@octokit/rest'
import {ReleaseNotes} from './releaseNotes' import {ReleaseNotes} from './releaseNotes'
import {Tags} from './tags' import {Tags} from './tags'
import {failOrError} from './utils' import {failOrError} from './utils'
import {fillAdditionalPlaceholders} from './transform'
export class ReleaseNotesBuilder { export class ReleaseNotesBuilder {
constructor( constructor(
@@ -19,6 +18,7 @@ export class ReleaseNotesBuilder {
private failOnError: boolean, private failOnError: boolean,
private ignorePreReleases: boolean, private ignorePreReleases: boolean,
private fetchReviewers: boolean = false, private fetchReviewers: boolean = false,
private fetchReleaseInformation: boolean = false,
private commitMode: boolean, private commitMode: boolean,
private configuration: Configuration private configuration: Configuration
) {} ) {}
@@ -62,17 +62,16 @@ export class ReleaseNotesBuilder {
this.configuration.tag_resolver || DefaultConfiguration.tag_resolver this.configuration.tag_resolver || DefaultConfiguration.tag_resolver
) )
const thisTag = tagRange.to?.name let thisTag = tagRange.to
if (!thisTag) { if (!thisTag) {
failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError) failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError)
return null return null
} else { } else {
this.toTag = thisTag core.setOutput('toTag', thisTag.name)
core.setOutput('toTag', thisTag) core.debug(`Resolved 'toTag' as ${thisTag.name}`)
core.debug(`Resolved 'toTag' as ${thisTag}`)
} }
const previousTag = tagRange.from?.name let previousTag = tagRange.from
if (previousTag == null) { if (previousTag == null) {
failOrError( failOrError(
`💥 Unable to retrieve previous tag given ${this.toTag}`, `💥 Unable to retrieve previous tag given ${this.toTag}`,
@@ -80,31 +79,44 @@ export class ReleaseNotesBuilder {
) )
return null return null
} }
this.fromTag = previousTag core.setOutput('fromTag', previousTag.name)
core.setOutput('fromTag', previousTag) core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`)
core.debug(`fromTag resolved via previousTag as: ${previousTag}`)
if (this.fetchReleaseInformation) {
// load release information from the GitHub API
core.info(`️ Fetching release information was enabled`)
thisTag = await tagsApi.fillTagInformation(
this.repositoryPath,
this.owner,
this.repo,
thisTag
)
previousTag = await tagsApi.fillTagInformation(
this.repositoryPath,
this.owner,
this.repo,
previousTag
)
} else {
core.debug(`️ Fetching release information was disabled`)
}
core.endGroup() core.endGroup()
const options = { const options = {
owner: this.owner, owner: this.owner,
repo: this.repo, repo: this.repo,
fromTag: this.fromTag, fromTag: previousTag,
toTag: this.toTag, toTag: thisTag,
includeOpen: this.includeOpen, includeOpen: this.includeOpen,
failOnError: this.failOnError, failOnError: this.failOnError,
fetchReviewers: this.fetchReviewers, fetchReviewers: this.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation,
commitMode: this.commitMode, commitMode: this.commitMode,
configuration: this.configuration configuration: this.configuration
} }
const releaseNotes = new ReleaseNotes(octokit, options) const releaseNotes = new ReleaseNotes(octokit, options)
return ( return await releaseNotes.pull()
(await releaseNotes.pull()) ||
fillAdditionalPlaceholders(
this.configuration.empty_template ||
DefaultConfiguration.empty_template,
options
)
)
} }
} }
+46 -1
View File
@@ -6,6 +6,7 @@ import {SemVer} from 'semver'
import {TagResolver} from './configuration' import {TagResolver} from './configuration'
import {createCommandManager} from './gitHelper' import {createCommandManager} from './gitHelper'
import {RegexTransformer, validateTransformer} from './transform' import {RegexTransformer, validateTransformer} from './transform'
import moment from 'moment'
export interface TagResult { export interface TagResult {
from: TagInfo | null from: TagInfo | null
@@ -14,7 +15,8 @@ export interface TagResult {
export interface TagInfo { export interface TagInfo {
name: string name: string
commit: string commit?: string
date?: moment.Moment
} }
export interface SortableTagInfo extends TagInfo { export interface SortableTagInfo extends TagInfo {
@@ -61,6 +63,49 @@ export class Tags {
return tagsInfo return tagsInfo
} }
async fillTagInformation(
repositoryPath: string,
owner: string,
repo: string,
tagInfo: TagInfo
): Promise<TagInfo> {
const options = this.octokit.repos.getReleaseByTag.endpoint.merge({
owner,
repo,
tag: tagInfo.name
})
try {
const response = await this.octokit.request(options)
type ReleaseInformation =
RestEndpointMethodTypes['repos']['getReleaseByTag']['response']['data']
const release: ReleaseInformation = response.data as ReleaseInformation
tagInfo.date = moment(release.created_at)
core.info(
`️ Retrieved information about the release associated with ${tagInfo.name} from the GitHub API`
)
} catch (error) {
core.info(
`⚠️ No release information found for ${tagInfo.name}, trying to retrieve tag creation time as fallback.`
)
const gitHelper = await createCommandManager(repositoryPath)
const creationTimeString = await gitHelper.tagCreation(tagInfo.name)
const creationTime = moment(creationTimeString)
if (creationTimeString !== null && creationTime.isValid()) {
tagInfo.date = creationTime
core.info(
`️ Resolved tag creation time (${creationTimeString}) from 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}`
)
} else {
core.info(
`⚠️ Could not retrieve tag creation time via git cli 'git for-each-ref --format="%(creatordate:rfc)" "refs/tags/${tagInfo.name}'`
)
}
}
return tagInfo
}
async findPredecessorTag( async findPredecessorTag(
sortedTags: TagInfo[], sortedTags: TagInfo[],
repositoryPath: string, repositoryPath: string,
+45 -3
View File
@@ -7,8 +7,10 @@ import {
} from './configuration' } from './configuration'
import {PullRequestInfo, sortPullRequests} from './pullRequests' import {PullRequestInfo, sortPullRequests} from './pullRequests'
import {ReleaseNotesOptions} from './releaseNotes' import {ReleaseNotesOptions} from './releaseNotes'
import {DiffInfo} from './commits'
export function buildChangelog( export function buildChangelog(
diffInfo: DiffInfo,
prs: PullRequestInfo[], prs: PullRequestInfo[],
options: ReleaseNotesOptions options: ReleaseNotesOptions
): string { ): string {
@@ -272,6 +274,27 @@ export function buildChangelog(
/\${{IGNORED_COUNT}}/g, /\${{IGNORED_COUNT}}/g,
ignoredPrs.length.toString() ignoredPrs.length.toString()
) )
// code change placeholders
transformedChangelog = transformedChangelog.replace(
/\${{CHANGED_FILES}}/g,
diffInfo.changedFiles.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{ADDITIONS}}/g,
diffInfo.additions.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{DELETIONS}}/g,
diffInfo.deletions.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{CHANGES}}/g,
diffInfo.changes.toString()
)
transformedChangelog = transformedChangelog.replace(
/\${{COMMITS}}/g,
diffInfo.commits.toString()
)
transformedChangelog = fillAdditionalPlaceholders( transformedChangelog = fillAdditionalPlaceholders(
transformedChangelog, transformedChangelog,
options options
@@ -286,13 +309,32 @@ export function fillAdditionalPlaceholders(
options: ReleaseNotesOptions options: ReleaseNotesOptions
): string { ): string {
let transformed = text let transformed = text
// repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner) transformed = transformed.replace(/\${{OWNER}}/g, options.owner)
transformed = transformed.replace(/\${{REPO}}/g, options.repo) transformed = transformed.replace(/\${{REPO}}/g, options.repo)
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag) transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name)
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag) transformed = transformed.replace(
/\${{FROM_TAG_DATE}}/g,
options.fromTag.date?.toISOString() || ''
)
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag.name)
transformed = transformed.replace(
/\${{TO_TAG_DATE}}/g,
options.toTag.date?.toISOString() || ''
)
const fromDate = options.fromTag.date
const toDate = options.toTag.date
if (fromDate !== undefined && toDate !== undefined) {
transformed = transformed.replace(
/\${{DAYS_SINCE}}/g,
toDate.diff(fromDate, 'days').toString() || ''
)
} else {
transformed = transformed.replace(/\${{DAYS_SINCE}}/g, '')
}
transformed = transformed.replace( transformed = transformed.replace(
/\${{RELEASE_DIFF}}/g, /\${{RELEASE_DIFF}}/g,
`https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag}...${options.toTag}` `https://github.com/${options.owner}/${options.repo}/compare/${options.fromTag.name}...${options.toTag.name}`
) )
return transformed return transformed
} }