Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added ability to lint Starlark packages (#1360)
## Description: Adds a way to lint starlark files ## Is this change user facing? YES ## References (if applicable): Closes #1228
- Loading branch information
Showing
4 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package lint | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"fmt" | ||
"github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel" | ||
"github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel/args" | ||
"github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/lowlevel/flags" | ||
"github.com/kurtosis-tech/kurtosis/cli/cli/command_str_consts" | ||
"github.com/kurtosis-tech/stacktrace" | ||
"github.com/sirupsen/logrus" | ||
"os" | ||
"os/exec" | ||
) | ||
|
||
const ( | ||
fileOrDirToLintArgKey = "file-or-dir" | ||
fileOrDirToLintArgKeyIsOptional = true | ||
fileOrDirToLintArgKeyIsGreedy = true | ||
|
||
formatFlagKey = "format" | ||
formatFlagShortKey = "f" | ||
formatFlagDefaultValue = "false" | ||
|
||
pyBlackDockerImage = "pyfound/black:23.9.1" | ||
dockerRunCmd = "run" | ||
removeContainerOnExit = "--rm" | ||
dockerBinary = "docker" | ||
lintVolumeName = "/lint" | ||
dockerVolumeFlag = "-v" | ||
dockerWorkDirFlag = "--workdir" | ||
blackBinaryName = "black" | ||
includeFlagForBlack = "--include" | ||
presentWorkingDirectory = "." | ||
checkFlagForBlack = "--check" | ||
allStarlarkFilesMatch = "\\.star?$" | ||
dirVolumeSeparator = ":" | ||
|
||
linterFailedAsThingsNeedToBeReformattedExitCode = 1 | ||
linterFailedWithInternalErrorsExitCode = 123 | ||
) | ||
|
||
var fileOrDirToLintDefaultValue = []string{"."} | ||
|
||
var dockerRunPrefix = []string{dockerRunCmd, removeContainerOnExit, dockerVolumeFlag} | ||
var dockerRunSuffix = []string{dockerWorkDirFlag, lintVolumeName, pyBlackDockerImage, blackBinaryName, presentWorkingDirectory, includeFlagForBlack, allStarlarkFilesMatch} | ||
|
||
// LintCmd we only fill in the required struct fields, hence the others remain nil | ||
// nolint: exhaustruct | ||
var LintCmd = &lowlevel.LowlevelKurtosisCommand{ | ||
CommandStr: command_str_consts.KurtosisLintCmdStr, | ||
ShortDescription: "Lints the Kurtosis package or file", | ||
LongDescription: "Lints the Kurtosis package or file", | ||
|
||
Args: []*args.ArgConfig{ | ||
{ | ||
Key: fileOrDirToLintArgKey, | ||
DefaultValue: fileOrDirToLintDefaultValue, | ||
IsOptional: fileOrDirToLintArgKeyIsOptional, | ||
IsGreedy: fileOrDirToLintArgKeyIsGreedy, | ||
ValidationFunc: validateFileOrDirToLintArg, | ||
}, | ||
}, | ||
|
||
Flags: []*flags.FlagConfig{ | ||
{ | ||
Key: formatFlagKey, | ||
Usage: "Use this flag to edit files in place instead of just verifying whether the formatting is correct", | ||
Shorthand: formatFlagShortKey, | ||
Type: flags.FlagType_Bool, | ||
Default: formatFlagDefaultValue, | ||
}, | ||
}, | ||
RunFunc: run, | ||
} | ||
|
||
func run(_ context.Context, flags *flags.ParsedFlags, args *args.ParsedArgs) error { | ||
fileOrDirToLintArg, err := args.GetGreedyArg(fileOrDirToLintArgKey) | ||
if err != nil { | ||
return stacktrace.Propagate(err, "an error occurred getting the value of argument with key '%v'", fileOrDirToLintArgKey) | ||
} | ||
|
||
formatFlag, err := flags.GetBool(formatFlagKey) | ||
if err != nil { | ||
return stacktrace.Propagate(err, "an error occurred getting the value of flag '%v'", formatFlag) | ||
} | ||
if !formatFlag { | ||
dockerRunSuffix = append(dockerRunSuffix, checkFlagForBlack) | ||
} | ||
|
||
logrus.Infof("This depends on '%v'; first run may take a while as we might have to download it", pyBlackDockerImage) | ||
|
||
if _, err := exec.LookPath(dockerBinary); err != nil { | ||
return stacktrace.Propagate(err, "'%v' uses '%v' underneath in order to use the '%v' image but it couldn't find '%v' in path", command_str_consts.KurtosisLintCmdStr, dockerBinary, pyBlackDockerImage, dockerBinary) | ||
} | ||
|
||
for _, fileOrDirToLint := range fileOrDirToLintArg { | ||
logrus.Infof("Linting '%v'", fileOrDirToLint) | ||
commandArgs := append(dockerRunPrefix, fileOrDirToLint+dirVolumeSeparator+lintVolumeName) | ||
commandArgs = append(commandArgs, dockerRunSuffix...) | ||
cmd := exec.Command(dockerBinary, commandArgs...) | ||
cmdOutput, err := cmd.CombinedOutput() | ||
if err != nil { | ||
if exitError, ok := err.(*exec.ExitError); ok { | ||
switch exitError.ExitCode() { | ||
case linterFailedAsThingsNeedToBeReformattedExitCode: | ||
fmt.Println(string(cmdOutput)) | ||
return stacktrace.NewError("linting failed, this means that there are some files that need to be formatted, run this command with the '--%v' flag", formatFlagKey) | ||
case linterFailedWithInternalErrorsExitCode: | ||
fmt.Println(string(cmdOutput)) | ||
return stacktrace.NewError("linting failed with an internal error please look at the output to see why; usually this happens if there's a mix of spaces & tabs") | ||
default: | ||
return stacktrace.Propagate(err, "linting failed with an unexpected exit code '%v'; This is a bug in Kurtosis", exitError.ExitCode()) | ||
} | ||
} | ||
return stacktrace.Propagate(err, "Linting failed and we couldn't get an exit code out of the err; This is a bug in Kurtosis") | ||
} | ||
fmt.Println(string(cmdOutput)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func validateFileOrDirToLintArg(_ context.Context, _ *flags.ParsedFlags, args *args.ParsedArgs) error { | ||
fileOrDirToLintArg, err := args.GetGreedyArg(fileOrDirToLintArgKey) | ||
if err != nil { | ||
return stacktrace.Propagate(err, "an error occurred getting the value of argument with key '%v'", fileOrDirToLintArgKey) | ||
} | ||
|
||
for _, fileOrDirToLint := range fileOrDirToLintArg { | ||
if _, err := os.Stat(fileOrDirToLint); err != nil { | ||
return stacktrace.Propagate(err, "an error occurred validating whether supplied path '%v' was valid", fileOrDirToLint) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
--- | ||
title: lint | ||
sidebar_label: lint | ||
slug: /lint | ||
--- | ||
|
||
The following command can be used to lint Starlark files in the given package | ||
|
||
To get running quickly, simply run | ||
|
||
```bash | ||
kurtosis lint . | ||
``` | ||
|
||
This will lint all the Starlark files in the given package | ||
|
||
Instead of just finding linting issues if you want to format the files as well use the `--format` flag | ||
|
||
```bash | ||
kurtosis lint . --format | ||
``` | ||
|
||
You can also lint a specific file via | ||
|
||
```bash | ||
kurtosis lint main.star | ||
``` | ||
|
||
Or to lint multiple files or directories at the same time | ||
|
||
```bash | ||
kurtosis lint this.star that.star also-this.star my-favorite-directory/ | ||
``` |