Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
Git Pre-Commit Hooks
Merged lorenz opened 1 year ago

Use cachix/git-hooks.nix which wraps pre-commit to manage Git pre-commit hooks.

Currently this exposes checks like cargo check, cargo clippy, shellcheck and formatting of Nix files by alejandra as a hook. This only works for Nix users and must be initialized by calling nix develop.

The resulting .pre-commit-config.yaml is currently ignored, but once we settle on a set of Git hooks that we like, we could add that file so that non-Nix users may use the same hooks via pre-commit directly.

Hooks are automatically executed by git commit, unless the --no-verify flag is passed (escape hatch) and are also part of nix flake check.

The second commit in the patch contains fixes to calm shellcheck.

17 files changed +176 -57 77386b0f 3dc9ecdb
modified .gitignore
@@ -2,3 +2,4 @@
/radicle-cli/target
/build/artifacts
/build/*.tar.gz
+
/.pre-commit-config.yaml
modified build/build
@@ -7,7 +7,8 @@ main() {
  # Set minimal locale.
  export LC_ALL=C
  # Set source date. This is honored by `asciidoctor` and other tools.
-
  export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
+
  SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)"
+
  export SOURCE_DATE_EPOCH

  if ! command -v rad > /dev/null; then
    echo "fatal: rad is not installed" >&2 ; exit 1
@@ -21,7 +22,7 @@ main() {
    echo "fatal: sha256sum is not installed" >&2 ; exit 1
  fi

-
  rev="$(git rev-parse --short HEAD)"
+
  rev="$(git rev-parse HEAD)"
  gitarchive="build/heartwood-$rev.tar.gz"
  keypath="$(rad path)/keys/radicle.pub"
  version="$(build/version)"
@@ -42,38 +43,39 @@ main() {
    --build-arg SOURCE_DATE_EPOCH \
    --build-arg TZ \
    --build-arg LC_ALL \
-
    --build-arg RADICLE_VERSION=$version \
-
    --build-arg GIT_HEAD=$rev \
-
    --arch amd64 --tag $image -f ./build/Dockerfile - < $gitarchive
+
    --build-arg "RADICLE_VERSION=$version" \
+
    --build-arg "GIT_HEAD=$rev" \
+
    --arch amd64 --tag "$image" -f ./build/Dockerfile - < "$gitarchive"

  echo "Creating container (radicle-build-container).."
-
  podman --cgroup-manager=cgroupfs create --ulimit=host --replace --name radicle-build-container $image
+
  podman --cgroup-manager=cgroupfs create --ulimit=host --replace --name radicle-build-container "$image"

  # Copy build artifacts to output folder.
  outdir=build/artifacts
  mkdir -p $outdir
  podman cp --overwrite radicle-build-container:/builds/. $outdir/

-
  for target in $(cat build/TARGETS); do
+
  while IFS= read -r target
+
  do
    echo "Signing artifacts for $target.."

    filename="radicle-$version-$target.tar.xz"
    filepath="$outdir/$filename"

    # Output SHA256 digest of archive.
-
    checksum="$(cd $outdir && sha256sum $filename)"
+
    checksum="$(cd $outdir && sha256sum "$filename")"
    echo "Checksum of $filepath is $(echo "$checksum" | cut -d' ' -f1)"
-
    echo "$checksum" > $filepath.sha256
+
    echo "$checksum" > "${filepath}.sha256"

    # Sign archive and verify archive.
-
    rm -f $filepath.sig # Delete existing signature
-
    ssh-keygen -Y sign -n file -f $keypath $filepath
-
    ssh-keygen -Y check-novalidate -n file -s $filepath.sig < $filepath
-
  done
+
    rm -f "${filepath}.sig" # Delete existing signature
+
    ssh-keygen -Y sign -n file -f "$keypath" "$filepath"
+
    ssh-keygen -Y check-novalidate -n file -s "$filepath.sig" < "$filepath"
+
  done < build/TARGETS

  # Remove build artifacts that aren't needed anymore.
  podman rm radicle-build-container > /dev/null
-
  podman rmi --ignore localhost/$image
+
  podman rmi --ignore "localhost/$image"
}

# Run build.
modified build/release
@@ -23,12 +23,12 @@ main() {
  fi

  printf "Releasing Radicle %s? [y/N] " "$version"
-
  read confirmation
+
  read -r confirmation

  case "$confirmation" in
    [Yy]*)
      echo "Creating 'latest' symlink.."
-
      ssh -i "$SSH_KEY" "$SSH_ADDRESS" ln -snf /mnt/radicle/files/releases/$version /mnt/radicle/files/releases/latest ;;
+
      ssh -i "$SSH_KEY" "$SSH_ADDRESS" ln -snf "/mnt/radicle/files/releases/$version" /mnt/radicle/files/releases/latest ;;
    *)
      echo "Operation aborted."
      exit 1 ;;
modified build/tag
@@ -19,8 +19,8 @@ if [ "$signing_key" != "$(rad self --ssh-key)" ]; then
fi

printf "\n"
-
printf "Tag the above commit with \033[35m$tag\033[0m, using \033[35m$(rad self --did)\033[0m? [y/N] "
-
read confirmation
+
printf "Tag the above commit with \033[35m%s\033[0m, using \033[35m$(rad self --did)\033[0m? [y/N] " "$tag"
+
read -r confirmation
rad auth

case "$confirmation" in
modified build/upload
@@ -17,22 +17,23 @@ main() {
  destination="/mnt/radicle/files/releases/$version"

  # Create remote folder.
-
  ssh -i $SSH_KEY $SSH_ADDRESS mkdir -p $destination
+
  ssh -i "$SSH_KEY" "$SSH_ADDRESS" mkdir -p "$destination"
  # Copy files over.
-
  scp -i $SSH_KEY build/artifacts/radicle-$version* $SSH_ADDRESS:$destination
-
  scp -i $SSH_KEY build/artifacts/radicle.json $SSH_ADDRESS:$destination
-
  scp -i $SSH_KEY build/heartwood-$version.tar.gz $SSH_ADDRESS:$destination
+
  scp -i "$SSH_KEY" "build/artifacts/radicle-$version"* "$SSH_ADDRESS:$destination"
+
  scp -i "$SSH_KEY" build/artifacts/radicle.json "$SSH_ADDRESS:$destination"
+
  scp -i "$SSH_KEY" "build/heartwood-$version.tar.gz" "$SSH_ADDRESS:$destination"

-
  for target in $(cat build/TARGETS); do
+
  while IFS= read -r target
+
  do
    archive=$destination/radicle-$version-$target.tar.xz
    symlink=$destination/radicle-$target.tar.xz

    echo "Creating symlinks for $target.."

-
    ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive $symlink
-
    ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive.sig $symlink.sig
-
    ssh -i $SSH_KEY $SSH_ADDRESS ln -snf $archive.sha256 $symlink.sha256
-
  done
+
    ssh -i "$SSH_KEY" "$SSH_ADDRESS" ln -snf "$archive" "$symlink"
+
    ssh -i "$SSH_KEY" "$SSH_ADDRESS" ln -snf "$archive.sig" "$symlink.sig"
+
    ssh -i "$SSH_KEY" "$SSH_ADDRESS" ln -snf "$archive.sha256" "$symlink.sha256"
+
  done < build/TARGETS

  # TODO(cloudhead): Don't pass `--tags` when we have canonical refs.
  echo "Pushing tags.."
modified build/version
@@ -6,4 +6,4 @@ fi
# Remove `v` prefix from version.
version=${version#v}

-
echo $version
+
echo "$version"
modified debian/build-deb
@@ -10,6 +10,7 @@ name="$(dpkg-parsechangelog -SSource)"
version="$(dpkg-parsechangelog -SVersion)"

# Get upstream version: everything before the last dash.
+
# shellcheck disable=SC2001
uv="$(echo "$version" | sed 's/-[^-]*$//')"
orig="${name}_${uv}.orig.tar.xz"

modified flake.lock
@@ -31,6 +31,22 @@
        "type": "github"
      }
    },
+
    "flake-compat": {
+
      "flake": false,
+
      "locked": {
+
        "lastModified": 1696426674,
+
        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+
        "owner": "edolstra",
+
        "repo": "flake-compat",
+
        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+
        "type": "github"
+
      },
+
      "original": {
+
        "owner": "edolstra",
+
        "repo": "flake-compat",
+
        "type": "github"
+
      }
+
    },
    "flake-utils": {
      "inputs": {
        "systems": "systems"
@@ -49,7 +65,44 @@
        "type": "github"
      }
    },
-
    "nixpkgs": {
+
    "gitignore": {
+
      "inputs": {
+
        "nixpkgs": [
+
          "pre-commit-hooks",
+
          "nixpkgs"
+
        ]
+
      },
+
      "locked": {
+
        "lastModified": 1709087332,
+
        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+
        "owner": "hercules-ci",
+
        "repo": "gitignore.nix",
+
        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+
        "type": "github"
+
      },
+
      "original": {
+
        "owner": "hercules-ci",
+
        "repo": "gitignore.nix",
+
        "type": "github"
+
      }
+
    },
+
    "nixpkgs-stable": {
+
      "locked": {
+
        "lastModified": 1740142985,
+
        "narHash": "sha256-fCPt2PVnQgiHXGlTRmU5/gFdG/+JT3ycpt+GxY1Vp+s=",
+
        "owner": "NixOS",
+
        "repo": "nixpkgs",
+
        "rev": "1d1ce35bb6052a23f5692cd89b7cc49acdcb8d0e",
+
        "type": "github"
+
      },
+
      "original": {
+
        "owner": "NixOS",
+
        "ref": "release-24.11",
+
        "repo": "nixpkgs",
+
        "type": "github"
+
      }
+
    },
+
    "nixpkgs-unstable": {
      "locked": {
        "lastModified": 1740142985,
        "narHash": "sha256-fCPt2PVnQgiHXGlTRmU5/gFdG/+JT3ycpt+GxY1Vp+s=",
@@ -65,12 +118,39 @@
        "type": "github"
      }
    },
+
    "pre-commit-hooks": {
+
      "inputs": {
+
        "flake-compat": "flake-compat",
+
        "gitignore": "gitignore",
+
        "nixpkgs": [
+
          "nixpkgs"
+
        ]
+
      },
+
      "locked": {
+
        "lastModified": 1742649964,
+
        "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
+
        "owner": "cachix",
+
        "repo": "git-hooks.nix",
+
        "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
+
        "type": "github"
+
      },
+
      "original": {
+
        "owner": "cachix",
+
        "repo": "git-hooks.nix",
+
        "type": "github"
+
      }
+
    },
    "root": {
      "inputs": {
        "advisory-db": "advisory-db",
        "crane": "crane",
        "flake-utils": "flake-utils",
-
        "nixpkgs": "nixpkgs",
+
        "nixpkgs": [
+
          "nixpkgs-stable"
+
        ],
+
        "nixpkgs-stable": "nixpkgs-stable",
+
        "nixpkgs-unstable": "nixpkgs-unstable",
+
        "pre-commit-hooks": "pre-commit-hooks",
        "rust-overlay": "rust-overlay"
      }
    },
modified flake.nix
@@ -2,17 +2,24 @@
  description = "Radicle";

  inputs = {
-
    nixpkgs.url = "github:NixOS/nixpkgs/release-24.11";
+
    # This looks redundant, but actually is nice.
+
    # Allows to model "stable" vs. "unstable" vs. "don't care".
+
    # Don't forget to also adjust the URL for home-manager below
+
    # accordingly.
+
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/release-24.11";
+
    nixpkgs-stable.url = "github:NixOS/nixpkgs/release-24.11";
+
    nixpkgs.follows = "nixpkgs-stable";

-
    crane = {
-
      url = "github:ipetkov/crane";
+
    crane.url = "github:ipetkov/crane";
+

+
    pre-commit-hooks = {
+
      url = "github:cachix/git-hooks.nix";
+
      inputs.nixpkgs.follows = "nixpkgs";
    };

    rust-overlay = {
      url = "github:oxalica/rust-overlay";
-
      inputs = {
-
        nixpkgs.follows = "nixpkgs";
-
      };
+
      inputs.nixpkgs.follows = "nixpkgs";
    };

    flake-utils.url = "github:numtide/flake-utils";
@@ -35,7 +42,7 @@
    advisory-db,
    rust-overlay,
    ...
-
  }:
+
  } @ inputs:
    flake-utils.lib.eachDefaultSystem (system: let
      lib = nixpkgs.lib;
      pkgs = import nixpkgs {
@@ -43,8 +50,8 @@
        overlays = [(import rust-overlay)];
      };

-
      rustToolChain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
-
      craneLib = (crane.mkLib pkgs).overrideToolchain rustToolChain;
+
      rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
+
      craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;

      srcFilters = path: type:
        builtins.any (suffix: lib.hasSuffix suffix path) [
@@ -105,6 +112,23 @@

      # Set of checks that are run: `nix flake check`
      checks = {
+
        pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
+
          src = ./.;
+
          settings.rust.check.cargoDeps = pkgs.rustPlatform.importCargoLock {lockFile = ./Cargo.lock;};
+
          hooks = {
+
            alejandra.enable = true;
+
            rustfmt.enable = true;
+
            cargo-check.enable = true;
+
            clippy = {
+
              enable = true;
+
              settings.denyWarnings = true;
+
              packageOverrides.cargo = rustToolchain;
+
              packageOverrides.clippy = rustToolchain;
+
            };
+
            shellcheck.enable = true;
+
          };
+
        };
+

        # Build the crate as part of `nix flake check` for convenience
        inherit (self.packages.${system}) radicle;

@@ -230,6 +254,9 @@
      };

      devShells.default = craneLib.devShell {
+
        inherit (self.checks.${system}.pre-commit-check) shellHook;
+
        buildInputs = self.checks.${system}.pre-commit-check.enabledPackages;
+

        # Extra inputs can be added here; cargo and rustc are provided by default.
        packages = with pkgs; [
          cargo-audit
@@ -241,7 +268,7 @@
          sqlite
        ];

-
        env.RUST_SRC_PATH = "${rustToolChain}/lib/rustlib/src/rust/library";
+
        env.RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library";
      };
    });
}
modified scripts/changelog
@@ -24,7 +24,7 @@ done

# Current/latest tag.
current=$(git describe --tags --match='v*' --abbrev=0)
-
version=$(echo $current | sed 's/^v//')
+
version=$(echo "$current" | sed 's/^v//')

if [ -z "$from" ]; then
  previous="$(git describe --abbrev=0 HEAD^)"
@@ -53,14 +53,16 @@ echo "* This update is recommended for everyone. No manual intervention is requi
echo
echo "## Changelog"

-
ncommits=$(git rev-list --count $previous..$current)
-
ncontribs=$(git log $previous..$current --format='%ae' | sort -u | wc -l)
+
range="${previous}..${current}"
+
ncommits=$(git rev-list --count "$range")
+
ncontribs=$(git log "$range" --format='%ae' | sort -u | wc -l)

echo
echo "This release contains $ncommits commit(s) by $ncontribs contributor(s)."
echo

-
git log --pretty=format:'* `%h` **%s** *<%ae>*' $previous..$current
+
# shellcheck disable=SC2016
+
git log --pretty=format:'* `%h` **%s** *<%ae>*' "$range"

echo
echo "## Checksums"
modified scripts/clear-refs-db.sh
@@ -5,8 +5,8 @@ DB="$(rad path)/node/node.db"

if command -v sqlite3 >/dev/null 2>&1; then
  if [ -f "$DB" ]; then
-
    echo -n "Clearing 'refs' table from $DB.. "
-
    sqlite3 $DB "DELETE FROM refs;"
+
    printf "Clearing 'refs' table from %s.. " "$DB"
+
    sqlite3 "$DB" "DELETE FROM refs;"
    echo "done."
  else
    echo "fatal: database file does not exist"
modified scripts/create-env.sh
@@ -6,12 +6,12 @@ unset SSH_AGENT_PID

tmp="$(mktemp -d)"

-
export RAD_HOME=$tmp/.radicle
+
export RAD_HOME="$tmp/.radicle"
export RAD_PASSPHRASE=

set -x
-
mkdir $tmp/acme
-
cd $tmp/acme
+
mkdir "$tmp/acme"
+
cd "$tmp/acme"
echo "ACME" > README
echo "Copyright (c) 1978-1986 ACME Corp." > COPY

modified scripts/delete-remote-branches.sh
@@ -20,7 +20,7 @@ for branch in $(git branch -r --format "%(refname:short)"); do
  # Extract the branch name without the "$remote/" prefix.
  branch=${branch#"$remote/"}
  # Never delete the master branch.
-
  if [ "$branch" == "master" ]; then
+
  if [ "$branch" = "master" ]; then
    continue
  fi

modified scripts/delete-remote-refs.sh
@@ -16,14 +16,14 @@ if [ "$REMOTE" = "$(rad self --nid)" ]; then
  exit 1
fi

-
cd $RAD_HOME/storage/$REPO
+
cd "$RAD_HOME/storage/$REPO"

refs=$(git for-each-ref --format="%(refname)")
pattern="refs/namespaces/$2/refs/*"

for ref in $refs; do
  case "$ref" in
-
    $pattern)
+
    "$pattern" )
      git update-ref -d "$ref"
      printf 'Deleted %s\n' "$ref"
      ;;
modified scripts/import-issue.sh
@@ -25,9 +25,12 @@ if ! command -v sed > /dev/null; then
fi

function removeImgTags {
-
  local html="$(cat)"
-
  local imgTags="$(echo "$html" | pcregrep -M '<img [^>]*>')"
+
  local html
+
  html="$(cat)"
+
  local imgTags
+
  imgTags="$(echo "$html" | pcregrep -M '<img [^>]*>')"

+
  # shellcheck disable=SC2066
  for imgTag in "$imgTags"; do
    html="$(echo "$html" | sed -z "s@$imgTag@@")"
  done
modified scripts/patch-rebase.sh
@@ -6,7 +6,7 @@ if [ "$#" -lt 1 ]; then
  exit 1
fi

-
rad patch checkout $1
+
rad patch checkout "$1"
git rebase master --autosquash
-
rad patch update $1 --message "Rebased on master"
+
rad patch update "$1" --message "Rebased on master"
git checkout master
modified scripts/show-sigrefs.sh
@@ -7,16 +7,18 @@ if [ "$#" -lt 2 ]; then
fi

RAD_HOME=${RAD_HOME:-"$HOME/.radicle"}
+
# shellcheck disable=SC2001
REPO=$(echo "$1" | sed 's/^rad://')
REMOTE=$2

-
cd $RAD_HOME/storage/$REPO
+
cd "$RAD_HOME/storage/$REPO"

sigrefs=$(git rev-parse "refs/namespaces/$REMOTE/refs/rad/sigrefs")
signed=$(git show "$sigrefs:refs")
actual=$(git for-each-ref "refs/namespaces/$REMOTE/refs/**" --format="%(objectname) %(refname)")

# Strip namespace prefix.
+
# shellcheck disable=SC2001
actual=$(echo "$actual" | sed "s@refs/namespaces/$REMOTE/@@")
# Remove `sigrefs` itself.
actual=$(echo "$actual" | grep -v "refs/rad/sigrefs$")