Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: run shellcheck and shfmt on shell scripts #353490

Open
wants to merge 3 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ indent_size = 2
[*.{pl,pm,py,sh}]
indent_size = 4

# Picked up by shfmt, too.
[*.sh]
indent_style = space
indent_size = 4
shell_variant = bash
binary_next_line = true
switch_case_indent = true
space_redirects = true

# Match gemfiles, set indent to spaces with width of two
[Gemfile]
indent_size = 2
Expand Down
105 changes: 105 additions & 0 deletions .github/workflows/check-bash-scripts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# This file was copied from check-nix-format.yml for the logic to apply
# this only to those files which are already conforming on the target branch.
name: Check that shell scripts are formatted and shellcheck-ed

on:
pull_request_target:
# See the comment at the same location in ./nixpkgs-vet.yml
types: [opened, synchronize, reopened, edited]
permissions:
contents: read

jobs:
nixos:
name: shell-check
runs-on: ubuntu-latest
if: "!contains(github.event.pull_request.title, '[skip treewide]')"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge
# Fetches the merge commit and its parents
fetch-depth: 2
- name: Checking out base branch
run: |
base=$(mktemp -d)
baseRev=$(git rev-parse HEAD^1)
git worktree add "$base" "$baseRev"
echo "baseRev=$baseRev" >> "$GITHUB_ENV"
echo "base=$base" >> "$GITHUB_ENV"
- name: Get Nixpkgs revision for shellcheck and shfmt
run: |
# Pin to a commit from nixpkgs-unstable to avoid e.g. building shellcheck or shfmt
# from staging.
# This should not be a URL, because it would allow PRs to run arbitrary code in CI!
rev=$(jq -r .rev ci/pinned-nixpkgs.json)
echo "url=https://github.com/NixOS/nixpkgs/archive/$rev.tar.gz" >> "$GITHUB_ENV"
- uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
with:
# explicitly enable sandbox
extra_nix_config: sandbox = true
nix_path: nixpkgs=${{ env.url }}
- name: Install shellcheck and shfmt
run: "nix-env -f '<nixpkgs>' -iAP shellcheck shfmt"
- name: Check that shell scripts are conforming
run: |
shfmtFiles=()
shellcheckFiles=()

# TODO: Make this more parallel

# Loop through all .sh files touched by the PR
while readarray -d '' -n 2 entry && (( ${#entry[@]} != 0 )); do
type=${entry[0]}
file=${entry[1]}
case $type in
A*)
source=""
dest=$file
;;
M*)
source=$file
dest=$file
;;
C*|R*)
source=$file
read -r -d '' dest
;;
*)
echo "Ignoring file $file with type $type"
continue
esac

# Ignore files that weren't already formatted
if [[ -n "$source" ]] && ! shfmt --diff ${{ env.base }}/"$source" >/dev/null; then
echo "Ignoring file $file because it's not formatted in the base commit"
elif ! shfmt --diff "$dest"; then
shfmtFiles+=("$dest")
fi

# Ignore files that weren't already shellcheck-ed
if [[ -n "$source" ]] && ! shellcheck ${{ env.base }}/"$source" >/dev/null; then
echo "Ignoring file $file because it's not shellcheck-ed in the base commit"
elif ! shellcheck "$dest"; then
shellcheckFiles+=("$dest")
fi
done < <(git diff -z --name-status ${{ env.baseRev }} -- '*.sh')

if (( "${#shfmtFiles[@]}" > 0 )); then
echo "Some new/changed shell scripts are not properly formatted"
echo "Please go to the Nixpkgs root directory, run \`nix-shell\`, then:"
echo "shfmt -w ${shfmtFiles[*]@Q}"
echo
fi

if (( "${#shellcheckFiles[@]}" > 0 )); then
echo "Some new/changed shell scripts are not properly shellcheck-ed"
echo "Please go to the Nixpkgs root directory, run \`nix-shell\`, then:"
echo "shellcheck ${shellcheckFiles[*]@Q}"
echo
fi

if (( "${#shfmtFiles[@]}" + "${#shellcheckFiles[@]}" > 0 ))
exit 1
fi
6 changes: 3 additions & 3 deletions .github/workflows/check-shell.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "Check shell"
name: "Check shell.nix"

on:
pull_request_target:
Expand All @@ -7,7 +7,7 @@ permissions: {}

jobs:
x86_64-linux:
name: shell-check-x86_64-linux
name: shell-nix-check-x86_64-linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand All @@ -19,7 +19,7 @@ jobs:
run: nix-build shell.nix

aarch64-darwin:
name: shell-check-aarch64-darwin
name: shell-nix-check-aarch64-darwin
runs-on: macos-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand Down
8 changes: 8 additions & 0 deletions .shellcheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# supports source=pkgs/stdenv/generic/setup.sh directives
external-sources=true
source-path=pkgs/stdenv/generic
shell=bash

# Otherwise all xxxPhase=... will fail this rule:
# xxxPhase appears unused. Verify use (...).
disable=SC2034
5 changes: 4 additions & 1 deletion pkgs/build-support/rust/hooks/cargo-build-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# shellcheck shell=bash disable=SC2154,SC2164
# shellcheck source=stdenv.sh
. /dev/null

declare cargoBuildType

cargoBuildHook() {
echo "Executing cargoBuildHook"
Expand Down
5 changes: 4 additions & 1 deletion pkgs/build-support/rust/hooks/cargo-check-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# shellcheck shell=bash disable=SC2154,SC2164
# shellcheck source=stdenv.sh
. /dev/null

declare cargoCheckType

cargoCheckHook() {
echo "Executing cargoCheckHook"
Expand Down
5 changes: 4 additions & 1 deletion pkgs/build-support/rust/hooks/cargo-nextest-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# shellcheck shell=bash disable=SC2154,SC2164
# shellcheck source=stdenv.sh
. /dev/null

declare cargoCheckType

cargoNextestHook() {
echo "Executing cargoNextestHook"
Expand Down
3 changes: 2 additions & 1 deletion pkgs/build-support/rust/hooks/maturin-build-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# shellcheck shell=bash disable=SC2154,SC2164
# shellcheck source=stdenv.sh
. /dev/null

maturinBuildHook() {
echo "Executing maturinBuildHook"
Expand Down
3 changes: 3 additions & 0 deletions pkgs/build-support/rust/hooks/rust-bindgen-hook.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# shellcheck source=stdenv.sh
. /dev/null

# populates LIBCLANG_PATH and BINDGEN_EXTRA_CLANG_ARGS for rust projects that
# depend on the bindgen crate

Expand Down
10 changes: 10 additions & 0 deletions pkgs/build-support/setup-hooks/multiple-outputs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,30 @@ _overrideFirst() {
# Setup chains of sane default values with easy overridability.
# The variables are global to be usable anywhere during the build.
# Typical usage in package is defining outputBin = "dev";
# Each variable is declare'd to make shellcheck aware of it.

declare outputDev
_overrideFirst outputDev "dev" "out"
declare outputBin
_overrideFirst outputBin "bin" "out"

declare outputInclude
_overrideFirst outputInclude "$outputDev"

# so-libs are often among the main things to keep, and so go to $out
declare outputLib
_overrideFirst outputLib "lib" "out"

declare outputDoc
_overrideFirst outputDoc "doc" "out"
declare outputDevdoc
_overrideFirst outputDevdoc "devdoc" REMOVE # documentation for developers
# man and info pages are small and often useful to distribute with binaries
declare outputMan
_overrideFirst outputMan "man" "$outputBin"
declare outputDevman
_overrideFirst outputDevman "devman" "devdoc" "$outputMan"
declare outputInfo
_overrideFirst outputInfo "info" "$outputBin"


Expand Down
3 changes: 2 additions & 1 deletion pkgs/by-name/ca/cargo-tauri/hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# shellcheck shell=bash disable=SC2034,SC2154,SC2164
# shellcheck source=stdenv.sh
. /dev/null

# We replace these
export dontCargoBuild=true
Expand Down
4 changes: 2 additions & 2 deletions pkgs/development/tools/build-managers/gn/setup-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# shellcheck shell=bash
# shellcheck source=stdenv.sh
. /dev/null

gnConfigurePhase() {
runHook preConfigure
Expand All @@ -9,7 +10,6 @@ gnConfigurePhase() {
echoCmd 'gn flags' "${flagsArray[@]}"

gn gen out/Release --args="${flagsArray[*]}"
# shellcheck disable=SC2164
cd out/Release/

runHook postConfigure
Expand Down
5 changes: 2 additions & 3 deletions pkgs/kde/frameworks/extra-cmake-modules/ecm-hook.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# shellcheck shell=bash
# Variables we use here are set by the stdenv, no use complaining about them
# shellcheck disable=SC2164
# shellcheck source=stdenv.sh
. /dev/null

ecmEnvHook() {
addToSearchPath XDG_DATA_DIRS "$1/share"
Expand Down
3 changes: 2 additions & 1 deletion pkgs/os-specific/bsd/setup-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# shellcheck shell=bash disable=SC2154,SC2164
# shellcheck source=stdenv.sh
. /dev/null

# BSD makefiles should be able to detect this
# but without they end up using gcc on Darwin stdenv
Expand Down
1 change: 1 addition & 0 deletions pkgs/stdenv/generic/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ argsStdenv@{ name ? "stdenv", preHook ? "", initialPath

let
defaultNativeBuildInputs = extraNativeBuildInputs ++
# Please match this list of .sh files with those in pkgs/stdenv/generic/stdenv.sh for shellcheck.
[
../../build-support/setup-hooks/audit-tmpdir.sh
../../build-support/setup-hooks/compress-man-pages.sh
Expand Down
Loading