feat: save super-linter output if requested (#5806)

- New SAVE_SUPER_LINTER_OUTPUT variable. When set to true,
  saves super-linter output to ${DEFAULT_WORKSPACE}/${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}
- New SUPER_LINTER_OUTPUT_DIRECTORY_NAME variable to set the output
  directory name instide the default workspace.

Close #5774
This commit is contained in:
Marco Ferrari 2024-07-01 14:50:52 +02:00 committed by GitHub
parent d74351fda7
commit 94bb3f5563
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 118 additions and 14 deletions

4
.gitignore vendored
View file

@ -90,3 +90,7 @@ test/reports
.lintr
test/linters/rust_clippy/**/Cargo.lock
test/linters/rust_clippy/**/target/**
# Super-linter ouputs
super-linter-output/
custom-super-linter-output-directory-name/

View file

@ -4,7 +4,7 @@
all: info docker test ## Run all targets.
.PHONY: test
test: info validate-container-image-labels test-lib inspec lint-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-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-linters ## Run the test suite
test: info validate-container-image-labels test-lib inspec lint-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-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-linters ## 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
@ -393,6 +393,18 @@ test-use-find-and-ignore-gitignored-files: ## Run super-linter with USE_FIND_ALG
$(SUPER_LINTER_TEST_CONTAINER_URL) \
"run_test_case_use_find_and_ignore_gitignored_files"
.PHONY: test-save-super-linter-output
test-save-super-linter-output: ## Run super-linter with SAVE_SUPER_LINTER_OUTPUT=true
$(CURDIR)/test/run-super-linter-tests.sh \
$(SUPER_LINTER_TEST_CONTAINER_URL) \
"run_test_cases_save_super_linter_output"
.PHONY: test-save-super-linter-output-custom-path
test-save-super-linter-output-custom-path: ## Run super-linter with SAVE_SUPER_LINTER_OUTPUT=true and save output in a custom directory
$(CURDIR)/test/run-super-linter-tests.sh \
$(SUPER_LINTER_TEST_CONTAINER_URL) \
"run_test_cases_save_super_linter_output_custom_path"
.PHONY: build-dev-container-image
build-dev-container-image: ## Build commit linter container image
DOCKER_BUILDKIT=1 docker buildx build --load \

View file

@ -240,6 +240,7 @@ You can configure super-linter using the following environment variables:
| **PYTHON_RUFF_CONFIG_FILE** | `.ruff.toml` | Filename for [ruff configuration](https://docs.astral.sh/ruff/configuration/) |
| **RENOVATE_SHAREABLE_CONFIG_PRESET_FILE_NAMES** | not set | Comma-separated filenames for [renovate shareable config preset](https://docs.renovatebot.com/config-presets/) (ex: `default.json`) |
| **RUBY_CONFIG_FILE** | `.ruby-lint.yml` | Filename for [rubocop configuration](https://docs.rubocop.org/rubocop/configuration.html) (ex: `.ruby-lint.yml`, `.rubocop.yml`) |
| **SAVE_SUPER_LINTER_OUTPUT** | `false` | If set to `true`, super-linter will save its output to `${DEFAULT_WORKSPACE}/${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}` |
| **SCALAFMT_CONFIG_FILE** | `.scalafmt.conf` | Filename for [scalafmt configuration](https://scalameta.org/scalafmt/docs/configuration.html) (ex: `.scalafmt.conf`) |
| **SNAKEMAKE_SNAKEFMT_CONFIG_FILE** | `.snakefmt.toml` | Filename for [Snakemake configuration](https://github.com/snakemake/snakefmt#configuration) (ex: `pyproject.toml`, `.snakefmt.toml`) |
| **SSL_CERT_SECRET** | `none` | SSL cert to add to the **Super-Linter** trust store. This is needed for users on `self-hosted` runners or need to inject the cert for security standards (ex. ${{ secrets.SSL_CERT }}) |
@ -248,6 +249,7 @@ You can configure super-linter using the following environment variables:
| **SSH_INSECURE_NO_VERIFY_GITHUB_KEY** | `false` | **INSECURE -** If set to `true`, does not verify the fingerprint of the github.com SSH key before adding this. This is not recommended! |
| **SQL_CONFIG_FILE** | `.sql-config.json` | Filename for [SQL-Lint configuration](https://sql-lint.readthedocs.io/en/latest/files/configuration.html) (ex: `sql-config.json` , `.config.json`) |
| **SQLFLUFF_CONFIG_FILE** | `/.sqlfluff` | Filename for [SQLFLUFF configuration](https://docs.sqlfluff.com/en/stable/configuration.html) (ex: `/.sqlfluff`, `pyproject.toml`) |
| **SUPER_LINTER_OUTPUT_DIRECTORY_NAME** | `super-linter-output` | Name of the directory where super-linter saves its output. |
| **SUPPRESS_FILE_TYPE_WARN** | `false` | If set to `true`, will hide warning messages about files without their proper extensions. Default is `false` |
| **SUPPRESS_POSSUM** | `false` | If set to `true`, will hide the ASCII possum at top of log output. Default is `false` |
| **TERRAFORM_TERRASCAN_CONFIG_FILE** | `terrascan.toml` | Filename for [terrascan configuration](https://github.com/accurics/terrascan) (ex: `terrascan.toml`) |
@ -451,6 +453,28 @@ path to the files that contains a CA that can be used to valide the certificate:
SSL_CERT_SECRET: ${{ secrets.ROOT_CA }}
```
## Super-linter outputs
If you set `SAVE_SUPER_LINTER_OUTPUT` to `true`, Super-linter saves its output
to `${DEFAULT_WORKSPACE}/${DEFAULT_SUPER_LINTER_OUTPUT_DIRECTORY_NAME}`, so you
can further process it, if needed.
Most outputs are in JSON format.
The output of previous Super-linter runs is not preserved when running locally.
## Linter reports and outputs
Some linters support configuring the format of their outputs for further
processing. To get access to that output, enable it using the respective linter
configuration file. If a linter requires a path for the output directory, you
can use the value of the `${DEFAULT_WORKSPACE}` variable.
If a linter doesn't support setting an arbitrary output path as described in the
previous paragraph, but only supports emitting results to standard output or
standard error streams, you can
[enable Super-linter outputs](#super-linter-outputs) and parse them.
## How to contribute
If you would like to help contribute to super-linter, see

View file

@ -131,7 +131,7 @@ function BuildFileList() {
fi
local PARALLEL_RESULTS_FILE_PATH
PARALLEL_RESULTS_FILE_PATH="/tmp/super-linter-parallel-results-build-file-list.json"
PARALLEL_RESULTS_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-results-build-file-list.json"
debug "PARALLEL_RESULTS_FILE_PATH when building the file list: ${PARALLEL_RESULTS_FILE_PATH}"
local -a PARALLEL_COMMAND
@ -148,7 +148,7 @@ function BuildFileList() {
PARALLEL_COMMAND+=("BuildFileArrays")
debug "PARALLEL_COMMAND to build the list of files and directories to lint: ${PARALLEL_COMMAND[*]}"
FILE_ARRAYS_DIRECTORY_PATH="/tmp/super-linter-file-arrays"
FILE_ARRAYS_DIRECTORY_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-file-arrays"
mkdir -p "${FILE_ARRAYS_DIRECTORY_PATH}"
export FILE_ARRAYS_DIRECTORY_PATH
debug "Created FILE_ARRAYS_DIRECTORY_PATH: ${FILE_ARRAYS_DIRECTORY_PATH}"

View file

@ -15,6 +15,7 @@ function ValidateBooleanConfigurationVariables() {
ValidateBooleanVariable "LOG_WARN" "${LOG_WARN}"
ValidateBooleanVariable "MULTI_STATUS" "${MULTI_STATUS}"
ValidateBooleanVariable "RUN_LOCAL" "${RUN_LOCAL}"
ValidateBooleanVariable "SAVE_SUPER_LINTER_OUTPUT" "${SAVE_SUPER_LINTER_OUTPUT}"
ValidateBooleanVariable "SSH_INSECURE_NO_VERIFY_GITHUB_KEY" "${SSH_INSECURE_NO_VERIFY_GITHUB_KEY}"
ValidateBooleanVariable "SSH_SETUP_GITHUB" "${SSH_SETUP_GITHUB}"
ValidateBooleanVariable "SUPPRESS_FILE_TYPE_WARN" "${SUPPRESS_FILE_TYPE_WARN}"

View file

@ -78,7 +78,7 @@ function LintCodebase() {
info "Linting ${FILE_TYPE} items..."
local PARALLEL_RESULTS_FILE_PATH
PARALLEL_RESULTS_FILE_PATH="/tmp/super-linter-worker-results-${FILE_TYPE}.json"
PARALLEL_RESULTS_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-worker-results-${FILE_TYPE}.json"
debug "PARALLEL_RESULTS_FILE_PATH for ${FILE_TYPE}: ${PARALLEL_RESULTS_FILE_PATH}"
local -a PARALLEL_COMMAND
@ -163,7 +163,7 @@ function LintCodebase() {
debug "PARALLEL_COMMAND_OUTPUT for ${FILE_TYPE} (exit code: ${PARALLEL_COMMAND_RETURN_CODE}): ${PARALLEL_COMMAND_OUTPUT}"
debug "Parallel output file (${PARALLEL_RESULTS_FILE_PATH}) contents for ${FILE_TYPE}:\n$(cat "${PARALLEL_RESULTS_FILE_PATH}")"
echo ${PARALLEL_COMMAND_RETURN_CODE} >"/tmp/super-linter-parallel-command-exit-code-${FILE_TYPE}"
echo ${PARALLEL_COMMAND_RETURN_CODE} >"${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-command-exit-code-${FILE_TYPE}"
if [ ${PARALLEL_COMMAND_RETURN_CODE} -ne 0 ]; then
error "Found errors when linting ${FILE_TYPE}. Exit code: ${PARALLEL_COMMAND_RETURN_CODE}."
@ -199,7 +199,7 @@ function LintCodebase() {
if [ ${PARALLEL_COMMAND_RETURN_CODE} -ne 0 ]; then
local STDOUT_LINTER_FILE_PATH
STDOUT_LINTER_FILE_PATH="/tmp/super-linter-parallel-stdout-${FILE_TYPE}"
STDOUT_LINTER_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-stdout-${FILE_TYPE}"
debug "Saving stdout for ${FILE_TYPE} to ${STDOUT_LINTER_FILE_PATH} in case we need it later"
printf '%s\n' "${STDOUT_LINTER_LOG_MESSAGE}" >"${STDOUT_LINTER_FILE_PATH}"
fi
@ -218,7 +218,7 @@ function LintCodebase() {
info "${STDERR_LINTER_LOG_MESSAGE}"
if [ ${PARALLEL_COMMAND_RETURN_CODE} -ne 0 ]; then
local STDERR_LINTER_FILE_PATH
STDERR_LINTER_FILE_PATH="/tmp/super-linter-parallel-stderr-${FILE_TYPE}"
STDERR_LINTER_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-stderr-${FILE_TYPE}"
debug "Saving stderr for ${FILE_TYPE} to ${STDERR_LINTER_FILE_PATH} in case we need it later"
printf '%s\n' "${STDERR_LINTER_LOG_MESSAGE}" >"${STDERR_LINTER_FILE_PATH}"
fi

View file

@ -79,6 +79,10 @@ export IGNORE_GITIGNORED_FILES
declare -l MULTI_STATUS
MULTI_STATUS="${MULTI_STATUS:-true}"
# We want a lowercase value
declare -l SAVE_SUPER_LINTER_OUTPUT
SAVE_SUPER_LINTER_OUTPUT="${SAVE_SUPER_LINTER_OUTPUT:-false}"
# We want a lowercase value
declare -l SSH_INSECURE_NO_VERIFY_GITHUB_KEY
SSH_INSECURE_NO_VERIFY_GITHUB_KEY="${SSH_INSECURE_NO_VERIFY_GITHUB_KEY:-false}"
@ -594,7 +598,7 @@ Footer() {
# but a number that's less than that because of how GNU parallel returns
# exit codes.
# Ref: https://www.gnu.org/software/parallel/parallel.html#exit-status
ERROR_COUNTER_FILE_PATH="/tmp/super-linter-parallel-command-exit-code-${LANGUAGE}"
ERROR_COUNTER_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-command-exit-code-${LANGUAGE}"
if [ ! -f "${ERROR_COUNTER_FILE_PATH}" ]; then
debug "Error counter ${ERROR_COUNTER_FILE_PATH} doesn't exist"
else
@ -607,7 +611,7 @@ Footer() {
# get feedback
if [[ "${LOG_VERBOSE}" != "true" ]]; then
local STDOUT_LINTER_FILE_PATH
STDOUT_LINTER_FILE_PATH="/tmp/super-linter-parallel-stdout-${LANGUAGE}"
STDOUT_LINTER_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-stdout-${LANGUAGE}"
if [[ -e "${STDOUT_LINTER_FILE_PATH}" ]]; then
error "$(cat "${STDOUT_LINTER_FILE_PATH}")"
else
@ -615,7 +619,7 @@ Footer() {
fi
local STDERR_LINTER_FILE_PATH
STDERR_LINTER_FILE_PATH="/tmp/super-linter-parallel-stderr-${LANGUAGE}"
STDERR_LINTER_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-parallel-stderr-${LANGUAGE}"
if [[ -e "${STDERR_LINTER_FILE_PATH}" ]]; then
error "$(cat "${STDERR_LINTER_FILE_PATH}")"
else
@ -702,8 +706,20 @@ cleanup() {
--force \
"${LOG_TEMP}" "${LOG_FILE_PATH}"
else
debug "Skipping the moving of the log file from ${LOG_TEMP} to ${LOG_FILE_PATH}"
debug "Skip moving the log file from ${LOG_TEMP} to ${LOG_FILE_PATH}"
fi
if [ "${SAVE_SUPER_LINTER_OUTPUT}" = "true" ]; then
if [ -e "${SUPER_LINTER_OUTPUT_DIRECTORY_PATH}" ]; then
debug "${SUPER_LINTER_OUTPUT_DIRECTORY_PATH} already exists. Deleting it before moving the new output directory there."
rm -fr "${SUPER_LINTER_OUTPUT_DIRECTORY_PATH}"
fi
debug "Moving Super-linter output from ${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH} to ${SUPER_LINTER_OUTPUT_DIRECTORY_PATH}"
mv "${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}" "${SUPER_LINTER_OUTPUT_DIRECTORY_PATH}"
else
debug "Skip moving the output directory from ${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH} to ${SUPER_LINTER_OUTPUT_DIRECTORY_PATH}"
fi
else
debug "GITHUB_WORKSPACE is not set. Skipping filesystem cleanup steps"
fi
@ -752,6 +768,20 @@ debug "TYPESCRIPT_STANDARD_TSCONFIG_FILE: ${TYPESCRIPT_STANDARD_TSCONFIG_FILE}"
R_RULES_FILE_PATH_IN_ROOT="${GITHUB_WORKSPACE}/${R_FILE_NAME}"
debug "R_RULES_FILE_PATH_IN_ROOT: ${R_RULES_FILE_PATH_IN_ROOT}"
DEFAULT_SUPER_LINTER_OUTPUT_DIRECTORY_NAME="super-linter-output"
SUPER_LINTER_OUTPUT_DIRECTORY_NAME="${SUPER_LINTER_OUTPUT_DIRECTORY_NAME:-${DEFAULT_SUPER_LINTER_OUTPUT_DIRECTORY_NAME}}"
export SUPER_LINTER_OUTPUT_DIRECTORY_NAME
debug "Super-linter output directory name: ${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}"
SUPER_LINTER_OUTPUT_DIRECTORY_PATH="${GITHUB_WORKSPACE}/${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}"
export SUPER_LINTER_OUTPUT_DIRECTORY_PATH
debug "Super-linter output directory path: ${SUPER_LINTER_OUTPUT_DIRECTORY_PATH}"
SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH="/tmp/${DEFAULT_SUPER_LINTER_OUTPUT_DIRECTORY_NAME}"
export SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH
debug "Super-linter private output directory path: ${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}"
mkdir -p "${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}"
############################
# Validate the environment #
############################
@ -818,7 +848,7 @@ endGitHubActionsLogGroup "${SUPER_LINTER_INITIALIZATION_LOG_GROUP_TITLE}"
# Run linters #
###############
declare PARALLEL_RESULTS_FILE_PATH
PARALLEL_RESULTS_FILE_PATH="/tmp/super-linter-results.json"
PARALLEL_RESULTS_FILE_PATH="${SUPER_LINTER_PRIVATE_OUTPUT_DIRECTORY_PATH}/super-linter-results.json"
debug "PARALLEL_RESULTS_FILE_PATH: ${PARALLEL_RESULTS_FILE_PATH}"
declare -a PARALLEL_COMMAND

View file

@ -137,7 +137,7 @@ function BuildFileArraysAnsibleGitHubWorkspaceTest() {
local TEST_CASE_RUN=false
# shellcheck disable=SC2034
local IGNORE_GENERATED_FILES=false
local FILE_ARRAYS_DIRECTORY_PATH="/tmp/super-linter-file-arrays"
local FILE_ARRAYS_DIRECTORY_PATH="/tmp/super-linter-output/super-linter-file-arrays"
mkdir -p "${FILE_ARRAYS_DIRECTORY_PATH}"
# shellcheck disable=SC2034

View file

@ -89,14 +89,30 @@ run_test_case_use_find_and_ignore_gitignored_files() {
COMMAND_TO_RUN+=(-e USE_FIND_ALGORITHM=true)
}
run_test_cases_save_super_linter_output() {
run_test_cases_expect_success
SAVE_SUPER_LINTER_OUTPUT="true"
}
run_test_cases_save_super_linter_output_custom_path() {
run_test_cases_save_super_linter_output
SUPER_LINTER_OUTPUT_DIRECTORY_NAME="custom-super-linter-output-directory-name"
}
# Run the test setup function
${TEST_FUNCTION_NAME}
CREATE_LOG_FILE="${CREATE_LOG_FILE:-false}"
SAVE_SUPER_LINTER_OUTPUT="${SAVE_SUPER_LINTER_OUTPUT:-false}"
if [ -n "${SUPER_LINTER_OUTPUT_DIRECTORY_NAME:-}" ]; then
COMMAND_TO_RUN+=(-e SUPER_LINTER_OUTPUT_DIRECTORY_NAME="${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}")
fi
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")
COMMAND_TO_RUN+=("${SUPER_LINTER_TEST_CONTAINER_URL}")
@ -120,7 +136,7 @@ echo "Super-linter exit code: ${SUPER_LINTER_EXIT_CODE}"
if [[ "${CREATE_LOG_FILE}" == true ]]; then
LOG_FILE_PATH="$(pwd)/super-linter.log"
if [ ! -e "${LOG_FILE_PATH}" ]; then
echo "Log file was requested but it's not available"
echo "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}"
@ -131,6 +147,23 @@ else
echo "Log file was not requested. CREATE_LOG_FILE: ${CREATE_LOG_FILE}"
fi
if [[ "${SAVE_SUPER_LINTER_OUTPUT}" == true ]]; then
SUPER_LINTER_OUTPUT_DIRECTORY_NAME="${SUPER_LINTER_OUTPUT_DIRECTORY_NAME:-"super-linter-output"}"
SUPER_LINTER_OUTPUT_PATH="$(pwd)/${SUPER_LINTER_OUTPUT_DIRECTORY_NAME}"
if [ ! -d "${SUPER_LINTER_OUTPUT_PATH}" ]; then
echo "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}"
fi
else
echo "Super-linter output was not requested. SAVE_SUPER_LINTER_OUTPUT: ${SAVE_SUPER_LINTER_OUTPUT}"
fi
if [ ${SUPER_LINTER_EXIT_CODE} -ne ${EXPECTED_EXIT_CODE} ]; then
echo "Super-linter exited with an unexpected code: ${SUPER_LINTER_EXIT_CODE}"
exit 1