- introduce new mode configuration (replaces commitMode) with the option for PR, COMMIT or HYBRID (whereas hybrid has commits and PRs alongside)
- introduce new default commit configuration automatically used if `COMMIT` mode is configured. this uses a label extractor to support conventional commits
This commit is contained in:
@@ -108,3 +108,44 @@ export const DefaultConfiguration: Configuration = {
|
||||
custom_placeholders: [],
|
||||
trim_values: false // defines if values are being trimmed prior to inserting
|
||||
}
|
||||
|
||||
export const DefaultCommitConfiguration: Configuration = {
|
||||
max_tags_to_fetch: DefaultConfiguration.max_tags_to_fetch,
|
||||
max_pull_requests: DefaultConfiguration.max_pull_requests,
|
||||
max_back_track_time_days: DefaultConfiguration.max_back_track_time_days,
|
||||
exclude_merge_branches: DefaultConfiguration.exclude_merge_branches,
|
||||
sort: DefaultConfiguration.sort,
|
||||
template: '#{{CHANGELOG}}', // the global template to host the changelog
|
||||
pr_template: '- #{{TITLE}}', // the per PR template to pick for commit based mode
|
||||
empty_template: DefaultConfiguration.empty_template,
|
||||
categories: [
|
||||
{
|
||||
title: '## 🚀 Features',
|
||||
labels: ['feature', 'feat']
|
||||
},
|
||||
{
|
||||
title: '## 🐛 Fixes',
|
||||
labels: ['fix', 'bug']
|
||||
},
|
||||
{
|
||||
title: '## 🧪 Tests',
|
||||
labels: ['test']
|
||||
},
|
||||
{
|
||||
title: '## 📦 Other',
|
||||
labels: []
|
||||
}
|
||||
], // the categories to support for the ordering
|
||||
ignore_labels: DefaultConfiguration.ignore_labels,
|
||||
label_extractor: [
|
||||
{
|
||||
pattern: '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\\([\\w\\-\\.]+\\))?(!)?: ([\\w ])+([\\s\\S]*)',
|
||||
target: '$1'
|
||||
}
|
||||
],
|
||||
transformers: DefaultConfiguration.transformers,
|
||||
tag_resolver: DefaultConfiguration.tag_resolver,
|
||||
base_branches: DefaultConfiguration.base_branches,
|
||||
custom_placeholders: DefaultConfiguration.custom_placeholders,
|
||||
trim_values: DefaultConfiguration.trim_values
|
||||
}
|
||||
|
||||
+7
-4
@@ -1,6 +1,6 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as github from '@actions/github'
|
||||
import {mergeConfiguration, parseConfiguration, resolveConfiguration, retrieveRepositoryPath, writeOutput} from './utils'
|
||||
import {mergeConfiguration, parseConfiguration, resolveConfiguration, resolveMode, retrieveRepositoryPath, writeOutput} from './utils'
|
||||
import {ReleaseNotesBuilder} from './releaseNotesBuilder'
|
||||
import {Configuration} from './configuration'
|
||||
import {GithubRepository} from './repositories/GithubRepository'
|
||||
@@ -51,8 +51,12 @@ async function run(): Promise<void> {
|
||||
core.info(`ℹ️ No configuration provided. Using Defaults.`)
|
||||
}
|
||||
|
||||
// mode of the action (PR, COMMIT, HYBRID)
|
||||
const mode = resolveMode(core.getInput('mode'), core.getInput('commitMode') === 'true')
|
||||
core.info(`ℹ️ Running in ${mode} mode.`)
|
||||
|
||||
// merge configs, use default values from DefaultConfig on missing definition
|
||||
const configuration = mergeConfiguration(configJson, configFile)
|
||||
const configuration = mergeConfiguration(configJson, configFile, mode)
|
||||
|
||||
// read in repository inputs
|
||||
const baseUrl = core.getInput('baseUrl')
|
||||
@@ -70,7 +74,6 @@ async function run(): Promise<void> {
|
||||
const fetchReviewers = core.getInput('fetchReviewers') === 'true'
|
||||
const fetchReleaseInformation = core.getInput('fetchReleaseInformation') === 'true'
|
||||
const fetchReviews = core.getInput('fetchReviews') === 'true'
|
||||
const commitMode = core.getInput('commitMode') === 'true'
|
||||
const exportCache = core.getInput('exportCache') === 'true'
|
||||
const exportOnly = core.getInput('exportOnly') === 'true'
|
||||
const cache = core.getInput('cache')
|
||||
@@ -91,7 +94,7 @@ async function run(): Promise<void> {
|
||||
fetchReviewers,
|
||||
fetchReleaseInformation,
|
||||
fetchReviews,
|
||||
commitMode,
|
||||
mode,
|
||||
exportCache,
|
||||
exportOnly,
|
||||
cache,
|
||||
|
||||
+35
-32
@@ -91,42 +91,45 @@ export class Commits {
|
||||
}
|
||||
|
||||
async generateCommitPRs(options: Options): Promise<[DiffInfo, PullRequestInfo[]]> {
|
||||
const {owner, repo, configuration} = options
|
||||
|
||||
const diffInfo = await this.getCommitHistory(options)
|
||||
const commits = diffInfo.commitInfo
|
||||
if (commits.length === 0) {
|
||||
return [diffInfo, []]
|
||||
}
|
||||
|
||||
const prCommits = filterCommits(commits, configuration.exclude_merge_branches)
|
||||
|
||||
core.info(`ℹ️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`)
|
||||
|
||||
const prs = prCommits.map(function (commit): PullRequestInfo {
|
||||
return {
|
||||
number: 0,
|
||||
title: commit.summary,
|
||||
htmlURL: '',
|
||||
baseBranch: '',
|
||||
createdAt: commit.commitDate,
|
||||
mergedAt: commit.commitDate,
|
||||
mergeCommitSha: commit.sha,
|
||||
author: commit.author || '',
|
||||
repoName: '',
|
||||
labels: [],
|
||||
milestone: '',
|
||||
body: commit.message || '',
|
||||
assignees: [],
|
||||
requestedReviewers: [],
|
||||
approvedReviewers: [],
|
||||
status: 'merged'
|
||||
}
|
||||
})
|
||||
return [diffInfo, prs]
|
||||
return convertCommitsToPrs(options, diffInfo)
|
||||
}
|
||||
}
|
||||
|
||||
export function convertCommitsToPrs(options: Options, diffInfo: DiffInfo): [DiffInfo, PullRequestInfo[]] {
|
||||
const {owner, repo, configuration} = options
|
||||
const commits = diffInfo.commitInfo
|
||||
if (commits.length === 0) {
|
||||
return [diffInfo, []]
|
||||
}
|
||||
|
||||
const prCommits = filterCommits(commits, configuration.exclude_merge_branches)
|
||||
|
||||
core.info(`ℹ️ Retrieved ${prCommits.length} commits for ${owner}/${repo}`)
|
||||
|
||||
const prs = prCommits.map(function (commit): PullRequestInfo {
|
||||
return {
|
||||
number: 0,
|
||||
title: commit.summary,
|
||||
htmlURL: '',
|
||||
baseBranch: '',
|
||||
createdAt: commit.commitDate,
|
||||
mergedAt: commit.commitDate,
|
||||
mergeCommitSha: commit.sha,
|
||||
author: commit.author || '',
|
||||
repoName: '',
|
||||
labels: [],
|
||||
milestone: '',
|
||||
body: commit.message || '',
|
||||
assignees: [],
|
||||
requestedReviewers: [],
|
||||
approvedReviewers: [],
|
||||
status: 'merged'
|
||||
}
|
||||
})
|
||||
return [diffInfo, prs]
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out all commits which match the exclude pattern
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,7 @@ import {PullConfiguration} from './types'
|
||||
import {TagInfo, Tags} from './tags'
|
||||
import {failOrError} from './utils'
|
||||
import {PullRequestInfo, PullRequests} from './pullRequests'
|
||||
import {Commits, DiffInfo} from './commits'
|
||||
import {Commits, DefaultDiffInfo, DiffInfo, convertCommitsToPrs} from './commits'
|
||||
import {BaseRepository} from '../repositories/BaseRepository'
|
||||
|
||||
export interface Options {
|
||||
@@ -17,7 +17,7 @@ export interface Options {
|
||||
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
|
||||
fetchReviews: boolean // defines if the action should fetch the reviews for the PR.
|
||||
commitMode: boolean // defines if we use the alternative commit based mode. note: this is only partially supported
|
||||
mode: 'PR' | 'COMMIT' | 'HYBRID' // defines the mode used. note: the commit or hybrid modes are not fully supported
|
||||
configuration: PullConfiguration // the configuration as defined in `configuration.ts`
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export class PullRequestCollector {
|
||||
private fetchReviewers = false,
|
||||
private fetchReleaseInformation = false,
|
||||
private fetchReviews = false,
|
||||
private commitMode = false,
|
||||
private mode: 'PR' | 'COMMIT' | 'HYBRID' = 'PR',
|
||||
private configuration: PullConfiguration
|
||||
) {}
|
||||
|
||||
@@ -102,29 +102,37 @@ export class PullRequestCollector {
|
||||
fetchReviewers: this.fetchReviewers,
|
||||
fetchReleaseInformation: this.fetchReleaseInformation,
|
||||
fetchReviews: this.fetchReviews,
|
||||
commitMode: this.commitMode,
|
||||
mode: this.mode,
|
||||
configuration: this.configuration
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export async function pullData(repositoryUtils: BaseRepository, options: Options): Promise<Data | null> {
|
||||
let mergedPullRequests: PullRequestInfo[]
|
||||
let diffInfo: DiffInfo
|
||||
let mergedPullRequests: PullRequestInfo[] = []
|
||||
let diffInfo: DiffInfo = Object.assign({}, DefaultDiffInfo)
|
||||
|
||||
const commitsApi = new Commits(repositoryUtils)
|
||||
if (!options.commitMode) {
|
||||
core.startGroup(`🚀 Load pull requests`)
|
||||
|
||||
core.startGroup(`🚀 Load data`)
|
||||
if (options.mode === 'COMMIT') {
|
||||
core.info(`🚀 Load commit history (⚠️ Executing experimental commit mode)`)
|
||||
const [info, prs] = await commitsApi.generateCommitPRs(options)
|
||||
mergedPullRequests = mergedPullRequests.concat(prs)
|
||||
diffInfo = info
|
||||
} else {
|
||||
// PR mode, HYBRID mode
|
||||
core.info(`🚀 Load pull requests`)
|
||||
const pullRequestsApi = new PullRequests(repositoryUtils, commitsApi)
|
||||
const [info, prs] = await pullRequestsApi.getMergedPullRequests(options)
|
||||
mergedPullRequests = prs
|
||||
diffInfo = info
|
||||
} else {
|
||||
core.startGroup(`🚀 Load commit history`)
|
||||
core.info(`⚠️ Executing experimental commit mode`)
|
||||
const [info, prs] = await commitsApi.generateCommitPRs(options)
|
||||
mergedPullRequests = prs
|
||||
diffInfo = info
|
||||
|
||||
if (options.mode === 'HYBRID') {
|
||||
core.info(`🚀 Converting commits to pull requests`)
|
||||
const [, fakeCommitPrs] = convertCommitsToPrs(options, info)
|
||||
mergedPullRequests = mergedPullRequests.concat(fakeCommitPrs)
|
||||
}
|
||||
}
|
||||
core.endGroup()
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface ReleaseNotesOptions {
|
||||
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
|
||||
fetchReviews: boolean // defines if the action should fetch the reviews for the PR.
|
||||
commitMode: boolean // defines if we use the alternative commit based mode. note: this is only partially supported
|
||||
mode: 'PR' | 'COMMIT' | 'HYBRID' // defines the mode used. note: the commit or hybrid modes are not fully supported
|
||||
configuration: Configuration // the configuration as defined in `configuration.ts`
|
||||
repositoryUtils: BaseRepository // the repository implementation used to generate the changelog
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export class ReleaseNotesBuilder {
|
||||
private fetchReviewers = false,
|
||||
private fetchReleaseInformation = false,
|
||||
private fetchReviews = false,
|
||||
private commitMode = false,
|
||||
private mode: 'PR' | 'COMMIT' | 'HYBRID' = 'PR',
|
||||
private exportCache = false,
|
||||
private exportOnly = false,
|
||||
private cache: string | null = null,
|
||||
@@ -92,7 +92,7 @@ export class ReleaseNotesBuilder {
|
||||
this.fetchReviewers,
|
||||
this.fetchReleaseInformation,
|
||||
this.fetchReviews,
|
||||
this.commitMode,
|
||||
this.mode,
|
||||
this.configuration
|
||||
).build()
|
||||
|
||||
@@ -110,7 +110,7 @@ export class ReleaseNotesBuilder {
|
||||
fetchReviewers: this.fetchReviewers,
|
||||
fetchReleaseInformation: this.fetchReleaseInformation,
|
||||
fetchReviews: this.fetchReviews,
|
||||
commitMode: this.commitMode,
|
||||
mode: this.mode,
|
||||
configuration: this.configuration,
|
||||
repositoryUtils: this.repositoryUtils
|
||||
}
|
||||
@@ -164,7 +164,7 @@ export class ReleaseNotesBuilder {
|
||||
fetchReviewers: this.fetchReviewers || orgOptions.fetchReviewers,
|
||||
fetchReleaseInformation: this.fetchReleaseInformation || orgOptions.fetchReleaseInformation,
|
||||
fetchReviews: this.fetchReviews || orgOptions.fetchReviews,
|
||||
commitMode: this.commitMode || orgOptions.commitMode,
|
||||
mode: this.mode || orgOptions.mode,
|
||||
configuration: this.configuration || orgOptions.configuration,
|
||||
repositoryUtils: this.repositoryUtils || orgOptions.repositoryUtils
|
||||
}
|
||||
|
||||
+44
-19
@@ -1,7 +1,7 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import {Configuration, DefaultConfiguration} from './configuration'
|
||||
import {Configuration, DefaultCommitConfiguration, DefaultConfiguration} from './configuration'
|
||||
import moment from 'moment'
|
||||
import {DiffInfo} from './pr-collector/commits'
|
||||
import {PullRequestInfo} from './pr-collector/pullRequests'
|
||||
@@ -117,6 +117,24 @@ export function checkExportedData(exportCache: boolean, cacheInput: string | nul
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveMode(mode: string | undefined, commitMode: boolean): 'PR' | 'COMMIT' | 'HYBRID' {
|
||||
if (commitMode === false || mode === undefined) {
|
||||
if (commitMode === true) {
|
||||
return 'COMMIT'
|
||||
} else {
|
||||
return 'PR'
|
||||
}
|
||||
} else {
|
||||
const upperCaseMode = mode.toUpperCase()
|
||||
if (upperCaseMode === 'COMMIT') {
|
||||
return 'COMMIT'
|
||||
} else if (upperCaseMode === 'HYBRID') {
|
||||
return 'HYBRID'
|
||||
}
|
||||
}
|
||||
return 'PR'
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the configuration given the file path, if not found it will fallback to the `DefaultConfiguration`
|
||||
*/
|
||||
@@ -173,25 +191,32 @@ export function parseConfiguration(config: string): Configuration | undefined {
|
||||
/**
|
||||
* Merges the configurations, will fallback to the DefaultConfiguration value
|
||||
*/
|
||||
export function mergeConfiguration(jc?: Configuration, fc?: Configuration): Configuration {
|
||||
export function mergeConfiguration(jc?: Configuration, fc?: Configuration, mode?: 'PR' | 'COMMIT' | 'HYBRID'): Configuration {
|
||||
let def: Configuration
|
||||
if (mode === 'COMMIT') {
|
||||
def = DefaultCommitConfiguration
|
||||
} else {
|
||||
def = DefaultConfiguration
|
||||
}
|
||||
|
||||
return {
|
||||
max_tags_to_fetch: jc?.max_tags_to_fetch || fc?.max_tags_to_fetch || DefaultConfiguration.max_tags_to_fetch,
|
||||
max_pull_requests: jc?.max_pull_requests || fc?.max_pull_requests || DefaultConfiguration.max_pull_requests,
|
||||
max_back_track_time_days: jc?.max_back_track_time_days || fc?.max_back_track_time_days || DefaultConfiguration.max_back_track_time_days,
|
||||
exclude_merge_branches: jc?.exclude_merge_branches || fc?.exclude_merge_branches || DefaultConfiguration.exclude_merge_branches,
|
||||
sort: jc?.sort || fc?.sort || DefaultConfiguration.sort,
|
||||
template: jc?.template || fc?.template || DefaultConfiguration.template,
|
||||
pr_template: jc?.pr_template || fc?.pr_template || DefaultConfiguration.pr_template,
|
||||
empty_template: jc?.empty_template || fc?.empty_template || DefaultConfiguration.empty_template,
|
||||
categories: jc?.categories || fc?.categories || DefaultConfiguration.categories,
|
||||
ignore_labels: jc?.ignore_labels || fc?.ignore_labels || DefaultConfiguration.ignore_labels,
|
||||
label_extractor: jc?.label_extractor || fc?.label_extractor || DefaultConfiguration.label_extractor,
|
||||
duplicate_filter: jc?.duplicate_filter || fc?.duplicate_filter || DefaultConfiguration.duplicate_filter,
|
||||
transformers: jc?.transformers || fc?.transformers || DefaultConfiguration.transformers,
|
||||
tag_resolver: jc?.tag_resolver || fc?.tag_resolver || DefaultConfiguration.tag_resolver,
|
||||
base_branches: jc?.base_branches || fc?.base_branches || DefaultConfiguration.base_branches,
|
||||
custom_placeholders: jc?.custom_placeholders || fc?.custom_placeholders || DefaultConfiguration.custom_placeholders,
|
||||
trim_values: jc?.trim_values || fc?.trim_values || DefaultConfiguration.trim_values
|
||||
max_tags_to_fetch: jc?.max_tags_to_fetch || fc?.max_tags_to_fetch || def.max_tags_to_fetch,
|
||||
max_pull_requests: jc?.max_pull_requests || fc?.max_pull_requests || def.max_pull_requests,
|
||||
max_back_track_time_days: jc?.max_back_track_time_days || fc?.max_back_track_time_days || def.max_back_track_time_days,
|
||||
exclude_merge_branches: jc?.exclude_merge_branches || fc?.exclude_merge_branches || def.exclude_merge_branches,
|
||||
sort: jc?.sort || fc?.sort || def.sort,
|
||||
template: jc?.template || fc?.template || def.template,
|
||||
pr_template: jc?.pr_template || fc?.pr_template || def.pr_template,
|
||||
empty_template: jc?.empty_template || fc?.empty_template || def.empty_template,
|
||||
categories: jc?.categories || fc?.categories || def.categories,
|
||||
ignore_labels: jc?.ignore_labels || fc?.ignore_labels || def.ignore_labels,
|
||||
label_extractor: jc?.label_extractor || fc?.label_extractor || def.label_extractor,
|
||||
duplicate_filter: jc?.duplicate_filter || fc?.duplicate_filter || def.duplicate_filter,
|
||||
transformers: jc?.transformers || fc?.transformers || def.transformers,
|
||||
tag_resolver: jc?.tag_resolver || fc?.tag_resolver || def.tag_resolver,
|
||||
base_branches: jc?.base_branches || fc?.base_branches || def.base_branches,
|
||||
custom_placeholders: jc?.custom_placeholders || fc?.custom_placeholders || def.custom_placeholders,
|
||||
trim_values: jc?.trim_values || fc?.trim_values || def.trim_values
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user