Skip to content

Commit

Permalink
Merge branch 'skip-inputs' (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhysd committed Jul 28, 2021
2 parents 7794d96 + f46fb6c commit 88a9df7
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 24 deletions.
3 changes: 3 additions & 0 deletions action_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type ActionMetadata struct {
// Outputs is "outputs" field of action.yaml. Key is name of output. Description is omitted
// since actionlint does not use it.
Outputs map[string]struct{} `yaml:"outputs" json:"outputs"`
// SkipInputs is flag to specify behavior of inputs check. When it is true, inputs for this
// action will not be checked.
SkipInputs bool `json:"skip_inputs"`
}

// LocalActionsCache is cache for local actions' metadata. It avoids repeating to find/read/parse
Expand Down
57 changes: 57 additions & 0 deletions linter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,68 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"

"golang.org/x/sys/execabs"
)

func TestLinterLintOK(t *testing.T) {
dir := filepath.Join("testdata", "ok")

es, err := ioutil.ReadDir(dir)
if err != nil {
panic(err)
}

fs := make([]string, 0, len(es))
for _, e := range es {
if e.IsDir() {
continue
}
n := e.Name()
if strings.HasSuffix(n, ".yaml") || strings.HasSuffix(n, ".yml") {
fs = append(fs, filepath.Join(dir, n))
}
}

proj := &Project{root: dir}
shellcheck, err := execabs.LookPath("shellcheck")
if err != nil {
t.Skip("skipped because \"shellcheck\" command does not exist in system")
}

pyflakes, err := execabs.LookPath("pyflakes")
if err != nil {
t.Skip("skipped because \"pyflakes\" command does not exist in system")
}

for _, f := range fs {
t.Run(filepath.Base(f), func(t *testing.T) {
opts := LinterOptions{
Shellcheck: shellcheck,
Pyflakes: pyflakes,
}

linter, err := NewLinter(ioutil.Discard, &opts)
if err != nil {
t.Fatal(err)
}

config := Config{}
linter.defaultConfig = &config

errs, err := linter.LintFile(f, proj)
if err != nil {
t.Fatal(err)
}
if len(errs) > 0 {
t.Fatal(errs)
}
})
}
}

func BenchmarkLintWorkflowFiles(b *testing.B) {
dir, err := os.Getwd()
if err != nil {
Expand Down
18 changes: 18 additions & 0 deletions popular_actions.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions rule_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ func (rule *RuleAction) checkRepoAction(spec string, exec *ExecAction) {
rule.debug("This action is not found in popular actions data set: %s", spec)
return
}
if meta.SkipInputs {
rule.debug("This action skips to check inputs: %s", spec)
return
}

rule.checkAction(meta, exec, func(m *ActionMetadata) string {
return strconv.Quote(spec)
Expand Down
30 changes: 23 additions & 7 deletions scripts/generate-popular-actions/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ var popularActions = []*action{
{"msys2/setup-msys2", []string{"v1", "v2"}, "v3", yamlExtYML},
{"ncipollo/release-action", []string{"v1"}, "v2", yamlExtYML},
{"nwtgck/actions-netlify", []string{"v1"}, "v2", yamlExtYML},
{"octokit/request-action", []string{"v1.x", "v2.x"}, "v3.x", yamlExtYML},
{"peaceiris/actions-gh-pages", []string{"v2", "v3"}, "v4", yamlExtYML},
{"peter-evans/create-pull-request", []string{"v1", "v2", "v3"}, "v4", yamlExtYML},
{"preactjs/compressed-size-action", []string{"v1", "v2"}, "v3", yamlExtYML},
Expand All @@ -128,6 +129,12 @@ var popularActions = []*action{
{"wearerequired/lint-action", []string{"v1"}, "v2", yamlExtYML},
}

// slugs not to check inputs. Some actions allow to specify inputs which are not defined in action.yml.
// In such cases, actionlint no longer can check the inputs, but it can still check outputs.
var doNotCheckInputs = map[string]struct{}{
"octokit/request-action": {},
}

func buildURL(slug, tag string, ext yamlExt) string {
path := ""
if ss := strings.Split(slug, "/"); len(ss) > 2 {
Expand All @@ -137,7 +144,7 @@ func buildURL(slug, tag string, ext yamlExt) string {
return fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/%saction.%s", slug, tag, path, ext.String())
}

func fetchRemote(actions []*action) (map[string]*actionlint.ActionMetadata, error) {
func fetchRemote(actions []*action, skipInputs map[string]struct{}) (map[string]*actionlint.ActionMetadata, error) {
type request struct {
slug string
tag string
Expand Down Expand Up @@ -183,6 +190,9 @@ func fetchRemote(actions []*action) (map[string]*actionlint.ActionMetadata, erro
ret <- &fetched{err: fmt.Errorf("coult not parse metadata for %s: %w", url, err)}
break
}
if _, ok := skipInputs[req.slug]; ok {
meta.SkipInputs = true
}
ret <- &fetched{spec: spec, meta: &meta}
case <-done:
return
Expand Down Expand Up @@ -233,7 +243,7 @@ func writeJSONL(out io.Writer, actions map[string]*actionlint.ActionMetadata) er
return nil
}

func writeGo(out io.Writer, actions map[string]*actionlint.ActionMetadata) error {
func writeGo(out io.Writer, actions map[string]*actionlint.ActionMetadata, skipInputs map[string]struct{}) error {
b := &bytes.Buffer{}
fmt.Fprint(b, `// Code generated by actionlint/scripts/generate-popular-actions. DO NOT EDIT.
Expand All @@ -258,7 +268,13 @@ var PopularActions = map[string]*ActionMetadata{
fmt.Fprintf(b, "%q: {\n", spec)
fmt.Fprintf(b, "Name: %q,\n", meta.Name)

if len(meta.Inputs) > 0 {
slug := spec[:strings.IndexRune(spec, '@')]
_, skip := skipInputs[slug]
if skip {
fmt.Fprintf(b, "SkipInputs: true,\n")
}

if len(meta.Inputs) > 0 && !skip {
names := make([]string, 0, len(meta.Inputs))
for n := range meta.Inputs {
names = append(names, n)
Expand Down Expand Up @@ -425,7 +441,7 @@ func detectNewReleaseURLs(actions []*action) ([]string, error) {
return us, nil
}

func run(args []string, stdout, stderr io.Writer, knownActions []*action) int {
func run(args []string, stdout, stderr io.Writer, knownActions []*action, skipInputs map[string]struct{}) int {
var source string
var format string
var quiet bool
Expand Down Expand Up @@ -508,7 +524,7 @@ Flags:`)
var actions map[string]*actionlint.ActionMetadata
if source == "remote" {
log.Println("Fetching data from https://github.com")
m, err := fetchRemote(knownActions)
m, err := fetchRemote(knownActions, skipInputs)
if err != nil {
fmt.Fprintln(stderr, err)
return 1
Expand All @@ -527,7 +543,7 @@ Flags:`)
switch format {
case "go":
log.Println("Generating Go source code to", where)
if err := writeGo(out, actions); err != nil {
if err := writeGo(out, actions, skipInputs); err != nil {
fmt.Fprintln(stderr, err)
return 1
}
Expand All @@ -544,5 +560,5 @@ Flags:`)
}

func main() {
os.Exit(run(os.Args, os.Stdout, os.Stderr, popularActions))
os.Exit(run(os.Args, os.Stdout, os.Stderr, popularActions, doNotCheckInputs))
}
Loading

0 comments on commit 88a9df7

Please sign in to comment.