- fix a ton of formatting issues automatically
- fix many javascript issues
This commit is contained in:
+79
-57
@@ -1,70 +1,92 @@
|
||||
import { Octokit, RestEndpointMethodTypes } from "@octokit/rest"
|
||||
import moment from 'moment';
|
||||
import * as core from '@actions/core';
|
||||
import moment from 'moment'
|
||||
import * as core from '@actions/core'
|
||||
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
||||
|
||||
export interface CommitInfo {
|
||||
sha: string
|
||||
summary: string
|
||||
message: string
|
||||
author: string
|
||||
date: moment.Moment
|
||||
prNumber: number | undefined
|
||||
sha: string
|
||||
summary: string
|
||||
message: string
|
||||
author: string
|
||||
date: moment.Moment
|
||||
prNumber: number | undefined
|
||||
}
|
||||
|
||||
export class Commits {
|
||||
constructor(private octokit: Octokit) { }
|
||||
constructor(private octokit: Octokit) {}
|
||||
|
||||
async getDiff(owner: string, repo: string, base: string, head: string): Promise<CommitInfo[]> {
|
||||
const commits: CommitInfo[] = await this.getDiffRemote(owner, repo, base, head)
|
||||
return this.sortCommits(commits)
|
||||
async getDiff(
|
||||
owner: string,
|
||||
repo: string,
|
||||
base: string,
|
||||
head: string
|
||||
): Promise<CommitInfo[]> {
|
||||
const commits: CommitInfo[] = await this.getDiffRemote(
|
||||
owner,
|
||||
repo,
|
||||
base,
|
||||
head
|
||||
)
|
||||
return this.sortCommits(commits)
|
||||
}
|
||||
|
||||
private async getDiffRemote(
|
||||
owner: string,
|
||||
repo: string,
|
||||
base: string,
|
||||
head: string
|
||||
): Promise<CommitInfo[]> {
|
||||
// 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.
|
||||
let commits: RestEndpointMethodTypes['repos']['compareCommits']['response']['data']['commits'] = []
|
||||
let compareHead = head
|
||||
while (true) {
|
||||
const compareResult = await this.octokit.repos.compareCommits({
|
||||
owner,
|
||||
repo,
|
||||
base,
|
||||
head: compareHead
|
||||
})
|
||||
if (compareResult.data.total_commits === 0) {
|
||||
break
|
||||
}
|
||||
commits = compareResult.data.commits.concat(commits)
|
||||
compareHead = `${commits[0].sha}^`
|
||||
}
|
||||
|
||||
private async getDiffRemote(owner: string, repo: string, base: string, head: string): Promise<CommitInfo[]> {
|
||||
// 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.
|
||||
let commits: RestEndpointMethodTypes["repos"]["compareCommits"]["response"]["data"]["commits"] = []
|
||||
let compareHead = head
|
||||
while (true) {
|
||||
const compareResult = await this.octokit.repos.compareCommits({ owner, repo, base, head: compareHead })
|
||||
if (compareResult.data.total_commits === 0) {
|
||||
break
|
||||
}
|
||||
commits = compareResult.data.commits.concat(commits)
|
||||
compareHead = `${commits[0].sha}^`
|
||||
}
|
||||
core.info(
|
||||
`Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`
|
||||
)
|
||||
return commits.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
|
||||
}))
|
||||
}
|
||||
|
||||
core.info(`Found ${commits.length} commits from the GitHub API for ${owner}/${repo}`)
|
||||
return commits.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[] {
|
||||
const commitsResult = []
|
||||
const shas: {[key: string]: boolean} = {}
|
||||
|
||||
for (const commit of commits) {
|
||||
if (shas[commit.sha]) {
|
||||
continue
|
||||
}
|
||||
shas[commit.sha] = true
|
||||
commitsResult.push(commit)
|
||||
}
|
||||
|
||||
private sortCommits(commits: CommitInfo[]): CommitInfo[] {
|
||||
const commitsResult = []
|
||||
const shas: { [key: string]: boolean } = {}
|
||||
commitsResult.sort((a, b) => {
|
||||
if (a.date.isBefore(b.date)) {
|
||||
return -1
|
||||
} else if (b.date.isBefore(a.date)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
for (const commit of commits) {
|
||||
if (shas[commit.sha]) {
|
||||
continue
|
||||
}
|
||||
shas[commit.sha] = true
|
||||
commitsResult.push(commit)
|
||||
}
|
||||
|
||||
commitsResult.sort((a, b) => {
|
||||
if (a.date.isBefore(b.date)) {
|
||||
return -1
|
||||
} else if (b.date.isBefore(a.date)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
return commitsResult
|
||||
}
|
||||
return commitsResult
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -1,27 +1,27 @@
|
||||
interface Configuration {
|
||||
sort: string;
|
||||
template: string;
|
||||
pr_template: string;
|
||||
empty_template: string;
|
||||
categories: Array<Category>;
|
||||
transformers: Array<Transformer>;
|
||||
export interface Configuration {
|
||||
sort: string
|
||||
template: string
|
||||
pr_template: string
|
||||
empty_template: string
|
||||
categories: Category[]
|
||||
transformers: Transformer[]
|
||||
}
|
||||
|
||||
interface Category {
|
||||
title: string;
|
||||
labels: Array<string>;
|
||||
export interface Category {
|
||||
title: string
|
||||
labels: string[]
|
||||
}
|
||||
|
||||
interface Transformer {
|
||||
pattern: string;
|
||||
target: string;
|
||||
export interface Transformer {
|
||||
pattern: string
|
||||
target: string
|
||||
}
|
||||
|
||||
const DefaultConfiguration: Configuration = {
|
||||
sort: "ASC",
|
||||
template: "${{CHANGELOG}}",
|
||||
pr_template: "- ${{TITLE}}\n - PR: #${{NUMBER}}",
|
||||
empty_template: "- no changes",
|
||||
categories: [],
|
||||
transformers: []
|
||||
export const DefaultConfiguration: Configuration = {
|
||||
sort: 'ASC',
|
||||
template: '${{CHANGELOG}}',
|
||||
pr_template: '- ${{TITLE}}\n - PR: #${{NUMBER}}',
|
||||
empty_template: '- no changes',
|
||||
categories: [],
|
||||
transformers: []
|
||||
}
|
||||
|
||||
+85
-78
@@ -1,108 +1,115 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as fs from 'fs'
|
||||
import * as io from '@actions/io'
|
||||
|
||||
export async function createCommandManager(
|
||||
workingDirectory: string
|
||||
workingDirectory: string
|
||||
): Promise<GitCommandManager> {
|
||||
return await GitCommandManager.createCommandManager(workingDirectory)
|
||||
return await GitCommandManager.createCommandManager(workingDirectory)
|
||||
}
|
||||
|
||||
|
||||
function directoryExistsSync(path: string, required?: boolean): boolean {
|
||||
if (!path) {
|
||||
throw new Error("Arg 'path' must not be empty")
|
||||
}
|
||||
if (!path) {
|
||||
throw new Error("Arg 'path' must not be empty")
|
||||
}
|
||||
|
||||
let stats: fs.Stats
|
||||
try {
|
||||
stats = fs.statSync(path)
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${path}' does not exist`)
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Encountered an error when checking whether path '${path}' exists: ${error.message}`
|
||||
)
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return true
|
||||
} else if (!required) {
|
||||
let stats: fs.Stats
|
||||
try {
|
||||
stats = fs.statSync(path)
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${path}' does not exist`)
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${path}' does not exist`)
|
||||
throw new Error(
|
||||
`Encountered an error when checking whether path '${path}' exists: ${error.message}`
|
||||
)
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return true
|
||||
} else if (!required) {
|
||||
return false
|
||||
}
|
||||
|
||||
throw new Error(`Directory '${path}' does not exist`)
|
||||
}
|
||||
|
||||
|
||||
class GitCommandManager {
|
||||
private gitPath = ''
|
||||
private workingDirectory = ''
|
||||
private gitPath = ''
|
||||
private workingDirectory = ''
|
||||
|
||||
// Private constructor; use createCommandManager()
|
||||
private constructor() { }
|
||||
// Private constructor; use createCommandManager()
|
||||
private constructor() {}
|
||||
|
||||
getWorkingDirectory(): string {
|
||||
return this.workingDirectory
|
||||
}
|
||||
getWorkingDirectory(): string {
|
||||
return this.workingDirectory
|
||||
}
|
||||
|
||||
async latestTag(): Promise<string> {
|
||||
const revListOutput = await this.execGit(['rev-list', '--tags', '--skip=0', '--max-count=1'])
|
||||
const output = await this.execGit(['describe', '--abbrev=0', '--tags', revListOutput.stdout.trim()])
|
||||
return output.stdout.trim()
|
||||
}
|
||||
async latestTag(): Promise<string> {
|
||||
const revListOutput = await this.execGit([
|
||||
'rev-list',
|
||||
'--tags',
|
||||
'--skip=0',
|
||||
'--max-count=1'
|
||||
])
|
||||
const output = await this.execGit([
|
||||
'describe',
|
||||
'--abbrev=0',
|
||||
'--tags',
|
||||
revListOutput.stdout.trim()
|
||||
])
|
||||
return output.stdout.trim()
|
||||
}
|
||||
|
||||
static async createCommandManager(
|
||||
workingDirectory: string
|
||||
): Promise<GitCommandManager> {
|
||||
const result = new GitCommandManager()
|
||||
await result.initializeCommandManager(workingDirectory)
|
||||
return result
|
||||
}
|
||||
static async createCommandManager(
|
||||
workingDirectory: string
|
||||
): Promise<GitCommandManager> {
|
||||
const result = new GitCommandManager()
|
||||
await result.initializeCommandManager(workingDirectory)
|
||||
return result
|
||||
}
|
||||
|
||||
private async execGit(
|
||||
args: string[],
|
||||
allowAllExitCodes = false,
|
||||
silent = false
|
||||
): Promise<GitOutput> {
|
||||
directoryExistsSync(this.workingDirectory, true)
|
||||
private async execGit(
|
||||
args: string[],
|
||||
allowAllExitCodes = false,
|
||||
silent = false
|
||||
): Promise<GitOutput> {
|
||||
directoryExistsSync(this.workingDirectory, true)
|
||||
|
||||
const result = new GitOutput()
|
||||
const result = new GitOutput()
|
||||
|
||||
const stdout: string[] = []
|
||||
const stdout: string[] = []
|
||||
|
||||
const options = {
|
||||
cwd: this.workingDirectory,
|
||||
silent,
|
||||
ignoreReturnCode: allowAllExitCodes,
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
stdout.push(data.toString())
|
||||
}
|
||||
}
|
||||
const options = {
|
||||
cwd: this.workingDirectory,
|
||||
silent,
|
||||
ignoreReturnCode: allowAllExitCodes,
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
stdout.push(data.toString())
|
||||
}
|
||||
|
||||
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
|
||||
result.stdout = stdout.join('')
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private async initializeCommandManager(
|
||||
workingDirectory: string
|
||||
): Promise<void> {
|
||||
this.workingDirectory = workingDirectory
|
||||
this.gitPath = await io.which('git', true)
|
||||
}
|
||||
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
|
||||
result.stdout = stdout.join('')
|
||||
return result
|
||||
}
|
||||
|
||||
private async initializeCommandManager(
|
||||
workingDirectory: string
|
||||
): Promise<void> {
|
||||
this.workingDirectory = workingDirectory
|
||||
this.gitPath = await io.which('git', true)
|
||||
}
|
||||
}
|
||||
|
||||
class GitOutput {
|
||||
stdout = ''
|
||||
exitCode = 0
|
||||
}
|
||||
stdout = ''
|
||||
exitCode = 0
|
||||
}
|
||||
|
||||
+21
-20
@@ -1,11 +1,9 @@
|
||||
import * as core from '@actions/core'
|
||||
import { wait } from './wait'
|
||||
import { readConfiguration } from './utils';
|
||||
import { ReleaseNotes } from './releaseNotes';
|
||||
import { createCommandManager } from './git-helper';
|
||||
import {readConfiguration} from './utils'
|
||||
import {ReleaseNotes} from './releaseNotes'
|
||||
import {createCommandManager} from './git-helper'
|
||||
import * as github from '@actions/github'
|
||||
import * as path from 'path';
|
||||
|
||||
import * as path from 'path'
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
@@ -17,10 +15,7 @@ async function run(): Promise<void> {
|
||||
core.debug(`GITHUB_WORKSPACE = '${githubWorkspacePath}'`)
|
||||
|
||||
let repositoryPath = core.getInput('path') || '.'
|
||||
repositoryPath = path.resolve(
|
||||
githubWorkspacePath,
|
||||
repositoryPath
|
||||
)
|
||||
repositoryPath = path.resolve(githubWorkspacePath, repositoryPath)
|
||||
core.debug(`repositoryPath = '${repositoryPath}'`)
|
||||
|
||||
const configurationFile: string = core.getInput('configuration')
|
||||
@@ -31,12 +26,12 @@ async function run(): Promise<void> {
|
||||
core.debug(`configurationPath = '${configurationPath}'`)
|
||||
const configuration = readConfiguration(configurationPath)
|
||||
|
||||
let token = core.getInput('token')
|
||||
const token = core.getInput('token')
|
||||
let owner = core.getInput('owner')
|
||||
let repo = core.getInput('repo')
|
||||
|
||||
let fromTag = core.getInput("fromTag")
|
||||
let toTag = core.getInput("toTag")
|
||||
const fromTag = core.getInput('fromTag')
|
||||
let toTag = core.getInput('toTag')
|
||||
|
||||
if (!toTag) {
|
||||
// if not specified try to retrieve tag from git
|
||||
@@ -48,10 +43,16 @@ async function run(): Promise<void> {
|
||||
|
||||
if (!owner || !repo) {
|
||||
// Qualified repository
|
||||
const qualifiedRepository = core.getInput('repository') || `${github.context.repo.owner}/${github.context.repo.repo}`
|
||||
const qualifiedRepository =
|
||||
core.getInput('repository') ||
|
||||
`${github.context.repo.owner}/${github.context.repo.repo}`
|
||||
core.debug(`qualified repository = '${qualifiedRepository}'`)
|
||||
const splitRepository = qualifiedRepository.split('/')
|
||||
if (splitRepository.length !== 2 || !splitRepository[0] || !splitRepository[1]) {
|
||||
if (
|
||||
splitRepository.length !== 2 ||
|
||||
!splitRepository[0] ||
|
||||
!splitRepository[1]
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid repository '${qualifiedRepository}'. Expected format {owner}/{repo}.`
|
||||
)
|
||||
@@ -76,11 +77,11 @@ async function run(): Promise<void> {
|
||||
}
|
||||
|
||||
const releaseNotes = new ReleaseNotes({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
fromTag: fromTag,
|
||||
toTag: toTag,
|
||||
configuration: configuration
|
||||
owner,
|
||||
repo,
|
||||
fromTag,
|
||||
toTag,
|
||||
configuration
|
||||
})
|
||||
|
||||
core.setOutput('changelog', await releaseNotes.pull(token))
|
||||
|
||||
+123
-106
@@ -1,126 +1,143 @@
|
||||
import { Octokit, RestEndpointMethodTypes } from "@octokit/rest"
|
||||
import moment from 'moment';
|
||||
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
||||
import moment from 'moment'
|
||||
|
||||
import { CommitInfo } from "./commits"
|
||||
import * as core from '@actions/core';
|
||||
import {CommitInfo} from './commits'
|
||||
import * as core from '@actions/core'
|
||||
|
||||
export interface PullRequestInfo {
|
||||
number: number
|
||||
title: string
|
||||
htmlURL: string
|
||||
mergedAt: moment.Moment
|
||||
author: string
|
||||
repoName: string
|
||||
labels: Array<string>
|
||||
body: string
|
||||
number: number
|
||||
title: string
|
||||
htmlURL: string
|
||||
mergedAt: moment.Moment
|
||||
author: string
|
||||
repoName: string
|
||||
labels: string[]
|
||||
body: string
|
||||
}
|
||||
|
||||
export class PullRequests {
|
||||
constructor(private octokit: Octokit) {}
|
||||
constructor(private octokit: Octokit) {}
|
||||
|
||||
async getSingle(owner: string, repo: string, prNumber: number): Promise<PullRequestInfo | null> {
|
||||
try {
|
||||
const pr = await this.octokit.pulls.get({ owner, repo, pull_number: prNumber })
|
||||
async getSingle(
|
||||
owner: string,
|
||||
repo: string,
|
||||
prNumber: number
|
||||
): Promise<PullRequestInfo | null> {
|
||||
try {
|
||||
const pr = await this.octokit.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber
|
||||
})
|
||||
|
||||
return {
|
||||
number: pr.data.number,
|
||||
title: pr.data.title,
|
||||
htmlURL: pr.data.html_url,
|
||||
mergedAt: moment(pr.data.merged_at),
|
||||
author: pr.data.user.login,
|
||||
repoName: pr.data.base.repo.full_name,
|
||||
labels: pr.data.labels.map(function (label) { return label.name }),
|
||||
body: pr.data.body
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}`)
|
||||
return null
|
||||
}
|
||||
return {
|
||||
number: pr.data.number,
|
||||
title: pr.data.title,
|
||||
htmlURL: pr.data.html_url,
|
||||
mergedAt: moment(pr.data.merged_at),
|
||||
author: pr.data.user.login,
|
||||
repoName: pr.data.base.repo.full_name,
|
||||
labels: pr.data.labels.map(function (label) {
|
||||
return label.name
|
||||
}),
|
||||
body: pr.data.body
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Cannot find PR ${owner}/${repo}#${prNumber} - ${e.message}`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async getBetweenDates(
|
||||
owner: string,
|
||||
repo: string,
|
||||
fromDate: moment.Moment,
|
||||
toDate: moment.Moment
|
||||
): Promise<PullRequestInfo[]> {
|
||||
const mergedPRs: PullRequestInfo[] = []
|
||||
const options = this.octokit.pulls.list.endpoint.merge({
|
||||
owner,
|
||||
repo,
|
||||
state: "closed",
|
||||
sort: "updated",
|
||||
direction: "desc"
|
||||
})
|
||||
async getBetweenDates(
|
||||
owner: string,
|
||||
repo: string,
|
||||
fromDate: moment.Moment,
|
||||
toDate: moment.Moment
|
||||
): Promise<PullRequestInfo[]> {
|
||||
const mergedPRs: PullRequestInfo[] = []
|
||||
const options = this.octokit.pulls.list.endpoint.merge({
|
||||
owner,
|
||||
repo,
|
||||
state: 'closed',
|
||||
sort: 'updated',
|
||||
direction: 'desc'
|
||||
})
|
||||
|
||||
for await (const response of this.octokit.paginate.iterator(options)) {
|
||||
type PullsListData = RestEndpointMethodTypes["pulls"]["list"]["response"]["data"]
|
||||
const prs: PullsListData = response.data as PullsListData
|
||||
|
||||
const firstPR = prs[0]
|
||||
if(firstPR.merged_at && fromDate.isAfter(moment(firstPR.merged_at))) {
|
||||
// bail out early to not keep iterating on PRs super old
|
||||
return sortPullRequests(mergedPRs, true)
|
||||
}
|
||||
|
||||
prs.filter(
|
||||
pr =>
|
||||
!!pr.merged_at &&
|
||||
fromDate.isBefore(moment(pr.merged_at)) &&
|
||||
toDate.isSameOrAfter(moment(pr.merged_at))
|
||||
).forEach(pr => {
|
||||
mergedPRs.push({
|
||||
number: pr.number,
|
||||
title: pr.title,
|
||||
htmlURL: pr.html_url,
|
||||
mergedAt: moment(pr.merged_at),
|
||||
author: pr.user.login,
|
||||
repoName: pr.base.repo.full_name,
|
||||
labels: pr.labels.map(function (label) { return label.name }),
|
||||
body: pr.body
|
||||
})
|
||||
})
|
||||
}
|
||||
for await (const response of this.octokit.paginate.iterator(options)) {
|
||||
type PullsListData = RestEndpointMethodTypes['pulls']['list']['response']['data']
|
||||
const prs: PullsListData = response.data as PullsListData
|
||||
|
||||
const firstPR = prs[0]
|
||||
if (firstPR.merged_at && fromDate.isAfter(moment(firstPR.merged_at))) {
|
||||
// bail out early to not keep iterating on PRs super old
|
||||
return sortPullRequests(mergedPRs, true)
|
||||
}
|
||||
|
||||
prs
|
||||
.filter(
|
||||
pr =>
|
||||
!!pr.merged_at &&
|
||||
fromDate.isBefore(moment(pr.merged_at)) &&
|
||||
toDate.isSameOrAfter(moment(pr.merged_at))
|
||||
)
|
||||
.forEach(pr => {
|
||||
mergedPRs.push({
|
||||
number: pr.number,
|
||||
title: pr.title,
|
||||
htmlURL: pr.html_url,
|
||||
mergedAt: moment(pr.merged_at),
|
||||
author: pr.user.login,
|
||||
repoName: pr.base.repo.full_name,
|
||||
labels: pr.labels.map(function (label) {
|
||||
return label.name
|
||||
}),
|
||||
body: pr.body
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
filterCommits(commits: CommitInfo[]): CommitInfo[] {
|
||||
const prRegex = /Merge pull request #(\d+)/
|
||||
const filteredCommits = []
|
||||
return sortPullRequests(mergedPRs, true)
|
||||
}
|
||||
|
||||
for (const commit of commits) {
|
||||
const match = commit.summary.match(prRegex)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
commit.prNumber = Number.parseInt(match[1], 10)
|
||||
filteredCommits.push(commit)
|
||||
}
|
||||
filterCommits(commits: CommitInfo[]): CommitInfo[] {
|
||||
const prRegex = /Merge pull request #(\d+)/
|
||||
const filteredCommits = []
|
||||
|
||||
return filteredCommits
|
||||
for (const commit of commits) {
|
||||
const match = commit.summary.match(prRegex)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
commit.prNumber = Number.parseInt(match[1], 10)
|
||||
filteredCommits.push(commit)
|
||||
}
|
||||
|
||||
return filteredCommits
|
||||
}
|
||||
}
|
||||
|
||||
export function sortPullRequests(pullRequests: PullRequestInfo[], ascending: Boolean): PullRequestInfo[] {
|
||||
if(ascending) {
|
||||
pullRequests.sort((a, b) => {
|
||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
||||
return -1
|
||||
} else if (b.mergedAt.isBefore(a.mergedAt)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
} else {
|
||||
pullRequests.sort((b, a) => {
|
||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
||||
return -1
|
||||
} else if (b.mergedAt.isBefore(a.mergedAt)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
return pullRequests
|
||||
}
|
||||
export function sortPullRequests(
|
||||
pullRequests: PullRequestInfo[],
|
||||
ascending: Boolean
|
||||
): PullRequestInfo[] {
|
||||
if (ascending) {
|
||||
pullRequests.sort((a, b) => {
|
||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
||||
return -1
|
||||
} else if (b.mergedAt.isBefore(a.mergedAt)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
} else {
|
||||
pullRequests.sort((b, a) => {
|
||||
if (a.mergedAt.isBefore(b.mergedAt)) {
|
||||
return -1
|
||||
} else if (b.mergedAt.isBefore(a.mergedAt)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
return pullRequests
|
||||
}
|
||||
|
||||
+108
-91
@@ -1,107 +1,124 @@
|
||||
import { Octokit } from "@octokit/rest"
|
||||
|
||||
import { Commits } from "./commits"
|
||||
import { PullRequestInfo, PullRequests } from "./pullRequests"
|
||||
import { buildChangelog } from './transform';
|
||||
import * as core from '@actions/core';
|
||||
import { Tags } from './tags';
|
||||
import {Octokit} from '@octokit/rest'
|
||||
import {Commits} from './commits'
|
||||
import {PullRequestInfo, PullRequests} from './pullRequests'
|
||||
import {buildChangelog} from './transform'
|
||||
import * as core from '@actions/core'
|
||||
import {Tags} from './tags'
|
||||
import {Configuration, DefaultConfiguration} from './configuration'
|
||||
|
||||
export interface ReleaseNotesOptions {
|
||||
owner: string
|
||||
repo: string
|
||||
fromTag: string | null
|
||||
toTag: string
|
||||
configuration: Configuration
|
||||
owner: string
|
||||
repo: string
|
||||
fromTag: string | null
|
||||
toTag: string
|
||||
configuration: Configuration
|
||||
}
|
||||
|
||||
export class ReleaseNotes {
|
||||
constructor(private options: ReleaseNotesOptions) {
|
||||
constructor(private options: ReleaseNotesOptions) {}
|
||||
|
||||
async pull(token?: string): Promise<string> {
|
||||
const octokit = new Octokit({
|
||||
auth: `token ${token || process.env.GITHUB_TOKEN}`
|
||||
})
|
||||
|
||||
const {owner, repo, fromTag, toTag, configuration} = this.options
|
||||
|
||||
if (!fromTag) {
|
||||
const tagsApi = new Tags(octokit)
|
||||
|
||||
const previousTag = await tagsApi.findPredecessorTag(owner, repo, toTag)
|
||||
if (previousTag == null) {
|
||||
core.error(`Unable to retrieve previous tag given ${toTag}`)
|
||||
return configuration.empty_template
|
||||
? configuration.empty_template
|
||||
: DefaultConfiguration.empty_template
|
||||
}
|
||||
|
||||
this.options.fromTag = previousTag.name
|
||||
}
|
||||
|
||||
async pull(token?: string): Promise<string> {
|
||||
const octokit = new Octokit({
|
||||
auth: `token ${token || process.env.GITHUB_TOKEN}`
|
||||
})
|
||||
const mergedPullRequests = await this.getMergedPullRequests(octokit)
|
||||
|
||||
const { owner, repo, fromTag, toTag, configuration } = this.options
|
||||
|
||||
if(fromTag == null) {
|
||||
const tagsApi = new Tags(octokit)
|
||||
|
||||
const previousTag = await tagsApi.findPredecessorTag(owner, repo, toTag)
|
||||
if(previousTag == null) {
|
||||
core.error(`Unable to retrieve previous tag given ${toTag}`)
|
||||
return configuration.empty_template ? configuration.empty_template : DefaultConfiguration.empty_template
|
||||
}
|
||||
|
||||
this.options.fromTag = previousTag.name
|
||||
}
|
||||
|
||||
const mergedPullRequests = await this.getMergedPullRequests(octokit)
|
||||
|
||||
if (mergedPullRequests.length == 0) {
|
||||
core.warning(`No pull requests found for between ${fromTag}...${toTag}`)
|
||||
return configuration.empty_template ? configuration.empty_template : DefaultConfiguration.empty_template
|
||||
}
|
||||
|
||||
return buildChangelog(mergedPullRequests, configuration)
|
||||
if (mergedPullRequests.length === 0) {
|
||||
core.warning(`No pull requests found for between ${fromTag}...${toTag}`)
|
||||
return configuration.empty_template
|
||||
? configuration.empty_template
|
||||
: DefaultConfiguration.empty_template
|
||||
}
|
||||
|
||||
private async getMergedPullRequests(octokit: Octokit): Promise<PullRequestInfo[]> {
|
||||
const { owner, repo, fromTag, toTag } = this.options
|
||||
core.info(`Comparing ${owner}/${repo} ${fromTag}...${toTag}`)
|
||||
return buildChangelog(mergedPullRequests, configuration)
|
||||
}
|
||||
|
||||
const commitsApi = new Commits(octokit)
|
||||
const commits = await commitsApi.getDiff(owner, repo, fromTag!!, toTag)
|
||||
private async getMergedPullRequests(
|
||||
octokit: Octokit
|
||||
): Promise<PullRequestInfo[]> {
|
||||
const {owner, repo, fromTag, toTag} = this.options
|
||||
core.info(`Comparing ${owner}/${repo} ${fromTag}...${toTag}`)
|
||||
|
||||
if (commits.length === 0) {
|
||||
return []
|
||||
}
|
||||
const commitsApi = new Commits(octokit)
|
||||
const commits = await commitsApi.getDiff(owner, repo, fromTag!!, toTag)
|
||||
|
||||
const firstCommit = commits[0]
|
||||
const lastCommit = commits[commits.length - 1]
|
||||
const fromDate = firstCommit.date
|
||||
const toDate = lastCommit.date
|
||||
|
||||
core.info(`Fetching PRs between dates ${fromDate.toISOString()} ${toDate.toISOString()} for ${owner}/${repo}`)
|
||||
|
||||
const pullRequestsApi = new PullRequests(octokit)
|
||||
const pullRequests = await pullRequestsApi.getBetweenDates(owner, repo, fromDate, toDate)
|
||||
|
||||
core.info(`Found ${pullRequests.length} merged PRs for ${owner}/${repo}`)
|
||||
|
||||
const prCommits = pullRequestsApi.filterCommits(commits)
|
||||
const filteredPullRequests = []
|
||||
const pullRequestsByNumber: { [key: number]: PullRequestInfo } = {}
|
||||
|
||||
for (const pr of pullRequests) {
|
||||
pullRequestsByNumber[pr.number] = pr
|
||||
}
|
||||
|
||||
for (const commit of prCommits) {
|
||||
if (!commit.prNumber) {
|
||||
continue
|
||||
}
|
||||
|
||||
const prRef = `${owner}/${repo}#${commit.prNumber}`
|
||||
|
||||
if (pullRequestsByNumber[commit.prNumber]) {
|
||||
filteredPullRequests.push(pullRequestsByNumber[commit.prNumber])
|
||||
} else if (fromDate.toISOString() === toDate.toISOString()) {
|
||||
core.info(`${prRef} not in date range, fetching explicitly`)
|
||||
const pullRequest = await pullRequestsApi.getSingle(owner, repo, commit.prNumber)
|
||||
|
||||
if (pullRequest) {
|
||||
filteredPullRequests.push(pullRequest)
|
||||
} else {
|
||||
core.warning(`${prRef} not found! Commit text: ${commit.summary}`)
|
||||
}
|
||||
} else {
|
||||
core.info(`${prRef} not in date range, likely a merge commit from a fork-to-fork PR`)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPullRequests
|
||||
if (commits.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const firstCommit = commits[0]
|
||||
const lastCommit = commits[commits.length - 1]
|
||||
const fromDate = firstCommit.date
|
||||
const toDate = lastCommit.date
|
||||
|
||||
core.info(
|
||||
`Fetching PRs between dates ${fromDate.toISOString()} ${toDate.toISOString()} for ${owner}/${repo}`
|
||||
)
|
||||
|
||||
const pullRequestsApi = new PullRequests(octokit)
|
||||
const pullRequests = await pullRequestsApi.getBetweenDates(
|
||||
owner,
|
||||
repo,
|
||||
fromDate,
|
||||
toDate
|
||||
)
|
||||
|
||||
core.info(`Found ${pullRequests.length} merged PRs for ${owner}/${repo}`)
|
||||
|
||||
const prCommits = pullRequestsApi.filterCommits(commits)
|
||||
const filteredPullRequests = []
|
||||
const pullRequestsByNumber: {[key: number]: PullRequestInfo} = {}
|
||||
|
||||
for (const pr of pullRequests) {
|
||||
pullRequestsByNumber[pr.number] = pr
|
||||
}
|
||||
|
||||
for (const commit of prCommits) {
|
||||
if (!commit.prNumber) {
|
||||
continue
|
||||
}
|
||||
|
||||
const prRef = `${owner}/${repo}#${commit.prNumber}`
|
||||
|
||||
if (pullRequestsByNumber[commit.prNumber]) {
|
||||
filteredPullRequests.push(pullRequestsByNumber[commit.prNumber])
|
||||
} else if (fromDate.toISOString() === toDate.toISOString()) {
|
||||
core.info(`${prRef} not in date range, fetching explicitly`)
|
||||
const pullRequest = await pullRequestsApi.getSingle(
|
||||
owner,
|
||||
repo,
|
||||
commit.prNumber
|
||||
)
|
||||
|
||||
if (pullRequest) {
|
||||
filteredPullRequests.push(pullRequest)
|
||||
} else {
|
||||
core.warning(`${prRef} not found! Commit text: ${commit.summary}`)
|
||||
}
|
||||
} else {
|
||||
core.info(
|
||||
`${prRef} not in date range, likely a merge commit from a fork-to-fork PR`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPullRequests
|
||||
}
|
||||
}
|
||||
|
||||
+71
-68
@@ -1,83 +1,86 @@
|
||||
import { Octokit, RestEndpointMethodTypes } from '@octokit/rest';
|
||||
import * as core from '@actions/core';
|
||||
import { PullRequestInfo } from './pullRequests';
|
||||
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'
|
||||
import * as core from '@actions/core'
|
||||
|
||||
export interface TagInfo {
|
||||
name: string,
|
||||
commit: string
|
||||
name: string
|
||||
commit: string
|
||||
}
|
||||
|
||||
export class Tags {
|
||||
constructor(private octokit: Octokit) { }
|
||||
constructor(private octokit: Octokit) {}
|
||||
|
||||
async getTags(owner: string, repo: string): Promise<TagInfo[]> {
|
||||
const tagsInfo: TagInfo[] = []
|
||||
const options = this.octokit.repos.listTags.endpoint.merge({
|
||||
owner,
|
||||
repo,
|
||||
direction: "desc",
|
||||
per_page: 100
|
||||
async getTags(owner: string, repo: string): Promise<TagInfo[]> {
|
||||
const tagsInfo: TagInfo[] = []
|
||||
const options = this.octokit.repos.listTags.endpoint.merge({
|
||||
owner,
|
||||
repo,
|
||||
direction: 'desc',
|
||||
per_page: 100
|
||||
})
|
||||
|
||||
const max = 200
|
||||
for await (const response of this.octokit.paginate.iterator(options)) {
|
||||
type TagsListData = RestEndpointMethodTypes['repos']['listTags']['response']['data']
|
||||
const tags: TagsListData = response.data as TagsListData
|
||||
|
||||
tags.forEach(tag => {
|
||||
tagsInfo.push({
|
||||
name: tag.name,
|
||||
commit: tag.commit.sha
|
||||
})
|
||||
})
|
||||
|
||||
const max: number = 200
|
||||
for await (const response of this.octokit.paginate.iterator(options)) {
|
||||
type TagsListData = RestEndpointMethodTypes["repos"]["listTags"]["response"]["data"]
|
||||
const tags: TagsListData = response.data as TagsListData
|
||||
// for performance only fetch newest 200 tags!!
|
||||
if (tagsInfo.length >= max) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
tags.forEach(tag => {
|
||||
tagsInfo.push({
|
||||
name: tag.name,
|
||||
commit: tag.commit.sha
|
||||
})
|
||||
})
|
||||
core.info(
|
||||
`Found ${tagsInfo.length} (fetching max: ${max}) tags from the GitHub API for ${owner}/${repo}`
|
||||
)
|
||||
return tagsInfo
|
||||
}
|
||||
|
||||
// for performance only fetch newest 200 tags!!
|
||||
if (tagsInfo.length >= max) {
|
||||
break
|
||||
}
|
||||
async findPredecessorTag(
|
||||
owner: string,
|
||||
repo: string,
|
||||
tag: string
|
||||
): Promise<TagInfo | null> {
|
||||
const tags = this.sortTags(await this.getTags(owner, repo))
|
||||
|
||||
const length = tags.length
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (tags[i].name.toLowerCase() === tag.toLowerCase()) {
|
||||
return tags[i + 1]
|
||||
}
|
||||
}
|
||||
|
||||
// not found, throw exception?
|
||||
return tags[0]
|
||||
}
|
||||
|
||||
private sortTags(commits: TagInfo[]): TagInfo[] {
|
||||
commits.sort((b, a) => {
|
||||
const partsA = a.name.replace(/^v/, '').split('-')
|
||||
const partsB = b.name.replace(/^v/, '').split('-')
|
||||
const versionCompare = partsA[0].localeCompare(partsB[0])
|
||||
if (versionCompare !== 0) {
|
||||
return versionCompare
|
||||
} else {
|
||||
if (partsA.length === 1) {
|
||||
return 0
|
||||
} else if (partsB.length === 1) {
|
||||
return 1
|
||||
} else {
|
||||
return partsA[1].localeCompare(partsB[1])
|
||||
}
|
||||
|
||||
core.info(`Found ${tagsInfo.length} (fetching max: ${max}) tags from the GitHub API for ${owner}/${repo}`)
|
||||
return tagsInfo
|
||||
}
|
||||
|
||||
|
||||
async findPredecessorTag(owner: string, repo: string, tag: string): Promise<TagInfo | null> {
|
||||
const tags = this.sortTags(await this.getTags(owner, repo))
|
||||
|
||||
var length = tags.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (tags[i].name.toLowerCase() === tag.toLowerCase()) {
|
||||
return tags[i + 1]
|
||||
}
|
||||
}
|
||||
|
||||
// not found, throw exception?
|
||||
return tags[0]
|
||||
}
|
||||
|
||||
private sortTags(commits: TagInfo[]): TagInfo[] {
|
||||
commits.sort((b, a) => {
|
||||
const partsA = a.name.replace(/^v/, '').split('-')
|
||||
const partsB = b.name.replace(/^v/, '').split('-')
|
||||
const versionCompare = partsA[0].localeCompare(partsB[0])
|
||||
if(versionCompare != 0) {
|
||||
return versionCompare
|
||||
} else {
|
||||
if(partsA.length == 1) {
|
||||
return 0
|
||||
} else if(partsB.length == 1) {
|
||||
return 1
|
||||
} else {
|
||||
return partsA[1].localeCompare(partsB[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
return commits
|
||||
}
|
||||
}
|
||||
})
|
||||
return commits
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
2020.3.2 ( should resolve 2020.3.1 )
|
||||
@@ -93,4 +96,4 @@ export class Tags {
|
||||
2020.3.1-a01
|
||||
|
||||
2020.3.0
|
||||
*/
|
||||
*/
|
||||
|
||||
+103
-91
@@ -1,114 +1,126 @@
|
||||
import { PullRequestInfo, sortPullRequests } from './pullRequests';
|
||||
import * as core from '@actions/core';
|
||||
import {PullRequestInfo, sortPullRequests} from './pullRequests'
|
||||
import * as core from '@actions/core'
|
||||
import {Category, Configuration, Transformer} from './configuration'
|
||||
|
||||
export function buildChangelog(prs: PullRequestInfo[], config: Configuration): string {
|
||||
// sort to target order
|
||||
prs = sortPullRequests(prs, config.sort.toUpperCase() === "ASC")
|
||||
export function buildChangelog(
|
||||
prs: PullRequestInfo[],
|
||||
config: Configuration
|
||||
): string {
|
||||
// sort to target order
|
||||
prs = sortPullRequests(prs, config.sort.toUpperCase() === 'ASC')
|
||||
|
||||
const validatedTransformers = validateTransfomers(config.transformers)
|
||||
let transformedMap = new Map<PullRequestInfo, string>();
|
||||
// convert PRs to their text representation
|
||||
prs.forEach(pr => {
|
||||
transformedMap.set(pr, transform(fillTemplate(pr, config.pr_template), validatedTransformers))
|
||||
const validatedTransformers = validateTransfomers(config.transformers)
|
||||
const transformedMap = new Map<PullRequestInfo, string>()
|
||||
// convert PRs to their text representation
|
||||
prs.forEach(pr => {
|
||||
transformedMap.set(
|
||||
pr,
|
||||
transform(fillTemplate(pr, config.pr_template), validatedTransformers)
|
||||
)
|
||||
})
|
||||
|
||||
// bring PRs into the order of categories
|
||||
const categorized = new Map<Category, string[]>()
|
||||
config.categories.forEach(category => {
|
||||
categorized.set(category, [])
|
||||
})
|
||||
const uncategorized: string[] = []
|
||||
|
||||
// bring elements in order
|
||||
transformedMap.forEach((body, pr) => {
|
||||
let matched = false
|
||||
|
||||
categorized.forEach((pullRequests, category) => {
|
||||
if (haveCommonElements(category.labels, pr.labels)) {
|
||||
pullRequests.push(body)
|
||||
matched = true
|
||||
}
|
||||
})
|
||||
|
||||
// bring PRs into the order of categories
|
||||
let categorized = new Map<Category, string[]>();
|
||||
config.categories.forEach(category => {
|
||||
categorized.set(category, [])
|
||||
})
|
||||
let uncategorized: Array<string> = [];
|
||||
if (!matched) {
|
||||
uncategorized.push(body)
|
||||
}
|
||||
})
|
||||
|
||||
// bring elements in order
|
||||
transformedMap.forEach((body, pr) => {
|
||||
let matched = false
|
||||
// construct final changelog
|
||||
let changelog = ''
|
||||
categorized.forEach((pullRequests, category) => {
|
||||
if (pullRequests.length > 0) {
|
||||
changelog = `${changelog + category.title}\n\n`
|
||||
|
||||
categorized.forEach((prs, category) => {
|
||||
if (findCommonElements3(category.labels, pr.labels)) {
|
||||
prs.push(body)
|
||||
matched = true
|
||||
}
|
||||
})
|
||||
pullRequests.forEach(pr => {
|
||||
changelog = `${changelog + pr}\n`
|
||||
})
|
||||
|
||||
if (!matched) {
|
||||
uncategorized.push(body)
|
||||
}
|
||||
})
|
||||
// add space between
|
||||
changelog = `${changelog}\n`
|
||||
}
|
||||
})
|
||||
|
||||
// construct final changelog
|
||||
let changelog = ""
|
||||
categorized.forEach((prs, category) => {
|
||||
if (prs.length > 0) {
|
||||
changelog = changelog + category.title + "\n\n"
|
||||
let changelogUncategorized = ''
|
||||
uncategorized.forEach(pr => {
|
||||
changelogUncategorized = `${changelogUncategorized + pr}\n`
|
||||
})
|
||||
|
||||
prs.forEach(pr => {
|
||||
changelog = changelog + pr + "\n"
|
||||
})
|
||||
|
||||
// add space between
|
||||
changelog = changelog + "\n"
|
||||
}
|
||||
})
|
||||
|
||||
let changelogUncategorized = ""
|
||||
uncategorized.forEach(pr => {
|
||||
changelogUncategorized = changelogUncategorized + pr + "\n"
|
||||
})
|
||||
|
||||
// fill template
|
||||
let transformedChangelog = config.template
|
||||
transformedChangelog = transformedChangelog.replace("${{CHANGELOG}}", changelog)
|
||||
transformedChangelog = transformedChangelog.replace("${{UNCATEGORIZED}}", changelogUncategorized)
|
||||
return transformedChangelog;
|
||||
// fill template
|
||||
let transformedChangelog = config.template
|
||||
transformedChangelog = transformedChangelog.replace(
|
||||
'${{CHANGELOG}}',
|
||||
changelog
|
||||
)
|
||||
transformedChangelog = transformedChangelog.replace(
|
||||
'${{UNCATEGORIZED}}',
|
||||
changelogUncategorized
|
||||
)
|
||||
return transformedChangelog
|
||||
}
|
||||
|
||||
function findCommonElements3(arr1: string[], arr2: string[]) {
|
||||
return arr1.some(item => arr2.includes(item))
|
||||
function haveCommonElements(arr1: string[], arr2: string[]): Boolean {
|
||||
return arr1.some(item => arr2.includes(item))
|
||||
}
|
||||
|
||||
function fillTemplate(pr: PullRequestInfo, template: string): string {
|
||||
let transformed = template
|
||||
transformed = transformed.replace("${{NUMBER}}", pr.number.toString())
|
||||
transformed = transformed.replace("${{TITLE}}", pr.title)
|
||||
transformed = transformed.replace("${{URL}}", pr.htmlURL)
|
||||
transformed = transformed.replace("${{MERGED_AT}}", pr.mergedAt.toString)
|
||||
transformed = transformed.replace("${{AUTHOR}}", pr.author)
|
||||
transformed = transformed.replace("${{BODY}}", pr.body)
|
||||
return transformed
|
||||
let transformed = template
|
||||
transformed = transformed.replace('${{NUMBER}}', pr.number.toString())
|
||||
transformed = transformed.replace('${{TITLE}}', pr.title)
|
||||
transformed = transformed.replace('${{URL}}', pr.htmlURL)
|
||||
transformed = transformed.replace('${{MERGED_AT}}', pr.mergedAt.toString())
|
||||
transformed = transformed.replace('${{AUTHOR}}', pr.author)
|
||||
transformed = transformed.replace('${{BODY}}', pr.body)
|
||||
return transformed
|
||||
}
|
||||
|
||||
function transform(filled: string, transformers: RegexTransformer[]): string {
|
||||
if (transformers.length == 0) {
|
||||
return filled
|
||||
}
|
||||
let transformed = filled
|
||||
transformers.forEach(({ pattern, target }) => {
|
||||
transformed = transformed.replace(pattern!!, target)
|
||||
})
|
||||
return transformed
|
||||
if (transformers.length === 0) {
|
||||
return filled
|
||||
}
|
||||
let transformed = filled
|
||||
transformers.forEach(({pattern, target}) => {
|
||||
transformed = transformed.replace(pattern!!, target)
|
||||
})
|
||||
return transformed
|
||||
}
|
||||
|
||||
function validateTransfomers(transformers: Transformer[]): RegexTransformer[] {
|
||||
return transformers
|
||||
.map((transformer) => {
|
||||
try {
|
||||
return {
|
||||
pattern: new RegExp(transformer.pattern.replace("\\\\", '\\'), "g"),
|
||||
target: transformer.target
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Bad replacer regex: ${transformer.pattern}`)
|
||||
return {
|
||||
pattern: null,
|
||||
target: ""
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(transformer => transformer.pattern != null)
|
||||
return transformers
|
||||
.map(transformer => {
|
||||
try {
|
||||
return {
|
||||
pattern: new RegExp(transformer.pattern.replace('\\\\', '\\'), 'g'),
|
||||
target: transformer.target
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Bad replacer regex: ${transformer.pattern}`)
|
||||
return {
|
||||
pattern: null,
|
||||
target: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(transformer => transformer.pattern != null)
|
||||
}
|
||||
|
||||
|
||||
interface RegexTransformer {
|
||||
pattern: RegExp | null;
|
||||
target: string;
|
||||
}
|
||||
pattern: RegExp | null
|
||||
target: string
|
||||
}
|
||||
|
||||
+7
-6
@@ -1,7 +1,8 @@
|
||||
const fs = require("fs");
|
||||
import * as fs from 'fs'
|
||||
import {Configuration} from './configuration'
|
||||
|
||||
export function readConfiguration(filename: string) {
|
||||
const rawdata = fs.readFileSync(filename);
|
||||
const configurationJSON: Configuration = JSON.parse(rawdata);
|
||||
return configurationJSON;
|
||||
}
|
||||
export function readConfiguration(filename: string): Configuration {
|
||||
const rawdata = fs.readFileSync(filename, 'utf8')
|
||||
const configurationJSON: Configuration = JSON.parse(rawdata)
|
||||
return configurationJSON
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user