feat: add install-mode (#768)

This commit is contained in:
Ludovic Fernandez
2023-06-11 19:16:14 +02:00
committed by GitHub
parent 5be60c708e
commit 185e7a2f8f
8 changed files with 316 additions and 32 deletions

View File

@ -1,10 +1,14 @@
import * as core from "@actions/core"
import * as tc from "@actions/tool-cache"
import { exec, ExecOptions } from "child_process"
import os from "os"
import path from "path"
import { promisify } from "util"
import { VersionConfig } from "./version"
const execShellCommand = promisify(exec)
const downloadURL = "https://github.com/golangci/golangci-lint/releases/download"
const getAssetURL = (versionConfig: VersionConfig): string => {
@ -31,13 +35,95 @@ const getAssetURL = (versionConfig: VersionConfig): string => {
return `${downloadURL}/${versionConfig.TargetVersion}/golangci-lint-${noPrefix}-${platform}-${arch}.${ext}`
}
// The installLint returns path to installed binary of golangci-lint.
export async function installLint(versionConfig: VersionConfig): Promise<string> {
export enum InstallMode {
Binary = "binary",
GoInstall = "goinstall",
}
type ExecRes = {
stdout: string
stderr: string
}
const printOutput = (res: ExecRes): void => {
if (res.stdout) {
core.info(res.stdout)
}
if (res.stderr) {
core.info(res.stderr)
}
}
/**
* Install golangci-lint.
*
* @param versionConfig information about version to install.
* @param mode installation mode.
* @returns path to installed binary of golangci-lint.
*/
export async function installLint(versionConfig: VersionConfig, mode: InstallMode): Promise<string> {
core.info(`Installation mode: ${mode}`)
switch (mode) {
case InstallMode.Binary:
return installBin(versionConfig)
case InstallMode.GoInstall:
return goInstall(versionConfig)
default:
return installBin(versionConfig)
}
}
/**
* Install golangci-lint via `go install`.
*
* @param versionConfig information about version to install.
* @returns path to installed binary of golangci-lint.
*/
export async function goInstall(versionConfig: VersionConfig): Promise<string> {
core.info(`Installing golangci-lint ${versionConfig.TargetVersion}...`)
const startedAt = Date.now()
const options: ExecOptions = { env: { ...process.env, CGO_ENABLED: "1" } }
const exres = await execShellCommand(
`go install github.com/golangci/golangci-lint/cmd/golangci-lint@${versionConfig.TargetVersion}`,
options
)
printOutput(exres)
const res = await execShellCommand(
`go install -n github.com/golangci/golangci-lint/cmd/golangci-lint@${versionConfig.TargetVersion}`,
options
)
printOutput(res)
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
const lintPath = res.stderr.trimStart().trimEnd().split(` `, 2)[1]
core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`)
return lintPath
}
/**
* Install golangci-lint via the precompiled binary.
*
* @param versionConfig information about version to install.
* @returns path to installed binary of golangci-lint.
*/
export async function installBin(versionConfig: VersionConfig): Promise<string> {
core.info(`Installing golangci-lint binary ${versionConfig.TargetVersion}...`)
const startedAt = Date.now()
const assetURL = getAssetURL(versionConfig)
core.info(`Downloading ${assetURL} ...`)
core.info(`Downloading binary ${assetURL} ...`)
const archivePath = await tc.downloadTool(assetURL)
let extractedDir = ""
let repl = /\.tar\.gz$/
if (assetURL.endsWith("zip")) {
@ -55,6 +141,8 @@ export async function installLint(versionConfig: VersionConfig): Promise<string>
const urlParts = assetURL.split(`/`)
const dirName = urlParts[urlParts.length - 1].replace(repl, ``)
const lintPath = path.join(extractedDir, dirName, `golangci-lint`)
core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`)
return lintPath
}

View File

@ -7,7 +7,7 @@ import { dir } from "tmp"
import { promisify } from "util"
import { restoreCache, saveCache } from "./cache"
import { installLint } from "./install"
import { installLint, InstallMode } from "./install"
import { findLintVersion } from "./version"
const execShellCommand = promisify(exec)
@ -15,8 +15,10 @@ const writeFile = promisify(fs.writeFile)
const createTempDir = promisify(dir)
async function prepareLint(): Promise<string> {
const versionConfig = await findLintVersion()
return await installLint(versionConfig)
const mode = core.getInput("install-mode").toLowerCase()
const versionConfig = await findLintVersion(<InstallMode>mode)
return await installLint(versionConfig, <InstallMode>mode)
}
async function fetchPatch(): Promise<string> {
@ -83,15 +85,15 @@ async function prepareEnv(): Promise<Env> {
const startedAt = Date.now()
// Prepare cache, lint and go in parallel.
const restoreCachePromise = restoreCache()
await restoreCache()
const prepareLintPromise = prepareLint()
const patchPromise = fetchPatch()
const lintPath = await prepareLintPromise
await restoreCachePromise
const patchPath = await patchPromise
core.info(`Prepared env in ${Date.now() - startedAt}ms`)
return { lintPath, patchPath }
}
@ -159,8 +161,10 @@ async function runLint(lintPath: string, patchPath: string): Promise<void> {
cmdArgs.cwd = path.resolve(workingDirectory)
}
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight()
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd()
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`)
const startedAt = Date.now()
try {
const res = await execShellCommand(cmd, cmdArgs)

View File

@ -3,6 +3,8 @@ import * as httpm from "@actions/http-client"
import * as fs from "fs"
import path from "path"
import { InstallMode } from "./install"
// TODO: make a class
export type Version = {
major: number
@ -17,6 +19,7 @@ const parseVersion = (s: string): Version => {
if (s == "latest" || s == "") {
return null
}
const match = s.match(versionRe)
if (!match) {
throw new Error(`invalid version string '${s}', expected format v1.2 or v1.2.3`)
@ -61,6 +64,7 @@ const isLessVersion = (a: Version, b: Version): boolean => {
const getRequestedLintVersion = (): Version => {
let requestedLintVersion = core.getInput(`version`)
const workingDirectory = core.getInput(`working-directory`)
let goMod = "go.mod"
if (workingDirectory) {
goMod = path.join(workingDirectory, goMod)
@ -79,6 +83,7 @@ const getRequestedLintVersion = (): Version => {
if (parsedRequestedLintVersion == null) {
return null
}
if (isLessVersion(parsedRequestedLintVersion, minVersion)) {
throw new Error(
`requested golangci-lint version '${requestedLintVersion}' isn't supported: we support only ${stringifyVersion(
@ -86,6 +91,7 @@ const getRequestedLintVersion = (): Version => {
)} and later versions`
)
}
return parsedRequestedLintVersion
}
@ -120,9 +126,16 @@ const getConfig = async (): Promise<Config> => {
}
}
export async function findLintVersion(): Promise<VersionConfig> {
export async function findLintVersion(mode: InstallMode): Promise<VersionConfig> {
core.info(`Finding needed golangci-lint version...`)
if (mode == InstallMode.GoInstall) {
const v: string = core.getInput(`version`)
return { TargetVersion: v ? v : "latest", AssetURL: "github.com/golangci/golangci-lint" }
}
const reqLintVersion = getRequestedLintVersion()
// if the patched version is passed, just use it
if (reqLintVersion?.major !== null && reqLintVersion?.minor != null && reqLintVersion?.patch !== null) {
return new Promise((resolve) => {
@ -133,6 +146,7 @@ export async function findLintVersion(): Promise<VersionConfig> {
})
})
}
const startedAt = Date.now()
const config = await getConfig()
@ -155,5 +169,6 @@ export async function findLintVersion(): Promise<VersionConfig> {
Date.now() - startedAt
}ms`
)
return versionConfig
}