Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
cf72500b28 | |||
d737e6d962 | |||
8870cfbcd4 | |||
3395f777a4 | |||
04eca20383 |
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
build: # make sure build/ci work properly
|
build: # make sure build/ci work properly
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- run: |
|
- run: |
|
||||||
npm install
|
npm install
|
||||||
npm run prepare-deps
|
npm run prepare-deps
|
||||||
@ -18,9 +18,9 @@ jobs:
|
|||||||
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:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- uses: ./
|
- uses: ./
|
||||||
with:
|
with:
|
||||||
version: v1.26
|
version: v1.28
|
||||||
args: --issues-exit-code=0 ./sample/...
|
args: --issues-exit-code=0 ./sample/...
|
||||||
only-new-issues: true
|
only-new-issues: true
|
||||||
|
@ -58,7 +58,7 @@ The restrictions of annotations are the following:
|
|||||||
|
|
||||||
The action was implemented with performance in mind:
|
The action was implemented with performance in mind:
|
||||||
|
|
||||||
1. We cache data by [@actions/cache](https://github.com/actions/cache) between builds: Go build cache, Go modules cache, golangci-lint analysis cache.
|
1. We cache data by [@actions/cache](https://github.com/actions/toolkit/tree/master/packages/cache) between builds: Go build cache, Go modules cache, golangci-lint analysis cache.
|
||||||
2. We don't use Docker because image pulling is slow.
|
2. We don't use Docker because image pulling is slow.
|
||||||
3. We do as much as we can in parallel, e.g. we download cache, go and golangci-lint binary in parallel.
|
3. We do as much as we can in parallel, e.g. we download cache, go and golangci-lint binary in parallel.
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ For example, in a repository of [golangci-lint](https://github.com/golangci/gola
|
|||||||
We use JavaScript-based action. We don't use Docker-based action because:
|
We use JavaScript-based action. We don't use Docker-based action because:
|
||||||
|
|
||||||
1. docker pulling is slow currently
|
1. docker pulling is slow currently
|
||||||
2. it's easier to use caching from [@actions/cache](https://github.com/actions/cache) until GitHub team hasn't supported reusing actions from actions
|
2. it's easier to use caching from [@actions/cache](https://github.com/actions/toolkit/tree/master/packages/cache)
|
||||||
|
|
||||||
Inside our action we perform 3 steps:
|
Inside our action we perform 3 steps:
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ description: 'Official golangci-lint action with line-attached annotations for f
|
|||||||
author: 'golangci'
|
author: 'golangci'
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'version of golangci-lint to use in form of v1.2.3'
|
description: 'version of golangci-lint to use in form of v1.2'
|
||||||
required: true
|
required: true
|
||||||
args:
|
args:
|
||||||
description: 'golangci-lint command line arguments'
|
description: 'golangci-lint command line arguments'
|
||||||
|
2724
dist/post_run/index.js
vendored
2724
dist/post_run/index.js
vendored
File diff suppressed because it is too large
Load Diff
2724
dist/run/index.js
vendored
2724
dist/run/index.js
vendored
File diff suppressed because it is too large
Load Diff
49
package-lock.json
generated
49
package-lock.json
generated
@ -4,6 +4,20 @@
|
|||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@actions/cache": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-CV2D9zp+d+nL7o6XK/I7vVh350JglPMp/jHi9ppRUkdBHPUeP0UHVUfygZaAs8WmxhhWY1MI0gWah+t0QYu3Fg==",
|
||||||
|
"requires": {
|
||||||
|
"@actions/core": "^1.2.4",
|
||||||
|
"@actions/exec": "^1.0.1",
|
||||||
|
"@actions/glob": "^0.1.0",
|
||||||
|
"@actions/http-client": "^1.0.8",
|
||||||
|
"@actions/io": "^1.0.1",
|
||||||
|
"semver": "^6.1.0",
|
||||||
|
"uuid": "^3.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.4.tgz",
|
||||||
@ -446,18 +460,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
|
||||||
"integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc="
|
"integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc="
|
||||||
},
|
},
|
||||||
"cache": {
|
|
||||||
"version": "git+https://github.com/golangci/cache.git#3df9f001c2d6c950a3deb6f2c1f88ddc2a609d25",
|
|
||||||
"from": "git+https://github.com/golangci/cache.git",
|
|
||||||
"requires": {
|
|
||||||
"@actions/core": "^1.2.0",
|
|
||||||
"@actions/exec": "^1.0.1",
|
|
||||||
"@actions/glob": "^0.1.0",
|
|
||||||
"@actions/http-client": "^1.0.8",
|
|
||||||
"@actions/io": "^1.0.1",
|
|
||||||
"uuid": "^3.3.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"callsites": {
|
"callsites": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||||
@ -1804,14 +1806,29 @@
|
|||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||||
},
|
},
|
||||||
"setup-go": {
|
"setup-go": {
|
||||||
"version": "git+https://github.com/actions/setup-go.git#0f551ac199fb202fc2c3bf3612df37a2f074ef66",
|
"version": "git+https://github.com/actions/setup-go.git#1616116e1b39417f86ba049745f1a8946d4d00e7",
|
||||||
"from": "git+https://github.com/actions/setup-go.git",
|
"from": "git+https://github.com/actions/setup-go.git#v2.1.0",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@actions/core": "^1.2.2",
|
"@actions/core": "^1.2.3",
|
||||||
"@actions/http-client": "^1.0.6",
|
"@actions/http-client": "^1.0.6",
|
||||||
"@actions/io": "^1.0.2",
|
"@actions/io": "^1.0.2",
|
||||||
"@actions/tool-cache": "^1.3.3",
|
"@actions/tool-cache": "^1.5.5",
|
||||||
"semver": "^6.1.1"
|
"semver": "^6.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/tool-cache": {
|
||||||
|
"version": "1.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.5.5.tgz",
|
||||||
|
"integrity": "sha512-y/YO37BOaXzOEHpvoGZDLCwvg6XZWQ7Ala4Np4xzrKD1r48mff+K/GAmzXMejnApU7kgqC6lL/aCKTZDCrhdmw==",
|
||||||
|
"requires": {
|
||||||
|
"@actions/core": "^1.2.3",
|
||||||
|
"@actions/exec": "^1.0.0",
|
||||||
|
"@actions/http-client": "^1.0.8",
|
||||||
|
"@actions/io": "^1.0.1",
|
||||||
|
"semver": "^6.1.0",
|
||||||
|
"uuid": "^3.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shebang-command": {
|
"shebang-command": {
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare-setup-go": "cd node_modules/setup-go && npm run build",
|
"prepare-setup-go": "cd node_modules/setup-go && npm run build",
|
||||||
"prepare-cache": "cd node_modules/cache && npm run build",
|
"prepare-deps": "npm run prepare-setup-go",
|
||||||
"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_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",
|
"watched_build_post_main": "tsc && ncc build -w -o dist/post_run/ src/post_main.ts",
|
||||||
@ -30,10 +29,10 @@
|
|||||||
"@actions/exec": "^1.0.1",
|
"@actions/exec": "^1.0.1",
|
||||||
"@actions/github": "^2.1.1",
|
"@actions/github": "^2.1.1",
|
||||||
"@actions/tool-cache": "^1.3.4",
|
"@actions/tool-cache": "^1.3.4",
|
||||||
|
"@actions/cache": "^0.2.1",
|
||||||
"@types/semver": "^7.1.0",
|
"@types/semver": "^7.1.0",
|
||||||
"@types/tmp": "^0.2.0",
|
"@types/tmp": "^0.2.0",
|
||||||
"cache": "git+https://github.com/golangci/cache.git",
|
"setup-go": "git+https://github.com/actions/setup-go.git#v2.1.0",
|
||||||
"setup-go": "git+https://github.com/actions/setup-go.git",
|
|
||||||
"tmp": "^0.2.1"
|
"tmp": "^0.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
76
src/cache.ts
76
src/cache.ts
@ -1,9 +1,11 @@
|
|||||||
|
import * as cache from "@actions/cache"
|
||||||
import * as core from "@actions/core"
|
import * as core from "@actions/core"
|
||||||
import restore from "cache/lib/restore"
|
|
||||||
import save from "cache/lib/save"
|
|
||||||
import * as crypto from "crypto"
|
import * as crypto from "crypto"
|
||||||
import * as fs from "fs"
|
import * as fs from "fs"
|
||||||
|
|
||||||
|
import { Events, State } from "./constants"
|
||||||
|
import * as utils from "./utils/actionUtils"
|
||||||
|
|
||||||
function checksumFile(hashName: string, path: string): Promise<string> {
|
function checksumFile(hashName: string, path: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const hash = crypto.createHash(hashName)
|
const hash = crypto.createHash(hashName)
|
||||||
@ -52,30 +54,80 @@ async function buildCacheKeys(): Promise<string[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function restoreCache(): Promise<void> {
|
export async function restoreCache(): Promise<void> {
|
||||||
|
if (!utils.isValidEvent()) {
|
||||||
|
utils.logWarning(
|
||||||
|
`Event Validation Error: The event type ${process.env[Events.Key]} is not supported because it's not tied to a branch or tag ref.`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const startedAt = Date.now()
|
const startedAt = Date.now()
|
||||||
|
|
||||||
const keys = await buildCacheKeys()
|
const keys = await buildCacheKeys()
|
||||||
const primaryKey = keys.pop()
|
const primaryKey = keys.pop()
|
||||||
const restoreKeys = keys.reverse()
|
const restoreKeys = keys.reverse()
|
||||||
core.info(`Primary analysis cache key is '${primaryKey}', restore keys are '${restoreKeys.join(` | `)}'`)
|
|
||||||
process.env[`INPUT_RESTORE-KEYS`] = restoreKeys.join(`\n`)
|
|
||||||
process.env.INPUT_KEY = primaryKey
|
|
||||||
|
|
||||||
process.env.INPUT_PATH = getCacheDirs().join(`\n`)
|
|
||||||
|
|
||||||
// Tell golangci-lint to use our cache directory.
|
// Tell golangci-lint to use our cache directory.
|
||||||
process.env.GOLANGCI_LINT_CACHE = getLintCacheDir()
|
process.env.GOLANGCI_LINT_CACHE = getLintCacheDir()
|
||||||
|
|
||||||
await restore()
|
if (!primaryKey) {
|
||||||
core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`)
|
utils.logWarning(`Invalid primary key`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
core.saveState(State.CachePrimaryKey, primaryKey)
|
||||||
|
try {
|
||||||
|
const cacheKey = await cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys)
|
||||||
|
if (!cacheKey) {
|
||||||
|
core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Store the matched cache key
|
||||||
|
utils.setCacheState(cacheKey)
|
||||||
|
core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === cache.ValidationError.name) {
|
||||||
|
throw error
|
||||||
|
} else {
|
||||||
|
core.warning(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveCache(): Promise<void> {
|
export async function saveCache(): Promise<void> {
|
||||||
|
// Validate inputs, this can cause task failure
|
||||||
|
if (!utils.isValidEvent()) {
|
||||||
|
utils.logWarning(
|
||||||
|
`Event Validation Error: The event type ${process.env[Events.Key]} is not supported because it's not tied to a branch or tag ref.`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const startedAt = Date.now()
|
const startedAt = Date.now()
|
||||||
|
|
||||||
const cacheDirs = getCacheDirs()
|
const cacheDirs = getCacheDirs()
|
||||||
process.env.INPUT_PATH = cacheDirs.join(`\n`)
|
const primaryKey = core.getState(State.CachePrimaryKey)
|
||||||
|
if (!primaryKey) {
|
||||||
|
utils.logWarning(`Error retrieving key from state.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await save()
|
const state = utils.getCacheState()
|
||||||
core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`)
|
|
||||||
|
if (utils.isExactKeyMatch(primaryKey, state)) {
|
||||||
|
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await cache.saveCache(cacheDirs, primaryKey)
|
||||||
|
core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === cache.ValidationError.name) {
|
||||||
|
throw error
|
||||||
|
} else if (error.name === cache.ReserveCacheError.name) {
|
||||||
|
core.info(error.message)
|
||||||
|
} else {
|
||||||
|
core.info(`[warning] ${error.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
18
src/constants.ts
Normal file
18
src/constants.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export enum Inputs {
|
||||||
|
Key = "key",
|
||||||
|
Path = "path",
|
||||||
|
RestoreKeys = "restore-keys",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum State {
|
||||||
|
CachePrimaryKey = "CACHE_KEY",
|
||||||
|
CacheMatchedKey = "CACHE_RESULT",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Events {
|
||||||
|
Key = "GITHUB_EVENT_NAME",
|
||||||
|
Push = "push",
|
||||||
|
PullRequest = "pull_request",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RefKey = "GITHUB_REF"
|
22
src/run.ts
22
src/run.ts
@ -136,14 +136,16 @@ async function runLint(lintPath: string, patchPath: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
addedArgs.push(`--out-format=github-actions`)
|
addedArgs.push(`--out-format=github-actions`)
|
||||||
|
|
||||||
if (patchPath && (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`))) {
|
if (patchPath) {
|
||||||
throw new Error(`please, don't specify manually --new* args when requesting only new issues`)
|
if (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}`)
|
}
|
||||||
|
addedArgs.push(`--new-from-patch=${patchPath}`)
|
||||||
|
|
||||||
// Override config values.
|
// Override config values.
|
||||||
addedArgs.push(`--new=false`)
|
addedArgs.push(`--new=false`)
|
||||||
addedArgs.push(`--new-from-rev=`)
|
addedArgs.push(`--new-from-rev=`)
|
||||||
|
}
|
||||||
|
|
||||||
const workingDirectory = core.getInput(`working-directory`)
|
const workingDirectory = core.getInput(`working-directory`)
|
||||||
const cmdArgs: ExecOptions = {}
|
const cmdArgs: ExecOptions = {}
|
||||||
@ -155,12 +157,14 @@ async function runLint(lintPath: string, patchPath: string): Promise<void> {
|
|||||||
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`)
|
||||||
}
|
}
|
||||||
|
if (!userArgNames.has(`path-prefix`)) {
|
||||||
|
addedArgs.push(`--path-prefix=${workingDirectory}`)
|
||||||
|
}
|
||||||
cmdArgs.cwd = path.resolve(workingDirectory)
|
cmdArgs.cwd = path.resolve(workingDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.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 {
|
||||||
const res = await execShellCommand(cmd, cmdArgs)
|
const res = await execShellCommand(cmd, cmdArgs)
|
||||||
|
37
src/utils/actionUtils.ts
Normal file
37
src/utils/actionUtils.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import * as core from "@actions/core"
|
||||||
|
|
||||||
|
import { RefKey, State } from "../constants"
|
||||||
|
|
||||||
|
export function isExactKeyMatch(key: string, cacheKey?: string): boolean {
|
||||||
|
return !!(
|
||||||
|
cacheKey &&
|
||||||
|
cacheKey.localeCompare(key, undefined, {
|
||||||
|
sensitivity: "accent",
|
||||||
|
}) === 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCacheState(state: string): void {
|
||||||
|
core.saveState(State.CacheMatchedKey, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCacheState(): string | undefined {
|
||||||
|
const cacheKey = core.getState(State.CacheMatchedKey)
|
||||||
|
if (cacheKey) {
|
||||||
|
core.debug(`Cache state/key: ${cacheKey}`)
|
||||||
|
return cacheKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logWarning(message: string): void {
|
||||||
|
const warningPrefix = "[warning]"
|
||||||
|
core.info(`${warningPrefix}${message}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache token authorized for all events that are tied to a ref
|
||||||
|
// See GitHub Context https://help.github.com/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#github-context
|
||||||
|
export function isValidEvent(): boolean {
|
||||||
|
return RefKey in process.env && Boolean(process.env[RefKey])
|
||||||
|
}
|
Reference in New Issue
Block a user