Support only-new-issues (#19)

Fixes #16
This commit is contained in:
Denis Isaev 2020-05-22 10:36:12 +03:00 committed by GitHub
parent 64c208bfbc
commit 10cbc929b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62797 additions and 8056 deletions

View File

@ -15,7 +15,6 @@ jobs:
npm install npm install
npm run prepare-deps npm run prepare-deps
npm run all npm run all
git diff --exit-code
test: # make sure the action works on a clean machine without building test: # make sure the action works on a clean machine without building
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -23,5 +22,5 @@ jobs:
- uses: ./ - uses: ./
with: with:
version: v1.26 version: v1.26
args: --issues-exit-code=0 ./... args: --issues-exit-code=0 ./sample/...
working-directory: sample only-new-issues: true

View File

@ -37,6 +37,9 @@ jobs:
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0 # args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
``` ```
We recommend running this action in a job separate from other jobs (`go test`, etc) We recommend running this action in a job separate from other jobs (`go test`, etc)

View File

@ -13,6 +13,14 @@ inputs:
working-directory: working-directory:
description: 'golangci-lint working directory, default is project root' description: 'golangci-lint working directory, default is project root'
required: false required: false
github-token:
description: 'the token is used for fetching patch of a pull request to show only new issues'
default: ${{ github.token }}
required: true
only-new-issues:
description: 'if set to true and the action runs on a pull request - the action outputs only newly found issues'
default: false
required: true
runs: runs:
using: 'node12' using: 'node12'

35305
dist/post_run/index.js vendored

File diff suppressed because it is too large Load Diff

35305
dist/run/index.js vendored

File diff suppressed because it is too large Load Diff

46
package-lock.json generated
View File

@ -257,6 +257,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/tmp": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.0.tgz",
"integrity": "sha512-flgpHJjntpBAdJD43ShRosQvNC0ME97DCfGvZEDlAThQmnerRXrLbX6YgzRBQCZTthET9eAWFAMaYP0m0Y4HzQ=="
},
"@types/uuid": { "@types/uuid": {
"version": "3.4.9", "version": "3.4.9",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.9.tgz", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.9.tgz",
@ -923,6 +928,17 @@
"chardet": "^0.7.0", "chardet": "^0.7.0",
"iconv-lite": "^0.4.24", "iconv-lite": "^0.4.24",
"tmp": "^0.0.33" "tmp": "^0.0.33"
},
"dependencies": {
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
}
}
} }
}, },
"fast-deep-equal": { "fast-deep-equal": {
@ -996,8 +1012,7 @@
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
"dev": true
}, },
"function-bind": { "function-bind": {
"version": "1.1.1", "version": "1.1.1",
@ -1029,7 +1044,6 @@
"version": "7.1.6", "version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@ -1125,7 +1139,6 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": { "requires": {
"once": "^1.3.0", "once": "^1.3.0",
"wrappy": "1" "wrappy": "1"
@ -1134,8 +1147,7 @@
"inherits": { "inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
"dev": true
}, },
"inquirer": { "inquirer": {
"version": "7.1.0", "version": "7.1.0",
@ -1625,8 +1637,7 @@
"path-is-absolute": { "path-is-absolute": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
"dev": true
}, },
"path-key": { "path-key": {
"version": "2.0.1", "version": "2.0.1",
@ -2035,12 +2046,21 @@
"dev": true "dev": true
}, },
"tmp": { "tmp": {
"version": "0.0.33", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
"dev": true,
"requires": { "requires": {
"os-tmpdir": "~1.0.2" "rimraf": "^3.0.0"
},
"dependencies": {
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"requires": {
"glob": "^7.1.3"
}
}
} }
}, },
"tslib": { "tslib": {

View File

@ -9,6 +9,8 @@
"prepare-cache": "cd node_modules/cache && npm run build", "prepare-cache": "cd node_modules/cache && npm run build",
"prepare-deps": "npm run prepare-setup-go && npm run prepare-cache", "prepare-deps": "npm run prepare-setup-go && npm run prepare-cache",
"build": "tsc && ncc build -o dist/run/ src/main.ts && ncc build -o dist/post_run/ src/post_main.ts", "build": "tsc && ncc build -o dist/run/ src/main.ts && ncc build -o dist/post_run/ src/post_main.ts",
"watched_build_main": "tsc && ncc build -w -o dist/run/ src/main.ts",
"watched_build_post_main": "tsc && ncc build -w -o dist/post_run/ src/post_main.ts",
"type-check": "tsc", "type-check": "tsc",
"lint": "eslint --max-warnings 1 **/*.ts --cache", "lint": "eslint --max-warnings 1 **/*.ts --cache",
"lint-fix": "eslint **/*.ts --cache --fix", "lint-fix": "eslint **/*.ts --cache --fix",
@ -29,8 +31,10 @@
"@actions/github": "^2.1.1", "@actions/github": "^2.1.1",
"@actions/tool-cache": "^1.3.4", "@actions/tool-cache": "^1.3.4",
"@types/semver": "^7.1.0", "@types/semver": "^7.1.0",
"@types/tmp": "^0.2.0",
"cache": "git+https://github.com/golangci/cache.git", "cache": "git+https://github.com/golangci/cache.git",
"setup-go": "git+https://github.com/actions/setup-go.git" "setup-go": "git+https://github.com/actions/setup-go.git",
"tmp": "^0.2.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.0.4", "@types/node": "^12.0.4",

View File

@ -10,6 +10,7 @@ import (
// Hash~ // Hash~
func Hash(data string) string { func Hash(data string) string {
retError() retError()
retError2()
h := md5.New() h := md5.New()
h.Write([]byte(data)) h.Write([]byte(data))
@ -19,3 +20,7 @@ func Hash(data string) string {
func retError() error { func retError() error {
return errors.New("err") return errors.New("err")
} }
func retError2() error {
return errors.New("err2")
}

View File

@ -1,7 +1,9 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import * as github from "@actions/github"
import { exec, ExecOptions } from "child_process" import { exec, ExecOptions } from "child_process"
import * as fs from "fs" import * as fs from "fs"
import * as path from "path" import * as path from "path"
import { dir } from "tmp"
import { promisify } from "util" import { promisify } from "util"
import { restoreCache, saveCache } from "./cache" import { restoreCache, saveCache } from "./cache"
@ -9,26 +11,91 @@ import { installGo, installLint } from "./install"
import { findLintVersion } from "./version" import { findLintVersion } from "./version"
const execShellCommand = promisify(exec) const execShellCommand = promisify(exec)
const writeFile = promisify(fs.writeFile)
const createTempDir = promisify(dir)
async function prepareLint(): Promise<string> { async function prepareLint(): Promise<string> {
const versionConfig = await findLintVersion() const versionConfig = await findLintVersion()
return await installLint(versionConfig) return await installLint(versionConfig)
} }
async function prepareEnv(): Promise<string> { async function fetchPatch(): Promise<string> {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim()
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`)
}
if (onlyNewIssues === `false`) {
return ``
}
const ctx = github.context
if (ctx.eventName !== `pull_request`) {
core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`)
return ``
}
const pull = ctx.payload.pull_request
if (!pull) {
core.warning(`No pull request in context`)
return ``
}
const octokit = new github.GitHub(core.getInput(`github-token`, { required: true }))
let patch: string
try {
const patchResp = await octokit.pulls.get({
owner: ctx.repo.owner,
repo: ctx.repo.repo,
[`pull_number`]: pull.number,
mediaType: {
format: `diff`,
},
})
if (patchResp.status !== 200) {
core.warning(`failed to fetch pull request patch: response status is ${patchResp.status}`)
return `` // don't fail the action, but analyze without patch
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
patch = patchResp.data as any
} catch (err) {
console.warn(`failed to fetch pull request patch:`, err)
return `` // don't fail the action, but analyze without patch
}
try {
const tempDir = await createTempDir()
const patchPath = path.join(tempDir, "pull.patch")
core.info(`Writing patch to ${patchPath}`)
await writeFile(patchPath, patch)
return patchPath
} catch (err) {
console.warn(`failed to save pull request patch:`, err)
return `` // don't fail the action, but analyze without patch
}
}
type Env = {
lintPath: string
patchPath: string
}
async function prepareEnv(): Promise<Env> {
const startedAt = Date.now() const startedAt = Date.now()
// Prepare cache, lint and go in parallel. // Prepare cache, lint and go in parallel.
const restoreCachePromise = restoreCache() const restoreCachePromise = restoreCache()
const prepareLintPromise = prepareLint() const prepareLintPromise = prepareLint()
const installGoPromise = installGo() const installGoPromise = installGo()
const patchPromise = fetchPatch()
const lintPath = await prepareLintPromise const lintPath = await prepareLintPromise
await installGoPromise await installGoPromise
await restoreCachePromise await restoreCachePromise
const patchPath = await patchPromise
core.info(`Prepared env in ${Date.now() - startedAt}ms`) core.info(`Prepared env in ${Date.now() - startedAt}ms`)
return lintPath return { lintPath, patchPath }
} }
type ExecRes = { type ExecRes = {
@ -45,21 +112,46 @@ const printOutput = (res: ExecRes): void => {
} }
} }
async function runLint(lintPath: string): Promise<void> { async function runLint(lintPath: string, patchPath: string): Promise<void> {
const debug = core.getInput(`debug`) const debug = core.getInput(`debug`)
if (debug.split(`,`).includes(`cache`)) { if (debug.split(`,`).includes(`cache`)) {
const res = await execShellCommand(`${lintPath} cache status`) const res = await execShellCommand(`${lintPath} cache status`)
printOutput(res) printOutput(res)
} }
const args = core.getInput(`args`) const userArgs = core.getInput(`args`)
if (args.includes(`-out-format`)) { const addedArgs: string[] = []
const userArgNames = new Set<string>()
userArgs
.split(/\s/)
.map(arg => arg.split(`=`)[0])
.filter(arg => arg.startsWith(`-`))
.forEach(arg => {
userArgNames.add(arg.replace(`-`, ``))
})
if (userArgNames.has(`out-format`)) {
throw new Error(`please, don't change out-format for golangci-lint: it can be broken in a future`) throw new Error(`please, don't change out-format for golangci-lint: it can be broken in a future`)
} }
addedArgs.push(`--out-format=github-actions`)
if (patchPath && (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`))) {
throw new Error(`please, don't specify manually --new* args when requesting only new issues`)
}
addedArgs.push(`--new-from-patch=${patchPath}`)
// Override config values.
addedArgs.push(`--new=false`)
addedArgs.push(`--new-from-rev=`)
const workingDirectory = core.getInput(`working-directory`) const workingDirectory = core.getInput(`working-directory`)
const cmdArgs: ExecOptions = {} const cmdArgs: ExecOptions = {}
if (workingDirectory != ``) { if (workingDirectory) {
if (patchPath) {
// TODO: make them compatible
throw new Error(`options working-directory and only-new-issues aren't compatible`)
}
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) { if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
throw new Error(`working-directory (${workingDirectory}) was not a path`) throw new Error(`working-directory (${workingDirectory}) was not a path`)
} }
@ -67,7 +159,7 @@ async function runLint(lintPath: string): Promise<void> {
cmdArgs.cwd = path.resolve(workingDirectory) cmdArgs.cwd = path.resolve(workingDirectory)
} }
const cmd = `${lintPath} run --out-format=github-actions ${args}`.trimRight() const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight()
core.info(`Running [${cmd}] in [${cmdArgs.cwd}] ...`) core.info(`Running [${cmd}] in [${cmdArgs.cwd}] ...`)
const startedAt = Date.now() const startedAt = Date.now()
try { try {
@ -91,8 +183,8 @@ async function runLint(lintPath: string): Promise<void> {
export async function run(): Promise<void> { export async function run(): Promise<void> {
try { try {
const lintPath = await core.group(`prepare environment`, prepareEnv) const { lintPath, patchPath } = await core.group(`prepare environment`, prepareEnv)
await core.group(`run golangci-lint`, () => runLint(lintPath)) await core.group(`run golangci-lint`, () => runLint(lintPath, patchPath))
} catch (error) { } catch (error) {
core.error(`Failed to run: ${error}, ${error.stack}`) core.error(`Failed to run: ${error}, ${error.stack}`)
core.setFailed(error.message) core.setFailed(error.message)