From 3a919529898de77ec3da873e3063ca4b10e7f5cc Mon Sep 17 00:00:00 2001 From: CfirTsabari Date: Tue, 15 Aug 2023 00:13:33 +0300 Subject: [PATCH] feat: working-directory with only-new-issues (#795) Co-authored-by: Fernandez Ludovic --- dist/post_run/index.js | 769 +++++++++++++++++++++-------------------- dist/run/index.js | 769 +++++++++++++++++++++-------------------- src/run.ts | 7 +- src/utils/diffUtils.ts | 56 +++ tsconfig.json | 2 +- 5 files changed, 841 insertions(+), 762 deletions(-) create mode 100644 src/utils/diffUtils.ts diff --git a/dist/post_run/index.js b/dist/post_run/index.js index 6baed07d8e..93af0d72d2 100644 --- a/dist/post_run/index.js +++ b/dist/post_run/index.js @@ -66324,15 +66324,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; @@ -66354,7 +66345,7 @@ function checksumFile(hashName, path) { stream.on("end", () => resolve(hash.digest("hex"))); }); } -const pathExists = (path) => __awaiter(void 0, void 0, void 0, function* () { return !!(yield fs.promises.stat(path).catch(() => false)); }); +const pathExists = async (path) => !!(await fs.promises.stat(path).catch(() => false)); const getLintCacheDir = () => { return path_1.default.resolve(`${process.env.HOME}/.cache/golangci-lint`); }; @@ -66383,106 +66374,100 @@ const getIntervalKey = (invalidationIntervalDays) => { const intervalNumber = Math.floor(secondsSinceEpoch / (invalidationIntervalDays * 86400)); return intervalNumber.toString(); }; -function buildCacheKeys() { - return __awaiter(this, void 0, void 0, function* () { - const keys = []; - // Periodically invalidate a cache because a new code being added. - // TODO: configure it via inputs. - let cacheKey = `golangci-lint.cache-${getIntervalKey(7)}-`; - keys.push(cacheKey); - // Get working directory from input - const workingDirectory = core.getInput(`working-directory`); - // create path to go.mod prepending the workingDirectory if it exists - const goModPath = path_1.default.join(workingDirectory, `go.mod`); - core.info(`Checking for go.mod: ${goModPath}`); - if (yield pathExists(goModPath)) { - // Add checksum to key to invalidate a cache when dependencies change. - cacheKey += yield checksumFile(`sha1`, goModPath); - } - else { - cacheKey += `nogomod`; - } - keys.push(cacheKey); - return keys; - }); +async function buildCacheKeys() { + const keys = []; + // Periodically invalidate a cache because a new code being added. + // TODO: configure it via inputs. + let cacheKey = `golangci-lint.cache-${getIntervalKey(7)}-`; + keys.push(cacheKey); + // Get working directory from input + const workingDirectory = core.getInput(`working-directory`); + // create path to go.mod prepending the workingDirectory if it exists + const goModPath = path_1.default.join(workingDirectory, `go.mod`); + core.info(`Checking for go.mod: ${goModPath}`); + if (await pathExists(goModPath)) { + // Add checksum to key to invalidate a cache when dependencies change. + cacheKey += await checksumFile(`sha1`, goModPath); + } + else { + cacheKey += `nogomod`; + } + keys.push(cacheKey); + return keys; } -function restoreCache() { - return __awaiter(this, void 0, void 0, function* () { - if (core.getInput(`skip-cache`, { required: true }).trim() == "true") - return; - if (!utils.isValidEvent()) { - utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); - return; - } - const startedAt = Date.now(); - const keys = yield buildCacheKeys(); - const primaryKey = keys.pop(); - const restoreKeys = keys.reverse(); - // Tell golangci-lint to use our cache directory. - process.env.GOLANGCI_LINT_CACHE = getLintCacheDir(); - if (!primaryKey) { - utils.logWarning(`Invalid primary key`); +async function restoreCache() { + if (core.getInput(`skip-cache`, { required: true }).trim() == "true") + return; + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } + const startedAt = Date.now(); + const keys = await buildCacheKeys(); + const primaryKey = keys.pop(); + const restoreKeys = keys.reverse(); + // Tell golangci-lint to use our cache directory. + process.env.GOLANGCI_LINT_CACHE = getLintCacheDir(); + if (!primaryKey) { + utils.logWarning(`Invalid primary key`); + return; + } + core.saveState(constants_1.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; } - core.saveState(constants_1.State.CachePrimaryKey, primaryKey); - try { - const cacheKey = yield 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`); + // 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; } - catch (error) { - if (error.name === cache.ValidationError.name) { - throw error; - } - else { - core.warning(error.message); - } + else { + core.warning(error.message); } - }); + } } exports.restoreCache = restoreCache; -function saveCache() { - return __awaiter(this, void 0, void 0, function* () { - if (core.getInput(`skip-cache`, { required: true }).trim() == "true") - return; - // Validate inputs, this can cause task failure - if (!utils.isValidEvent()) { - utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); - return; - } - const startedAt = Date.now(); - const cacheDirs = getCacheDirs(); - const primaryKey = core.getState(constants_1.State.CachePrimaryKey); - if (!primaryKey) { - utils.logWarning(`Error retrieving key from state.`); - return; - } - const state = utils.getCacheState(); - if (utils.isExactKeyMatch(primaryKey, state)) { - core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`); - return; +async function saveCache() { + if (core.getInput(`skip-cache`, { required: true }).trim() == "true") + return; + // Validate inputs, this can cause task failure + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } + const startedAt = Date.now(); + const cacheDirs = getCacheDirs(); + const primaryKey = core.getState(constants_1.State.CachePrimaryKey); + if (!primaryKey) { + utils.logWarning(`Error retrieving key from state.`); + return; + } + const state = utils.getCacheState(); + 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; } - try { - yield cache.saveCache(cacheDirs, primaryKey); - core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`); + else if (error.name === cache.ReserveCacheError.name) { + core.info(error.message); } - 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}`); - } + else { + core.info(`[warning] ${error.message}`); } - }); + } } exports.saveCache = saveCache; @@ -66546,15 +66531,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; @@ -66610,18 +66586,16 @@ const printOutput = (res) => { * @param mode installation mode. * @returns path to installed binary of golangci-lint. */ -function installLint(versionConfig, mode) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Installation mode: ${mode}`); - switch (mode) { - case InstallMode.Binary: - return installBin(versionConfig); - case InstallMode.GoInstall: - return goInstall(versionConfig); - default: - return installBin(versionConfig); - } - }); +async function installLint(versionConfig, mode) { + core.info(`Installation mode: ${mode}`); + switch (mode) { + case InstallMode.Binary: + return installBin(versionConfig); + case InstallMode.GoInstall: + return goInstall(versionConfig); + default: + return installBin(versionConfig); + } } exports.installLint = installLint; /** @@ -66630,20 +66604,18 @@ exports.installLint = installLint; * @param versionConfig information about version to install. * @returns path to installed binary of golangci-lint. */ -function goInstall(versionConfig) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Installing golangci-lint ${versionConfig.TargetVersion}...`); - const startedAt = Date.now(); - const options = { env: Object.assign(Object.assign({}, process.env), { CGO_ENABLED: "1" }) }; - const exres = yield execShellCommand(`go install github.com/golangci/golangci-lint/cmd/golangci-lint@${versionConfig.TargetVersion}`, options); - printOutput(exres); - const res = yield 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 `. - const lintPath = res.stderr.trimStart().trimEnd().split(` `, 2)[1]; - core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); - return lintPath; - }); +async function goInstall(versionConfig) { + core.info(`Installing golangci-lint ${versionConfig.TargetVersion}...`); + const startedAt = Date.now(); + const options = { 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 `. + const lintPath = res.stderr.trimStart().trimEnd().split(` `, 2)[1]; + core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); + return lintPath; } exports.goInstall = goInstall; /** @@ -66652,33 +66624,31 @@ exports.goInstall = goInstall; * @param versionConfig information about version to install. * @returns path to installed binary of golangci-lint. */ -function installBin(versionConfig) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Installing golangci-lint binary ${versionConfig.TargetVersion}...`); - const startedAt = Date.now(); - const assetURL = getAssetURL(versionConfig); - core.info(`Downloading binary ${assetURL} ...`); - const archivePath = yield tc.downloadTool(assetURL); - let extractedDir = ""; - let repl = /\.tar\.gz$/; - if (assetURL.endsWith("zip")) { - extractedDir = yield tc.extractZip(archivePath, process.env.HOME); - repl = /\.zip$/; +async function installBin(versionConfig) { + core.info(`Installing golangci-lint binary ${versionConfig.TargetVersion}...`); + const startedAt = Date.now(); + const assetURL = getAssetURL(versionConfig); + core.info(`Downloading binary ${assetURL} ...`); + const archivePath = await tc.downloadTool(assetURL); + let extractedDir = ""; + let repl = /\.tar\.gz$/; + if (assetURL.endsWith("zip")) { + extractedDir = await tc.extractZip(archivePath, process.env.HOME); + repl = /\.zip$/; + } + else { + // We want to always overwrite files if the local cache already has them + const args = ["xz"]; + if (process.platform.toString() != "darwin") { + args.push("--overwrite"); } - else { - // We want to always overwrite files if the local cache already has them - const args = ["xz"]; - if (process.platform.toString() != "darwin") { - args.push("--overwrite"); - } - extractedDir = yield tc.extractTar(archivePath, process.env.HOME, args); - } - const urlParts = assetURL.split(`/`); - const dirName = urlParts[urlParts.length - 1].replace(repl, ``); - const lintPath = path_1.default.join(extractedDir, dirName, `golangci-lint`); - core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); - return lintPath; - }); + extractedDir = await tc.extractTar(archivePath, process.env.HOME, args); + } + const urlParts = assetURL.split(`/`); + const dirName = urlParts[urlParts.length - 1].replace(repl, ``); + const lintPath = path_1.default.join(extractedDir, dirName, `golangci-lint`); + core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); + return lintPath; } exports.installBin = installBin; @@ -66713,15 +66683,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.postRun = exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -66733,83 +66694,78 @@ const tmp_1 = __nccwpck_require__(8517); const util_1 = __nccwpck_require__(3837); const cache_1 = __nccwpck_require__(4810); const install_1 = __nccwpck_require__(1649); +const diffUtils_1 = __nccwpck_require__(3617); const version_1 = __nccwpck_require__(1946); const execShellCommand = (0, util_1.promisify)(child_process_1.exec); const writeFile = (0, util_1.promisify)(fs.writeFile); const createTempDir = (0, util_1.promisify)(tmp_1.dir); -function prepareLint() { - return __awaiter(this, void 0, void 0, function* () { - const mode = core.getInput("install-mode").toLowerCase(); - const versionConfig = yield (0, version_1.findLintVersion)(mode); - return yield (0, install_1.installLint)(versionConfig, mode); - }); -} -function fetchPatch() { - return __awaiter(this, void 0, void 0, function* () { - 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 = github.getOctokit(core.getInput(`github-token`, { required: true })); - let patch; - try { - const patchResp = yield octokit.rest.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; - } - catch (err) { - console.warn(`failed to fetch pull request patch:`, err); - return ``; // don't fail the action, but analyze without patch - } - try { - const tempDir = yield createTempDir(); - const patchPath = path.join(tempDir, "pull.patch"); - core.info(`Writing patch to ${patchPath}`); - yield writeFile(patchPath, patch); - return patchPath; - } - catch (err) { - console.warn(`failed to save pull request patch:`, err); +async function prepareLint() { + const mode = core.getInput("install-mode").toLowerCase(); + const versionConfig = await (0, version_1.findLintVersion)(mode); + return await (0, install_1.installLint)(versionConfig, mode); +} +async function fetchPatch() { + 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 = github.getOctokit(core.getInput(`github-token`, { required: true })); + let patch; + try { + const patchResp = await octokit.rest.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 } - }); -} -function prepareEnv() { - return __awaiter(this, void 0, void 0, function* () { - const startedAt = Date.now(); - // Prepare cache, lint and go in parallel. - yield (0, cache_1.restoreCache)(); - const prepareLintPromise = prepareLint(); - const patchPromise = fetchPatch(); - const lintPath = yield prepareLintPromise; - const patchPath = yield patchPromise; - core.info(`Prepared env in ${Date.now() - startedAt}ms`); - return { lintPath, patchPath }; - }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + patch = patchResp.data; + } + 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, (0, diffUtils_1.alterDiffPatch)(patch)); + return patchPath; + } + catch (err) { + console.warn(`failed to save pull request patch:`, err); + return ``; // don't fail the action, but analyze without patch + } +} +async function prepareEnv() { + const startedAt = Date.now(); + // Prepare cache, lint and go in parallel. + await (0, cache_1.restoreCache)(); + const prepareLintPromise = prepareLint(); + const patchPromise = fetchPatch(); + const lintPath = await prepareLintPromise; + const patchPath = await patchPromise; + core.info(`Prepared env in ${Date.now() - startedAt}ms`); + return { lintPath, patchPath }; } const printOutput = (res) => { if (res.stdout) { @@ -66819,103 +66775,93 @@ const printOutput = (res) => { core.info(res.stderr); } }; -function runLint(lintPath, patchPath) { - return __awaiter(this, void 0, void 0, function* () { - const debug = core.getInput(`debug`); - if (debug.split(`,`).includes(`cache`)) { - const res = yield execShellCommand(`${lintPath} cache status`); - printOutput(res); - } - let userArgs = core.getInput(`args`); - const addedArgs = []; - const userArgsList = userArgs - .trim() - .split(/\s+/) - .filter((arg) => arg.startsWith(`-`)) - .map((arg) => arg.replace(/^-+/, ``)) - .map((arg) => arg.split(/=(.*)/, 2)) - .map(([key, value]) => [key.toLowerCase(), value !== null && value !== void 0 ? value : ""]); - const userArgsMap = new Map(userArgsList); - const userArgNames = new Set(userArgsList.map(([key]) => key)); - const formats = (userArgsMap.get("out-format") || "") - .trim() - .split(",") - .filter((f) => f.length > 0) - .filter((f) => !f.startsWith(`github-actions`)) - .concat("github-actions") - .join(","); - addedArgs.push(`--out-format=${formats}`); - userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim(); - if (patchPath) { - 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}`); - // Override config values. - addedArgs.push(`--new=false`); - addedArgs.push(`--new-from-rev=`); - } - const workingDirectory = core.getInput(`working-directory`); - const cmdArgs = {}; - 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()) { - 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); - } - const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd(); - core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`); - const startedAt = Date.now(); - try { - const res = yield execShellCommand(cmd, cmdArgs); - printOutput(res); - core.info(`golangci-lint found no issues`); +async function runLint(lintPath, patchPath) { + const debug = core.getInput(`debug`); + if (debug.split(`,`).includes(`cache`)) { + const res = await execShellCommand(`${lintPath} cache status`); + printOutput(res); + } + let userArgs = core.getInput(`args`); + const addedArgs = []; + const userArgsList = userArgs + .trim() + .split(/\s+/) + .filter((arg) => arg.startsWith(`-`)) + .map((arg) => arg.replace(/^-+/, ``)) + .map((arg) => arg.split(/=(.*)/, 2)) + .map(([key, value]) => [key.toLowerCase(), value ?? ""]); + const userArgsMap = new Map(userArgsList); + const userArgNames = new Set(userArgsList.map(([key]) => key)); + const formats = (userArgsMap.get("out-format") || "") + .trim() + .split(",") + .filter((f) => f.length > 0) + .filter((f) => !f.startsWith(`github-actions`)) + .concat("github-actions") + .join(","); + addedArgs.push(`--out-format=${formats}`); + userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim(); + if (patchPath) { + 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}`); + // Override config values. + addedArgs.push(`--new=false`); + addedArgs.push(`--new-from-rev=`); + } + const workingDirectory = core.getInput(`working-directory`); + const cmdArgs = {}; + if (workingDirectory) { + if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) { + throw new Error(`working-directory (${workingDirectory}) was not a path`); } - catch (exc) { - // This logging passes issues to GitHub annotations but comments can be more convenient for some users. - // TODO: support reviewdog or leaving comments by GitHub API. - printOutput(exc); - if (exc.code === 1) { - core.setFailed(`issues found`); - } - else { - core.setFailed(`golangci-lint exit with code ${exc.code}`); - } + if (!userArgNames.has(`path-prefix`)) { + addedArgs.push(`--path-prefix=${workingDirectory}`); } - core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`); - }); -} -function run() { - return __awaiter(this, void 0, void 0, function* () { - try { - const { lintPath, patchPath } = yield core.group(`prepare environment`, prepareEnv); - core.addPath(path.dirname(lintPath)); - yield core.group(`run golangci-lint`, () => runLint(lintPath, patchPath)); + cmdArgs.cwd = path.resolve(workingDirectory); + } + 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); + printOutput(res); + core.info(`golangci-lint found no issues`); + } + catch (exc) { + // This logging passes issues to GitHub annotations but comments can be more convenient for some users. + // TODO: support reviewdog or leaving comments by GitHub API. + printOutput(exc); + if (exc.code === 1) { + core.setFailed(`issues found`); } - catch (error) { - core.error(`Failed to run: ${error}, ${error.stack}`); - core.setFailed(error.message); + else { + core.setFailed(`golangci-lint exit with code ${exc.code}`); } - }); + } + core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`); +} +async function run() { + try { + const { lintPath, patchPath } = await core.group(`prepare environment`, prepareEnv); + core.addPath(path.dirname(lintPath)); + await core.group(`run golangci-lint`, () => runLint(lintPath, patchPath)); + } + catch (error) { + core.error(`Failed to run: ${error}, ${error.stack}`); + core.setFailed(error.message); + } } exports.run = run; -function postRun() { - return __awaiter(this, void 0, void 0, function* () { - try { - yield (0, cache_1.saveCache)(); - } - catch (error) { - core.error(`Failed to post-run: ${error}, ${error.stack}`); - core.setFailed(error.message); - } - }); +async function postRun() { + try { + await (0, cache_1.saveCache)(); + } + catch (error) { + core.error(`Failed to post-run: ${error}, ${error.stack}`); + core.setFailed(error.message); + } } exports.postRun = postRun; @@ -66989,7 +66935,7 @@ exports.isValidEvent = isValidEvent; /***/ }), -/***/ 1946: +/***/ 3617: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -67017,14 +66963,83 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.alterDiffPatch = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const path = __importStar(__nccwpck_require__(1017)); +// If needed alter diff file to be compatible with working directory +function alterDiffPatch(patch) { + const workingDirectory = core.getInput(`working-directory`); + if (workingDirectory) { + return alterPatchWithWorkingDirectory(patch, workingDirectory); + } + return patch; +} +exports.alterDiffPatch = alterDiffPatch; +function alterPatchWithWorkingDirectory(patch, workingDirectory) { + const workspace = process.env["GITHUB_WORKSPACE"] || ""; + const wd = path.relative(workspace, workingDirectory); + // ignore diff sections not related to the working directory + let ignore = false; + const lines = patch.split("\n"); + const filteredLines = []; + // starts with "--- a/xxx/" or "+++ a/xxx/" or "--- b/xxx/" or "+++ b/xxx/" + const cleanDiff = new RegExp(`^((?:\\+{3}|-{3}) [ab]\\/)${escapeRegExp(wd)}\\/(.*)`, "gm"); + // contains " a/xxx/" or " b/xxx/" + const firstLine = new RegExp(`( [ab]\\/)${escapeRegExp(wd)}\\/(.*)`, "gm"); + for (const line of lines) { + if (line.startsWith("diff --git")) { + ignore = !line.includes(` a/${wd}/`); + if (ignore) { + continue; + } + filteredLines.push(line.replaceAll(firstLine, "$1$2")); + } + else { + if (ignore) { + continue; + } + filteredLines.push(line.replaceAll(cleanDiff, "$1$2")); + } + } + // Join the modified lines back into a diff string + return filteredLines.join("\n"); +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions +function escapeRegExp(exp) { + return exp.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + + +/***/ }), + +/***/ 1946: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; @@ -67102,58 +67117,56 @@ const getRequestedLintVersion = () => { } return parsedRequestedLintVersion; }; -const getConfig = () => __awaiter(void 0, void 0, void 0, function* () { +const getConfig = async () => { const http = new httpm.HttpClient(`golangci/golangci-lint-action`, [], { allowRetries: true, maxRetries: 5, }); try { const url = `https://raw.githubusercontent.com/golangci/golangci-lint/master/assets/github-action-config.json`; - const response = yield http.get(url); + const response = await http.get(url); if (response.message.statusCode !== 200) { throw new Error(`failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); } - const body = yield response.readBody(); + const body = await response.readBody(); return JSON.parse(body); } catch (exc) { throw new Error(`failed to get action config: ${exc.message}`); } -}); -function findLintVersion(mode) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Finding needed golangci-lint version...`); - if (mode == install_1.InstallMode.GoInstall) { - const v = 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 === null || reqLintVersion === void 0 ? void 0 : reqLintVersion.major) !== null && (reqLintVersion === null || reqLintVersion === void 0 ? void 0 : reqLintVersion.minor) != null && (reqLintVersion === null || reqLintVersion === void 0 ? void 0 : reqLintVersion.patch) !== null) { - return new Promise((resolve) => { - const versionWithoutV = `${reqLintVersion.major}.${reqLintVersion.minor}.${reqLintVersion.patch}`; - resolve({ - TargetVersion: `v${versionWithoutV}`, - AssetURL: `https://github.com/golangci/golangci-lint/releases/download/v${versionWithoutV}/golangci-lint-${versionWithoutV}-linux-amd64.tar.gz`, - }); +}; +async function findLintVersion(mode) { + core.info(`Finding needed golangci-lint version...`); + if (mode == install_1.InstallMode.GoInstall) { + const v = 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) => { + const versionWithoutV = `${reqLintVersion.major}.${reqLintVersion.minor}.${reqLintVersion.patch}`; + resolve({ + TargetVersion: `v${versionWithoutV}`, + AssetURL: `https://github.com/golangci/golangci-lint/releases/download/v${versionWithoutV}/golangci-lint-${versionWithoutV}-linux-amd64.tar.gz`, }); - } - const startedAt = Date.now(); - const config = yield getConfig(); - if (!config.MinorVersionToConfig) { - core.warning(JSON.stringify(config)); - throw new Error(`invalid config: no MinorVersionToConfig field`); - } - const versionConfig = config.MinorVersionToConfig[(0, exports.stringifyVersion)(reqLintVersion)]; - if (!versionConfig) { - throw new Error(`requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}' doesn't exist`); - } - if (versionConfig.Error) { - throw new Error(`failed to use requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}': ${versionConfig.Error}`); - } - core.info(`Requested golangci-lint '${(0, exports.stringifyVersion)(reqLintVersion)}', using '${versionConfig.TargetVersion}', calculation took ${Date.now() - startedAt}ms`); - return versionConfig; - }); + }); + } + const startedAt = Date.now(); + const config = await getConfig(); + if (!config.MinorVersionToConfig) { + core.warning(JSON.stringify(config)); + throw new Error(`invalid config: no MinorVersionToConfig field`); + } + const versionConfig = config.MinorVersionToConfig[(0, exports.stringifyVersion)(reqLintVersion)]; + if (!versionConfig) { + throw new Error(`requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}' doesn't exist`); + } + if (versionConfig.Error) { + throw new Error(`failed to use requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}': ${versionConfig.Error}`); + } + core.info(`Requested golangci-lint '${(0, exports.stringifyVersion)(reqLintVersion)}', using '${versionConfig.TargetVersion}', calculation took ${Date.now() - startedAt}ms`); + return versionConfig; } exports.findLintVersion = findLintVersion; diff --git a/dist/run/index.js b/dist/run/index.js index 4a5d1d68b2..40bf4f67c9 100644 --- a/dist/run/index.js +++ b/dist/run/index.js @@ -66324,15 +66324,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; @@ -66354,7 +66345,7 @@ function checksumFile(hashName, path) { stream.on("end", () => resolve(hash.digest("hex"))); }); } -const pathExists = (path) => __awaiter(void 0, void 0, void 0, function* () { return !!(yield fs.promises.stat(path).catch(() => false)); }); +const pathExists = async (path) => !!(await fs.promises.stat(path).catch(() => false)); const getLintCacheDir = () => { return path_1.default.resolve(`${process.env.HOME}/.cache/golangci-lint`); }; @@ -66383,106 +66374,100 @@ const getIntervalKey = (invalidationIntervalDays) => { const intervalNumber = Math.floor(secondsSinceEpoch / (invalidationIntervalDays * 86400)); return intervalNumber.toString(); }; -function buildCacheKeys() { - return __awaiter(this, void 0, void 0, function* () { - const keys = []; - // Periodically invalidate a cache because a new code being added. - // TODO: configure it via inputs. - let cacheKey = `golangci-lint.cache-${getIntervalKey(7)}-`; - keys.push(cacheKey); - // Get working directory from input - const workingDirectory = core.getInput(`working-directory`); - // create path to go.mod prepending the workingDirectory if it exists - const goModPath = path_1.default.join(workingDirectory, `go.mod`); - core.info(`Checking for go.mod: ${goModPath}`); - if (yield pathExists(goModPath)) { - // Add checksum to key to invalidate a cache when dependencies change. - cacheKey += yield checksumFile(`sha1`, goModPath); - } - else { - cacheKey += `nogomod`; - } - keys.push(cacheKey); - return keys; - }); +async function buildCacheKeys() { + const keys = []; + // Periodically invalidate a cache because a new code being added. + // TODO: configure it via inputs. + let cacheKey = `golangci-lint.cache-${getIntervalKey(7)}-`; + keys.push(cacheKey); + // Get working directory from input + const workingDirectory = core.getInput(`working-directory`); + // create path to go.mod prepending the workingDirectory if it exists + const goModPath = path_1.default.join(workingDirectory, `go.mod`); + core.info(`Checking for go.mod: ${goModPath}`); + if (await pathExists(goModPath)) { + // Add checksum to key to invalidate a cache when dependencies change. + cacheKey += await checksumFile(`sha1`, goModPath); + } + else { + cacheKey += `nogomod`; + } + keys.push(cacheKey); + return keys; } -function restoreCache() { - return __awaiter(this, void 0, void 0, function* () { - if (core.getInput(`skip-cache`, { required: true }).trim() == "true") - return; - if (!utils.isValidEvent()) { - utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); - return; - } - const startedAt = Date.now(); - const keys = yield buildCacheKeys(); - const primaryKey = keys.pop(); - const restoreKeys = keys.reverse(); - // Tell golangci-lint to use our cache directory. - process.env.GOLANGCI_LINT_CACHE = getLintCacheDir(); - if (!primaryKey) { - utils.logWarning(`Invalid primary key`); +async function restoreCache() { + if (core.getInput(`skip-cache`, { required: true }).trim() == "true") + return; + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } + const startedAt = Date.now(); + const keys = await buildCacheKeys(); + const primaryKey = keys.pop(); + const restoreKeys = keys.reverse(); + // Tell golangci-lint to use our cache directory. + process.env.GOLANGCI_LINT_CACHE = getLintCacheDir(); + if (!primaryKey) { + utils.logWarning(`Invalid primary key`); + return; + } + core.saveState(constants_1.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; } - core.saveState(constants_1.State.CachePrimaryKey, primaryKey); - try { - const cacheKey = yield 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`); + // 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; } - catch (error) { - if (error.name === cache.ValidationError.name) { - throw error; - } - else { - core.warning(error.message); - } + else { + core.warning(error.message); } - }); + } } exports.restoreCache = restoreCache; -function saveCache() { - return __awaiter(this, void 0, void 0, function* () { - if (core.getInput(`skip-cache`, { required: true }).trim() == "true") - return; - // Validate inputs, this can cause task failure - if (!utils.isValidEvent()) { - utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); - return; - } - const startedAt = Date.now(); - const cacheDirs = getCacheDirs(); - const primaryKey = core.getState(constants_1.State.CachePrimaryKey); - if (!primaryKey) { - utils.logWarning(`Error retrieving key from state.`); - return; - } - const state = utils.getCacheState(); - if (utils.isExactKeyMatch(primaryKey, state)) { - core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`); - return; +async function saveCache() { + if (core.getInput(`skip-cache`, { required: true }).trim() == "true") + return; + // Validate inputs, this can cause task failure + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } + const startedAt = Date.now(); + const cacheDirs = getCacheDirs(); + const primaryKey = core.getState(constants_1.State.CachePrimaryKey); + if (!primaryKey) { + utils.logWarning(`Error retrieving key from state.`); + return; + } + const state = utils.getCacheState(); + 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; } - try { - yield cache.saveCache(cacheDirs, primaryKey); - core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`); + else if (error.name === cache.ReserveCacheError.name) { + core.info(error.message); } - 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}`); - } + else { + core.info(`[warning] ${error.message}`); } - }); + } } exports.saveCache = saveCache; @@ -66546,15 +66531,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; @@ -66610,18 +66586,16 @@ const printOutput = (res) => { * @param mode installation mode. * @returns path to installed binary of golangci-lint. */ -function installLint(versionConfig, mode) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Installation mode: ${mode}`); - switch (mode) { - case InstallMode.Binary: - return installBin(versionConfig); - case InstallMode.GoInstall: - return goInstall(versionConfig); - default: - return installBin(versionConfig); - } - }); +async function installLint(versionConfig, mode) { + core.info(`Installation mode: ${mode}`); + switch (mode) { + case InstallMode.Binary: + return installBin(versionConfig); + case InstallMode.GoInstall: + return goInstall(versionConfig); + default: + return installBin(versionConfig); + } } exports.installLint = installLint; /** @@ -66630,20 +66604,18 @@ exports.installLint = installLint; * @param versionConfig information about version to install. * @returns path to installed binary of golangci-lint. */ -function goInstall(versionConfig) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Installing golangci-lint ${versionConfig.TargetVersion}...`); - const startedAt = Date.now(); - const options = { env: Object.assign(Object.assign({}, process.env), { CGO_ENABLED: "1" }) }; - const exres = yield execShellCommand(`go install github.com/golangci/golangci-lint/cmd/golangci-lint@${versionConfig.TargetVersion}`, options); - printOutput(exres); - const res = yield 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 `. - const lintPath = res.stderr.trimStart().trimEnd().split(` `, 2)[1]; - core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); - return lintPath; - }); +async function goInstall(versionConfig) { + core.info(`Installing golangci-lint ${versionConfig.TargetVersion}...`); + const startedAt = Date.now(); + const options = { 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 `. + const lintPath = res.stderr.trimStart().trimEnd().split(` `, 2)[1]; + core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); + return lintPath; } exports.goInstall = goInstall; /** @@ -66652,33 +66624,31 @@ exports.goInstall = goInstall; * @param versionConfig information about version to install. * @returns path to installed binary of golangci-lint. */ -function installBin(versionConfig) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Installing golangci-lint binary ${versionConfig.TargetVersion}...`); - const startedAt = Date.now(); - const assetURL = getAssetURL(versionConfig); - core.info(`Downloading binary ${assetURL} ...`); - const archivePath = yield tc.downloadTool(assetURL); - let extractedDir = ""; - let repl = /\.tar\.gz$/; - if (assetURL.endsWith("zip")) { - extractedDir = yield tc.extractZip(archivePath, process.env.HOME); - repl = /\.zip$/; +async function installBin(versionConfig) { + core.info(`Installing golangci-lint binary ${versionConfig.TargetVersion}...`); + const startedAt = Date.now(); + const assetURL = getAssetURL(versionConfig); + core.info(`Downloading binary ${assetURL} ...`); + const archivePath = await tc.downloadTool(assetURL); + let extractedDir = ""; + let repl = /\.tar\.gz$/; + if (assetURL.endsWith("zip")) { + extractedDir = await tc.extractZip(archivePath, process.env.HOME); + repl = /\.zip$/; + } + else { + // We want to always overwrite files if the local cache already has them + const args = ["xz"]; + if (process.platform.toString() != "darwin") { + args.push("--overwrite"); } - else { - // We want to always overwrite files if the local cache already has them - const args = ["xz"]; - if (process.platform.toString() != "darwin") { - args.push("--overwrite"); - } - extractedDir = yield tc.extractTar(archivePath, process.env.HOME, args); - } - const urlParts = assetURL.split(`/`); - const dirName = urlParts[urlParts.length - 1].replace(repl, ``); - const lintPath = path_1.default.join(extractedDir, dirName, `golangci-lint`); - core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); - return lintPath; - }); + extractedDir = await tc.extractTar(archivePath, process.env.HOME, args); + } + const urlParts = assetURL.split(`/`); + const dirName = urlParts[urlParts.length - 1].replace(repl, ``); + const lintPath = path_1.default.join(extractedDir, dirName, `golangci-lint`); + core.info(`Installed golangci-lint into ${lintPath} in ${Date.now() - startedAt}ms`); + return lintPath; } exports.installBin = installBin; @@ -66713,15 +66683,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.postRun = exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -66733,83 +66694,78 @@ const tmp_1 = __nccwpck_require__(8517); const util_1 = __nccwpck_require__(3837); const cache_1 = __nccwpck_require__(4810); const install_1 = __nccwpck_require__(1649); +const diffUtils_1 = __nccwpck_require__(3617); const version_1 = __nccwpck_require__(1946); const execShellCommand = (0, util_1.promisify)(child_process_1.exec); const writeFile = (0, util_1.promisify)(fs.writeFile); const createTempDir = (0, util_1.promisify)(tmp_1.dir); -function prepareLint() { - return __awaiter(this, void 0, void 0, function* () { - const mode = core.getInput("install-mode").toLowerCase(); - const versionConfig = yield (0, version_1.findLintVersion)(mode); - return yield (0, install_1.installLint)(versionConfig, mode); - }); -} -function fetchPatch() { - return __awaiter(this, void 0, void 0, function* () { - 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 = github.getOctokit(core.getInput(`github-token`, { required: true })); - let patch; - try { - const patchResp = yield octokit.rest.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; - } - catch (err) { - console.warn(`failed to fetch pull request patch:`, err); - return ``; // don't fail the action, but analyze without patch - } - try { - const tempDir = yield createTempDir(); - const patchPath = path.join(tempDir, "pull.patch"); - core.info(`Writing patch to ${patchPath}`); - yield writeFile(patchPath, patch); - return patchPath; - } - catch (err) { - console.warn(`failed to save pull request patch:`, err); +async function prepareLint() { + const mode = core.getInput("install-mode").toLowerCase(); + const versionConfig = await (0, version_1.findLintVersion)(mode); + return await (0, install_1.installLint)(versionConfig, mode); +} +async function fetchPatch() { + 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 = github.getOctokit(core.getInput(`github-token`, { required: true })); + let patch; + try { + const patchResp = await octokit.rest.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 } - }); -} -function prepareEnv() { - return __awaiter(this, void 0, void 0, function* () { - const startedAt = Date.now(); - // Prepare cache, lint and go in parallel. - yield (0, cache_1.restoreCache)(); - const prepareLintPromise = prepareLint(); - const patchPromise = fetchPatch(); - const lintPath = yield prepareLintPromise; - const patchPath = yield patchPromise; - core.info(`Prepared env in ${Date.now() - startedAt}ms`); - return { lintPath, patchPath }; - }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + patch = patchResp.data; + } + 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, (0, diffUtils_1.alterDiffPatch)(patch)); + return patchPath; + } + catch (err) { + console.warn(`failed to save pull request patch:`, err); + return ``; // don't fail the action, but analyze without patch + } +} +async function prepareEnv() { + const startedAt = Date.now(); + // Prepare cache, lint and go in parallel. + await (0, cache_1.restoreCache)(); + const prepareLintPromise = prepareLint(); + const patchPromise = fetchPatch(); + const lintPath = await prepareLintPromise; + const patchPath = await patchPromise; + core.info(`Prepared env in ${Date.now() - startedAt}ms`); + return { lintPath, patchPath }; } const printOutput = (res) => { if (res.stdout) { @@ -66819,103 +66775,93 @@ const printOutput = (res) => { core.info(res.stderr); } }; -function runLint(lintPath, patchPath) { - return __awaiter(this, void 0, void 0, function* () { - const debug = core.getInput(`debug`); - if (debug.split(`,`).includes(`cache`)) { - const res = yield execShellCommand(`${lintPath} cache status`); - printOutput(res); - } - let userArgs = core.getInput(`args`); - const addedArgs = []; - const userArgsList = userArgs - .trim() - .split(/\s+/) - .filter((arg) => arg.startsWith(`-`)) - .map((arg) => arg.replace(/^-+/, ``)) - .map((arg) => arg.split(/=(.*)/, 2)) - .map(([key, value]) => [key.toLowerCase(), value !== null && value !== void 0 ? value : ""]); - const userArgsMap = new Map(userArgsList); - const userArgNames = new Set(userArgsList.map(([key]) => key)); - const formats = (userArgsMap.get("out-format") || "") - .trim() - .split(",") - .filter((f) => f.length > 0) - .filter((f) => !f.startsWith(`github-actions`)) - .concat("github-actions") - .join(","); - addedArgs.push(`--out-format=${formats}`); - userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim(); - if (patchPath) { - 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}`); - // Override config values. - addedArgs.push(`--new=false`); - addedArgs.push(`--new-from-rev=`); - } - const workingDirectory = core.getInput(`working-directory`); - const cmdArgs = {}; - 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()) { - 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); - } - const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd(); - core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`); - const startedAt = Date.now(); - try { - const res = yield execShellCommand(cmd, cmdArgs); - printOutput(res); - core.info(`golangci-lint found no issues`); +async function runLint(lintPath, patchPath) { + const debug = core.getInput(`debug`); + if (debug.split(`,`).includes(`cache`)) { + const res = await execShellCommand(`${lintPath} cache status`); + printOutput(res); + } + let userArgs = core.getInput(`args`); + const addedArgs = []; + const userArgsList = userArgs + .trim() + .split(/\s+/) + .filter((arg) => arg.startsWith(`-`)) + .map((arg) => arg.replace(/^-+/, ``)) + .map((arg) => arg.split(/=(.*)/, 2)) + .map(([key, value]) => [key.toLowerCase(), value ?? ""]); + const userArgsMap = new Map(userArgsList); + const userArgNames = new Set(userArgsList.map(([key]) => key)); + const formats = (userArgsMap.get("out-format") || "") + .trim() + .split(",") + .filter((f) => f.length > 0) + .filter((f) => !f.startsWith(`github-actions`)) + .concat("github-actions") + .join(","); + addedArgs.push(`--out-format=${formats}`); + userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim(); + if (patchPath) { + 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}`); + // Override config values. + addedArgs.push(`--new=false`); + addedArgs.push(`--new-from-rev=`); + } + const workingDirectory = core.getInput(`working-directory`); + const cmdArgs = {}; + if (workingDirectory) { + if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) { + throw new Error(`working-directory (${workingDirectory}) was not a path`); } - catch (exc) { - // This logging passes issues to GitHub annotations but comments can be more convenient for some users. - // TODO: support reviewdog or leaving comments by GitHub API. - printOutput(exc); - if (exc.code === 1) { - core.setFailed(`issues found`); - } - else { - core.setFailed(`golangci-lint exit with code ${exc.code}`); - } + if (!userArgNames.has(`path-prefix`)) { + addedArgs.push(`--path-prefix=${workingDirectory}`); } - core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`); - }); -} -function run() { - return __awaiter(this, void 0, void 0, function* () { - try { - const { lintPath, patchPath } = yield core.group(`prepare environment`, prepareEnv); - core.addPath(path.dirname(lintPath)); - yield core.group(`run golangci-lint`, () => runLint(lintPath, patchPath)); + cmdArgs.cwd = path.resolve(workingDirectory); + } + 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); + printOutput(res); + core.info(`golangci-lint found no issues`); + } + catch (exc) { + // This logging passes issues to GitHub annotations but comments can be more convenient for some users. + // TODO: support reviewdog or leaving comments by GitHub API. + printOutput(exc); + if (exc.code === 1) { + core.setFailed(`issues found`); } - catch (error) { - core.error(`Failed to run: ${error}, ${error.stack}`); - core.setFailed(error.message); + else { + core.setFailed(`golangci-lint exit with code ${exc.code}`); } - }); + } + core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`); +} +async function run() { + try { + const { lintPath, patchPath } = await core.group(`prepare environment`, prepareEnv); + core.addPath(path.dirname(lintPath)); + await core.group(`run golangci-lint`, () => runLint(lintPath, patchPath)); + } + catch (error) { + core.error(`Failed to run: ${error}, ${error.stack}`); + core.setFailed(error.message); + } } exports.run = run; -function postRun() { - return __awaiter(this, void 0, void 0, function* () { - try { - yield (0, cache_1.saveCache)(); - } - catch (error) { - core.error(`Failed to post-run: ${error}, ${error.stack}`); - core.setFailed(error.message); - } - }); +async function postRun() { + try { + await (0, cache_1.saveCache)(); + } + catch (error) { + core.error(`Failed to post-run: ${error}, ${error.stack}`); + core.setFailed(error.message); + } } exports.postRun = postRun; @@ -66989,7 +66935,7 @@ exports.isValidEvent = isValidEvent; /***/ }), -/***/ 1946: +/***/ 3617: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -67017,14 +66963,83 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.alterDiffPatch = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const path = __importStar(__nccwpck_require__(1017)); +// If needed alter diff file to be compatible with working directory +function alterDiffPatch(patch) { + const workingDirectory = core.getInput(`working-directory`); + if (workingDirectory) { + return alterPatchWithWorkingDirectory(patch, workingDirectory); + } + return patch; +} +exports.alterDiffPatch = alterDiffPatch; +function alterPatchWithWorkingDirectory(patch, workingDirectory) { + const workspace = process.env["GITHUB_WORKSPACE"] || ""; + const wd = path.relative(workspace, workingDirectory); + // ignore diff sections not related to the working directory + let ignore = false; + const lines = patch.split("\n"); + const filteredLines = []; + // starts with "--- a/xxx/" or "+++ a/xxx/" or "--- b/xxx/" or "+++ b/xxx/" + const cleanDiff = new RegExp(`^((?:\\+{3}|-{3}) [ab]\\/)${escapeRegExp(wd)}\\/(.*)`, "gm"); + // contains " a/xxx/" or " b/xxx/" + const firstLine = new RegExp(`( [ab]\\/)${escapeRegExp(wd)}\\/(.*)`, "gm"); + for (const line of lines) { + if (line.startsWith("diff --git")) { + ignore = !line.includes(` a/${wd}/`); + if (ignore) { + continue; + } + filteredLines.push(line.replaceAll(firstLine, "$1$2")); + } + else { + if (ignore) { + continue; + } + filteredLines.push(line.replaceAll(cleanDiff, "$1$2")); + } + } + // Join the modified lines back into a diff string + return filteredLines.join("\n"); +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions +function escapeRegExp(exp) { + return exp.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + + +/***/ }), + +/***/ 1946: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; @@ -67102,58 +67117,56 @@ const getRequestedLintVersion = () => { } return parsedRequestedLintVersion; }; -const getConfig = () => __awaiter(void 0, void 0, void 0, function* () { +const getConfig = async () => { const http = new httpm.HttpClient(`golangci/golangci-lint-action`, [], { allowRetries: true, maxRetries: 5, }); try { const url = `https://raw.githubusercontent.com/golangci/golangci-lint/master/assets/github-action-config.json`; - const response = yield http.get(url); + const response = await http.get(url); if (response.message.statusCode !== 200) { throw new Error(`failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`); } - const body = yield response.readBody(); + const body = await response.readBody(); return JSON.parse(body); } catch (exc) { throw new Error(`failed to get action config: ${exc.message}`); } -}); -function findLintVersion(mode) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`Finding needed golangci-lint version...`); - if (mode == install_1.InstallMode.GoInstall) { - const v = 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 === null || reqLintVersion === void 0 ? void 0 : reqLintVersion.major) !== null && (reqLintVersion === null || reqLintVersion === void 0 ? void 0 : reqLintVersion.minor) != null && (reqLintVersion === null || reqLintVersion === void 0 ? void 0 : reqLintVersion.patch) !== null) { - return new Promise((resolve) => { - const versionWithoutV = `${reqLintVersion.major}.${reqLintVersion.minor}.${reqLintVersion.patch}`; - resolve({ - TargetVersion: `v${versionWithoutV}`, - AssetURL: `https://github.com/golangci/golangci-lint/releases/download/v${versionWithoutV}/golangci-lint-${versionWithoutV}-linux-amd64.tar.gz`, - }); +}; +async function findLintVersion(mode) { + core.info(`Finding needed golangci-lint version...`); + if (mode == install_1.InstallMode.GoInstall) { + const v = 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) => { + const versionWithoutV = `${reqLintVersion.major}.${reqLintVersion.minor}.${reqLintVersion.patch}`; + resolve({ + TargetVersion: `v${versionWithoutV}`, + AssetURL: `https://github.com/golangci/golangci-lint/releases/download/v${versionWithoutV}/golangci-lint-${versionWithoutV}-linux-amd64.tar.gz`, }); - } - const startedAt = Date.now(); - const config = yield getConfig(); - if (!config.MinorVersionToConfig) { - core.warning(JSON.stringify(config)); - throw new Error(`invalid config: no MinorVersionToConfig field`); - } - const versionConfig = config.MinorVersionToConfig[(0, exports.stringifyVersion)(reqLintVersion)]; - if (!versionConfig) { - throw new Error(`requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}' doesn't exist`); - } - if (versionConfig.Error) { - throw new Error(`failed to use requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}': ${versionConfig.Error}`); - } - core.info(`Requested golangci-lint '${(0, exports.stringifyVersion)(reqLintVersion)}', using '${versionConfig.TargetVersion}', calculation took ${Date.now() - startedAt}ms`); - return versionConfig; - }); + }); + } + const startedAt = Date.now(); + const config = await getConfig(); + if (!config.MinorVersionToConfig) { + core.warning(JSON.stringify(config)); + throw new Error(`invalid config: no MinorVersionToConfig field`); + } + const versionConfig = config.MinorVersionToConfig[(0, exports.stringifyVersion)(reqLintVersion)]; + if (!versionConfig) { + throw new Error(`requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}' doesn't exist`); + } + if (versionConfig.Error) { + throw new Error(`failed to use requested golangci-lint version '${(0, exports.stringifyVersion)(reqLintVersion)}': ${versionConfig.Error}`); + } + core.info(`Requested golangci-lint '${(0, exports.stringifyVersion)(reqLintVersion)}', using '${versionConfig.TargetVersion}', calculation took ${Date.now() - startedAt}ms`); + return versionConfig; } exports.findLintVersion = findLintVersion; diff --git a/src/run.ts b/src/run.ts index df82c2cfa5..64e4164618 100644 --- a/src/run.ts +++ b/src/run.ts @@ -8,6 +8,7 @@ import { promisify } from "util" import { restoreCache, saveCache } from "./cache" import { installLint, InstallMode } from "./install" +import { alterDiffPatch } from "./utils/diffUtils" import { findLintVersion } from "./version" const execShellCommand = promisify(exec) @@ -68,7 +69,7 @@ async function fetchPatch(): Promise { const tempDir = await createTempDir() const patchPath = path.join(tempDir, "pull.patch") core.info(`Writing patch to ${patchPath}`) - await writeFile(patchPath, patch) + await writeFile(patchPath, alterDiffPatch(patch)) return patchPath } catch (err) { console.warn(`failed to save pull request patch:`, err) @@ -157,10 +158,6 @@ async function runLint(lintPath: string, patchPath: string): Promise { const workingDirectory = core.getInput(`working-directory`) const cmdArgs: ExecOptions = {} 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()) { throw new Error(`working-directory (${workingDirectory}) was not a path`) } diff --git a/src/utils/diffUtils.ts b/src/utils/diffUtils.ts new file mode 100644 index 0000000000..e8bd32ebb0 --- /dev/null +++ b/src/utils/diffUtils.ts @@ -0,0 +1,56 @@ +import * as core from "@actions/core" +import * as path from "path" + +// If needed alter diff file to be compatible with working directory +export function alterDiffPatch(patch: string): string { + const workingDirectory = core.getInput(`working-directory`) + + if (workingDirectory) { + return alterPatchWithWorkingDirectory(patch, workingDirectory) + } + + return patch +} + +function alterPatchWithWorkingDirectory(patch: string, workingDirectory: string): string { + const workspace = process.env["GITHUB_WORKSPACE"] || "" + + const wd = path.relative(workspace, workingDirectory) + + // ignore diff sections not related to the working directory + let ignore = false + + const lines = patch.split("\n") + const filteredLines = [] + + // starts with "--- a/xxx/" or "+++ a/xxx/" or "--- b/xxx/" or "+++ b/xxx/" + const cleanDiff = new RegExp(`^((?:\\+{3}|-{3}) [ab]\\/)${escapeRegExp(wd)}\\/(.*)`, "gm") + + // contains " a/xxx/" or " b/xxx/" + const firstLine = new RegExp(`( [ab]\\/)${escapeRegExp(wd)}\\/(.*)`, "gm") + + for (const line of lines) { + if (line.startsWith("diff --git")) { + ignore = !line.includes(` a/${wd}/`) + if (ignore) { + continue + } + + filteredLines.push(line.replaceAll(firstLine, "$1$2")) + } else { + if (ignore) { + continue + } + + filteredLines.push(line.replaceAll(cleanDiff, "$1$2")) + } + } + + // Join the modified lines back into a diff string + return filteredLines.join("\n") +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions +function escapeRegExp(exp: string): string { + return exp.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string +} diff --git a/tsconfig.json b/tsconfig.json index c5b3f2dba3..859372b659 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "target": "ES2021", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "outDir": "./lib", /* Redirect output structure to the directory. */ "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */