Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
(GH-130) Implement multi-tool validate command
Browse files Browse the repository at this point in the history
Definitions:
- When referring to the `code directory`, I mean the directory
containing the code which the validation tools are executed against.

This commit adds functionality to run multiple validator tools in series
or parallel. Multiple tools can be specified in groups which are
contained within a file named `validate.yml`. This file should be included
in the base of the code directory. See the example of a `validate.yml`
file at the bottom of this commit message.

The group of tools which the user wishes to validate with can be
selected using the `--groups [group_name]` flag.

The number of tools concurrently validating can be specified using the
`--workerCount [int]` flag. The `--serial` flag will effectively
set the `workerCount=1`.

When validation is complete, logs for each validator can be outputted to
either a log file, or to the terminal. The output location can be
specified using the `--resultsView [string]` flag. It can be set to either
'terminal' or 'file'. Single tool validation (not using `validate.yml
file`) will output to the terminal by default, whereas multi-tool
validation will output to log files. Output files will be stored to
`{code directory}/.prm-validate/`.

Appropriate unit and acceptance tests have been added.

Example `validate.yml` file:
```yaml
groups:
  - id: "ci"
    tools:
      - name: puppetlabs/epp
        args: [--example, args]
      - name: puppetlabs/parser
      - name: puppetlabs/puppet-lint
      - name: puppetlabs/onceover
      - name: puppetlabs/puppet-syntax
      - name: puppetlabs/metadata-json-lint
      - name: puppetlabs/spec_puppet
  - id: "quick_validate"
    tools:
      - name: puppetlabs/epp
      - name: puppetlabs/rubocop
      - name: puppetlabs/parser
      - name: puppetlabs/r10k
```

Note: Worker pool implementation adapted from
https://brandur.org/go-worker-pool.
  • Loading branch information
petergmurphy committed Apr 27, 2022
1 parent 7b1e1d7 commit 72dd01c
Show file tree
Hide file tree
Showing 30 changed files with 1,382 additions and 316 deletions.
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Inspired by https://github.com/golangci/golangci-lint/blob/54bfbb9a52299b6ecbdde9365282aa40a5561bf1/.golangci.yml#L1
run:
go: 1.18
linters-settings:
linters:
disable-all: true
Expand Down
4 changes: 3 additions & 1 deletion acceptance/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var defaultToolPath string

const APP = "prm"

// This test may not work locally if the default tool path is set to a different location in the `~/.`config/.prm.yaml` file.
func Test_PrmInstall_InstallsTo_DefaultToolPath(t *testing.T) {
testutils.SkipAcceptanceTest(t)

Expand Down Expand Up @@ -429,7 +430,8 @@ func Test_PrmInstall_WithGitUri_RemovesHiddenGitDir(t *testing.T) {
func removeInstalledTool(toolPath string) {
_, err := os.Stat(toolPath)
if err != nil {
panic(fmt.Sprintf("removeInstalledTool(): Could not determine if tool path (%v) exists: %v", toolPath, err))
note := "NOTE: This test may not work locally if the default tool path is set to a different location in the `~/.`config/.prm.yaml` file."
panic(fmt.Sprintf("removeInstalledTool(): Could not determine if tool path (%v) exists: %v\n%v", toolPath, err, note))
}

os.RemoveAll(toolPath)
Expand Down
2 changes: 1 addition & 1 deletion acceptance/set/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func Test_PrmSet_Puppet_NoArgs(t *testing.T) {
stdout, stderr, exitCode := testutils.RunAppCommand("set puppet", "")

// Assert
assert.Equal(t, "Error: please specify a Puppet version after 'set puppet'\n", stdout)
assert.Contains(t, stdout, "please specify a Puppet version after 'set puppet'\n")
assert.Equal(t, "exit status 1", stderr)
assert.Equal(t, 1, exitCode)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class invalid {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invalid
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This is a valid class
# @summary
# Is wonderously valid
#
class valid::valid {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
plugin:
author: puppetlabs
id: puppet-lint
display: puppet-lint
version: 0.1.0
upstream_project_url: https://github.com/puppetlabs/puppet-lint/

gem:
name: [puppet-lint]
executable: puppet-lint

common:
can_validate: true
needs_write_access: false
help_arg: '--help'
success_exit_code: 0
interleave_stdout_err: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
plugin:
author: puppetlabs
id: rubocop
display: Rubocop
version: 0.1.0
upstream_project_url: https://github.com/rubocop/rubocop

gem:
name: [rubocop, rubocop-performance, rubocop-rspec]
executable: rubocop

common:
can_validate: true
needs_write_access: false
help_arg: '--help'
success_exit_code: 0
interleave_stdout_err: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
sleep 10
exit 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
plugin:
author: puppetlabs
id: timeout
display: timeout
version: 0.1.0
upstream_project_url: https://example.com/use-script

puppet:
enabled: true

common:
can_validate: true
use_script: script
88 changes: 88 additions & 0 deletions acceptance/validate/validate_params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package validate_test

import (
"fmt"
"github.com/puppetlabs/pct/acceptance/testutils"
"github.com/stretchr/testify/assert"
"path/filepath"
"testing"
)

func Test_PrmValidate_List_Flag_Valid_ToolDir(t *testing.T) {
testutils.SkipAcceptanceTest(t)
skipValidationTests(t)

// Setup
testutils.SetAppName(APP)
toolDir, _ := filepath.Abs("../../acceptance/validate/testdata/tooldir")
testutils.RunAppCommand("set puppet 7.12.1", "")

// Exec
stdout, stderr, exitCode := testutils.RunAppCommand(fmt.Sprintf("validate --toolpath %s -l", toolDir), "")

// Assert
mustContain := []string{
" Rubocop | puppetlabs | rubocop | https://github.com/rubocop/rubocop | 0.1.0 \n",
" puppet-lint | puppetlabs | puppet-lint | https://github.com/puppetlabs/puppet-lint/ | 0.1.0 \n",
}

for _, s := range mustContain {
assert.Contains(t, stdout, s)
}
assert.Equal(t, "", stderr)
assert.Equal(t, 0, exitCode)
}

func Test_PrmValidate_List_Flag_Invalid_ToolDir(t *testing.T) {
testutils.SkipAcceptanceTest(t)
skipValidationTests(t)

// Setup
testutils.SetAppName(APP)
toolDir, _ := filepath.Abs("../../acceptance/invalid/tooldir")
testutils.RunAppCommand("set puppet 7.12.1", "")

// Exec
stdout, stderr, exitCode := testutils.RunAppCommand(fmt.Sprintf("validate -l --toolpath %s", toolDir), "")

assert.Contains(t, stdout, fmt.Sprintf("no validators found in %s", toolDir))
assert.Equal(t, "exit status 1", stderr)
assert.Equal(t, 1, exitCode)
}

func Test_PrmValidate_Tool_Timeout_Flag_Exceeded(t *testing.T) {
testutils.SkipAcceptanceTest(t)
skipValidationTests(t)

// Setup
testutils.SetAppName(APP)
toolDir, _ := filepath.Abs("../../acceptance/validate/testdata/tooldir")
cacheDir := testutils.GetTmpDir(t)
codeDir := createCodeDir(t, "puppet-lint-playground")
testutils.RunAppCommand("set puppet 7.12.1", "")

// Exec
stdout, stderr, exitCode := testutils.RunAppCommand(fmt.Sprintf("validate puppetlabs/timeout --toolpath %s --cachedir %s --codedir %s --toolTimeout 5", toolDir, cacheDir, codeDir), "")

assert.Contains(t, stdout, "context deadline exceeded")
assert.Equal(t, "exit status 1", stderr)
assert.Equal(t, 1, exitCode)
}

func Test_PrmValidate_Invalid_Tool_Timeout_Flag(t *testing.T) {
testutils.SkipAcceptanceTest(t)
skipValidationTests(t)

// Setup
testutils.SetAppName(APP)
toolDir, _ := filepath.Abs("../../acceptance/validate/testdata/tooldir")
codeDir := createCodeDir(t, "puppet-lint-playground")
testutils.RunAppCommand("set puppet 7.12.1", "")

// Exec
stdout, stderr, exitCode := testutils.RunAppCommand(fmt.Sprintf("validate puppetlabs/timeout --toolpath %s --codedir %s --toolTimeout -5", toolDir, codeDir), "")

assert.Contains(t, stdout, "the --toolTimeout flag must be set to a value greater than 1")
assert.Equal(t, "exit status 1", stderr)
assert.Equal(t, 1, exitCode)
}
Loading

0 comments on commit 72dd01c

Please sign in to comment.