fix: add missing fix mode options and test cases (#5987)

- Add missing fix mode options for: CLANG_FORMAT, ENV,
  GOOGLE_JAVA_FORMAT, NATURAL_LANGUAGE, PYTHON_ISORT, RUST_CLIPPY.
- Refactor linter tests to make them shorter because there's no need to
  have big test files.
- Refactor 'bad' linter tests for linters that support fix mode so they
  contain only automatically fixable issues. This is needed to avoid
  adding another set of 'bad' linter tests for fix mode.
- Provide configuration files for linters that support fix mode and for
  which the default configuration is not suitable to enable fix mode:
  ansible-lint, ESLint, golangci-lint.
- Add a test case for linter commands options for linters that support
  fix mode, to ensure that fix mode and check-only mode options have
  been defined.
- Refactor the fix mode test to check if linters actually applied
  modifications to files.
- Update documentation about adding test cases for linters that support
  fix mode.
- Don't exit with a fatal error if VALIDATE_xxx is false when testing
  fix mode because not all linters support fix mode. To enable this, set
  the new FIX_MODE_TEST_CASE_RUN variable to true.
This commit is contained in:
Marco Ferrari 2024-08-12 12:31:38 +02:00 committed by GitHub
parent ea16cd9a1b
commit 91dc6d7234
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 595 additions and 712 deletions

44
.github/linters/.eslintrc.yml vendored Normal file
View file

@ -0,0 +1,44 @@
---
env:
browser: true
es6: true
jest: true
node: true
extends:
- "eslint:recommended"
ignorePatterns:
- "!.*"
- "**/node_modules/.*"
parser: '@typescript-eslint/parser'
plugins:
- '@typescript-eslint'
# Don't set the jsonSyntax parser option for JSON, JSON5, and JSONC
# so we can use eslint-plugin-jsonc to automatically fix issues
# in tests, otherwise ESLint reports parsing errors and stops
overrides:
- files:
- "*.json"
extends:
- plugin:jsonc/recommended-with-json
parser: jsonc-eslint-parser
- files:
- "*.jsonc"
extends:
- plugin:jsonc/recommended-with-jsonc
parser: jsonc-eslint-parser
- files:
- "*.json5"
extends:
- plugin:jsonc/recommended-with-json5
parser: jsonc-eslint-parser
- files:
- "*.jsx"
- "*.tsx"
extends:
- plugin:react/recommended
...

7
.github/linters/.golangci.yml vendored Normal file
View file

@ -0,0 +1,7 @@
---
# This file is only used in tests
# TODO: move in a dedicated directory in test/linters-config
linters:
enable:
- gofmt
...

View file

@ -38,6 +38,7 @@
"**/test/linters/typescript_es/**",
"**/test/linters/typescript_prettier/**",
"**/test/linters/typescript_standard/**",
"**/test/linters-config/**",
"**/github_conf/**",
"**/workflows/cd.yml",
"**/workflows/ci.yml"

View file

@ -4,7 +4,7 @@
all: info docker test ## Run all targets.
.PHONY: test
test: info validate-container-image-labels docker-build-check docker-dev-container-build-check test-lib inspec lint-codebase fix-codebase test-default-config-files test-actions-runner-debug test-actions-steps-debug test-runner-debug test-find lint-subset-files test-custom-ssl-cert test-non-default-workdir test-git-flags test-non-default-home-directory test-git-initial-commit test-git-merge-commit-push test-log-level test-use-find-and-ignore-gitignored-files test-linters-expect-failure-log-level-notice test-bash-exec-library-expect-success test-bash-exec-library-expect-failure test-save-super-linter-output test-save-super-linter-output-custom-path test-save-super-linter-custom-summary test-linters test-linters-fix-mode-expect-success ## Run the test suite
test: info validate-container-image-labels docker-build-check docker-dev-container-build-check test-lib inspec lint-codebase fix-codebase test-default-config-files test-actions-runner-debug test-actions-steps-debug test-runner-debug test-find lint-subset-files test-custom-ssl-cert test-non-default-workdir test-git-flags test-non-default-home-directory test-git-initial-commit test-git-merge-commit-push test-log-level test-use-find-and-ignore-gitignored-files test-linters-expect-failure-log-level-notice test-bash-exec-library-expect-success test-bash-exec-library-expect-failure test-save-super-linter-output test-save-super-linter-output-custom-path test-save-super-linter-custom-summary test-linters test-linters-fix-mode ## Run the test suite
# if this session isn't interactive, then we don't want to allocate a
# TTY, which would fail, but if it is interactive, we do want to attach
@ -318,6 +318,14 @@ test-globals-languages: ## Test globals/languages.sh
--entrypoint /tmp/lint/test/lib/globalsLanguagesTest.sh \
$(SUPER_LINTER_TEST_CONTAINER_URL)
.PHONY: test-globals-linter-command-options
test-globals-linter-command-options: ## Test globals/LinterCommandsOptions.sh
docker run \
-v "$(CURDIR):/tmp/lint" \
-w /tmp/lint \
--entrypoint /tmp/lint/test/lib/globalsLinterCommandsOptionsTest.sh \
$(SUPER_LINTER_TEST_CONTAINER_URL)
.PHONY: test-linter-rules
test-linter-rules: ## Test linterRules.sh
docker run \
@ -416,14 +424,13 @@ test-non-default-home-directory: ## Test a non-default HOME directory
"run_test_cases_non_default_home" \
"$(IMAGE)"
.PHONY: test-linters-fix-mode-expect-success
test-linters-fix-mode-expect-success: ## Run the linters test suite (fix mode) expecting successes
.PHONY: test-linters-fix-mode
test-linters-fix-mode: ## Run the linters test suite (fix mode)
$(CURDIR)/test/run-super-linter-tests.sh \
$(SUPER_LINTER_TEST_CONTAINER_URL) \
"run_test_case_fix_mode" \
"$(IMAGE)"
.PHONY: test-linters
test-linters: test-linters-expect-success test-linters-expect-failure ## Run the linters test suite

View file

@ -234,7 +234,7 @@ You can configure Super-linter using the following environment variables:
| **FIX_RUST_2015** | `false` | Option to enable fix mode for `RUST_2015`. |
| **FIX_RUST_2018** | `false` | Option to enable fix mode for `RUST_2018`. |
| **FIX_RUST_2021** | `false` | Option to enable fix mode for `RUST_2021`. |
| **FIX_RUST_CLIPPY** | `false` | Option to enable fix mode for `RUST_CLIPPY`. |
| **FIX_RUST_CLIPPY** | `false` | Option to enable fix mode for `RUST_CLIPPY`. When `FIX_RUST_CLIPPY` is `true`, Clippy is allowed to fix issues in the workspace even if there are unstaged and staged changes in the workspace. |
| **FIX_SCALAFMT** | `false` | Option to enable fix mode for `SCALAFMT`. |
| **FIX_SHELL_SHFMT** | `false` | Option to enable fix mode for `SHELL_SHFMT`. |
| **FIX_SNAKEMAKE_SNAKEFMT** | `false` | Option to enable fix mode for `SNAKEMAKE_SNAKEFMT`. |
@ -421,6 +421,20 @@ Super-linter supports the following locations to deliver fixes:
- If you're running Super-linter locally, you can commit the changes as you
would with any other change in your working directory.
### Fix mode for ansible-lint
ansible-lint requires that the `yaml` rule is enabled to for the ansible-lint
fix mode to work. The default ansible-lint configuration that Super-linter ships
disables the `yaml` rule because it might not be compatible with yamllint. If
you need to enable the ansible-lint fix mode, provide an ansible-lint
configuration that doesn't ignore the `yaml` rule.
### Fix mode file and directory ownership
When fix mode is enabled, some linters and formatters don't maintain the
original file or directory ownership, and use the user that Super-linter uses
to run the linter or formatter.
## Configure linters
Super-linter provides default configurations for some linters in the [`TEMPLATES/`](TEMPLATES/)

View file

@ -7,11 +7,16 @@ new tool, it should include:
- `README.md`
- Provide test cases:
1. Create the `test/linters/<LANGUGAGE>` directory.
1. Create the `test/linters/<LANGUAGE_NAME>` directory.
2. Provide at least one test case with a file that is supposed to pass validation,
with the right file extension if needed: `test/linters/<LANGUAGE>/<name-of-tool>-good`
with the right file extension if needed: `test/linters/<LANGUAGE_NAME>/<name-of-tool>-good`
3. Provide at least one test case with a file that is supposed to fail validation,
with the right file extension if needed: `test/linters/<LANGUAGE>/<name-of-tool>-bad`
with the right file extension if needed: `test/linters/<LANGUAGE_NAME>/<name-of-tool>-bad`.
If the linter supports fix mode, the test case supposed to fail validation
should only contain violations that the fix mode can automatically fix.
Avoid test cases that fail only because of syntax errors, when possible.
4. If the linter supports check-only mode or fix mode, add the `<LANGUGAGE>`
to the `LANGUAGES_WITH_FIX_MODE` array in `test/testUtils.sh`
- Update the test suite to check for installed packages, the commands that your new tool needs in the `PATH`, and the expected version command:

View file

@ -7,6 +7,7 @@ function ValidateBooleanConfigurationVariables() {
ValidateBooleanVariable "DISABLE_ERRORS" "${DISABLE_ERRORS}"
ValidateBooleanVariable "ENABLE_GITHUB_ACTIONS_GROUP_TITLE" "${ENABLE_GITHUB_ACTIONS_GROUP_TITLE}"
ValidateBooleanVariable "ENABLE_GITHUB_ACTIONS_STEP_SUMMARY" "${ENABLE_GITHUB_ACTIONS_STEP_SUMMARY}"
ValidateBooleanVariable "FIX_MODE_TEST_CASE_RUN" "${FIX_MODE_TEST_CASE_RUN}"
ValidateBooleanVariable "IGNORE_GENERATED_FILES" "${IGNORE_GENERATED_FILES}"
ValidateBooleanVariable "IGNORE_GITIGNORED_FILES" "${IGNORE_GITIGNORED_FILES}"
ValidateBooleanVariable "LOG_DEBUG" "${LOG_DEBUG}"

View file

@ -15,7 +15,12 @@ function LintCodebase() {
unset -n VALIDATE_LANGUAGE
return 0
else
fatal "Don't disable any validation when running in test mode. VALIDATE_${FILE_TYPE} is set to: ${VALIDATE_LANGUAGE}. Set it to: true"
if [[ "${FIX_MODE_TEST_CASE_RUN}" == "true" ]]; then
debug "Don't fail the test even if VALIDATE_${FILE_TYPE} is set to ${VALIDATE_LANGUAGE} because ${FILE_TYPE} might not support fix mode"
return 0
else
fatal "Don't disable any validation when running in test mode. VALIDATE_${FILE_TYPE} is set to: ${VALIDATE_LANGUAGE}. Set it to: true"
fi
fi
fi

View file

@ -35,10 +35,12 @@ STANDARD_FIX_MODE_OPTIONS=(--fix)
# Define configuration options to enable "fix mode".
# Not all linters and formatters support this.
ANSIBLE_FIX_MODE_OPTIONS=(--fix)
CLANG_FORMAT_FIX_MODE_OPTIONS=(-i)
CSS_FIX_MODE_OPTIONS=(--fix)
ENV_FIX_MODE_OPTIONS=(fix)
ENV_FIX_MODE_OPTIONS=(fix --no-backup)
GO_FIX_MODE_OPTIONS=("${GOLANGCI_LINT_FIX_MODE_OPTIONS[@]}")
GO_MODULES_FIX_MODE_OPTIONS=("${GOLANGCI_LINT_FIX_MODE_OPTIONS[@]}")
GOOGLE_JAVA_FORMAT_FIX_MODE_OPTIONS=(--replace)
GROOVY_FIX_MODE_OPTIONS=(--fix)
JAVASCRIPT_ES_FIX_MODE_OPTIONS=("${ESLINT_FIX_MODE_OPTIONS[@]}")
JAVASCRIPT_PRETTIER_FIX_MODE_OPTIONS=("${PRETTIER_FIX_MODE_OPTIONS[@]}")
@ -47,11 +49,13 @@ JSON_FIX_MODE_OPTIONS=("${ESLINT_FIX_MODE_OPTIONS[@]}")
JSONC_FIX_MODE_OPTIONS=("${ESLINT_FIX_MODE_OPTIONS[@]}")
JSX_FIX_MODE_OPTIONS=("${ESLINT_FIX_MODE_OPTIONS[@]}")
MARKDOWN_FIX_MODE_OPTIONS=(--fix)
NATURAL_LANGUAGE_FIX_MODE_OPTIONS=(--fix)
POWERSHELL_FIX_MODE_OPTIONS=(-Fix)
PROTOBUF_FIX_MODE_OPTIONS=(-fix)
PYTHON_ISORT_FIX_MODE_OPTIONS=(--overwrite-in-place)
PYTHON_RUFF_FIX_MODE_OPTIONS=(--fix)
RUBY_FIX_MODE_OPTIONS=(--autocorrect)
RUST_CLIPPY_FIX_MODE_OPTIONS=(--fix)
RUST_CLIPPY_FIX_MODE_OPTIONS=(--fix --allow-dirty --allow-staged)
SHELL_SHFMT_FIX_MODE_OPTIONS=(--write)
SQLFLUFF_FIX_MODE_OPTIONS=(fix)
TSX_FIX_MODE_OPTIONS=("${ESLINT_FIX_MODE_OPTIONS[@]}")

View file

@ -113,6 +113,10 @@ declare -l TEST_CASE_RUN
TEST_CASE_RUN="${TEST_CASE_RUN:-"false"}"
export TEST_CASE_RUN
declare -l FIX_MODE_TEST_CASE_RUN
FIX_MODE_TEST_CASE_RUN="${FIX_MODE_TEST_CASE_RUN:-"false"}"
export FIX_MODE_TEST_CASE_RUN
# We want a lowercase value
declare -l USE_FIND_ALGORITHM
USE_FIND_ALGORITHM="${USE_FIND_ALGORITHM:-false}"

View file

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# Default log level
# shellcheck disable=SC2034
LOG_LEVEL="DEBUG"
# shellcheck source=/dev/null
source "lib/functions/log.sh"
# shellcheck source=/dev/null
source "test/testUtils.sh"
# The sqlfluff command needs this, but we don't want to make this test
# dependant on other files
# shellcheck disable=SC2034
SQLFLUFF_LINTER_RULES="SQLFLUFF_LINTER_RULES"
# shellcheck source=/dev/null
source "lib/globals/linterCommandsOptions.sh"
LanguagesWithFixModeTest() {
local FUNCTION_NAME
FUNCTION_NAME="${FUNCNAME[0]}"
info "${FUNCTION_NAME} start"
for LANGUAGE in "${LANGUAGES_WITH_FIX_MODE[@]}"; do
local FIX_MODE_OPTIONS_VARIABLE_NAME="${LANGUAGE}_FIX_MODE_OPTIONS"
local CHECK_ONLY_MODE_OPTIONS_VARIABLE_NAME="${LANGUAGE}_CHECK_ONLY_MODE_OPTIONS"
if [[ -v "${FIX_MODE_OPTIONS_VARIABLE_NAME}" ]] ||
[[ -v "${CHECK_ONLY_MODE_OPTIONS_VARIABLE_NAME}" ]]; then
debug "${LANGUAGE} has check-only mode or fix mode options as expected"
else
fatal "${LANGUAGE} is in the list of languages that support fix mode, but neither check-only mode, nor fix mode options were found"
fi
done
notice "${FUNCTION_NAME} PASS"
}
LanguagesWithFixModeTest

View file

@ -32,13 +32,12 @@ BASH_EXEC_IGNORE_LIBRARIES="false"
GITHUB_WORKSPACE="$(pwd)"
# shellcheck disable=SC2034
IGNORE_GITIGNORED_FILES="false"
LINTER_RULES_PATH="TEMPLATES"
# shellcheck disable=SC2034
TYPESCRIPT_STANDARD_TSCONFIG_FILE=".github/linters/tsconfig.json"
# shellcheck disable=SC2034
YAML_ERROR_ON_WARNING="false"
for LANGUAGE in "${LANGUAGE_ARRAY_FOR_LINTER_RULES[@]}"; do
GetLinterRules "${LANGUAGE}" "${LINTER_RULES_PATH}"
GetLinterRules "${LANGUAGE}" "TEMPLATES"
done
ValidateValidationVariables

View file

@ -43,7 +43,12 @@ function GetLinterRulesTest() {
GetLinterRules "${LANGUAGE}" "${DEFAULT_RULES_LOCATION}"
done
local EXPECTED_TEST_LANGUAGE_LINTER_RULES="${DEFAULT_RULES_LOCATION}/${TEST_LANGUAGE_FILE_NAME}"
local EXPECTED_TEST_LANGUAGE_LINTER_RULES="${GITHUB_WORKSPACE}"
if [[ -n "${LINTER_RULES_PATH:-}" ]]; then
EXPECTED_TEST_LANGUAGE_LINTER_RULES="${EXPECTED_TEST_LANGUAGE_LINTER_RULES}/${LINTER_RULES_PATH}"
fi
EXPECTED_TEST_LANGUAGE_LINTER_RULES="${EXPECTED_TEST_LANGUAGE_LINTER_RULES}/${TEST_LANGUAGE_FILE_NAME}"
if [[ "${TEST_LANGUAGE_LINTER_RULES}" == "${EXPECTED_TEST_LANGUAGE_LINTER_RULES}" ]]; then
debug "TEST_LANGUAGE_LINTER_RULES (${TEST_LANGUAGE_LINTER_RULES}) matches the expected value (${EXPECTED_TEST_LANGUAGE_LINTER_RULES})"
else

View file

@ -0,0 +1,9 @@
---
# Customize the ansible-lint configuration file because fix mode needs the
# yaml rule not to be disabled, but we disable the yaml rule in the default
# ansible-lint configuration
parseable: true
quiet: true
use_default_rules: true
verbosity: 1
...

View file

@ -0,0 +1,44 @@
---
env:
browser: true
es6: true
jest: true
node: true
extends:
- "eslint:recommended"
ignorePatterns:
- "!.*"
- "**/node_modules/.*"
parser: '@typescript-eslint/parser'
plugins:
- '@typescript-eslint'
# Don't set the jsonSyntax parser option for JSON, JSON5, and JSONC
# so we can use eslint-plugin-jsonc to automatically fix issues
# in tests, otherwise ESLint reports parsing errors and stops
overrides:
- files:
- "*.json"
extends:
- plugin:jsonc/recommended-with-json
parser: jsonc-eslint-parser
- files:
- "*.jsonc"
extends:
- plugin:jsonc/recommended-with-jsonc
parser: jsonc-eslint-parser
- files:
- "*.json5"
extends:
- plugin:jsonc/recommended-with-json5
parser: jsonc-eslint-parser
- files:
- "*.jsx"
- "*.tsx"
extends:
- plugin:react/recommended
...

View file

@ -0,0 +1,5 @@
---
linters:
enable:
- gofmt
...

View file

@ -1,8 +1,11 @@
---
- name: Remove temp files
become: true
file:
path: "{{ item }}"
state: absent
with_items:
- "/tmp/test-1"
- name: Test playbook
hosts: all
tasks:
- name: Remove temp files
become: true
file:
path: "{{ item }}"
state: absent
with_items:
- "/tmp/test-1"

View file

@ -8,4 +8,4 @@
path: "{{ item }}"
state: absent
with_items:
- "/tmp/test-1"
- /tmp/test-1

View file

@ -1,3 +1,7 @@
if len(in) == 0 {
return "", fmt.Errorf("Input is empty")
package main
import "fmt"
func main() {
fmt.Println("hello world")
}

View file

@ -1,18 +1,7 @@
package main
import (
"github.com/go-playground/validator/v10"
"github.com/labstack/echo/v4"
)
import "fmt"
if len(in) == 0 {
return "", fmt.Errorf("Input is empty")
func main() {
fmt.Println("hello world")
}
x := 0
{
var x int
x++
}
fmt.Println(x)

View file

@ -1,199 +1,10 @@
var http = require('http')
var createHandler = require('github-webhook-handler')
var teamId = "teamId"
var booleanTest = false;
var handler = createHandler({
path: /webhook, secret : (process.env.SECRET) })
var userArray = ['user1']
here is some garbage = that
var teamDescription = Team of Robots
var teamPrivacy = 'closed' // closed (visible) / secret (hidden) are options here
var teamName = process.env.GHES_TEAM_NAME
var teamAccess = 'pull' // pull,push,admin options here
var teamId = ''
var orgRepos = []
// var creator = ""
var foo = someFunction();
var bar = a + 1;
http.createServer(function (req, res) {
handler(req, res, function (err) {
console.log(err)
res.statusCode = 404
res.end('no such location')
})
}).listen(3000)
handler.on('error', function (err) {
console.await.error('Error:', err.message)
})
handler.on('repository', function (event) {
if (event.payload.action === 'created') {
const repo = event.payload.repository.full_name
console.log(repo)
const org = event.payload.repository.owner.login
getTeamID(org)
setTimeout(checkTeamIDVariable, 1000)
}
})
handler.on('team', function (event) {
// TODO user events such as being removed from team or org
if (event.payload.action === 'deleted') {
// const name = event.payload.team.name
const org = event.payload.organization.login
getRepositories(org)
setTimeout(checkReposVariable, 5000)
} else if (event.payload.action === 'removed_from_repository') {
const org = event.payload.organization.login
getTeamID(org)
// const repo = event.payload.repository.full_name
setTimeout(checkTeamIDVariable, 1000)
}
})
function getTeamID(org) {
const https = require('https')
const options = {
hostname: (process.env.GHE_HOST),
port: 443
path: '/api/v3/orgs/' + org + '/teams',
method: 'GET',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json'
}
}
req.on('error, (error) => {
console.error(error)
})
req.end()
}
function checkTeamIDVariable(repo) {
if (typeof teamId != 'undefined') {
addTeamToRepo(repo, teamId)
function checkTeamIDVariable(teamId, booleanTest) {
if (typeof teamId != "undefined" || Boolean(!!booleanTest)) {
console.log(teamId)
}
}
function checkReposVariable(org) {
if (typeof orgRepos !== 'undefined') {
// for(var repo of orgRepos) {
// addTeamToRepo(repo, teamId)
// }
reCreateTeam(org)
}
}
function addTeamToRepo(repo, teamId) {
const https = require('https')
const data = JSON.stringify({
permission: teamAccess
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443,
path: '/api/v3/teams/' + teamId + '/repos/' + repo,
method: 'PUT',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
let body = []
const req = https.request(options, (res) => {
res.on('data', (chunk) => {
body.push(chunk)
}).on('end', () => {
body = Buffer.concat(body).toString()
console.log(res.statusCode)
console.log('added team to ' + repo)
})
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
}
function reCreateTeam(org) {
const https = require('https')
const data = JSON.stringify({
name: teamName,
description: teamDescription,
privacy: teamPrivacy
maintainers: userArray,
repo_names: orgRepos
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443
path: '/api/v3/orgs/' + org + '/teams',
method: 'POST',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
// const body = []
const req = https.request(options, (res) => {
if (res.statusCode !== 201) {
console.log('Status code: ' + res.statusCode)
console.log('Added ' + teamName + ' to ' + org + ' Failed')
res.on('data', function (chunk) {
console.log('BODY: ' + chunk)
})
} else {
console.log('Added ' + teamName ' to ' + org)
}
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
}
function getRepositories(org) {
orgRepos = []
const https = require('https')
const options = {
hostname: (process.env.GHE_HOST),
port: '443',
path: '/api/v3/orgs/' + org + "/repos",
method: 'GET',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json'
}
}
req.on('error', (error) => {
console.error(error)
})
req.end()
}
checkTeamIDVariable(teamId, booleanTest)

View file

@ -1,137 +1,10 @@
const http = require('http')
const createHandler = require('github-webhook-handler')
const handler = createHandler({ path: '/webhook', secret: (process.env.SECRET) })
var teamId = "teamId"
var booleanTest = false;
const userArray = ['user1']
const teamDescription = 'Team of Robots'
const teamPrivacy = 'closed' // closed (visible) / secret (hidden) are options here
const teamName = process.env.GHES_TEAM_NAME
const teamAccess = 'pull' // pull,push,admin options here
const teamId = ''
// var creator = ""
http.createServer(function (req, res) {
handler(req, res, function (err) {
console.log(err)
res.statusCode = 404
res.end('no such location')
})
}).listen(3000)
handler.on('error', function (err) {
console.error('Error:', err.message)
})
handler.on('repository', function (event) {
if (event.payload.action === 'created') {
const repo = event.payload.repository.full_name
console.log(repo)
setTimeout(checkTeamIDVariable, 1000)
}
})
handler.on('team', function (event) {
// TODO user events such as being removed from team or org
if (event.payload.action === 'deleted') {
// const name = event.payload.team.name
setTimeout(checkReposVariable, 5000)
} else if (event.payload.action === 'removed_from_repository') {
// const repo = event.payload.repository.full_name
setTimeout(checkTeamIDVariable, 1000)
}
})
function checkTeamIDVariable (repo) {
if (typeof teamId !== 'undefined') {
addTeamToRepo(repo, teamId)
function checkTeamIDVariable(teamId, booleanTest) {
if (typeof teamId != "undefined" || booleanTest) {
console.log(teamId)
}
}
function checkReposVariable (org) {
if (typeof orgRepos !== 'undefined') {
// for(var repo of orgRepos) {
// addTeamToRepo(repo, teamId)
// }
reCreateTeam(org)
}
}
function addTeamToRepo (repo, teamId) {
const https = require('https')
const data = JSON.stringify({
permission: teamAccess
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443,
path: '/api/v3/teams/' + teamId + '/repos/' + repo,
method: 'PUT',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
let body = []
const req = https.request(options, (res) => {
res.on('data', (chunk) => {
body.push(chunk)
}).on('end', () => {
body = Buffer.concat(body).toString()
console.log(res.statusCode)
console.log('added team to ' + repo)
})
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
}
function reCreateTeam (org) {
const https = require('https')
const data = JSON.stringify({
name: teamName,
description: teamDescription,
privacy: teamPrivacy,
maintainers: userArray
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443,
path: '/api/v3/orgs/' + org + '/teams',
method: 'POST',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
// const body = []
const req = https.request(options, (res) => {
if (res.statusCode !== 201) {
console.log('Status code: ' + res.statusCode)
console.log('Added ' + teamName + ' to ' + org + ' Failed')
res.on('data', function (chunk) {
console.log('BODY: ' + chunk)
})
} else {
console.log('Added ' + teamName + ' to ' + org)
}
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
}
checkTeamIDVariable(teamId, booleanTest)

View file

@ -1,12 +1,8 @@
var http = require('http')
var createHandler = require( 'github-webhook-handler')
var handler = createHandler( { path : /webhook, secret : (process.env.SECRET) })
var userArray = ['user1']
var userArray = [ 'user1' ]
here is some garbage = that
var teamDescription = Team of Robots
var teamPrivacy = 'closed' // closed (visible) / secret (hidden) are options here
var teamName = process.env.GHES_TEAM_NAME
@ -62,8 +58,7 @@ function getTeamID (org) {
const options = {
hostname: (process.env.GHE_HOST),
port: 443
path: '/api/v3/orgs/' + org + '/teams',
port: 443,
method: 'GET',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
@ -84,7 +79,7 @@ function getTeamID (org) {
})
})
req.on('error, (error) => {
req.on('error', (error) => {
console.error(error)
})
@ -151,14 +146,14 @@ function reCreateTeam (org) {
const data = JSON.stringify({
name: teamName,
description: teamDescription,
privacy: teamPrivacy
privacy: teamPrivacy,
maintainers: userArray,
repo_names: orgRepos
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443
port: 443,
path: '/api/v3/orgs/' + org + '/teams',
method: 'POST',
headers: {
@ -176,7 +171,7 @@ function reCreateTeam (org) {
console.log('BODY: ' + chunk)
})
} else {
console.log('Added ' + teamName ' to ' + org)
console.log('Added ' + teamName + ' to ' + org)
}
})

View file

@ -1,199 +1,9 @@
var http = require('http')
var createHandler = require('github-webhook-handler')
var teamId = "teamId"
var handler = createHandler({
path: /webhook, secret : (process.env.SECRET) })
var userArray = ['user1']
here is some garbage = that
var teamDescription = Team of Robots
var teamPrivacy = 'closed' // closed (visible) / secret (hidden) are options here
var teamName = process.env.GHES_TEAM_NAME
var teamAccess = 'pull' // pull,push,admin options here
var teamId = ''
var orgRepos = []
// var creator = ""
var foo = someFunction();
var bar = a + 1;
http.createServer(function (req, res) {
handler(req, res, function (err) {
console.log(err)
res.statusCode = 404
res.end('no such location')
})
}).listen(3000)
handler.on('error', function (err) {
console.await.error('Error:', err.message)
})
handler.on('repository', function (event) {
if (event.payload.action === 'created') {
const repo = event.payload.repository.full_name
console.log(repo)
const org = event.payload.repository.owner.login
getTeamID(org)
setTimeout(checkTeamIDVariable, 1000)
}
})
handler.on('team', function (event) {
// TODO user events such as being removed from team or org
if (event.payload.action === 'deleted') {
// const name = event.payload.team.name
const org = event.payload.organization.login
getRepositories(org)
setTimeout(checkReposVariable, 5000)
} else if (event.payload.action === 'removed_from_repository') {
const org = event.payload.organization.login
getTeamID(org)
// const repo = event.payload.repository.full_name
setTimeout(checkTeamIDVariable, 1000)
}
})
function getTeamID(org) {
const https = require('https')
const options = {
hostname: (process.env.GHE_HOST),
port: 443
path: '/api/v3/orgs/' + org + '/teams',
method: 'GET',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json'
}
}
req.on('error, (error) => {
console.error(error)
})
req.end()
}
function checkTeamIDVariable(repo) {
if (typeof teamId != 'undefined') {
addTeamToRepo(repo, teamId)
function checkTeamIDVariable(teamId) {
if (typeof teamId != "undefined") {
console.log(teamId)
}
}
function checkReposVariable(org) {
if (typeof orgRepos !== 'undefined') {
// for(var repo of orgRepos) {
// addTeamToRepo(repo, teamId)
// }
reCreateTeam(org)
}
}
function addTeamToRepo(repo, teamId) {
const https = require('https')
const data = JSON.stringify({
permission: teamAccess
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443,
path: '/api/v3/teams/' + teamId + '/repos/' + repo,
method: 'PUT',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
let body = []
const req = https.request(options, (res) => {
res.on('data', (chunk) => {
body.push(chunk)
}).on('end', () => {
body = Buffer.concat(body).toString()
console.log(res.statusCode)
console.log('added team to ' + repo)
})
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
}
function reCreateTeam(org) {
const https = require('https')
const data = JSON.stringify({
name: teamName,
description: teamDescription,
privacy: teamPrivacy
maintainers: userArray,
repo_names: orgRepos
})
const options = {
hostname: (process.env.GHE_HOST),
port: 443
path: '/api/v3/orgs/' + org + '/teams',
method: 'POST',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
// const body = []
const req = https.request(options, (res) => {
if (res.statusCode !== 201) {
console.log('Status code: ' + res.statusCode)
console.log('Added ' + teamName + ' to ' + org + ' Failed')
res.on('data', function (chunk) {
console.log('BODY: ' + chunk)
})
} else {
console.log('Added ' + teamName ' to ' + org)
}
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
}
function getRepositories(org) {
orgRepos = []
const https = require('https')
const options = {
hostname: (process.env.GHE_HOST),
port: '443',
path: '/api/v3/orgs/' + org + "/repos",
method: 'GET',
headers: {
Authorization: 'token ' + (process.env.GHE_TOKEN),
'Content-Type': 'application/json'
}
}
req.on('error', (error) => {
console.error(error)
})
req.end()
}
checkTeamIDVariable(teamId)

View file

@ -1,12 +1,14 @@
{
"arrow_spacing": {
"level": ["ignore"]
"level": [
"ignore"
]
},
"foo": "bar",
"foo": "baz",
"braces_spacing": {
"level": 'ignore',
"spaces": 0
"spaces": 0,
"empty_object_spaces": 0
}
}

View file

@ -1,12 +1,14 @@
{
"arrow_spacing": {
"level": ["ignore"]
"level": [
"ignore"
]
},
"foo": "bar",
"foo": "baz",
"braces_spacing": {
"level": 'ignore',
"spaces": 0
"spaces": 0,
"empty_object_spaces": 0
}
}

View file

@ -1,11 +1,13 @@
{
"arrow_spacing": {
"level": ["ignore"]
"level": [
"ignore"
]
},
// more test
"braces_spacing": {
"level": 'ignore',
"spaces": 0
"spaces": 0,
"empty_object_spaces": 0
}
}

View file

@ -1 +1,3 @@
const element = <h1>Hello, world!
import React from 'react';
var Hello = <a target='_blank' href="https://example.com/"></a>

View file

@ -1 +1,4 @@
import React from 'react';
const element = <h1>Hello, world!</h1>;
console.log(element)

View file

@ -1,20 +1,15 @@
## Bad Markdown
# Bad Markdown
This is just standard good markdown.
###### Second level header
This header does **NOT** follow the step down from `level 1`.
## Second level header
- Here it *is*
- Some more indention
- why so much?
```
ls -la
```
# Walk away
We're all done **here**.
- [Link Action]https://github.com
- [Link Action]<https://github.com>
[ Link Action ](https://github.com)

View file

@ -1,6 +1,5 @@
syntax = "proto3";
// A broken example of the official reference
// See https://developers.google.com/protocol-buffers/docs/reference/proto3-spec#proto_file
package examplePb;
option java_package = "com.example.foo";
@ -34,14 +33,7 @@ message outer {
message AccountForAdmin {}
message SpecialEndOfSupport {}
required inner inner_message = 7;
group Result = 8 {
string url = 9;
}
repeated group Result = 10 {
}
repeated inner paper = 11;
repeated group Regular = 12 {
}
}
service SearchApi {
rpc search (SearchRequest) returns (SearchResponse) {};

View file

@ -1,4 +1,5 @@
a=1;b=2
c=a+b
BROKEN_VAR=BROKEN_VAR
import pandas
import numpy as np
c = 1 + 2
print(c)

View file

@ -1,4 +1,7 @@
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
fn main() {
let x = 3.14;
let _y = 1_f64 / x;
let mut options = OpenOptions::new();
options.mode(644);
}

View file

@ -1 +1,3 @@
DELETE from person;
SELECT
a
FROM foo AS zoo;

View file

@ -1 +1 @@
var foo = bar as
var Hello = <a target='_blank' href="https://example.com/"></a>

View file

@ -1 +1,4 @@
var foo = bar as foo;
import React from 'react';
const element = <h1>Hello, world!</h1>;
console.log(element)

View file

@ -1,8 +1,10 @@
const spiderman = (person: String) => {
return 'Hello, ' + person;
var teamId = "teamId"
var booleanTest = false;
function checkTeamIDVariable(teamId, booleanTest) {
if (typeof teamId != "undefined" || Boolean(!!booleanTest)) {
console.log(teamId)
}
}
var handler = createHandler( { path : /webhook, secret : (process.env.SECRET) })
let user = 1;
console.log(spiderman(user));
checkTeamIDVariable(teamId, booleanTest)

View file

@ -6,7 +6,5 @@ const spiderman = (person: String) => {
return 'Hello, ' + person;
}
var handler = createHandler( { path : /webhook, secret : (process.env.SECRET) })
let user = 1;
console.log(spiderman(user));

View file

@ -1,12 +1,11 @@
enum Test {
Hoo = 'hoo'
Hoo = "hoo"
}
const spiderman = (person: String) => {
return 'Hello, ' + person;
const spiderman = (person: string): string => {
return `Hello, ${person}`
}
var handler = createHandler( { path : /webhook, secret : (process.env.SECRET) })
let user = 1;
console.log(spiderman(user));
const user = "Peter Parker"
console.log(spiderman(user))
console.log(Test.Hoo)

View file

@ -10,7 +10,7 @@ source "test/testUtils.sh"
SUPER_LINTER_TEST_CONTAINER_URL="${1}"
TEST_FUNCTION_NAME="${2}"
SUPER_LINTER_CONTAINER_IMAGE_TYPE="${3}"
echo "Super-linter container image type: ${SUPER_LINTER_CONTAINER_IMAGE_TYPE}"
debug "Super-linter container image type: ${SUPER_LINTER_CONTAINER_IMAGE_TYPE}"
DEFAULT_BRANCH="main"
@ -22,8 +22,13 @@ ignore_test_cases() {
COMMAND_TO_RUN+=(-e FILTER_REGEX_EXCLUDE=".*(/test/linters/|CHANGELOG.md).*")
}
configure_typescript_for_test_cases() {
COMMAND_TO_RUN+=(--env TYPESCRIPT_STANDARD_TSCONFIG_FILE=".github/linters/tsconfig.json")
}
configure_linters_for_test_cases() {
COMMAND_TO_RUN+=(-e TEST_CASE_RUN=true -e JSCPD_CONFIG_FILE=".jscpd-test-linters.json" -e RENOVATE_SHAREABLE_CONFIG_PRESET_FILE_NAMES="default.json,hoge.json" -e TYPESCRIPT_STANDARD_TSCONFIG_FILE=".github/linters/tsconfig.json")
COMMAND_TO_RUN+=(-e TEST_CASE_RUN=true -e JSCPD_CONFIG_FILE=".jscpd-test-linters.json" -e RENOVATE_SHAREABLE_CONFIG_PRESET_FILE_NAMES="default.json,hoge.json")
configure_typescript_for_test_cases
}
run_test_cases_expect_failure() {
@ -68,7 +73,9 @@ run_test_case_bash_exec_library_expect_success() {
initialize_git_repository_and_test_args() {
local GIT_REPOSITORY_PATH="${1}"
# shellcheck disable=SC2064 # Once the path is set, we don't expect it to change
trap "rm -fr '${GIT_REPOSITORY_PATH}'" EXIT
trap "sudo rm -fr '${GIT_REPOSITORY_PATH}'" EXIT
debug "GIT_REPOSITORY_PATH: ${GIT_REPOSITORY_PATH}"
local GITHUB_EVENT_FILE_PATH="${2}"
@ -87,7 +94,13 @@ initialize_git_repository_and_test_args() {
COMMAND_TO_RUN+=(-e GITHUB_EVENT_PATH="/tmp/lint/$(basename "${GITHUB_EVENT_FILE_PATH}")")
COMMAND_TO_RUN+=(-e MULTI_STATUS=false)
COMMAND_TO_RUN+=(-e VALIDATE_ALL_CODEBASE=false)
COMMAND_TO_RUN+=(-e VALIDATE_JSON=true)
}
initialize_github_sha() {
local GIT_REPOSITORY_PATH="${1}"
local TEST_GITHUB_SHA
TEST_GITHUB_SHA="$(git -C "${GIT_REPOSITORY_PATH}" rev-parse HEAD)"
COMMAND_TO_RUN+=(-e GITHUB_SHA="${TEST_GITHUB_SHA}")
}
run_test_case_git_initial_commit() {
@ -95,10 +108,8 @@ run_test_case_git_initial_commit() {
GIT_REPOSITORY_PATH="$(mktemp -d)"
initialize_git_repository_and_test_args "${GIT_REPOSITORY_PATH}" "test/data/github-event/github-event-push.json"
local TEST_GITHUB_SHA
TEST_GITHUB_SHA="$(git -C "${GIT_REPOSITORY_PATH}" rev-parse HEAD)"
COMMAND_TO_RUN+=(-e GITHUB_SHA="${TEST_GITHUB_SHA}")
initialize_github_sha "${GIT_REPOSITORY_PATH}"
COMMAND_TO_RUN+=(-e VALIDATE_JSON=true)
}
run_test_case_merge_commit_push() {
@ -128,9 +139,8 @@ run_test_case_merge_commit_push() {
git -C "${GIT_REPOSITORY_PATH}" log --all --graph --abbrev-commit --decorate --format=oneline
local TEST_GITHUB_SHA
TEST_GITHUB_SHA="$(git -C "${GIT_REPOSITORY_PATH}" rev-parse HEAD)"
COMMAND_TO_RUN+=(-e GITHUB_SHA="${TEST_GITHUB_SHA}")
initialize_github_sha "${GIT_REPOSITORY_PATH}"
COMMAND_TO_RUN+=(-e VALIDATE_JSON=true)
}
run_test_case_use_find_and_ignore_gitignored_files() {
@ -155,46 +165,54 @@ run_test_case_custom_summary() {
}
run_test_case_fix_mode() {
run_test_cases_expect_success
CREATE_LOG_FILE="true"
SAVE_SUPER_LINTER_OUTPUT="true"
COMMAND_TO_RUN+=(--env FIX_ANSIBLE="true")
COMMAND_TO_RUN+=(--env FIX_CLANG_FORMAT="true")
COMMAND_TO_RUN+=(--env FIX_CSHARP="true")
COMMAND_TO_RUN+=(--env FIX_CSS="true")
COMMAND_TO_RUN+=(--env FIX_ENV="true")
COMMAND_TO_RUN+=(--env FIX_GO_MODULES="true")
COMMAND_TO_RUN+=(--env FIX_GO="true")
COMMAND_TO_RUN+=(--env FIX_GOOGLE_JAVA_FORMAT="true")
COMMAND_TO_RUN+=(--env FIX_GROOVY="true")
COMMAND_TO_RUN+=(--env FIX_JAVASCRIPT_ES="true")
COMMAND_TO_RUN+=(--env FIX_JAVASCRIPT_PRETTIER="true")
COMMAND_TO_RUN+=(--env FIX_JAVASCRIPT_STANDARD="true")
COMMAND_TO_RUN+=(--env FIX_JSON="true")
COMMAND_TO_RUN+=(--env FIX_JSONC="true")
COMMAND_TO_RUN+=(--env FIX_JSX="true")
COMMAND_TO_RUN+=(--env FIX_MARKDOWN="true")
COMMAND_TO_RUN+=(--env FIX_POWERSHELL="true")
COMMAND_TO_RUN+=(--env FIX_PROTOBUF="true")
COMMAND_TO_RUN+=(--env FIX_PYTHON_BLACK="true")
COMMAND_TO_RUN+=(--env FIX_PYTHON_ISORT="true")
COMMAND_TO_RUN+=(--env FIX_PYTHON_RUFF="true")
COMMAND_TO_RUN+=(--env FIX_RUBY="true")
COMMAND_TO_RUN+=(--env FIX_RUST_2015="true")
COMMAND_TO_RUN+=(--env FIX_RUST_2018="true")
COMMAND_TO_RUN+=(--env FIX_RUST_2021="true")
# Temporarily disable fix mode for rust clippy due to a dependency on another PR
# COMMAND_TO_RUN+=(--env FIX_RUST_CLIPPY="true")
COMMAND_TO_RUN+=(--env FIX_SCALAFMT="true")
COMMAND_TO_RUN+=(--env FIX_SHELL_SHFMT="true")
COMMAND_TO_RUN+=(--env FIX_SNAKEMAKE_SNAKEFMT="true")
COMMAND_TO_RUN+=(--env FIX_SQLFLUFF="true")
COMMAND_TO_RUN+=(--env FIX_TERRAFORM_FMT="true")
COMMAND_TO_RUN+=(--env FIX_TSX="true")
COMMAND_TO_RUN+=(--env FIX_TYPESCRIPT_ES="true")
COMMAND_TO_RUN+=(--env FIX_TYPESCRIPT_PRETTIER="true")
COMMAND_TO_RUN+=(--env FIX_TYPESCRIPT_STANDARD="true")
GIT_REPOSITORY_PATH="$(mktemp -d)"
initialize_git_repository_and_test_args "${GIT_REPOSITORY_PATH}" "test/data/github-event/github-event-push.json"
local LINTERS_TEST_CASES_FIX_MODE_DESTINATION_PATH="${GIT_REPOSITORY_PATH}/${LINTERS_TEST_CASE_DIRECTORY}"
mkdir -p "${LINTERS_TEST_CASES_FIX_MODE_DESTINATION_PATH}"
for LANGUAGE in "${LANGUAGES_WITH_FIX_MODE[@]}"; do
if [[ "${SUPER_LINTER_CONTAINER_IMAGE_TYPE}" == "slim" ]] &&
! IsLanguageInSlimImage "${LANGUAGE}"; then
debug "Skip ${LANGUAGE} because it's not available in the Super-linter ${SUPER_LINTER_CONTAINER_IMAGE_TYPE} image"
continue
fi
local -l LOWERCASE_LANGUAGE="${LANGUAGE}"
cp -rv "${LINTERS_TEST_CASE_DIRECTORY}/${LOWERCASE_LANGUAGE}" "${LINTERS_TEST_CASES_FIX_MODE_DESTINATION_PATH}/"
eval "COMMAND_TO_RUN+=(--env FIX_${LANGUAGE}=\"true\")"
eval "COMMAND_TO_RUN+=(--env VALIDATE_${LANGUAGE}=\"true\")"
done
# Copy gitignore so we don't commit eventual leftovers from previous runs
cp -v ".gitignore" "${GIT_REPOSITORY_PATH}/"
# Copy fix mode linter configuration files because default ones are not always
# suitable for fix mode
local FIX_MODE_LINTERS_CONFIG_DIR="${GIT_REPOSITORY_PATH}/.github/linters"
mkdir -p "${FIX_MODE_LINTERS_CONFIG_DIR}"
cp -rv "test/linters-config/fix-mode/." "${FIX_MODE_LINTERS_CONFIG_DIR}/"
cp -rv ".github/linters/tsconfig.json" "${FIX_MODE_LINTERS_CONFIG_DIR}/"
git -C "${GIT_REPOSITORY_PATH}" add .
git -C "${GIT_REPOSITORY_PATH}" commit --no-verify -m "feat: add fix mode test cases"
initialize_github_sha "${GIT_REPOSITORY_PATH}"
CREATE_LOG_FILE="true"
SAVE_SUPER_LINTER_OUTPUT="true"
VERIFY_FIX_MODE="true"
# Enable test mode so we run linters and formatters only against their test
# cases
COMMAND_TO_RUN+=(--env FIX_MODE_TEST_CASE_RUN=true)
COMMAND_TO_RUN+=(--env TEST_CASE_RUN=true)
COMMAND_TO_RUN+=(--env ANSIBLE_DIRECTORY="/test/linters/ansible/bad")
configure_typescript_for_test_cases
# Some linters report a non-zero exit code even if they fix all the issues
EXPECTED_EXIT_CODE=2
}
# Run the test setup function
@ -203,28 +221,30 @@ ${TEST_FUNCTION_NAME}
CREATE_LOG_FILE="${CREATE_LOG_FILE:-false}"
SAVE_SUPER_LINTER_OUTPUT="${SAVE_SUPER_LINTER_OUTPUT:-false}"
SUPER_LINTER_WORKSPACE="${SUPER_LINTER_WORKSPACE:-$(pwd)}"
COMMAND_TO_RUN+=(-v "${SUPER_LINTER_WORKSPACE}":"/tmp/lint")
if [ -n "${SUPER_LINTER_OUTPUT_DIRECTORY_NAME:-}" ]; then
COMMAND_TO_RUN+=(-e SUPER_LINTER_OUTPUT_DIRECTORY_NAME="${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}")
fi
SUPER_LINTER_OUTPUT_DIRECTORY_NAME="${SUPER_LINTER_OUTPUT_DIRECTORY_NAME:-"super-linter-output"}"
SUPER_LINTER_MAIN_OUTPUT_PATH="$(pwd)/${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}"
echo "Super-linter main output path: ${SUPER_LINTER_MAIN_OUTPUT_PATH}"
SUPER_LINTER_MAIN_OUTPUT_PATH="${SUPER_LINTER_WORKSPACE}/${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}"
debug "Super-linter main output path: ${SUPER_LINTER_MAIN_OUTPUT_PATH}"
SUPER_LINTER_OUTPUT_PATH="${SUPER_LINTER_MAIN_OUTPUT_PATH}/super-linter"
echo "Super-linter output path: ${SUPER_LINTER_OUTPUT_PATH}"
debug "Super-linter output path: ${SUPER_LINTER_OUTPUT_PATH}"
COMMAND_TO_RUN+=(-e CREATE_LOG_FILE="${CREATE_LOG_FILE}")
COMMAND_TO_RUN+=(-e LOG_LEVEL="${LOG_LEVEL:-"DEBUG"}")
COMMAND_TO_RUN+=(-e RUN_LOCAL="${RUN_LOCAL:-true}")
COMMAND_TO_RUN+=(-e SAVE_SUPER_LINTER_OUTPUT="${SAVE_SUPER_LINTER_OUTPUT}")
COMMAND_TO_RUN+=(-v "${SUPER_LINTER_WORKSPACE:-$(pwd)}":"/tmp/lint")
SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH="$(pwd)/github-step-summary.md"
SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH="${SUPER_LINTER_WORKSPACE}/github-step-summary.md"
# We can't put this inside SUPER_LINTER_MAIN_OUTPUT_PATH because it doesn't exist
# before Super-linter creates it, and we want to verify that as well.
echo "SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH: ${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
debug "SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH: ${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
if [ -n "${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH:-}" ]; then
echo "Expected Super-linter step summary file path: ${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH}"
debug "Expected Super-linter step summary file path: ${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH}"
ENABLE_GITHUB_ACTIONS_STEP_SUMMARY="true"
SAVE_SUPER_LINTER_SUMMARY="true"
@ -240,71 +260,105 @@ if [ -n "${SUPER_LINTER_SUMMARY_FILE_NAME:-}" ]; then
COMMAND_TO_RUN+=(-e SUPER_LINTER_SUMMARY_FILE_NAME="${SUPER_LINTER_SUMMARY_FILE_NAME}")
fi
SUPER_LINTER_SUMMARY_FILE_NAME="${SUPER_LINTER_SUMMARY_FILE_NAME:-"super-linter-summary.md"}"
echo "SUPER_LINTER_SUMMARY_FILE_NAME: ${SUPER_LINTER_SUMMARY_FILE_NAME}"
debug "SUPER_LINTER_SUMMARY_FILE_NAME: ${SUPER_LINTER_SUMMARY_FILE_NAME}"
SUPER_LINTER_SUMMARY_FILE_PATH="${SUPER_LINTER_MAIN_OUTPUT_PATH}/${SUPER_LINTER_SUMMARY_FILE_NAME}"
echo "Super-linter summary output path: ${SUPER_LINTER_SUMMARY_FILE_PATH}"
debug "Super-linter summary output path: ${SUPER_LINTER_SUMMARY_FILE_PATH}"
LOG_FILE_PATH="$(pwd)/super-linter.log"
LOG_FILE_PATH="${SUPER_LINTER_WORKSPACE}/super-linter.log"
COMMAND_TO_RUN+=("${SUPER_LINTER_TEST_CONTAINER_URL}")
declare -i EXPECTED_EXIT_CODE
EXPECTED_EXIT_CODE=${EXPECTED_EXIT_CODE:-0}
echo "Cleaning eventual leftovers before running tests: ${LEFTOVERS_TO_CLEAN[*]}"
debug "Cleaning eventual leftovers before running tests: ${LEFTOVERS_TO_CLEAN[*]}"
LEFTOVERS_TO_CLEAN+=("${LOG_FILE_PATH}")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_MAIN_OUTPUT_PATH}")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_SUMMARY_FILE_PATH}")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_SUMMARY_FILE_PATH}")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_WORKSPACE}/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/bad/target")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_WORKSPACE}/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/bad/Cargo.lock")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_WORKSPACE}/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/good/target")
LEFTOVERS_TO_CLEAN+=("${SUPER_LINTER_WORKSPACE}/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/good/Cargo.lock")
# Delete leftovers in pwd in case the workspace is not pwd
LEFTOVERS_TO_CLEAN+=("$(pwd)/$(basename "${LOG_FILE_PATH}")")
LEFTOVERS_TO_CLEAN+=("$(pwd)/$(basename "${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}")")
LEFTOVERS_TO_CLEAN+=("$(pwd)/$(basename "${SUPER_LINTER_MAIN_OUTPUT_PATH}")")
LEFTOVERS_TO_CLEAN+=("$(pwd)/$(basename "${SUPER_LINTER_SUMMARY_FILE_PATH}")")
LEFTOVERS_TO_CLEAN+=("$(pwd)/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/bad/target")
LEFTOVERS_TO_CLEAN+=("$(pwd)/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/bad/Cargo.lock")
LEFTOVERS_TO_CLEAN+=("$(pwd)/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/good/target")
LEFTOVERS_TO_CLEAN+=("$(pwd)/${LINTERS_TEST_CASE_DIRECTORY}/rust_clippy/good/Cargo.lock")
sudo rm -rfv "${LEFTOVERS_TO_CLEAN[@]}"
if [[ "${ENABLE_GITHUB_ACTIONS_STEP_SUMMARY}" == "true" ]]; then
echo "Creating GitHub Actions step summary file: ${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
debug "Creating GitHub Actions step summary file: ${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
touch "${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
fi
if [ ${EXPECTED_EXIT_CODE} -ne 0 ]; then
echo "Disable failures on error because the expected exit code is ${EXPECTED_EXIT_CODE}"
set +o errexit
fi
debug "Command to run: ${COMMAND_TO_RUN[*]}"
echo "Command to run: ${COMMAND_TO_RUN[*]}"
# Disable failures on error so we can continue with tests regardless
# of the Super-linter exit code
set +o errexit
"${COMMAND_TO_RUN[@]}"
SUPER_LINTER_EXIT_CODE=$?
# Enable the errexit option in case we disabled it
# Enable the errexit option that we check later
set -o errexit
echo "Super-linter exit code: ${SUPER_LINTER_EXIT_CODE}"
debug "Super-linter workspace: ${SUPER_LINTER_WORKSPACE}"
debug "Super-linter exit code: ${SUPER_LINTER_EXIT_CODE}"
if [[ "${CREATE_LOG_FILE}" == true ]]; then
if [ ! -e "${LOG_FILE_PATH}" ]; then
echo "Log file was requested but it's not available at ${LOG_FILE_PATH}"
debug "Log file was requested but it's not available at ${LOG_FILE_PATH}"
exit 1
else
sudo chown -R "$(id -u)":"$(id -g)" "${LOG_FILE_PATH}"
echo "Log file contents:"
cat "${LOG_FILE_PATH}"
debug "Log file path: ${LOG_FILE_PATH}"
if [[ "${CI:-}" == "true" ]]; then
debug "Log file contents:"
cat "${LOG_FILE_PATH}"
else
debug "Not in CI environment, skip emitting log file (${LOG_FILE_PATH}) contents"
fi
if [[ "${SUPER_LINTER_WORKSPACE}" != "$(pwd)" ]]; then
debug "Copying Super-linter log from the workspace (${SUPER_LINTER_WORKSPACE}) to the current working directory for easier inspection"
cp -v "${LOG_FILE_PATH}" "$(pwd)/"
fi
fi
else
echo "Log file was not requested. CREATE_LOG_FILE: ${CREATE_LOG_FILE}"
debug "Log file was not requested. CREATE_LOG_FILE: ${CREATE_LOG_FILE}"
fi
if [[ "${SAVE_SUPER_LINTER_OUTPUT}" == true ]]; then
if [ ! -d "${SUPER_LINTER_OUTPUT_PATH}" ]; then
echo "Super-linter output was requested but it's not available at ${SUPER_LINTER_OUTPUT_PATH}"
debug "Super-linter output was requested but it's not available at ${SUPER_LINTER_OUTPUT_PATH}"
exit 1
else
sudo chown -R "$(id -u)":"$(id -g)" "${SUPER_LINTER_OUTPUT_PATH}"
echo "Super-linter output path (${SUPER_LINTER_OUTPUT_PATH}) contents:"
ls -alhR "${SUPER_LINTER_OUTPUT_PATH}"
if [[ "${CI:-}" == "true" ]]; then
debug "Super-linter output path (${SUPER_LINTER_OUTPUT_PATH}) contents:"
ls -alhR "${SUPER_LINTER_OUTPUT_PATH}"
else
debug "Not in CI environment, skip emitting ${SUPER_LINTER_OUTPUT_PATH} contents"
fi
if [[ "${SUPER_LINTER_WORKSPACE}" != "$(pwd)" ]]; then
debug "Copying Super-linter output from the workspace (${SUPER_LINTER_WORKSPACE}) to the current working directory for easier inspection"
SUPER_LINTER_OUTPUT_PATH_PWD="$(pwd)/super-linter-output/"
mkdir -p "${SUPER_LINTER_OUTPUT_PATH_PWD}"
cp -r "${SUPER_LINTER_OUTPUT_PATH}" "${SUPER_LINTER_OUTPUT_PATH_PWD}"
fi
fi
else
echo "Super-linter output was not requested. SAVE_SUPER_LINTER_OUTPUT: ${SAVE_SUPER_LINTER_OUTPUT}"
debug "Super-linter output was not requested. SAVE_SUPER_LINTER_OUTPUT: ${SAVE_SUPER_LINTER_OUTPUT}"
if [ -e "${SUPER_LINTER_OUTPUT_PATH}" ]; then
echo "Super-linter output was not requested but it's available at ${SUPER_LINTER_OUTPUT_PATH}"
debug "Super-linter output was not requested but it's available at ${SUPER_LINTER_OUTPUT_PATH}"
exit 1
fi
fi
@ -312,37 +366,96 @@ fi
if [ -n "${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH:-}" ]; then
# Remove eventual HTML comments from the expected file because we use them to disable certain linter rules
if ! diff "${SUPER_LINTER_SUMMARY_FILE_PATH}" <(grep -vE '^\s*<!--' "${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH}"); then
echo "Super-linter summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents don't match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
debug "Super-linter summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents don't match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
exit 1
else
echo "Super-linter summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
debug "Super-linter summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
fi
if ! diff "${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}" <(grep -vE '^\s*<!--' "${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH}"); then
echo "Super-linter GitHub step summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents don't match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
debug "Super-linter GitHub step summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents don't match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
exit 1
else
echo "Super-linter GitHub step summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
debug "Super-linter GitHub step summary (${SUPER_LINTER_SUMMARY_FILE_PATH}) contents match with the expected contents (${EXPECTED_SUPER_LINTER_SUMMARY_FILE_PATH})"
fi
if [[ "${SUPER_LINTER_WORKSPACE}" != "$(pwd)" ]]; then
debug "Copying Super-linter summary from the workspace (${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}) to the current working directory for easier inspection"
cp "${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}" "$(pwd)/"
fi
if [[ "${SUPER_LINTER_WORKSPACE}" != "$(pwd)" ]]; then
debug "Copying Super-linter GitHub step summary from the workspace (${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}) to the current working directory for easier inspection"
cp "${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}" "$(pwd)/"
fi
else
echo "Super-linter summary output was not requested."
debug "Super-linter summary output was not requested."
if [ -e "${SUPER_LINTER_SUMMARY_FILE_PATH}" ]; then
echo "Super-linter summary was not requested but it's available at ${SUPER_LINTER_SUMMARY_FILE_PATH}"
debug "Super-linter summary was not requested but it's available at ${SUPER_LINTER_SUMMARY_FILE_PATH}"
exit 1
fi
if [ -e "${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}" ]; then
echo "Super-linter GitHub step summary was not requested but it's available at ${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
debug "Super-linter GitHub step summary was not requested but it's available at ${SUPER_LINTER_GITHUB_STEP_SUMMARY_FILE_PATH}"
exit 1
fi
fi
if [ ${SUPER_LINTER_EXIT_CODE} -ne ${EXPECTED_EXIT_CODE} ]; then
echo "Super-linter exited with an unexpected code: ${SUPER_LINTER_EXIT_CODE}"
debug "Super-linter exited with an unexpected code: ${SUPER_LINTER_EXIT_CODE}"
exit 1
else
echo "Super-linter exited with the expected code: ${SUPER_LINTER_EXIT_CODE}"
debug "Super-linter exited with the expected code: ${SUPER_LINTER_EXIT_CODE}"
fi
VERIFY_FIX_MODE="${VERIFY_FIX_MODE:-"false"}"
if [[ "${VERIFY_FIX_MODE:-}" == "true" ]]; then
debug "Verifying fix mode"
for LANGUAGE in "${LANGUAGES_WITH_FIX_MODE[@]}"; do
if [[ "${SUPER_LINTER_CONTAINER_IMAGE_TYPE}" == "slim" ]] &&
! IsLanguageInSlimImage "${LANGUAGE}"; then
debug "Skip ${LANGUAGE} because it's not available in the Super-linter ${SUPER_LINTER_CONTAINER_IMAGE_TYPE} image"
continue
fi
declare -l LOWERCASE_LANGUAGE="${LANGUAGE}"
BAD_TEST_CASE_SOURCE_PATH="${LINTERS_TEST_CASE_DIRECTORY}/${LOWERCASE_LANGUAGE}"
debug "Source path to the ${LANGUAGE} test case expected to fail: ${BAD_TEST_CASE_SOURCE_PATH}"
BAD_TEST_CASE_DESTINATION_PATH="${SUPER_LINTER_WORKSPACE}/${LINTERS_TEST_CASE_DIRECTORY}/${LOWERCASE_LANGUAGE}"
debug "Destination path to ${LANGUAGE} test case expected to fail: ${BAD_TEST_CASE_DESTINATION_PATH}"
if [[ ! -e "${BAD_TEST_CASE_SOURCE_PATH}" ]]; then
fatal "${BAD_TEST_CASE_SOURCE_PATH} doesn't exist"
fi
if [[ ! -e "${BAD_TEST_CASE_DESTINATION_PATH}" ]]; then
fatal "${BAD_TEST_CASE_DESTINATION_PATH} doesn't exist"
fi
if find "${BAD_TEST_CASE_DESTINATION_PATH}" \( -type f ! -readable -or -type d \( ! -readable -or ! -executable -or ! -writable \) \) -print | grep -q .; then
if [[ "${LANGUAGE}" == "RUST_CLIPPY" ]] ||
[[ "${LANGUAGE}" == "SHELL_SHFMT" ]] ||
[[ "${LANGUAGE}" == "SQLFLUFF" ]]; then
debug "${LANGUAGE} is a known case of a tool that doesn't preserve the ownership of files or directories in fix mode. Need to recursively change ownership of ${BAD_TEST_CASE_DESTINATION_PATH}"
sudo chown -R "$(id -u)":"$(id -g)" "${BAD_TEST_CASE_DESTINATION_PATH}"
else
ls -alR "${BAD_TEST_CASE_DESTINATION_PATH}"
fatal "Cannot verify fix mode for ${LANGUAGE}: ${BAD_TEST_CASE_DESTINATION_PATH} is not readable, or contains unreadable files."
fi
else
debug "${BAD_TEST_CASE_DESTINATION_PATH} and its contents are readable"
fi
if [[ "${LANGUAGE}" == "RUST_CLIPPY" ]]; then
rm -rf \
"${BAD_TEST_CASE_DESTINATION_PATH}"/*/Cargo.lock \
"${BAD_TEST_CASE_DESTINATION_PATH}"/*/target
fi
if AssertFileContentsMatch "${BAD_TEST_CASE_DESTINATION_PATH}" "${BAD_TEST_CASE_SOURCE_PATH}"; then
fatal "${BAD_TEST_CASE_DESTINATION_PATH} contents match ${BAD_TEST_CASE_SOURCE_PATH} contents and they should differ because fix mode for ${LANGUAGE} should have fixed linting and formatting issues."
fi
done
fi
# Check if super-linter leaves leftovers behind
@ -354,16 +467,16 @@ TEMP_ITEMS_TO_CLEAN+=("$(pwd)/.ruff_cache")
TEMP_ITEMS_TO_CLEAN+=("$(pwd)/logback.log")
for item in "${TEMP_ITEMS_TO_CLEAN[@]}"; do
echo "Check if ${item} exists"
debug "Check if ${item} exists"
if [[ -e "${item}" ]]; then
echo "Error: ${item} exists and it should have been deleted"
debug "Error: ${item} exists and it should have been deleted"
exit 1
else
echo "${item} does not exist as expected"
debug "${item} does not exist as expected"
fi
done
if ! CheckUnexpectedGitChanges "$(pwd)"; then
echo "There are unexpected modifications to the working directory after running tests."
debug "There are unexpected modifications to the working directory after running tests."
exit 1
fi

View file

@ -11,6 +11,64 @@ LOG_LEVEL="DEBUG"
# shellcheck source=/dev/null
source "lib/functions/log.sh"
# TODO: use TEST_CASE_FOLDER instead of redefining this after we extract the
# initialization of TEST_CASE_FOLDER from linter.sh
# shellcheck disable=SC2034
LINTERS_TEST_CASE_DIRECTORY="test/linters"
# shellcheck disable=SC2034
LANGUAGES_WITH_FIX_MODE=(
"ANSIBLE"
"CLANG_FORMAT"
"CSHARP"
"CSS"
"ENV"
"GO_MODULES"
"GO"
"GOOGLE_JAVA_FORMAT"
"GROOVY"
"JAVASCRIPT_ES"
"JAVASCRIPT_PRETTIER"
"JAVASCRIPT_STANDARD"
"JSON"
"JSONC"
"JSX"
"MARKDOWN"
"NATURAL_LANGUAGE"
"POWERSHELL"
"PROTOBUF"
"PYTHON_BLACK"
"PYTHON_ISORT"
"PYTHON_RUFF"
"RUBY"
"RUST_2015"
"RUST_2018"
"RUST_2021"
"RUST_CLIPPY"
"SCALAFMT"
"SHELL_SHFMT"
"SNAKEMAKE_SNAKEFMT"
"SQLFLUFF"
"TERRAFORM_FMT"
"TSX"
"TYPESCRIPT_ES"
"TYPESCRIPT_PRETTIER"
"TYPESCRIPT_STANDARD"
)
# TODO: extract this list from linter.sh (see REMOVE_ARRAY) instead of
# redefining it here
# shellcheck disable=SC2034
LANGUAGES_NOT_IN_SLIM_IMAGE=(
"ARM"
"CSHARP"
"POWERSHELL"
"RUST_2015"
"RUST_2018"
"RUST_2021"
"RUST_CLIPPY"
)
function AssertArraysElementsContentMatch() {
local ARRAY_1_VARIABLE_NAME="${1}"
local ARRAY_2_VARIABLE_NAME="${2}"
@ -42,3 +100,26 @@ function CheckUnexpectedGitChanges() {
return 1
fi
}
AssertFileContentsMatch() {
local FILE_1_PATH="${1}"
local FILE_2_PATH="${2}"
if diff -r "${FILE_1_PATH}" "${FILE_2_PATH}"; then
echo "${FILE_1_PATH} contents match with ${FILE_2_PATH} contents"
return 0
else
echo "${FILE_1_PATH} contents don't match with ${FILE_2_PATH} contents"
return 1
fi
}
IsLanguageInSlimImage() {
local LANGUAGE="${1}"
if [[ " ${LANGUAGES_NOT_IN_SLIM_IMAGE[*]} " =~ [[:space:]]${LANGUAGE}[[:space:]] ]]; then
debug "${LANGUAGE} is not available in the Super-linter slim image"
return 1
else
debug "${LANGUAGE} is available in the Super-linter slim image"
return 0
fi
}