Full Code of luizm/action-sh-checker for AI

master 883217215b11 cached
7 files
13.9 KB
4.3k tokens
1 requests
Download .txt
Repository: luizm/action-sh-checker
Branch: master
Commit: 883217215b11
Files: 7
Total size: 13.9 KB

Directory structure:
gitextract_prljnb1b/

├── .github/
│   └── workflows/
│       └── ci.yml
├── Dockerfile
├── LICENSE
├── README.md
├── action.yml
├── entrypoint.sh
└── upgrade.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/ci.yml
================================================
---
name: Build

on:
  push:
    branches:
      - master

  pull_request:
    branches:
      - master

  workflow_dispatch:

jobs:
  lint:
    name: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: sh-checker
        uses: ./. # Use the local action, at the current version
        with:
          sh_checker_comment: true
          sh_checker_only_diff: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: Dockerfile
================================================
FROM alpine:3.18.4
LABEL "name"="sh-checker"
LABEL "maintainer"="Luiz Muller <contact@luizm.dev>"

ARG shfmt_version=3.12.0
ARG shellcheck_version=0.11.0
ARG gh_version=2.37.0

RUN apk add --no-cache bash git jq curl checkbashisms xz \
    && apk add --no-cache --virtual .build-deps tar \
    && wget "https://github.com/mvdan/sh/releases/download/v${shfmt_version}/shfmt_v${shfmt_version}_linux_amd64" -O /usr/local/bin/shfmt \
    && chmod +x /usr/local/bin/shfmt \
    && wget "https://github.com/koalaman/shellcheck/releases/download/v${shellcheck_version}/shellcheck-v${shellcheck_version}.linux.x86_64.tar.xz"  -O- | tar xJ -C /usr/local/bin/ --strip-components=1 --wildcards '*/shellcheck' \
    && chmod +x /usr/local/bin/shellcheck \
    && curl -L https://github.com/cli/cli/releases/download/v${gh_version}/gh_${gh_version}_linux_amd64.tar.gz | tar xz -C /usr/local/ --strip-components=1 \
    && apk del --no-cache .build-deps \
    && rm -rf /tmp/*

# https://github.com/actions/runner-images/issues/6775#issuecomment-1410270956
RUN git config --system --add safe.directory /github/workspace

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Luiz Muller

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# sh-checker

[![Build](https://github.com/luizm/action-sh-checker/actions/workflows/ci.yml/badge.svg)](https://github.com/luizm/action-sh-checker/actions/workflows/ci.yml)

A [GitHub action](https://docs.github.com/en/free-pro-team@latest/actions) that performs static analysis of shell scripts using [shellcheck](https://github.com/koalaman/shellcheck), [shfmt](https://github.com/mvdan/sh) and [checkbashisms](https://linux.die.net/man/1/checkbashisms)

![Screen Shot 2020-04-01 at 12 18 59](https://user-images.githubusercontent.com/6004689/78155536-f9a8a080-7413-11ea-8b5c-2c96484feb61.png)

## Usage

Job example to check all sh files but ignore the directory `.terraform` and file `dir/example.sh`

```yaml
name: example
on:
  - pull_request
jobs:
  sh-checker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run the sh-checker
        uses: luizm/action-sh-checker@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SHELLCHECK_OPTS: -e SC1004 # exclude some shellcheck warnings.
          SHFMT_OPTS: -s # arguments to shfmt.
        with:
          sh_checker_comment: true
          sh_checker_exclude: ".terraform ^dir/example.sh"
```

### Environment Variables

`SHELLCHECK_OPTS`: Used to specify shellcheck arguments.

`SHFMT_OPTS`: Used to specify shfmt arguments.

### Inputs

`sh_checker_only_diff`: (optional) Only check the files that were changed in the pull request. Default is to check all files in the repo.

`sh_checker_exclude`: (optional) Directory or file name that doesn't need to be checked.

`sh_checker_comment`: (optional) If true, it will show the errors as commentaries in the pull requests. Default is false.

`sh_checker_shfmt_disable`: (optional) If true, it will skip shfmt. Default is false.

`sh_checker_shellcheck_disable`: (optional) If true, it will skip shellcheck. Default is false.

`sh_checker_checkbashisms_enable`: (optional) If true, run checkbashisms tool against scripts. Default is false.

### Secrets

`GITHUB_TOKEN`: The GitHub API token used to post comments to pull requests. Required only if `sh_checker_only_diff` or `sh_checker_comment` is set to true.


================================================
FILE: action.yml
================================================
name: "sh-checker"
description: "Run shellcheck and/or shfmt on all shell script files and include commentaries, there is a exclude parameter"
author: "luizm"
branding:
  icon: "terminal"
  color: "black"
inputs:
  sh_checker_exclude:
    description: "Directory or file name that doesn't need to be checked"
    required: false
  sh_checker_shfmt_disable:
    description: "If true, it will skip the shfmt. Default is false"
    required: false
  sh_checker_shellcheck_disable:
    description: "If true, it will skip the shellcheck. Default is false"
    required: false
  sh_checker_checkbashisms_enable:
    description: "If true, run checkbashisms tool against scripts. Default is false"
    required: false
    default: "false"
  sh_checker_comment:
    description: "If true, it will show the errors as commentaries in the pull requests. Default is false"
    required: false
  sh_checker_only_diff:
    description: "If true, run only on files changed in the PR branch. Default is false"
    required: false
runs:
  using: "docker"
  image: "Dockerfile"


================================================
FILE: entrypoint.sh
================================================
#!/usr/bin/env bash

cd "$GITHUB_WORKSPACE" || {
	printf 'Directory not found: "%s"\n' "$GITHUB_WORKSPACE"
	exit 1
}

SHELLCHECK_DISABLE=0
SHFMT_DISABLE=0
SH_CHECKER_COMMENT=0
CHECKBASHISMS_ENABLE=0
SH_CHECKER_ONLY_DIFF=0

shopt -s nocasematch

if [[ "${INPUT_SH_CHECKER_SHELLCHECK_DISABLE}" =~ ^(1|true|on|yes)$ ]]; then
	SHELLCHECK_DISABLE=1
fi

if [[ "${INPUT_SH_CHECKER_SHFMT_DISABLE}" =~ ^(1|true|on|yes)$ ]]; then
	SHFMT_DISABLE=1
fi

if [[ "${INPUT_SH_CHECKER_COMMENT}" =~ ^(1|true|on|yes)$ ]]; then
	SH_CHECKER_COMMENT=1
fi

if [[ "${INPUT_SH_CHECKER_CHECKBASHISMS_ENABLE}" =~ ^(1|true|on|yes)$ ]]; then
	CHECKBASHISMS_ENABLE=1
fi

if [[ "${INPUT_SH_CHECKER_ONLY_DIFF}" =~ ^(1|true|on|yes)$ ]]; then
	SH_CHECKER_ONLY_DIFF=1
fi

if ((SHELLCHECK_DISABLE == 1 && SHFMT_DISABLE == 1 && CHECKBASHISMS_ENABLE != 1)); then
	echo "All checks are disabled: \`sh_checker_shellcheck_disable\` and \`sh_checker_shfmt_disable\` are both set to 1/true."
fi

# Internal functions
_show_sh_files() {
	# Store the array of files to check in sh_files
	# using a global, as returning arrays in bash is ugly
	# setting IFS to \n allows for spaces in file names:
	if ((SH_CHECKER_ONLY_DIFF == 1)); then
		# Compute the intersection of all shell scripts in the repo and files changes on the PR branch
		if [[ "$GITHUB_REF" =~ ^refs/pull/ ]]; then
			# The `on: pull_request` trigger does not give branch information, so we need to supply the PR number to gh
			# See https://frontside.com/blog/2020-05-26-github-actions-pull_request/
			# and https://docs.github.com/en/actions/learn-github-actions/variables
			pr_number="$(echo "$GITHUB_REF" | cut -d/ -f3)"
		else
			pr_number="" # have gh figure out the PR number from the branch name
		fi
		IFS=$'\n' mapfile -t sh_files < <(sort <(shfmt -f .) <(gh pr diff "$pr_number" --name-only) | uniq -d)
		echo "Checking only the shell script(s) changed in the PR branch:"
		printf '"%s"\n' "${sh_files[@]}"
	else
		IFS=$'\n' mapfile -t sh_files < <(shfmt -f .)
	fi

	if [ -z "$INPUT_SH_CHECKER_EXCLUDE" ]; then
		return 0
	fi

	OLDIFS="$IFS"
	IFS=$' \t\n' read -d '' -ra excludes <<<"$INPUT_SH_CHECKER_EXCLUDE"
	IFS=$'\n'
	sh_all=("${sh_files[@]}")
	sh_files=()
	excluded=()
	local sh exclude
	for sh in "${sh_all[@]}"; do
		for exclude in "${excludes[@]}"; do
			grep -q -E "$exclude" <<<"$sh" || continue
			excluded+=("$sh")
			continue 2
		done
		sh_files+=("$sh")
	done
	if (("${#excluded[@]}" != 0)); then
		printf 'The following %d shell script(s) will not be checked:\n' "${#excluded[@]}"
		printf '"%s"\n' "${excluded[@]}"
	fi
	IFS="$OLDIFS"
}

_comment_on_github() {
	local content
	IFS= read -r -d '' content <<EOF
#### \`sh-checker report\`

To get the full details, please check in the [job]("https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID") output.

<details>
<summary>shellcheck errors</summary>

\`\`\`
$1
\`\`\`
</details>

<details>
<summary>shfmt errors</summary>

\`\`\`
$2
\`\`\`
</details>

EOF
	local -r payload=$(jq -R --slurp '{body: .}' <<<"$content")
	local -r comment_url=$(jq -r .pull_request.comments_url <"$GITHUB_EVENT_PATH")

	echo "Commenting on the pull request"
	curl -s -S -H "Authorization: token $GITHUB_TOKEN" --header "Content-Type: application/json" --data @- "$comment_url" <<<"$payload"
}

_show_sh_files

((${#sh_files[@]} == 0)) && {
	if ((SH_CHECKER_ONLY_DIFF == 1)); then
		echo "No shell scripts were changed."
		exit 0
	fi
	if [ -n "$INPUT_SH_CHECKER_EXCLUDE" ]; then
		if ((${#excluded[@]} == ${#sh_all[@]})); then
			printf 'All %d shell script(s) have been excluded per your sh_checker_exclude setting:\n' "${#sh_all[@]}"
			IFS=$' \t\n' printf '"%s"\n' "${excludes[@]}"
			exit 0
		fi
	fi
	echo "No shell scripts were found in this repository. Please check your settings."
	exit 0
}

# Validate sh files
shellcheck_code=0
checkbashisms_code=0
shfmt_code=0
exit_code=0
shellcheck_error='shellcheck checking is disabled.'
shfmt_error='shfmt checking is disabled.'

if ((SHELLCHECK_DISABLE != 1)); then
	printf "Validating %d shell script(s) using 'shellcheck %s':\\n" "${#sh_files[@]}" "$SHELLCHECK_OPTS"
	IFS=$' \t\n' read -d '' -ra args <<<"$SHELLCHECK_OPTS"
	shellcheck_output="$(shellcheck "${args[@]}" "${sh_files[@]}" 2>&1)"
	shellcheck_code=$?
	if ((shellcheck_code == 0)); then
		printf -v shellcheck_error "'shellcheck %s' found no issues.\\n" "$SHELLCHECK_OPTS"
	else
		# .shellcheck returns 0-4: https://github.com/koalaman/shellcheck/blob/dff8f9492a153b4ad8ac7d085136ce532e8ea081/shellcheck.hs#L191
		exit_code=$shellcheck_code
		IFS= read -r -d '' shellcheck_error <<EOF

'shellcheck $SHELLCHECK_OPTS' returned error $shellcheck_code finding the following syntactical issues:

----------
$shellcheck_output
----------

You can address the above issues in one of three ways:
1. Manually correct the issue in the offending shell script;
2. Disable specific issues by adding the comment:
  # shellcheck disable=NNNN
above the line that contains the issue, where NNNN is the error code;
3. Add '-e NNNN' to the SHELLCHECK_OPTS setting in your .yml action file.


EOF
	fi
	printf '%s' "$shellcheck_error"
fi

if ((SHFMT_DISABLE != 1)); then
	printf "Validating %d shell script(s) using 'shfmt %s':\\n" "${#sh_files[@]}" "$SHFMT_OPTS"
	IFS=$' \t\n' read -d '' -ra args <<<"$SHFMT_OPTS"
	# Error with a diff when the formatting differs
	args+=('-d')
	# Disable colorization of diff output
	export NO_COLOR=1
	shfmt_output="$(shfmt "${args[@]}" "${sh_files[@]}" 2>&1)"
	shfmt_code=$?
	if ((shfmt_code == 0)); then
		printf -v shfmt_error "'shfmt %s' found no issues.\\n" "$SHFMT_OPTS"
	else
		# shfmt returns 0 or 1: https://github.com/mvdan/sh/blob/dbbad59b44d586c0f3d044a3820c18c41b495e2a/cmd/shfmt/main.go#L72
		((exit_code |= 8))
		IFS= read -r -d '' shfmt_error <<EOF

'shfmt $SHFMT_OPTS' returned error $shfmt_code finding the following formatting issues:

----------
$shfmt_output
----------

You can reformat the above files to meet shfmt's requirements by typing:

  shfmt $SHFMT_OPTS -w filename

EOF
	fi
	printf '%s' "$shfmt_error"
fi

if ((CHECKBASHISMS_ENABLE == 1)); then
	printf '\n\nValidating %d shell script(s) files using checkbashisms:\n' "${#sh_files[@]}"
	checkbashisms "${sh_files[@]}"
	checkbashisms_code=$?
	if ((checkbashisms_code == 0)); then
		printf '\ncheckbashisms found no issues.\n'
	else
		printf '\ncheckbashisms returned error %d finding the bashisms listed above.\n' "$checkbashisms_code"
		if ((checkbashisms_code == 4)); then
			# see https://github.com/duggan/shlint/blob/0fcd979319e3f37c2cd53ccea0b51e16fda710a1/lib/checkbashisms#L489
			printf "\\nIgnoring the spurious non-issue titled 'could not find any possible bashisms in bash script'\\n"
		else
			# checkbashisms returns 0-3: https://linux.die.net/man/1/checkbashisms
			((exit_code |= (checkbashisms_code << 4)))
		fi
	fi
fi

if ((shellcheck_code != 0 || shfmt_code != 0)); then
	if [[ "$GITHUB_EVENT_NAME" == "pull_request" || "$GITHUB_EVENT_NAME" == "pull_request_target" ]] && ((SH_CHECKER_COMMENT == 1)); then
		_comment_on_github "$shellcheck_error" "$shfmt_error"
	fi
fi

if ((exit_code == 0)); then
	printf '\nNo issues found in the %d shell script(s) scanned :)\n' "${#sh_files[@]}"
fi

# shellcheck disable=SC2086
exit $exit_code


================================================
FILE: upgrade.sh
================================================
#!/usr/bin/env bash
# shellcheck disable=SC2312 # (info): Consider invoking this command separately to avoid masking its return value (or use '|| true' to ignore).

set -e

if command -v curl >/dev/null; then
  # -sq == --silent --disable
  dl="curl -sq"
else
  # -q0 == --quiet --output-document
  dl='wget --no-config -qO -'
fi

ALPINE_VER=$(${dl} 'https://registry.hub.docker.com/v2/repositories/library/alpine/tags/' | jq -r '.results[1].name')
GH_VER=$(${dl} https://api.github.com/repos/cli/cli/tags | jq -r '.[0].name')
SHELLCHECK_VER=$(${dl} https://api.github.com/repos/koalaman/shellcheck/tags | jq -r '.[0].name')
SHFMT_VER=$(${dl} https://api.github.com/repos/mvdan/sh/tags | jq -r '.[0].name')

GH_VER="${GH_VER/v/}"
SHELLCHECK_VER="${SHELLCHECK_VER/v/}"
SHFMT_VER="${SHFMT_VER/v/}"

sed -Ei "
s/^(FROM\s+alpine:).*/\1${ALPINE_VER}/;
s/^(ARG\s+gh_version=).*/\1${GH_VER}/;
s/^(ARG\s+shellcheck_version=).*/\1${SHELLCHECK_VER}/;
s/^(ARG\s+shfmt_version=).*/\1${SHFMT_VER}/;
" Dockerfile

git diff
Download .txt
gitextract_prljnb1b/

├── .github/
│   └── workflows/
│       └── ci.yml
├── Dockerfile
├── LICENSE
├── README.md
├── action.yml
├── entrypoint.sh
└── upgrade.sh
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (15K chars).
[
  {
    "path": ".github/workflows/ci.yml",
    "chars": 470,
    "preview": "---\nname: Build\n\non:\n  push:\n    branches:\n      - master\n\n  pull_request:\n    branches:\n      - master\n\n  workflow_disp"
  },
  {
    "path": "Dockerfile",
    "chars": 1200,
    "preview": "FROM alpine:3.18.4\nLABEL \"name\"=\"sh-checker\"\nLABEL \"maintainer\"=\"Luiz Muller <contact@luizm.dev>\"\n\nARG shfmt_version=3.1"
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2020 Luiz Muller\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "README.md",
    "chars": 2182,
    "preview": "# sh-checker\n\n[![Build](https://github.com/luizm/action-sh-checker/actions/workflows/ci.yml/badge.svg)](https://github.c"
  },
  {
    "path": "action.yml",
    "chars": 1062,
    "preview": "name: \"sh-checker\"\ndescription: \"Run shellcheck and/or shfmt on all shell script files and include commentaries, there i"
  },
  {
    "path": "entrypoint.sh",
    "chars": 7248,
    "preview": "#!/usr/bin/env bash\n\ncd \"$GITHUB_WORKSPACE\" || {\n\tprintf 'Directory not found: \"%s\"\\n' \"$GITHUB_WORKSPACE\"\n\texit 1\n}\n\nSH"
  },
  {
    "path": "upgrade.sh",
    "chars": 1009,
    "preview": "#!/usr/bin/env bash\n# shellcheck disable=SC2312 # (info): Consider invoking this command separately to avoid masking its"
  }
]

About this extraction

This page contains the full source code of the luizm/action-sh-checker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (13.9 KB), approximately 4.3k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!