diff --git a/Makefile b/Makefile index 46876919..59bd181e 100644 --- a/Makefile +++ b/Makefile @@ -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-log-level 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-linters-expect-failure-log-level-notice test-bash-exec-library-expect-success test-bash-exec-library-expect-failure 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 @@ -373,6 +373,12 @@ test-bash-exec-library-expect-failure: ## Run the linters test cases for BASH_EX $(SUPER_LINTER_TEST_CONTAINER_URL) \ "run_test_case_bash_exec_library_expect_failure" +.PHONY: test-git-initial-commit +test-git-initial-commit: ## Run super-linter against a repository that only has one commit + $(CURDIR)/test/run-super-linter-tests.sh \ + $(SUPER_LINTER_TEST_CONTAINER_URL) \ + "run_test_case_git_initial_commit" + .PHONY: build-dev-container-image build-dev-container-image: ## Build commit linter container image DOCKER_BUILDKIT=1 docker buildx build --load \ diff --git a/lib/functions/buildFileList.sh b/lib/functions/buildFileList.sh index 9363f1d3..37d2aa6e 100755 --- a/lib/functions/buildFileList.sh +++ b/lib/functions/buildFileList.sh @@ -16,7 +16,11 @@ function GenerateFileDiff() { if [ "${GITHUB_EVENT_NAME:-}" == "push" ]; then local DIFF_TREE_CMD - DIFF_TREE_CMD="git -C \"${GITHUB_WORKSPACE}\" diff-tree --no-commit-id --name-only -r ${GITHUB_SHA} ${GITHUB_BEFORE_SHA} | xargs -I % sh -c 'echo \"${GITHUB_WORKSPACE}/%\"' 2>&1" + if [[ "${GITHUB_SHA}" == "${GIT_ROOT_COMMIT_SHA}" ]]; then + GITHUB_BEFORE_SHA="" + debug "Set GITHUB_BEFORE_SHA (${GITHUB_BEFORE_SHA}) to an empty string because there's no commit before the initial commit to diff against." + fi + DIFF_TREE_CMD="git -C \"${GITHUB_WORKSPACE}\" diff-tree --no-commit-id --name-only -r --root ${GITHUB_SHA} ${GITHUB_BEFORE_SHA} | xargs -I % sh -c 'echo \"${GITHUB_WORKSPACE}/%\"' 2>&1" RunFileDiffCommand "${DIFF_TREE_CMD}" if [ ${#RAW_FILE_ARRAY[@]} -eq 0 ]; then debug "Generating the file array with diff-tree produced [0] items, trying with git diff against the default branch..." diff --git a/lib/linter.sh b/lib/linter.sh index f670c7aa..c58d270d 100755 --- a/lib/linter.sh +++ b/lib/linter.sh @@ -385,19 +385,26 @@ GetGitHubVars() { # Ensure that Git can access the local repository ConfigureGitSafeDirectories - if [ -z "${GITHUB_EVENT_PATH}" ]; then + if [ -z "${GITHUB_EVENT_PATH:-}" ]; then fatal "Failed to get GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}]" else info "Successfully found GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}]" debug "${GITHUB_EVENT_PATH} contents: $(cat "${GITHUB_EVENT_PATH}")" fi - if [ -z "${GITHUB_SHA}" ]; then + if [ -z "${GITHUB_SHA:-}" ]; then fatal "Failed to get GITHUB_SHA: ${GITHUB_SHA}" else info "Successfully found GITHUB_SHA: ${GITHUB_SHA}" fi + if ! GIT_ROOT_COMMIT_SHA="$(git -C "${GITHUB_WORKSPACE}" rev-list --max-parents=0 "${GITHUB_SHA}")"; then + fatal "Failed to get the root commit: ${GIT_ROOT_COMMIT_SHA}" + else + debug "Successfully found the root commit: ${GIT_ROOT_COMMIT_SHA}" + fi + export GIT_ROOT_COMMIT_SHA + ################################################## # Need to pull the GitHub Vars from the env file # ################################################## @@ -416,21 +423,26 @@ GetGitHubVars() { elif [ "${GITHUB_EVENT_NAME}" == "push" ]; then debug "This is a GitHub push event." - GITHUB_PUSH_COMMIT_COUNT=$(GetGithubPushEventCommitCount "$GITHUB_EVENT_PATH") - if [ -z "${GITHUB_PUSH_COMMIT_COUNT}" ]; then - fatal "Failed to get GITHUB_PUSH_COMMIT_COUNT" - fi - info "Successfully found GITHUB_PUSH_COMMIT_COUNT: ${GITHUB_PUSH_COMMIT_COUNT}" + if [[ "${GITHUB_SHA}" == "${GIT_ROOT_COMMIT_SHA}" ]]; then + debug "${GITHUB_SHA} is the initial commit. Skip initializing GITHUB_BEFORE_SHA because there no commit before the initial commit" + else + debug "${GITHUB_SHA} is not the initial commit" + GITHUB_PUSH_COMMIT_COUNT=$(GetGithubPushEventCommitCount "$GITHUB_EVENT_PATH") + if [ -z "${GITHUB_PUSH_COMMIT_COUNT}" ]; then + fatal "Failed to get GITHUB_PUSH_COMMIT_COUNT" + fi + info "Successfully found GITHUB_PUSH_COMMIT_COUNT: ${GITHUB_PUSH_COMMIT_COUNT}" - # Ref: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context - debug "Get the hash of the commit to start the diff from from Git because the GitHub push event payload may not contain references to base_ref or previous commit." - # shellcheck disable=SC2086 # We checked that GITHUB_PUSH_COMMIT_COUNT is an integer - if ! GITHUB_BEFORE_SHA=$(git -C "${GITHUB_WORKSPACE}" rev-parse HEAD~${GITHUB_PUSH_COMMIT_COUNT}); then - fatal "Failed to initialize GITHUB_BEFORE_SHA for a push event. Output: ${GITHUB_BEFORE_SHA}" - fi + # Ref: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context + debug "Get the hash of the commit to start the diff from from Git because the GitHub push event payload may not contain references to base_ref or previous commit." + # shellcheck disable=SC2086 # We checked that GITHUB_PUSH_COMMIT_COUNT is an integer + if ! GITHUB_BEFORE_SHA=$(git -C "${GITHUB_WORKSPACE}" rev-parse HEAD~${GITHUB_PUSH_COMMIT_COUNT}); then + fatal "Failed to initialize GITHUB_BEFORE_SHA for a push event. Output: ${GITHUB_BEFORE_SHA}" + fi - ValidateGitBeforeShaReference - info "Successfully found GITHUB_BEFORE_SHA: ${GITHUB_BEFORE_SHA}" + ValidateGitBeforeShaReference + info "Successfully found GITHUB_BEFORE_SHA: ${GITHUB_BEFORE_SHA}" + fi fi ############################ @@ -482,20 +494,20 @@ GetGitHubVars() { fatal "Cannot enable status reports when running locally." fi - if [ -z "${GITHUB_TOKEN}" ]; then + if [ -z "${GITHUB_TOKEN:-}" ]; then fatal "Failed to get [GITHUB_TOKEN]. Terminating because status reports were explicitly enabled, but GITHUB_TOKEN was not provided." else info "Successfully found GITHUB_TOKEN." fi - if [ -z "${GITHUB_REPOSITORY}" ]; then + if [ -z "${GITHUB_REPOSITORY:-}" ]; then error "Failed to get [GITHUB_REPOSITORY]!" fatal "[${GITHUB_REPOSITORY}]" else info "Successfully found GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}" fi - if [ -z "${GITHUB_RUN_ID}" ]; then + if [ -z "${GITHUB_RUN_ID:-}" ]; then error "Failed to get [GITHUB_RUN_ID]!" fatal "[${GITHUB_RUN_ID}]" else diff --git a/test/lib/buildFileListTest.sh b/test/lib/buildFileListTest.sh index 7e08ee73..5b6e4977 100755 --- a/test/lib/buildFileListTest.sh +++ b/test/lib/buildFileListTest.sh @@ -32,12 +32,19 @@ git config --global user.name "Super-linter" function InitGitRepositoryAndCommitFiles() { local REPOSITORY_PATH="${1}" && shift - local FILES_TO_COMMIT="${1}" + local FILES_TO_COMMIT="${1}" && shift + local COMMIT_FILE_INITIAL_COMMIT="${1}" git -C "${REPOSITORY_PATH}" init + if [[ "${COMMIT_FILE_INITIAL_COMMIT}" == "true" ]]; then + touch "${REPOSITORY_PATH}/test-initial-commit.txt" + git -C "${REPOSITORY_PATH}" add . + fi git -C "${REPOSITORY_PATH}" commit --allow-empty -m "Initial commit" GITHUB_BEFORE_SHA=$(git -C "${REPOSITORY_PATH}" rev-parse HEAD) debug "GITHUB_BEFORE_SHA: ${GITHUB_BEFORE_SHA}" + GIT_ROOT_COMMIT_SHA="${GITHUB_BEFORE_SHA}" + debug "GIT_ROOT_COMMIT_SHA: ${GIT_ROOT_COMMIT_SHA}" git -C "${REPOSITORY_PATH}" checkout -b test-branch @@ -56,9 +63,13 @@ function InitGitRepositoryAndCommitFiles() { function GenerateFileDiffOneFileTest() { local GITHUB_WORKSPACE GITHUB_WORKSPACE="$(mktemp -d)" + # shellcheck disable=SC2064 # Once the path is set, we don't expect it to change + trap "rm -fr '${GITHUB_WORKSPACE}'" EXIT echo "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}" - InitGitRepositoryAndCommitFiles "${GITHUB_WORKSPACE}" 1 + local FILES_TO_COMMIT="${FILES_TO_COMMIT:-1}" + local COMMIT_FILE_INITIAL_COMMIT="${COMMIT_FILE_INITIAL_COMMIT:-"false"}" + InitGitRepositoryAndCommitFiles "${GITHUB_WORKSPACE}" "${FILES_TO_COMMIT}" "${COMMIT_FILE_INITIAL_COMMIT}" # shellcheck source=/dev/null source "lib/functions/buildFileList.sh" @@ -78,16 +89,28 @@ function GenerateFileDiffOneFileTest() { function GenerateFileDiffOneFilePushEventTest() { # shellcheck disable=SC2034 local GITHUB_EVENT_NAME="push" + local FILES_TO_COMMIT=1 + local COMMIT_FILE_INITIAL_COMMIT="false" + GenerateFileDiffOneFileTest "${FUNCNAME[0]}" +} + +function GenerateFileDiffInitialCommitPushEventTest() { + # shellcheck disable=SC2034 + local GITHUB_EVENT_NAME="push" + local FILES_TO_COMMIT=0 + local COMMIT_FILE_INITIAL_COMMIT="true" GenerateFileDiffOneFileTest "${FUNCNAME[0]}" } function GenerateFileDiffTwoFilesTest() { local GITHUB_WORKSPACE GITHUB_WORKSPACE="$(mktemp -d)" + # shellcheck disable=SC2064 # Once the path is set, we don't expect it to change + trap "rm -fr '${GITHUB_WORKSPACE}'" EXIT debug "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}" local FILES_TO_COMMIT=2 - InitGitRepositoryAndCommitFiles "${GITHUB_WORKSPACE}" ${FILES_TO_COMMIT} + InitGitRepositoryAndCommitFiles "${GITHUB_WORKSPACE}" ${FILES_TO_COMMIT} "false" # shellcheck source=/dev/null source "lib/functions/buildFileList.sh" @@ -114,3 +137,4 @@ GenerateFileDiffOneFileTest GenerateFileDiffOneFilePushEventTest GenerateFileDiffTwoFilesTest GenerateFileDiffTwoFilesPushEventTest +GenerateFileDiffInitialCommitPushEventTest diff --git a/test/run-super-linter-tests.sh b/test/run-super-linter-tests.sh index 5311220d..9e59d546 100755 --- a/test/run-super-linter-tests.sh +++ b/test/run-super-linter-tests.sh @@ -7,14 +7,22 @@ set -o pipefail SUPER_LINTER_TEST_CONTAINER_URL="${1}" TEST_FUNCTION_NAME="${2}" -COMMAND_TO_RUN=(docker run -e DEFAULT_BRANCH=main -e ENABLE_GITHUB_ACTIONS_GROUP_TITLE=true -e JSCPD_CONFIG_FILE=".jscpd-test-linters.json" -e RENOVATE_SHAREABLE_CONFIG_PRESET_FILE_NAMES="default.json,hoge.json" -e RUN_LOCAL=true -e TEST_CASE_RUN=true -e TYPESCRIPT_STANDARD_TSCONFIG_FILE=".github/linters/tsconfig.json" -v "$(pwd):/tmp/lint") +DEFAULT_BRANCH="main" + +COMMAND_TO_RUN=(docker run -e DEFAULT_BRANCH="${DEFAULT_BRANCH}" -e ENABLE_GITHUB_ACTIONS_GROUP_TITLE=true) + +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") +} run_test_cases_expect_failure() { + configure_linters_for_test_cases COMMAND_TO_RUN+=(-e ANSIBLE_DIRECTORY="/test/linters/ansible/bad" -e CHECKOV_FILE_NAME=".checkov-test-linters-failure.yaml" -e FILTER_REGEX_INCLUDE=".*bad.*") EXPECTED_EXIT_CODE=1 } run_test_cases_expect_success() { + configure_linters_for_test_cases COMMAND_TO_RUN+=(-e ANSIBLE_DIRECTORY="/test/linters/ansible/good" -e CHECKOV_FILE_NAME=".checkov-test-linters-success.yaml" -e FILTER_REGEX_INCLUDE=".*good.*") } @@ -43,11 +51,39 @@ run_test_case_bash_exec_library_expect_success() { COMMAND_TO_RUN+=(-e BASH_EXEC_IGNORE_LIBRARIES="true") } +run_test_case_git_initial_commit() { + local GIT_REPOSITORY_PATH + GIT_REPOSITORY_PATH="$(mktemp -d)" + # shellcheck disable=SC2064 # Once the path is set, we don't expect it to change + trap "rm -fr '${GIT_REPOSITORY_PATH}'" EXIT + + git -C "${GIT_REPOSITORY_PATH}" init --initial-branch="${DEFAULT_BRANCH}" + git -C "${GIT_REPOSITORY_PATH}" config user.name "Super-linter Test" + git -C "${GIT_REPOSITORY_PATH}" config user.email "super-linter-test@example.com" + cp -v test/data/github-event/github-event-push.json "${GIT_REPOSITORY_PATH}/" + git -C "${GIT_REPOSITORY_PATH}" add . + git -C "${GIT_REPOSITORY_PATH}" commit -m "feat: initial commit" + + local TEST_GITHUB_SHA + TEST_GITHUB_SHA="$(git -C "${GIT_REPOSITORY_PATH}" rev-parse HEAD)" + + RUN_LOCAL=false + SUPER_LINTER_WORKSPACE="${GIT_REPOSITORY_PATH}" + COMMAND_TO_RUN+=(-e GITHUB_WORKSPACE="/tmp/lint") + COMMAND_TO_RUN+=(-e GITHUB_EVENT_NAME="push") + COMMAND_TO_RUN+=(-e GITHUB_EVENT_PATH="/tmp/lint/github-event-push.json") + COMMAND_TO_RUN+=(-e GITHUB_SHA="${TEST_GITHUB_SHA}") + COMMAND_TO_RUN+=(-e MULTI_STATUS=false) + COMMAND_TO_RUN+=(-e VALIDATE_ALL_CODEBASE=false) + COMMAND_TO_RUN+=(-e VALIDATE_JSON=true) +} + # Run the test setup function ${TEST_FUNCTION_NAME} COMMAND_TO_RUN+=(-e LOG_LEVEL="${LOG_LEVEL:-"DEBUG"}") - +COMMAND_TO_RUN+=(-e RUN_LOCAL="${RUN_LOCAL:-true}") +COMMAND_TO_RUN+=(-v "${SUPER_LINTER_WORKSPACE:-$(pwd)}:/tmp/lint") COMMAND_TO_RUN+=("${SUPER_LINTER_TEST_CONTAINER_URL}") declare -i EXPECTED_EXIT_CODE