mirror of
https://github.com/wagoid/commitlint-github-action.git
synced 2026-03-31 06:46:56 +00:00
refactor: move action files to src folder
This commit is contained in:
parent
550792f0ca
commit
25a8edceb7
7 changed files with 3 additions and 3 deletions
161
src/action.js
Normal file
161
src/action.js
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
const { existsSync } = require('fs')
|
||||
const { resolve } = require('path')
|
||||
const core = require('@actions/core')
|
||||
const github = require('@actions/github')
|
||||
const lint = require('@commitlint/lint')
|
||||
const { format } = require('@commitlint/format')
|
||||
const load = require('@commitlint/load')
|
||||
const gitCommits = require('./gitCommits')
|
||||
const generateOutputs = require('./generateOutputs')
|
||||
|
||||
const pullRequestEvent = 'pull_request'
|
||||
|
||||
const { GITHUB_TOKEN, GITHUB_EVENT_NAME, GITHUB_SHA } = process.env
|
||||
|
||||
const configPath = resolve(
|
||||
process.env.GITHUB_WORKSPACE,
|
||||
core.getInput('configFile'),
|
||||
)
|
||||
|
||||
const { context: eventContext } = github
|
||||
|
||||
const pushEventHasOnlyOneCommit = from => {
|
||||
const gitEmptySha = '0000000000000000000000000000000000000000'
|
||||
|
||||
return from === gitEmptySha
|
||||
}
|
||||
|
||||
const getRangeForPushEvent = () => {
|
||||
let from = eventContext.payload.before
|
||||
const to = GITHUB_SHA
|
||||
|
||||
if (eventContext.payload.forced) {
|
||||
// When a commit is forced, "before" field from the push event data may point to a commit that doesn't exist
|
||||
console.warn(
|
||||
'Commit was forced, checking only the latest commit from push instead of a range of commit messages',
|
||||
)
|
||||
from = null
|
||||
}
|
||||
|
||||
if (pushEventHasOnlyOneCommit(from)) {
|
||||
from = null
|
||||
}
|
||||
|
||||
return [from, to]
|
||||
}
|
||||
|
||||
const getRangeForEvent = async () => {
|
||||
if (GITHUB_EVENT_NAME !== pullRequestEvent) return getRangeForPushEvent()
|
||||
|
||||
const octokit = new github.GitHub(GITHUB_TOKEN)
|
||||
const { owner, repo, number } = eventContext.issue
|
||||
const { data: commits } = await octokit.pulls.listCommits({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: number,
|
||||
})
|
||||
const commitShas = commits.map(commit => commit.sha)
|
||||
const [from] = commitShas
|
||||
const to = commitShas[commitShas.length - 1]
|
||||
// Git revision range doesn't include the "from" field in "git log", so for "from" we use the parent commit of PR's first commit
|
||||
const fromParent = `${from}^1`
|
||||
|
||||
return [fromParent, to]
|
||||
}
|
||||
|
||||
function getHistoryCommits(from, to) {
|
||||
const options = {
|
||||
from,
|
||||
to,
|
||||
}
|
||||
|
||||
if (core.getInput('firstParent') === 'true') {
|
||||
options.firstParent = true
|
||||
}
|
||||
|
||||
if (!from) {
|
||||
options.maxCount = 1
|
||||
}
|
||||
|
||||
return gitCommits(options)
|
||||
}
|
||||
|
||||
function getOptsFromConfig(config) {
|
||||
return {
|
||||
parserOpts:
|
||||
config.parserPreset != null && config.parserPreset.parserOpts != null
|
||||
? config.parserPreset.parserOpts
|
||||
: {},
|
||||
plugins: config.plugins != null ? config.plugins : {},
|
||||
ignores: config.ignores != null ? config.ignores : [],
|
||||
defaultIgnores:
|
||||
config.defaultIgnores != null ? config.defaultIgnores : true,
|
||||
}
|
||||
}
|
||||
|
||||
const formatErrors = lintedCommits =>
|
||||
format(
|
||||
{ results: lintedCommits.map(commit => commit.lintResult) },
|
||||
{
|
||||
color: true,
|
||||
helpUrl: core.getInput('helpURL'),
|
||||
},
|
||||
)
|
||||
|
||||
const hasOnlyWarnings = lintedCommits =>
|
||||
lintedCommits.length &&
|
||||
lintedCommits.every(
|
||||
({ lintResult }) => lintResult.valid && lintResult.warnings.length,
|
||||
)
|
||||
|
||||
const setFailed = formattedResults => {
|
||||
core.setFailed(`You have commit messages with errors\n\n${formattedResults}`)
|
||||
}
|
||||
|
||||
const handleOnlyWarnings = formattedResults => {
|
||||
if (core.getInput('failOnWarnings') === 'true') {
|
||||
setFailed(formattedResults)
|
||||
} else {
|
||||
console.log(`You have commit messages with warnings\n\n${formattedResults}`)
|
||||
}
|
||||
}
|
||||
|
||||
const showLintResults = async ([from, to]) => {
|
||||
const failOnWarnings = core.getInput('failOnWarnings')
|
||||
const commits = await getHistoryCommits(from, to)
|
||||
const config = existsSync(configPath)
|
||||
? await load({}, { file: configPath })
|
||||
: {}
|
||||
const opts = getOptsFromConfig(config)
|
||||
const lintedCommits = await Promise.all(
|
||||
commits.map(async commit => ({
|
||||
lintResult: await lint(commit.message, config.rules, opts),
|
||||
hash: commit.hash,
|
||||
})),
|
||||
)
|
||||
const formattedResults = formatErrors(lintedCommits)
|
||||
|
||||
generateOutputs(lintedCommits)
|
||||
|
||||
if (hasOnlyWarnings(lintedCommits)) {
|
||||
handleOnlyWarnings(formattedResults)
|
||||
} else if (formattedResults) {
|
||||
setFailed(formattedResults)
|
||||
} else {
|
||||
console.log('Lint free! 🎉')
|
||||
}
|
||||
}
|
||||
|
||||
const exitWithMessage = message => error => {
|
||||
core.setFailed(`${message}\n${error.message}\n${error.stack}`)
|
||||
}
|
||||
|
||||
const commitLinterAction = () =>
|
||||
getRangeForEvent()
|
||||
.catch(
|
||||
exitWithMessage("error trying to get list of pull request's commits"),
|
||||
)
|
||||
.then(showLintResults)
|
||||
.catch(exitWithMessage('error running commitlint'))
|
||||
|
||||
module.exports = commitLinterAction
|
||||
450
src/action.test.js
Normal file
450
src/action.test.js
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
const { git } = require('@commitlint/test')
|
||||
const execa = require('execa')
|
||||
const td = require('testdouble')
|
||||
const {
|
||||
updateEnvVars,
|
||||
gitEmptyCommit,
|
||||
getCommitHashes,
|
||||
updatePushEnvVars,
|
||||
createPushEventPayload,
|
||||
createPullRequestEventPayload,
|
||||
updatePullRequestEnvVars,
|
||||
} = require('./testUtils')
|
||||
|
||||
const resultsOutputId = 'results'
|
||||
|
||||
const {
|
||||
matchers: { contains },
|
||||
} = td
|
||||
|
||||
const initialEnv = { ...process.env }
|
||||
|
||||
const listCommits = td.func('listCommits')
|
||||
|
||||
const runAction = () => {
|
||||
const github = require('@actions/github')
|
||||
class MockOctokit {
|
||||
constructor() {
|
||||
this.pulls = {
|
||||
listCommits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateEnvVars({ GITHBU_TOKEN: 'test-github-token' })
|
||||
td.replace(github, 'GitHub', MockOctokit)
|
||||
|
||||
return require('./action')()
|
||||
}
|
||||
|
||||
describe('Commit Linter action', () => {
|
||||
let core
|
||||
let cwd
|
||||
|
||||
beforeEach(() => {
|
||||
core = require('@actions/core')
|
||||
td.replace(core, 'getInput')
|
||||
td.replace(core, 'setFailed')
|
||||
td.replace(core, 'setOutput')
|
||||
td.when(core.getInput('configFile')).thenReturn('./commitlint.config.js')
|
||||
td.when(core.getInput('firstParent')).thenReturn('true')
|
||||
td.when(core.getInput('failOnWarnings')).thenReturn('false')
|
||||
td.when(core.getInput('helpURL')).thenReturn(
|
||||
'https://github.com/conventional-changelog/commitlint/#what-is-commitlint',
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
td.reset()
|
||||
process.env = initialEnv
|
||||
jest.resetModules()
|
||||
})
|
||||
|
||||
it('should fail for single push with incorrect message', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'wrong message')
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(contains('You have commit messages with errors')))
|
||||
})
|
||||
|
||||
it('should pass for single push with correct message', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'chore: correct message')
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'log')
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(), { times: 0, ignoreExtraArgs: true })
|
||||
td.verify(console.log('Lint free! 🎉'))
|
||||
})
|
||||
|
||||
it('should fail for push range with wrong messages', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'message from before push')
|
||||
await gitEmptyCommit(cwd, 'wrong message 1')
|
||||
await gitEmptyCommit(cwd, 'wrong message 2')
|
||||
const [before, , to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { before, to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(contains('wrong message 1')))
|
||||
td.verify(core.setFailed(contains('wrong message 2')))
|
||||
})
|
||||
|
||||
it('should pass for push range with correct messages', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'message from before push')
|
||||
await gitEmptyCommit(cwd, 'chore: correct message 1')
|
||||
await gitEmptyCommit(cwd, 'chore: correct message 2')
|
||||
const [before, , to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { before, to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'log')
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(), { times: 0, ignoreExtraArgs: true })
|
||||
td.verify(console.log('Lint free! 🎉'))
|
||||
})
|
||||
|
||||
it('should lint only last commit for forced push', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'message from before push')
|
||||
await gitEmptyCommit(cwd, 'wrong message 1')
|
||||
await gitEmptyCommit(cwd, 'wrong message 2')
|
||||
const [before, , to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { before, to, forced: true })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'warn')
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
console.warn(
|
||||
'Commit was forced, checking only the latest commit from push instead of a range of commit messages',
|
||||
),
|
||||
)
|
||||
td.verify(core.setFailed(contains('wrong message 1')), { times: 0 })
|
||||
td.verify(core.setFailed(contains('wrong message 2')))
|
||||
})
|
||||
|
||||
it('should lint only last commit when "before" field is an empty sha', async () => {
|
||||
const gitEmptySha = '0000000000000000000000000000000000000000'
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'message from before push')
|
||||
await gitEmptyCommit(cwd, 'wrong message 1')
|
||||
await gitEmptyCommit(cwd, 'chore(WRONG): message 2')
|
||||
const [before, , to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { before: gitEmptySha, to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(contains('wrong message 1')), { times: 0 })
|
||||
td.verify(core.setFailed(contains('chore(WRONG): message 2')))
|
||||
})
|
||||
|
||||
it('should fail for commit with scope that is not a lerna package', async () => {
|
||||
cwd = await git.bootstrap('fixtures/lerna-scopes')
|
||||
td.when(core.getInput('configFile')).thenReturn('./commitlint.config.yml')
|
||||
await gitEmptyCommit(cwd, 'chore(wrong): not including package scope')
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
core.setFailed(contains('chore(wrong): not including package scope')),
|
||||
)
|
||||
})
|
||||
|
||||
it('should pass for scope that is a lerna package', async () => {
|
||||
cwd = await git.bootstrap('fixtures/lerna-scopes')
|
||||
td.when(core.getInput('configFile')).thenReturn('./commitlint.config.yml')
|
||||
await gitEmptyCommit(cwd, 'chore(second-package): this works')
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'log')
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(console.log('Lint free! 🎉'))
|
||||
})
|
||||
|
||||
it("should fail for commit that doesn't comply with jira rules", async () => {
|
||||
cwd = await git.bootstrap('fixtures/jira')
|
||||
td.when(core.getInput('configFile')).thenReturn('./commitlint.config.js')
|
||||
await gitEmptyCommit(cwd, 'ib-21212121212121: without jira ticket')
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
core.setFailed(contains('ib-21212121212121: without jira ticket')),
|
||||
)
|
||||
td.verify(
|
||||
core.setFailed(
|
||||
contains(
|
||||
'ib-21212121212121 taskId must not be loonger than 9 characters',
|
||||
),
|
||||
),
|
||||
)
|
||||
td.verify(
|
||||
core.setFailed(
|
||||
contains('ib-21212121212121 taskId must be uppercase case'),
|
||||
),
|
||||
)
|
||||
td.verify(
|
||||
core.setFailed(
|
||||
contains('ib-21212121212121 commitStatus must be uppercase case'),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
it('should NOT consider commits from another branch', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'chore: commit before')
|
||||
await gitEmptyCommit(cwd, 'chore: correct message')
|
||||
await execa.command('git checkout -b another-branch', { cwd })
|
||||
await gitEmptyCommit(cwd, 'wrong commit from another branch')
|
||||
await execa.command('git checkout -', { cwd })
|
||||
await execa.command('git merge --no-ff another-branch', { cwd })
|
||||
const [before, , to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { before, to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'log')
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(console.log('Lint free! 🎉'))
|
||||
})
|
||||
|
||||
it('should consider commits from another branch when firstParent is false', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'chore: commit before')
|
||||
await gitEmptyCommit(cwd, 'chore: correct message')
|
||||
await execa.command('git checkout -b another-branch', { cwd })
|
||||
await gitEmptyCommit(cwd, 'wrong commit from another branch')
|
||||
await execa.command('git checkout -', { cwd })
|
||||
await execa.command('git merge --no-ff another-branch', { cwd })
|
||||
const [before, , , to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { before, to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.when(core.getInput('firstParent')).thenReturn('false')
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(contains('wrong commit from another branch')))
|
||||
})
|
||||
|
||||
it('should lint all commits from a pull request', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
td.when(core.getInput('configFile')).thenReturn('./commitlint.config.js')
|
||||
await gitEmptyCommit(cwd, 'message from before push')
|
||||
await gitEmptyCommit(cwd, 'wrong message 1')
|
||||
await gitEmptyCommit(cwd, 'wrong message 2')
|
||||
await gitEmptyCommit(cwd, 'wrong message 3')
|
||||
await createPullRequestEventPayload(cwd)
|
||||
const [, first, second, to] = await getCommitHashes(cwd)
|
||||
updatePullRequestEnvVars(cwd, to)
|
||||
td.when(
|
||||
listCommits({
|
||||
owner: 'wagoid',
|
||||
repo: 'commitlint-github-action',
|
||||
pull_number: '1',
|
||||
}),
|
||||
).thenResolve({
|
||||
data: [first, second, to].map(sha => ({ sha })),
|
||||
})
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(contains('message from before push')), {
|
||||
times: 0,
|
||||
})
|
||||
td.verify(core.setFailed(contains('wrong message 1')))
|
||||
td.verify(core.setFailed(contains('wrong message 2')))
|
||||
td.verify(core.setFailed(contains('wrong message 3')))
|
||||
})
|
||||
|
||||
it('should show an error message when failing to fetch commits', async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
td.when(core.getInput('configFile')).thenReturn('./commitlint.config.js')
|
||||
await gitEmptyCommit(cwd, 'commit message')
|
||||
await createPullRequestEventPayload(cwd)
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
updatePullRequestEnvVars(cwd, to)
|
||||
td.when(
|
||||
listCommits({
|
||||
owner: 'wagoid',
|
||||
repo: 'commitlint-github-action',
|
||||
pull_number: '1',
|
||||
}),
|
||||
).thenReject(new Error('HttpError: Bad credentials'))
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
core.setFailed(
|
||||
contains("error trying to get list of pull request's commits"),
|
||||
),
|
||||
)
|
||||
td.verify(core.setFailed(contains('HttpError: Bad credentials')))
|
||||
})
|
||||
|
||||
describe('when all errors are just warnings', () => {
|
||||
let expectedResultsOutput
|
||||
|
||||
beforeEach(async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(
|
||||
cwd,
|
||||
'chore: correct message\nsome context without leading blank line',
|
||||
)
|
||||
const [to] = await getCommitHashes(cwd)
|
||||
await createPushEventPayload(cwd, { to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'log')
|
||||
|
||||
expectedResultsOutput = [
|
||||
{
|
||||
hash: to,
|
||||
message:
|
||||
'chore: correct message\n\nsome context without leading blank line',
|
||||
valid: true,
|
||||
errors: [],
|
||||
warnings: ['body must have leading blank line'],
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
it('should pass and show that warnings exist', async () => {
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setFailed(), { times: 0, ignoreExtraArgs: true })
|
||||
td.verify(console.log(contains('You have commit messages with warnings')))
|
||||
})
|
||||
|
||||
it('should show the results in an output', async () => {
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setOutput(resultsOutputId, expectedResultsOutput))
|
||||
})
|
||||
|
||||
describe('and failOnWarnings is set to true', () => {
|
||||
beforeEach(() => {
|
||||
td.when(core.getInput('failOnWarnings')).thenReturn('true')
|
||||
})
|
||||
|
||||
it('should fail', async () => {
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
core.setFailed(contains('You have commit messages with errors')),
|
||||
)
|
||||
})
|
||||
|
||||
it('should show the results in an output', async () => {
|
||||
await runAction()
|
||||
|
||||
td.verify(core.setOutput(resultsOutputId, expectedResultsOutput))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a subset of errors are just warnings', () => {
|
||||
let firstHash
|
||||
let secondHash
|
||||
|
||||
beforeEach(async () => {
|
||||
cwd = await git.bootstrap('fixtures/conventional')
|
||||
await gitEmptyCommit(cwd, 'message from before push')
|
||||
await gitEmptyCommit(
|
||||
cwd,
|
||||
'chore: correct message\nsome context without leading blank line',
|
||||
)
|
||||
await gitEmptyCommit(cwd, 'wrong message')
|
||||
const [before, firstCommit, to] = await getCommitHashes(cwd)
|
||||
firstHash = firstCommit
|
||||
secondHash = to
|
||||
await createPushEventPayload(cwd, { before, to })
|
||||
updatePushEnvVars(cwd, to)
|
||||
td.replace(process, 'cwd', () => cwd)
|
||||
td.replace(console, 'log')
|
||||
})
|
||||
|
||||
it('should fail', async () => {
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
core.setFailed(contains('You have commit messages with errors')),
|
||||
)
|
||||
})
|
||||
|
||||
it('should show the results in an output', async () => {
|
||||
await runAction()
|
||||
|
||||
const expectedResultsOutput = [
|
||||
{
|
||||
hash: secondHash,
|
||||
message: 'wrong message',
|
||||
valid: false,
|
||||
errors: ['subject may not be empty', 'type may not be empty'],
|
||||
warnings: [],
|
||||
},
|
||||
{
|
||||
hash: firstHash,
|
||||
message:
|
||||
'chore: correct message\n\nsome context without leading blank line',
|
||||
valid: true,
|
||||
errors: [],
|
||||
warnings: ['body must have leading blank line'],
|
||||
},
|
||||
]
|
||||
|
||||
td.verify(core.setOutput(resultsOutputId, expectedResultsOutput))
|
||||
})
|
||||
|
||||
describe('and failOnWarnings is set to true', () => {
|
||||
beforeEach(() => {
|
||||
td.when(core.getInput('failOnWarnings')).thenReturn('true')
|
||||
})
|
||||
|
||||
it('should fail', async () => {
|
||||
await runAction()
|
||||
|
||||
td.verify(
|
||||
core.setFailed(contains('You have commit messages with errors')),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
24
src/generateOutputs.js
Normal file
24
src/generateOutputs.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const core = require('@actions/core')
|
||||
|
||||
const resultsOutputId = 'results'
|
||||
|
||||
const mapMessageValidation = item => item.message
|
||||
|
||||
const mapResultOutput = ({
|
||||
hash,
|
||||
lintResult: { valid, errors, warnings, input },
|
||||
}) => ({
|
||||
hash,
|
||||
message: input,
|
||||
valid,
|
||||
errors: errors.map(mapMessageValidation),
|
||||
warnings: warnings.map(mapMessageValidation),
|
||||
})
|
||||
|
||||
const generateOutputs = lintedCommits => {
|
||||
const resultsOutput = lintedCommits.map(mapResultOutput)
|
||||
|
||||
core.setOutput(resultsOutputId, resultsOutput)
|
||||
}
|
||||
|
||||
module.exports = generateOutputs
|
||||
43
src/gitCommits.js
Normal file
43
src/gitCommits.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
const dargs = require('dargs')
|
||||
const execa = require('execa')
|
||||
|
||||
const commitDelimiter = '--------->commit---------'
|
||||
|
||||
const hashDelimiter = '--------->hash---------'
|
||||
|
||||
const format = `%H${hashDelimiter}%B%n${commitDelimiter}`
|
||||
|
||||
const buildGitArgs = gitOpts => {
|
||||
const { from, to, ...otherOpts } = gitOpts
|
||||
var formatArg = `--format=${format}`
|
||||
var fromToArg = [from, to].filter(Boolean).join('..')
|
||||
|
||||
var gitArgs = ['log', formatArg, fromToArg]
|
||||
|
||||
return gitArgs.concat(
|
||||
dargs(gitOpts, {
|
||||
includes: Object.keys(otherOpts),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const gitCommits = async gitOpts => {
|
||||
var args = buildGitArgs(gitOpts)
|
||||
|
||||
var { stdout } = await execa('git', args, {
|
||||
cwd: process.cwd(),
|
||||
})
|
||||
|
||||
const commits = stdout.split(`${commitDelimiter}\n`).map(messageItem => {
|
||||
const [hash, message] = messageItem.split(hashDelimiter)
|
||||
|
||||
return {
|
||||
hash,
|
||||
message,
|
||||
}
|
||||
})
|
||||
|
||||
return commits
|
||||
}
|
||||
|
||||
module.exports = gitCommits
|
||||
74
src/testUtils.js
Normal file
74
src/testUtils.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const { promisify } = require('util')
|
||||
const execa = require('execa')
|
||||
const td = require('testdouble')
|
||||
|
||||
const writeFile = promisify(fs.writeFile)
|
||||
|
||||
const updateEnvVars = (exports.updateEnvVars = envVars => {
|
||||
Object.keys(envVars).forEach(key => {
|
||||
process.env[key] = envVars[key]
|
||||
})
|
||||
})
|
||||
|
||||
exports.gitEmptyCommit = (cwd, message) =>
|
||||
execa('git', ['commit', '--allow-empty', '-m', message], { cwd })
|
||||
|
||||
exports.getCommitHashes = async cwd => {
|
||||
const { stdout } = await execa.command('git log --pretty=%H', { cwd })
|
||||
const hashes = stdout.split('\n').reverse()
|
||||
|
||||
return hashes
|
||||
}
|
||||
|
||||
exports.updatePushEnvVars = (cwd, to) => {
|
||||
updateEnvVars({
|
||||
GITHUB_WORKSPACE: cwd,
|
||||
GITHUB_EVENT_NAME: 'push',
|
||||
GITHUB_SHA: to,
|
||||
})
|
||||
}
|
||||
|
||||
exports.createPushEventPayload = async (
|
||||
cwd,
|
||||
{ before = null, to, forced = false },
|
||||
) => {
|
||||
const payload = {
|
||||
after: to,
|
||||
before,
|
||||
forced,
|
||||
}
|
||||
const eventPath = path.join(cwd, 'pushEventPayload.json')
|
||||
|
||||
updateEnvVars({ GITHUB_EVENT_PATH: eventPath })
|
||||
await writeFile(eventPath, JSON.stringify(payload), 'utf8')
|
||||
}
|
||||
|
||||
exports.createPullRequestEventPayload = async cwd => {
|
||||
const payload = {
|
||||
number: '1',
|
||||
repository: {
|
||||
owner: {
|
||||
login: 'wagoid',
|
||||
},
|
||||
name: 'commitlint-github-action',
|
||||
},
|
||||
}
|
||||
|
||||
const eventPath = path.join(cwd, 'pullRequestEventPayload.json')
|
||||
|
||||
updateEnvVars({
|
||||
GITHUB_EVENT_PATH: eventPath,
|
||||
GITHUB_REPOSITORY: 'wagoid/commitlint-github-action',
|
||||
})
|
||||
await writeFile(eventPath, JSON.stringify(payload), 'utf8')
|
||||
}
|
||||
|
||||
exports.updatePullRequestEnvVars = (cwd, to) => {
|
||||
updateEnvVars({
|
||||
GITHUB_WORKSPACE: cwd,
|
||||
GITHUB_EVENT_NAME: 'pull_request',
|
||||
GITHUB_SHA: to,
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue