mirror of
https://github.com/golangci/golangci-lint-action.git
synced 2026-02-08 00:37:26 +00:00
feat: add support for reading golangci-lint version from go.mod
Implements automatic version detection from go.mod files to keep golangci-lint versions synchronized between the module and CI. - Add new `go-mod-path` input parameter to specify custom go.mod location - Automatically detect and use version from go.mod when no explicit version provided - Force `goinstall` mode when using go.mod versions for compatibility - Support both default go.mod and custom paths (e.g., tools/go.mod) This eliminates the need to manually update versions in multiple places and ensures CI uses the same golangci-lint version as the project. Fixes #1268 Signed-off-by: Pedro Tanaka <pedro.tanaka@shopify.com>
This commit is contained in:
parent
9511564208
commit
17e961267d
6 changed files with 183 additions and 13 deletions
87
README.md
87
README.md
|
|
@ -105,6 +105,68 @@ You will also likely need to add the following `.gitattributes` file to ensure t
|
|||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Using go.mod Version Example</summary>
|
||||
|
||||
If you have golangci-lint as a dependency in your go.mod file, you can use that version automatically:
|
||||
|
||||
```yaml
|
||||
name: golangci-lint
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
# No version specified - will read from go.mod automatically
|
||||
```
|
||||
|
||||
Or if you have a separate tools module:
|
||||
|
||||
```yaml
|
||||
name: golangci-lint
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
go-mod-path: tools/go.mod
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Go Workspace Example</summary>
|
||||
|
||||
|
|
@ -280,6 +342,29 @@ with:
|
|||
|
||||
</details>
|
||||
|
||||
### `go-mod-path`
|
||||
|
||||
(optional)
|
||||
|
||||
Path to a go.mod file to read the golangci-lint version from.
|
||||
If specified and `version` is not set, the action will parse the go.mod file to determine the golangci-lint version.
|
||||
|
||||
Default is "go.mod" in the working directory.
|
||||
|
||||
**Note:** When a version is read from go.mod, it automatically uses `goinstall` install-mode to ensure compatibility with your module's dependencies.
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
|
||||
```yml
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
go-mod-path: tools/go.mod
|
||||
# ...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### `install-mode`
|
||||
|
||||
(optional)
|
||||
|
|
@ -288,6 +373,8 @@ The mode to install golangci-lint: it can be `binary`, `goinstall`, or `none`.
|
|||
|
||||
The default value is `binary`.
|
||||
|
||||
**Note:** When using `go-mod-path` to read the version from a go.mod file, the install-mode is automatically set to `goinstall`.
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@ inputs:
|
|||
- `goinstall`: the value can be v2.3.4, `latest`, or the hash of a commit.
|
||||
- `none`: the value is ignored.
|
||||
required: false
|
||||
go-mod-path:
|
||||
description: |
|
||||
Path to a go.mod file to read the golangci-lint version from.
|
||||
If specified and version is not set, the action will parse the go.mod file
|
||||
to determine the golangci-lint version. Default is "go.mod" in the working directory.
|
||||
Note: When a version is read from go.mod, it automatically uses `goinstall` install-mode.
|
||||
required: false
|
||||
install-mode:
|
||||
description: "The mode to install golangci-lint. It can be 'binary', 'goinstall', or 'none'."
|
||||
default: "binary"
|
||||
|
|
|
|||
32
dist/post_run/index.js
generated
vendored
32
dist/post_run/index.js
generated
vendored
|
|
@ -92671,7 +92671,7 @@ const printOutput = (res) => {
|
|||
* @returns path to installed binary of golangci-lint.
|
||||
*/
|
||||
async function install() {
|
||||
const mode = core.getInput("install-mode").toLowerCase();
|
||||
let mode = core.getInput("install-mode").toLowerCase();
|
||||
if (mode === InstallMode.None) {
|
||||
const binPath = await (0, which_1.default)("golangci-lint", { nothrow: true });
|
||||
if (!binPath) {
|
||||
|
|
@ -92679,6 +92679,11 @@ async function install() {
|
|||
}
|
||||
return binPath;
|
||||
}
|
||||
// If version is being read from go.mod, force goinstall mode
|
||||
if ((0, version_1.isVersionFromGoMod)()) {
|
||||
core.info(`Version detected from go.mod file, using goinstall mode`);
|
||||
mode = InstallMode.GoInstall;
|
||||
}
|
||||
const versionInfo = await (0, version_1.getVersion)(mode);
|
||||
return await installBinary(versionInfo, mode);
|
||||
}
|
||||
|
|
@ -93358,6 +93363,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.stringifyVersion = void 0;
|
||||
exports.isVersionFromGoMod = isVersionFromGoMod;
|
||||
exports.getVersion = getVersion;
|
||||
const core = __importStar(__nccwpck_require__(7484));
|
||||
const httpm = __importStar(__nccwpck_require__(4844));
|
||||
|
|
@ -93412,8 +93418,9 @@ const isLessVersion = (a, b) => {
|
|||
const getRequestedVersion = () => {
|
||||
let requestedVersion = core.getInput(`version`);
|
||||
const workingDirectory = core.getInput(`working-directory`);
|
||||
let goMod = "go.mod";
|
||||
if (workingDirectory) {
|
||||
const goModPath = core.getInput(`go-mod-path`);
|
||||
let goMod = goModPath || "go.mod";
|
||||
if (!path_1.default.isAbsolute(goMod) && workingDirectory) {
|
||||
goMod = path_1.default.join(workingDirectory, goMod);
|
||||
}
|
||||
if (requestedVersion == "" && fs.existsSync(goMod)) {
|
||||
|
|
@ -93451,10 +93458,27 @@ const fetchVersionMapping = async () => {
|
|||
throw new Error(`failed to get action config: ${exc.message}`);
|
||||
}
|
||||
};
|
||||
function isVersionFromGoMod() {
|
||||
const requestedVersion = core.getInput(`version`);
|
||||
const goModPath = core.getInput(`go-mod-path`);
|
||||
const workingDirectory = core.getInput(`working-directory`);
|
||||
let goMod = goModPath || "go.mod";
|
||||
if (!path_1.default.isAbsolute(goMod) && workingDirectory) {
|
||||
goMod = path_1.default.join(workingDirectory, goMod);
|
||||
}
|
||||
return requestedVersion == "" && fs.existsSync(goMod);
|
||||
}
|
||||
async function getVersion(mode) {
|
||||
core.info(`Finding needed golangci-lint version...`);
|
||||
if (mode == install_1.InstallMode.GoInstall) {
|
||||
const v = core.getInput(`version`);
|
||||
let v = core.getInput(`version`);
|
||||
// If no explicit version is provided, check go.mod
|
||||
if (!v && isVersionFromGoMod()) {
|
||||
const reqVersion = getRequestedVersion();
|
||||
if (reqVersion) {
|
||||
v = (0, exports.stringifyVersion)(reqVersion);
|
||||
}
|
||||
}
|
||||
return { TargetVersion: v ? v : "latest" };
|
||||
}
|
||||
const reqVersion = getRequestedVersion();
|
||||
|
|
|
|||
32
dist/run/index.js
generated
vendored
32
dist/run/index.js
generated
vendored
|
|
@ -92671,7 +92671,7 @@ const printOutput = (res) => {
|
|||
* @returns path to installed binary of golangci-lint.
|
||||
*/
|
||||
async function install() {
|
||||
const mode = core.getInput("install-mode").toLowerCase();
|
||||
let mode = core.getInput("install-mode").toLowerCase();
|
||||
if (mode === InstallMode.None) {
|
||||
const binPath = await (0, which_1.default)("golangci-lint", { nothrow: true });
|
||||
if (!binPath) {
|
||||
|
|
@ -92679,6 +92679,11 @@ async function install() {
|
|||
}
|
||||
return binPath;
|
||||
}
|
||||
// If version is being read from go.mod, force goinstall mode
|
||||
if ((0, version_1.isVersionFromGoMod)()) {
|
||||
core.info(`Version detected from go.mod file, using goinstall mode`);
|
||||
mode = InstallMode.GoInstall;
|
||||
}
|
||||
const versionInfo = await (0, version_1.getVersion)(mode);
|
||||
return await installBinary(versionInfo, mode);
|
||||
}
|
||||
|
|
@ -93358,6 +93363,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.stringifyVersion = void 0;
|
||||
exports.isVersionFromGoMod = isVersionFromGoMod;
|
||||
exports.getVersion = getVersion;
|
||||
const core = __importStar(__nccwpck_require__(7484));
|
||||
const httpm = __importStar(__nccwpck_require__(4844));
|
||||
|
|
@ -93412,8 +93418,9 @@ const isLessVersion = (a, b) => {
|
|||
const getRequestedVersion = () => {
|
||||
let requestedVersion = core.getInput(`version`);
|
||||
const workingDirectory = core.getInput(`working-directory`);
|
||||
let goMod = "go.mod";
|
||||
if (workingDirectory) {
|
||||
const goModPath = core.getInput(`go-mod-path`);
|
||||
let goMod = goModPath || "go.mod";
|
||||
if (!path_1.default.isAbsolute(goMod) && workingDirectory) {
|
||||
goMod = path_1.default.join(workingDirectory, goMod);
|
||||
}
|
||||
if (requestedVersion == "" && fs.existsSync(goMod)) {
|
||||
|
|
@ -93451,10 +93458,27 @@ const fetchVersionMapping = async () => {
|
|||
throw new Error(`failed to get action config: ${exc.message}`);
|
||||
}
|
||||
};
|
||||
function isVersionFromGoMod() {
|
||||
const requestedVersion = core.getInput(`version`);
|
||||
const goModPath = core.getInput(`go-mod-path`);
|
||||
const workingDirectory = core.getInput(`working-directory`);
|
||||
let goMod = goModPath || "go.mod";
|
||||
if (!path_1.default.isAbsolute(goMod) && workingDirectory) {
|
||||
goMod = path_1.default.join(workingDirectory, goMod);
|
||||
}
|
||||
return requestedVersion == "" && fs.existsSync(goMod);
|
||||
}
|
||||
async function getVersion(mode) {
|
||||
core.info(`Finding needed golangci-lint version...`);
|
||||
if (mode == install_1.InstallMode.GoInstall) {
|
||||
const v = core.getInput(`version`);
|
||||
let v = core.getInput(`version`);
|
||||
// If no explicit version is provided, check go.mod
|
||||
if (!v && isVersionFromGoMod()) {
|
||||
const reqVersion = getRequestedVersion();
|
||||
if (reqVersion) {
|
||||
v = (0, exports.stringifyVersion)(reqVersion);
|
||||
}
|
||||
}
|
||||
return { TargetVersion: v ? v : "latest" };
|
||||
}
|
||||
const reqVersion = getRequestedVersion();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import path from "path"
|
|||
import { promisify } from "util"
|
||||
import which from "which"
|
||||
|
||||
import { getVersion, VersionInfo } from "./version"
|
||||
import { getVersion, isVersionFromGoMod, VersionInfo } from "./version"
|
||||
|
||||
const execShellCommand = promisify(exec)
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ const printOutput = (res: ExecRes): void => {
|
|||
* @returns path to installed binary of golangci-lint.
|
||||
*/
|
||||
export async function install(): Promise<string> {
|
||||
const mode = core.getInput("install-mode").toLowerCase()
|
||||
let mode = core.getInput("install-mode").toLowerCase()
|
||||
|
||||
if (mode === InstallMode.None) {
|
||||
const binPath = await which("golangci-lint", { nothrow: true })
|
||||
|
|
@ -46,6 +46,12 @@ export async function install(): Promise<string> {
|
|||
return binPath
|
||||
}
|
||||
|
||||
// If version is being read from go.mod, force goinstall mode
|
||||
if (isVersionFromGoMod()) {
|
||||
core.info(`Version detected from go.mod file, using goinstall mode`)
|
||||
mode = InstallMode.GoInstall
|
||||
}
|
||||
|
||||
const versionInfo = await getVersion(<InstallMode>mode)
|
||||
|
||||
return await installBinary(versionInfo, <InstallMode>mode)
|
||||
|
|
|
|||
|
|
@ -68,9 +68,10 @@ const isLessVersion = (a: Version, b: Version): boolean => {
|
|||
const getRequestedVersion = (): Version => {
|
||||
let requestedVersion = core.getInput(`version`)
|
||||
const workingDirectory = core.getInput(`working-directory`)
|
||||
const goModPath = core.getInput(`go-mod-path`)
|
||||
|
||||
let goMod = "go.mod"
|
||||
if (workingDirectory) {
|
||||
let goMod = goModPath || "go.mod"
|
||||
if (!path.isAbsolute(goMod) && workingDirectory) {
|
||||
goMod = path.join(workingDirectory, goMod)
|
||||
}
|
||||
|
||||
|
|
@ -129,11 +130,32 @@ const fetchVersionMapping = async (): Promise<VersionMapping> => {
|
|||
}
|
||||
}
|
||||
|
||||
export function isVersionFromGoMod(): boolean {
|
||||
const requestedVersion = core.getInput(`version`)
|
||||
const goModPath = core.getInput(`go-mod-path`)
|
||||
const workingDirectory = core.getInput(`working-directory`)
|
||||
|
||||
let goMod = goModPath || "go.mod"
|
||||
if (!path.isAbsolute(goMod) && workingDirectory) {
|
||||
goMod = path.join(workingDirectory, goMod)
|
||||
}
|
||||
|
||||
return requestedVersion == "" && fs.existsSync(goMod)
|
||||
}
|
||||
|
||||
export async function getVersion(mode: InstallMode): Promise<VersionInfo> {
|
||||
core.info(`Finding needed golangci-lint version...`)
|
||||
|
||||
if (mode == InstallMode.GoInstall) {
|
||||
const v: string = core.getInput(`version`)
|
||||
let v: string = core.getInput(`version`)
|
||||
|
||||
// If no explicit version is provided, check go.mod
|
||||
if (!v && isVersionFromGoMod()) {
|
||||
const reqVersion = getRequestedVersion()
|
||||
if (reqVersion) {
|
||||
v = stringifyVersion(reqVersion)
|
||||
}
|
||||
}
|
||||
|
||||
return { TargetVersion: v ? v : "latest" }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue