- introduce new configuration flag to fetchReleaseInformation

- if enabled, it will unlock the ability to use new placeholders
  - `${{ DAYS_SINCE }}`
  - `${{ FROM_TAG_DATE }}`
  - `${{ TO_TAG_DATE }}`
- refactor to carry on the full `TagInfo` information instead of only the tagname
- refresh testcases to new apis
This commit is contained in:
Mike Penz
2022-07-26 16:47:23 +02:00
parent 09ae38aa7f
commit c061d0e577
12 changed files with 291 additions and 83 deletions
+9
View File
@@ -44,6 +44,15 @@ class GitCommandManager {
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(
workingDirectory: string
): Promise<GitCommandManager> {
+3
View File
@@ -36,6 +36,8 @@ async function run(): Promise<void> {
const ignorePreReleases = core.getInput('ignorePreReleases') === 'true'
const failOnError = core.getInput('failOnError') === 'true'
const fetchReviewers = core.getInput('fetchReviewers') === 'true'
const fetchReleaseInformation =
core.getInput('fetchReleaseInformation') === 'true'
const commitMode = core.getInput('commitMode') === 'true'
const result = await new ReleaseNotesBuilder(
@@ -50,6 +52,7 @@ async function run(): Promise<void> {
failOnError,
ignorePreReleases,
fetchReviewers,
fetchReleaseInformation,
commitMode,
configuration
).build()
+7 -3
View File
@@ -5,15 +5,17 @@ import {PullRequestInfo, PullRequests} from './pullRequests'
import {Octokit} from '@octokit/rest'
import {buildChangelog, fillAdditionalPlaceholders} from './transform'
import {failOrError} from './utils'
import {TagInfo} from './tags'
export interface ReleaseNotesOptions {
owner: string // the owner of the repository
repo: string // the repository
fromTag: string // the tag/ref to start from
toTag: string // the tag/ref up to
fromTag: TagInfo // the tag/ref to start from
toTag: TagInfo // the tag/ref up to
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
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
configuration: Configuration // the configuration as defined in `configuration.ts`
}
@@ -83,7 +85,7 @@ export class ReleaseNotes {
const commitsApi = new Commits(octokit)
let diffInfo: DiffInfo
try {
diffInfo = await commitsApi.getDiff(owner, repo, fromTag, toTag)
diffInfo = await commitsApi.getDiff(owner, repo, fromTag.name, toTag.name)
} catch (error) {
failOrError(
`💥 Failed to retrieve - Invalid tag? - Because of: ${error}`,
@@ -212,6 +214,8 @@ export class ReleaseNotes {
)
}
}
} else {
core.debug(`️ Fetching reviewers was disabled`)
}
return [diffInfo, finalPrs]
+30 -10
View File
@@ -18,6 +18,7 @@ export class ReleaseNotesBuilder {
private failOnError: boolean,
private ignorePreReleases: boolean,
private fetchReviewers: boolean = false,
private fetchReleaseInformation: boolean = false,
private commitMode: boolean,
private configuration: Configuration
) {}
@@ -61,17 +62,16 @@ export class ReleaseNotesBuilder {
this.configuration.tag_resolver || DefaultConfiguration.tag_resolver
)
const thisTag = tagRange.to?.name
let thisTag = tagRange.to
if (!thisTag) {
failOrError(`💥 Missing or couldn't resolve 'toTag'`, this.failOnError)
return null
} else {
this.toTag = thisTag
core.setOutput('toTag', thisTag)
core.debug(`Resolved 'toTag' as ${thisTag}`)
core.setOutput('toTag', thisTag.name)
core.debug(`Resolved 'toTag' as ${thisTag.name}`)
}
const previousTag = tagRange.from?.name
let previousTag = tagRange.from
if (previousTag == null) {
failOrError(
`💥 Unable to retrieve previous tag given ${this.toTag}`,
@@ -79,19 +79,39 @@ export class ReleaseNotesBuilder {
)
return null
}
this.fromTag = previousTag
core.setOutput('fromTag', previousTag)
core.debug(`fromTag resolved via previousTag as: ${previousTag}`)
core.setOutput('fromTag', previousTag.name)
core.debug(`fromTag resolved via previousTag as: ${previousTag.name}`)
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()
const options = {
owner: this.owner,
repo: this.repo,
fromTag: this.fromTag,
toTag: this.toTag,
fromTag: previousTag,
toTag: thisTag,
includeOpen: this.includeOpen,
failOnError: this.failOnError,
fetchReviewers: this.fetchReviewers,
fetchReleaseInformation: this.fetchReleaseInformation,
commitMode: this.commitMode,
configuration: this.configuration
}
+44 -1
View File
@@ -6,6 +6,7 @@ import {SemVer} from 'semver'
import {TagResolver} from './configuration'
import {createCommandManager} from './gitHelper'
import {RegexTransformer, validateTransformer} from './transform'
import moment from 'moment'
export interface TagResult {
from: TagInfo | null
@@ -14,7 +15,8 @@ export interface TagResult {
export interface TagInfo {
name: string
commit: string
commit?: string
date?: moment.Moment
}
export interface SortableTagInfo extends TagInfo {
@@ -61,6 +63,47 @@ export class Tags {
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 for ${owner}/${repo}`
)
} 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}`
)
}
}
return tagInfo
}
async findPredecessorTag(
sortedTags: TagInfo[],
repositoryPath: string,
+29 -3
View File
@@ -312,11 +312,37 @@ export function fillAdditionalPlaceholders(
// repository placeholders
transformed = transformed.replace(/\${{OWNER}}/g, options.owner)
transformed = transformed.replace(/\${{REPO}}/g, options.repo)
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag)
transformed = transformed.replace(/\${{TO_TAG}}/g, options.toTag)
transformed = transformed.replace(/\${{FROM_TAG}}/g, options.fromTag.name)
transformed = transformed.replace(
/\${{FROM_TAG_SHA}}/g,
options.fromTag.commit || ''
)
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_SHA}}/g,
options.toTag.commit || ''
)
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(
/\${{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
}