Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71c7fe09cd | ||
|
|
45f3830794 | ||
|
|
b8d0a69d4d | ||
|
|
c5f8ee6005 | ||
|
|
9983f0b8e9 | ||
|
|
0d339e2de0 | ||
|
|
7dcb0d1b3a | ||
|
|
f8658265ae | ||
|
|
c42899c89e | ||
|
|
00fb6ef297 | ||
|
|
dc475afcd1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
lefthook.yml
|
||||||
.direnv
|
.direnv
|
||||||
result
|
result
|
||||||
template/flake.lock
|
template/flake.lock
|
||||||
32
README.md
32
README.md
@@ -15,7 +15,7 @@
|
|||||||
## Use the template
|
## Use the template
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix flake new myapp -t 'git+https://git.dgren.dev/eric/nix-flake-lib?ref=v3.0.0#default' --refresh
|
nix flake new myapp -t 'git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.4.0#default' --refresh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Use the library
|
## Use the library
|
||||||
@@ -23,7 +23,7 @@ nix flake new myapp -t 'git+https://git.dgren.dev/eric/nix-flake-lib?ref=v3.0.0#
|
|||||||
Add this flake input:
|
Add this flake input:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
inputs.repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=v3.0.0";
|
inputs.repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.4.0";
|
||||||
inputs.repo-lib.inputs.nixpkgs.follows = "nixpkgs";
|
inputs.repo-lib.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ outputs = { self, nixpkgs, repo-lib, ... }:
|
|||||||
|
|
||||||
perSystem = { pkgs, system, ... }: {
|
perSystem = { pkgs, system, ... }: {
|
||||||
tools = [
|
tools = [
|
||||||
(repo-lib.lib.tools.fromPackage {
|
(repo-lib.lib.tools.fromCommand {
|
||||||
name = "Nix";
|
name = "Nix";
|
||||||
package = pkgs.nix;
|
|
||||||
version.args = [ "--version" ];
|
version.args = [ "--version" ];
|
||||||
|
command = "nix";
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -66,14 +66,24 @@ outputs = { self, nixpkgs, repo-lib, ... }:
|
|||||||
`mkRepo` generates:
|
`mkRepo` generates:
|
||||||
|
|
||||||
- `devShells.${system}.default`
|
- `devShells.${system}.default`
|
||||||
- `checks.${system}.pre-commit-check`
|
- `checks.${system}.hook-check`
|
||||||
|
- `checks.${system}.lefthook-check`
|
||||||
- `formatter.${system}`
|
- `formatter.${system}`
|
||||||
- `packages.${system}.release` when `config.release != null`
|
- `packages.${system}.release` when `config.release != null`
|
||||||
- merged `packages` and `apps` from `perSystem`
|
- merged `packages` and `apps` from `perSystem`
|
||||||
|
|
||||||
|
Checks are installed through `lefthook`, with `pre-commit` and `pre-push` commands configured to run in parallel.
|
||||||
|
repo-lib also sets Lefthook `output = [ "failure" "summary" ]` by default.
|
||||||
|
|
||||||
|
For advanced Lefthook features, use raw `config.lefthook` or `perSystem.lefthook`. Those attrsets are merged after generated checks, so you can augment a generated command with fields that the simple `checks` abstraction does not carry, such as `stage_fixed`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config.lefthook.pre-push.commands.tests.stage_fixed = true;
|
||||||
|
```
|
||||||
|
|
||||||
## Tool banners
|
## Tool banners
|
||||||
|
|
||||||
Tools are declared once, from packages. They are added to the shell automatically and rendered in the startup banner.
|
Tools are declared once. Package-backed tools are added to the shell automatically, and both package-backed and command-backed tools are rendered in the startup banner.
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
(repo-lib.lib.tools.fromPackage {
|
(repo-lib.lib.tools.fromPackage {
|
||||||
@@ -86,6 +96,16 @@ Tools are declared once, from packages. They are added to the shell automaticall
|
|||||||
|
|
||||||
Required tools fail shell startup if their version probe fails. This keeps banner output honest instead of silently hiding misconfiguration.
|
Required tools fail shell startup if their version probe fails. This keeps banner output honest instead of silently hiding misconfiguration.
|
||||||
|
|
||||||
|
When a tool should come from the host environment instead of `nixpkgs`, use `fromCommand`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
(repo-lib.lib.tools.fromCommand {
|
||||||
|
name = "Nix";
|
||||||
|
command = "nix";
|
||||||
|
version.args = [ "--version" ];
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Purity model
|
## Purity model
|
||||||
|
|
||||||
The default path is pure: declare tools and packages in Nix, then let `mkRepo` assemble the shell.
|
The default path is pure: declare tools and packages in Nix, then let `mkRepo` assemble the shell.
|
||||||
|
|||||||
77
flake.lock
generated
77
flake.lock
generated
@@ -1,79 +1,26 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"flake-compat": {
|
"lefthook-nix": {
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1767039857,
|
|
||||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"git-hooks": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"gitignore": "gitignore",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1772024342,
|
|
||||||
"narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "git-hooks.nix",
|
|
||||||
"rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "git-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gitignore": {
|
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"git-hooks",
|
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1709087332,
|
"lastModified": 1770377107,
|
||||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
"narHash": "sha256-/QEXSDeAo5RK81PtM0yDhmt9k3v1/pse/jsrT1yXNhU=",
|
||||||
"owner": "hercules-ci",
|
"owner": "sudosubin",
|
||||||
"repo": "gitignore.nix",
|
"repo": "lefthook.nix",
|
||||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
"rev": "9cdaf7ce95ae77cbabc5b556bdd35d3cf0b849f5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "hercules-ci",
|
"owner": "sudosubin",
|
||||||
"repo": "gitignore.nix",
|
"repo": "lefthook.nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1770073757,
|
|
||||||
"narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "47472570b1e607482890801aeaf29bfb749884f6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1772542754,
|
"lastModified": 1772542754,
|
||||||
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=",
|
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=",
|
||||||
@@ -89,7 +36,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1770107345,
|
"lastModified": 1770107345,
|
||||||
"narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=",
|
"narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=",
|
||||||
@@ -107,14 +54,14 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"git-hooks": "git-hooks",
|
"lefthook-nix": "lefthook-nix",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs",
|
||||||
"treefmt-nix": "treefmt-nix"
|
"treefmt-nix": "treefmt-nix"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_3"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1770228511,
|
"lastModified": 1770228511,
|
||||||
|
|||||||
30
flake.nix
30
flake.nix
@@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
git-hooks.url = "github:cachix/git-hooks.nix";
|
lefthook-nix.url = "github:sudosubin/lefthook.nix";
|
||||||
|
lefthook-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -13,13 +14,14 @@
|
|||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
treefmt-nix,
|
treefmt-nix,
|
||||||
git-hooks,
|
lefthook-nix,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
lib = nixpkgs.lib;
|
lib = nixpkgs.lib;
|
||||||
repoLib = import ./packages/repo-lib/lib.nix {
|
repoLib = import ./packages/repo-lib/lib.nix {
|
||||||
inherit nixpkgs treefmt-nix git-hooks;
|
inherit nixpkgs treefmt-nix;
|
||||||
|
lefthookNix = lefthook-nix;
|
||||||
releaseScriptPath = ./packages/release/release.sh;
|
releaseScriptPath = ./packages/release/release.sh;
|
||||||
shellHookTemplatePath = ./packages/repo-lib/shell-hook.sh;
|
shellHookTemplatePath = ./packages/repo-lib/shell-hook.sh;
|
||||||
};
|
};
|
||||||
@@ -36,21 +38,21 @@
|
|||||||
replace = {
|
replace = {
|
||||||
path = "template/flake.nix";
|
path = "template/flake.nix";
|
||||||
regex = ''^([[:space:]]*repo-lib\.url = ")git\+https://git\.dgren\.dev/eric/nix-flake-lib[^"]*(";)'';
|
regex = ''^([[:space:]]*repo-lib\.url = ")git\+https://git\.dgren\.dev/eric/nix-flake-lib[^"]*(";)'';
|
||||||
replacement = ''\1git+https://git.dgren.dev/eric/nix-flake-lib?ref=$FULL_TAG\2'';
|
replacement = ''\1git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/$FULL_TAG\2'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
replace = {
|
replace = {
|
||||||
path = "README.md";
|
path = "README.md";
|
||||||
regex = ''(nix flake new myapp -t ')git\+https://git\.dgren\.dev/eric/nix-flake-lib[^']*(#default' --refresh)'';
|
regex = ''(nix flake new myapp -t ')git\+https://git\.dgren\.dev/eric/nix-flake-lib[^']*(#default' --refresh)'';
|
||||||
replacement = ''\1git+https://git.dgren.dev/eric/nix-flake-lib?ref=$FULL_TAG\2'';
|
replacement = ''\1git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/$FULL_TAG\2'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
replace = {
|
replace = {
|
||||||
path = "README.md";
|
path = "README.md";
|
||||||
regex = ''^([[:space:]]*inputs\.repo-lib\.url = ")git\+https://git\.dgren\.dev/eric/nix-flake-lib[^"]*(";)'';
|
regex = ''^([[:space:]]*inputs\.repo-lib\.url = ")git\+https://git\.dgren\.dev/eric/nix-flake-lib[^"]*(";)'';
|
||||||
replacement = ''\1git+https://git.dgren.dev/eric/nix-flake-lib?ref=$FULL_TAG\2'';
|
replacement = ''\1git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/$FULL_TAG\2'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -64,10 +66,17 @@
|
|||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
tools = [
|
tools = [
|
||||||
(repoLib.tools.fromPackage {
|
(repoLib.tools.fromCommand {
|
||||||
name = "Nix";
|
name = "Nix";
|
||||||
package = pkgs.nix;
|
command = "nix";
|
||||||
version.args = [ "--version" ];
|
version = {
|
||||||
|
args = [ "--version" ];
|
||||||
|
group = 1;
|
||||||
|
};
|
||||||
|
banner = {
|
||||||
|
color = "BLUE";
|
||||||
|
icon = "";
|
||||||
|
};
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -87,10 +96,10 @@
|
|||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
bash
|
bash
|
||||||
git
|
git
|
||||||
|
nix
|
||||||
gnused
|
gnused
|
||||||
coreutils
|
coreutils
|
||||||
gnugrep
|
gnugrep
|
||||||
nix
|
|
||||||
perl
|
perl
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -98,7 +107,6 @@
|
|||||||
export REPO_LIB_ROOT=${./.}
|
export REPO_LIB_ROOT=${./.}
|
||||||
export NIXPKGS_FLAKE_PATH=${nixpkgs}
|
export NIXPKGS_FLAKE_PATH=${nixpkgs}
|
||||||
export HOME="$TMPDIR"
|
export HOME="$TMPDIR"
|
||||||
export NIX_CONFIG="experimental-features = nix-command flakes"
|
|
||||||
${pkgs.bash}/bin/bash ${./tests/release.sh}
|
${pkgs.bash}/bin/bash ${./tests/release.sh}
|
||||||
touch "$out"
|
touch "$out"
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
treefmt-nix,
|
treefmt-nix,
|
||||||
git-hooks,
|
lefthookNix,
|
||||||
releaseScriptPath ? ./release.sh,
|
releaseScriptPath ? ./release.sh,
|
||||||
shellHookTemplatePath ? ../repo-lib/shell-hook.sh,
|
shellHookTemplatePath ? ../repo-lib/shell-hook.sh,
|
||||||
}:
|
}:
|
||||||
@@ -9,7 +9,7 @@ import ../repo-lib/lib.nix {
|
|||||||
inherit
|
inherit
|
||||||
nixpkgs
|
nixpkgs
|
||||||
treefmt-nix
|
treefmt-nix
|
||||||
git-hooks
|
lefthookNix
|
||||||
releaseScriptPath
|
releaseScriptPath
|
||||||
shellHookTemplatePath
|
shellHookTemplatePath
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ ROOT_DIR="$(git rev-parse --show-toplevel)"
|
|||||||
GITLINT_FILE="$ROOT_DIR/.gitlint"
|
GITLINT_FILE="$ROOT_DIR/.gitlint"
|
||||||
START_HEAD=""
|
START_HEAD=""
|
||||||
CREATED_TAG=""
|
CREATED_TAG=""
|
||||||
|
VERSION_META_LINES=()
|
||||||
|
VERSION_META_EXPORT_NAMES=()
|
||||||
|
|
||||||
# ── logging ────────────────────────────────────────────────────────────────
|
# ── logging ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -168,6 +170,119 @@ compute_full_version() {
|
|||||||
export BASE_VERSION CHANNEL PRERELEASE_NUM FULL_VERSION FULL_TAG
|
export BASE_VERSION CHANNEL PRERELEASE_NUM FULL_VERSION FULL_TAG
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta_env_name() {
|
||||||
|
local key="$1"
|
||||||
|
key="${key//[^[:alnum:]]/_}"
|
||||||
|
key="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
|
||||||
|
printf 'VERSION_META_%s\n' "$key"
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_version_meta_exports() {
|
||||||
|
local export_name
|
||||||
|
for export_name in "${VERSION_META_EXPORT_NAMES[@]:-}"; do
|
||||||
|
unset "$export_name"
|
||||||
|
done
|
||||||
|
VERSION_META_EXPORT_NAMES=()
|
||||||
|
}
|
||||||
|
|
||||||
|
load_version_metadata() {
|
||||||
|
VERSION_META_LINES=()
|
||||||
|
[[ ! -f "$ROOT_DIR/VERSION" ]] && return 0
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n $line ]]; do
|
||||||
|
VERSION_META_LINES+=("$line")
|
||||||
|
done < <(tail -n +4 "$ROOT_DIR/VERSION" 2>/dev/null || true)
|
||||||
|
}
|
||||||
|
|
||||||
|
export_version_metadata() {
|
||||||
|
clear_version_meta_exports
|
||||||
|
|
||||||
|
local line key value export_name
|
||||||
|
for line in "${VERSION_META_LINES[@]:-}"; do
|
||||||
|
[[ $line != *=* ]] && continue
|
||||||
|
key="${line%%=*}"
|
||||||
|
value="${line#*=}"
|
||||||
|
[[ -z $key ]] && continue
|
||||||
|
export_name="$(meta_env_name "$key")"
|
||||||
|
printf -v "$export_name" '%s' "$value"
|
||||||
|
export "${export_name?}=$value"
|
||||||
|
VERSION_META_EXPORT_NAMES+=("$export_name")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
write_version_file() {
|
||||||
|
local channel_to_write="$1"
|
||||||
|
local n_to_write="$2"
|
||||||
|
{
|
||||||
|
printf '%s\n%s\n%s\n' "$BASE_VERSION" "$channel_to_write" "$n_to_write"
|
||||||
|
local line
|
||||||
|
for line in "${VERSION_META_LINES[@]:-}"; do
|
||||||
|
printf '%s\n' "$line"
|
||||||
|
done
|
||||||
|
} >"$ROOT_DIR/VERSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
version_meta_get() {
|
||||||
|
local key="${1-}"
|
||||||
|
local line
|
||||||
|
for line in "${VERSION_META_LINES[@]:-}"; do
|
||||||
|
if [[ $line == "$key="* ]]; then
|
||||||
|
printf '%s\n' "${line#*=}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
version_meta_set() {
|
||||||
|
local key="${1-}"
|
||||||
|
local value="${2-}"
|
||||||
|
[[ -z $key ]] && echo "Error: version_meta_set requires a key" >&2 && exit 1
|
||||||
|
|
||||||
|
local updated=0
|
||||||
|
local index
|
||||||
|
for index in "${!VERSION_META_LINES[@]}"; do
|
||||||
|
if [[ ${VERSION_META_LINES[index]} == "$key="* ]]; then
|
||||||
|
VERSION_META_LINES[index]="$key=$value"
|
||||||
|
updated=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $updated -eq 0 ]]; then
|
||||||
|
VERSION_META_LINES+=("$key=$value")
|
||||||
|
fi
|
||||||
|
|
||||||
|
export_version_metadata
|
||||||
|
version_meta_write
|
||||||
|
}
|
||||||
|
|
||||||
|
version_meta_unset() {
|
||||||
|
local key="${1-}"
|
||||||
|
[[ -z $key ]] && echo "Error: version_meta_unset requires a key" >&2 && exit 1
|
||||||
|
|
||||||
|
local filtered=()
|
||||||
|
local line
|
||||||
|
for line in "${VERSION_META_LINES[@]:-}"; do
|
||||||
|
[[ $line == "$key="* ]] && continue
|
||||||
|
filtered+=("$line")
|
||||||
|
done
|
||||||
|
VERSION_META_LINES=("${filtered[@]}")
|
||||||
|
|
||||||
|
export_version_metadata
|
||||||
|
version_meta_write
|
||||||
|
}
|
||||||
|
|
||||||
|
version_meta_write() {
|
||||||
|
local channel_to_write="$CHANNEL"
|
||||||
|
local n_to_write="${PRERELEASE_NUM:-1}"
|
||||||
|
if [[ $channel_to_write == "stable" || -z $channel_to_write ]]; then
|
||||||
|
channel_to_write="stable"
|
||||||
|
n_to_write="0"
|
||||||
|
fi
|
||||||
|
write_version_file "$channel_to_write" "$n_to_write"
|
||||||
|
}
|
||||||
|
|
||||||
# ── gitlint ────────────────────────────────────────────────────────────────
|
# ── gitlint ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
get_gitlint_title_regex() {
|
get_gitlint_title_regex() {
|
||||||
@@ -205,6 +320,8 @@ run_release_steps() {
|
|||||||
# and never contaminates the stdout of do_read_version.
|
# and never contaminates the stdout of do_read_version.
|
||||||
init_version_file() {
|
init_version_file() {
|
||||||
if [[ -f "$ROOT_DIR/VERSION" ]]; then
|
if [[ -f "$ROOT_DIR/VERSION" ]]; then
|
||||||
|
load_version_metadata
|
||||||
|
export_version_metadata
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -233,11 +350,16 @@ init_version_file() {
|
|||||||
n_to_write="0"
|
n_to_write="0"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s\n%s\n%s\n' "$BASE_VERSION" "$channel_to_write" "$n_to_write" >"$ROOT_DIR/VERSION"
|
VERSION_META_LINES=()
|
||||||
|
write_version_file "$channel_to_write" "$n_to_write"
|
||||||
|
export_version_metadata
|
||||||
log "Initialized $ROOT_DIR/VERSION from highest tag: v$highest_tag"
|
log "Initialized $ROOT_DIR/VERSION from highest tag: v$highest_tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
do_read_version() {
|
do_read_version() {
|
||||||
|
load_version_metadata
|
||||||
|
export_version_metadata
|
||||||
|
|
||||||
local base_line channel_line n_line
|
local base_line channel_line n_line
|
||||||
base_line="$(sed -n '1p' "$ROOT_DIR/VERSION" | tr -d '\r')"
|
base_line="$(sed -n '1p' "$ROOT_DIR/VERSION" | tr -d '\r')"
|
||||||
channel_line="$(sed -n '2p' "$ROOT_DIR/VERSION" | tr -d '\r')"
|
channel_line="$(sed -n '2p' "$ROOT_DIR/VERSION" | tr -d '\r')"
|
||||||
@@ -257,7 +379,8 @@ do_write_version() {
|
|||||||
channel_to_write="stable"
|
channel_to_write="stable"
|
||||||
n_to_write="0"
|
n_to_write="0"
|
||||||
fi
|
fi
|
||||||
printf '%s\n%s\n%s\n' "$BASE_VERSION" "$channel_to_write" "$n_to_write" >"$ROOT_DIR/VERSION"
|
write_version_file "$channel_to_write" "$n_to_write"
|
||||||
|
export_version_metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── user-provided hook ─────────────────────────────────────────────────────
|
# ── user-provided hook ─────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
treefmt-nix,
|
treefmt-nix,
|
||||||
git-hooks,
|
lefthookNix,
|
||||||
releaseScriptPath,
|
releaseScriptPath,
|
||||||
shellHookTemplatePath,
|
shellHookTemplatePath,
|
||||||
}:
|
}:
|
||||||
@@ -44,11 +44,37 @@ let
|
|||||||
|
|
||||||
sanitizeName = name: lib.strings.sanitizeDerivationName name;
|
sanitizeName = name: lib.strings.sanitizeDerivationName name;
|
||||||
|
|
||||||
|
defaultShellBanner = {
|
||||||
|
style = "simple";
|
||||||
|
icon = "🚀";
|
||||||
|
title = "Dev shell ready";
|
||||||
|
titleColor = "GREEN";
|
||||||
|
subtitle = "";
|
||||||
|
subtitleColor = "GRAY";
|
||||||
|
borderColor = "BLUE";
|
||||||
|
};
|
||||||
|
|
||||||
|
normalizeShellBanner =
|
||||||
|
rawBanner:
|
||||||
|
let
|
||||||
|
banner = defaultShellBanner // rawBanner;
|
||||||
|
in
|
||||||
|
if
|
||||||
|
!(builtins.elem banner.style [
|
||||||
|
"simple"
|
||||||
|
"pretty"
|
||||||
|
])
|
||||||
|
then
|
||||||
|
throw "repo-lib: config.shell.banner.style must be one of simple or pretty"
|
||||||
|
else
|
||||||
|
banner;
|
||||||
|
|
||||||
normalizeStrictTool =
|
normalizeStrictTool =
|
||||||
pkgs: tool:
|
pkgs: tool:
|
||||||
let
|
let
|
||||||
version = {
|
version = {
|
||||||
args = [ "--version" ];
|
args = [ "--version" ];
|
||||||
|
match = null;
|
||||||
regex = null;
|
regex = null;
|
||||||
group = 0;
|
group = 0;
|
||||||
line = 1;
|
line = 1;
|
||||||
@@ -56,22 +82,26 @@ let
|
|||||||
// (tool.version or { });
|
// (tool.version or { });
|
||||||
banner = {
|
banner = {
|
||||||
color = "YELLOW";
|
color = "YELLOW";
|
||||||
|
icon = null;
|
||||||
|
iconColor = null;
|
||||||
}
|
}
|
||||||
// (tool.banner or { });
|
// (tool.banner or { });
|
||||||
executable =
|
executable =
|
||||||
if tool ? exe && tool.exe != null then
|
if tool ? command && tool.command != null then
|
||||||
|
tool.command
|
||||||
|
else if tool ? exe && tool.exe != null then
|
||||||
"${lib.getExe' tool.package tool.exe}"
|
"${lib.getExe' tool.package tool.exe}"
|
||||||
else
|
else
|
||||||
"${lib.getExe tool.package}";
|
"${lib.getExe tool.package}";
|
||||||
in
|
in
|
||||||
if !(tool ? package) then
|
if !(tool ? command && tool.command != null) && !(tool ? package) then
|
||||||
throw "repo-lib: tool '${tool.name or "<unnamed>"}' is missing 'package'"
|
throw "repo-lib: tool '${tool.name or "<unnamed>"}' is missing 'package' or 'command'"
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kind = "strict";
|
kind = "strict";
|
||||||
inherit executable version banner;
|
inherit executable version banner;
|
||||||
name = tool.name;
|
name = tool.name;
|
||||||
package = tool.package;
|
package = tool.package or null;
|
||||||
required = tool.required or true;
|
required = tool.required or true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,11 +117,13 @@ let
|
|||||||
versionCommand = tool.versionCmd or "--version";
|
versionCommand = tool.versionCmd or "--version";
|
||||||
banner = {
|
banner = {
|
||||||
color = tool.color or "YELLOW";
|
color = tool.color or "YELLOW";
|
||||||
|
icon = tool.icon or null;
|
||||||
|
iconColor = tool.iconColor or null;
|
||||||
};
|
};
|
||||||
required = tool.required or false;
|
required = tool.required or false;
|
||||||
};
|
};
|
||||||
|
|
||||||
normalizeCheck =
|
checkToLefthookConfig =
|
||||||
pkgs: name: rawCheck:
|
pkgs: name: rawCheck:
|
||||||
let
|
let
|
||||||
check = {
|
check = {
|
||||||
@@ -120,13 +152,85 @@ let
|
|||||||
then
|
then
|
||||||
throw "repo-lib: check '${name}' has unsupported stage '${check.stage}'"
|
throw "repo-lib: check '${name}' has unsupported stage '${check.stage}'"
|
||||||
else
|
else
|
||||||
{
|
lib.setAttrByPath [ check.stage "commands" name ] {
|
||||||
enable = true;
|
run = "${wrapper}/bin/${wrapperName}${hookStageFileArgs check.stage check.passFilenames}";
|
||||||
entry = "${wrapper}/bin/${wrapperName}";
|
|
||||||
pass_filenames = check.passFilenames;
|
|
||||||
stages = [ check.stage ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
normalizeLefthookConfig =
|
||||||
|
label: raw: if builtins.isAttrs raw then raw else throw "repo-lib: ${label} must be an attrset";
|
||||||
|
|
||||||
|
normalizeHookStage =
|
||||||
|
hookName: stage:
|
||||||
|
if
|
||||||
|
builtins.elem stage [
|
||||||
|
"pre-commit"
|
||||||
|
"pre-push"
|
||||||
|
"commit-msg"
|
||||||
|
]
|
||||||
|
then
|
||||||
|
stage
|
||||||
|
else
|
||||||
|
throw "repo-lib: hook '${hookName}' has unsupported stage '${stage}' for lefthook";
|
||||||
|
|
||||||
|
hookStageFileArgs =
|
||||||
|
stage: passFilenames:
|
||||||
|
if !passFilenames then
|
||||||
|
""
|
||||||
|
else if stage == "pre-commit" then
|
||||||
|
" {staged_files}"
|
||||||
|
else if stage == "pre-push" then
|
||||||
|
" {push_files}"
|
||||||
|
else if stage == "commit-msg" then
|
||||||
|
" {1}"
|
||||||
|
else
|
||||||
|
throw "repo-lib: unsupported lefthook stage '${stage}'";
|
||||||
|
|
||||||
|
hookToLefthookConfig =
|
||||||
|
name: hook:
|
||||||
|
let
|
||||||
|
supportedFields = [
|
||||||
|
"description"
|
||||||
|
"enable"
|
||||||
|
"entry"
|
||||||
|
"name"
|
||||||
|
"package"
|
||||||
|
"pass_filenames"
|
||||||
|
"stages"
|
||||||
|
];
|
||||||
|
unsupportedFields = builtins.filter (field: !(builtins.elem field supportedFields)) (
|
||||||
|
builtins.attrNames hook
|
||||||
|
);
|
||||||
|
stages = builtins.map (stage: normalizeHookStage name stage) (hook.stages or [ "pre-commit" ]);
|
||||||
|
passFilenames = hook.pass_filenames or false;
|
||||||
|
in
|
||||||
|
if unsupportedFields != [ ] then
|
||||||
|
throw ''
|
||||||
|
repo-lib: hook '${name}' uses unsupported fields for lefthook: ${lib.concatStringsSep ", " unsupportedFields}
|
||||||
|
''
|
||||||
|
else if !(hook ? entry) then
|
||||||
|
throw "repo-lib: hook '${name}' is missing 'entry'"
|
||||||
|
else
|
||||||
|
lib.foldl' lib.recursiveUpdate { } (
|
||||||
|
builtins.map (
|
||||||
|
stage:
|
||||||
|
lib.setAttrByPath [ stage "commands" name ] {
|
||||||
|
run = "${hook.entry}${hookStageFileArgs stage passFilenames}";
|
||||||
|
}
|
||||||
|
) stages
|
||||||
|
);
|
||||||
|
|
||||||
|
parallelHookStageConfig =
|
||||||
|
stage:
|
||||||
|
if
|
||||||
|
builtins.elem stage [
|
||||||
|
"pre-commit"
|
||||||
|
"pre-push"
|
||||||
|
]
|
||||||
|
then
|
||||||
|
lib.setAttrByPath [ stage "parallel" ] true
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
|
||||||
normalizeReleaseStep =
|
normalizeReleaseStep =
|
||||||
step:
|
step:
|
||||||
if step ? writeFile then
|
if step ? writeFile then
|
||||||
@@ -245,10 +349,10 @@ let
|
|||||||
|
|
||||||
buildShellHook =
|
buildShellHook =
|
||||||
{
|
{
|
||||||
preCommitShellHook,
|
hooksShellHook,
|
||||||
shellEnvScript,
|
shellEnvScript,
|
||||||
bootstrap,
|
bootstrap,
|
||||||
toolBannerScript,
|
shellBannerScript,
|
||||||
extraShellText,
|
extraShellText,
|
||||||
toolLabelWidth,
|
toolLabelWidth,
|
||||||
}:
|
}:
|
||||||
@@ -257,19 +361,19 @@ let
|
|||||||
in
|
in
|
||||||
builtins.replaceStrings
|
builtins.replaceStrings
|
||||||
[
|
[
|
||||||
"\${pre-commit-check.shellHook}"
|
"@HOOKS_SHELL_HOOK@"
|
||||||
"@TOOL_LABEL_WIDTH@"
|
"@TOOL_LABEL_WIDTH@"
|
||||||
"@SHELL_ENV_SCRIPT@"
|
"@SHELL_ENV_SCRIPT@"
|
||||||
"@BOOTSTRAP@"
|
"@BOOTSTRAP@"
|
||||||
"@TOOL_BANNER_SCRIPT@"
|
"@SHELL_BANNER_SCRIPT@"
|
||||||
"@EXTRA_SHELL_TEXT@"
|
"@EXTRA_SHELL_TEXT@"
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
preCommitShellHook
|
hooksShellHook
|
||||||
(toString toolLabelWidth)
|
(toString toolLabelWidth)
|
||||||
shellEnvScript
|
shellEnvScript
|
||||||
bootstrap
|
bootstrap
|
||||||
toolBannerScript
|
shellBannerScript
|
||||||
extraShellText
|
extraShellText
|
||||||
]
|
]
|
||||||
template;
|
template;
|
||||||
@@ -286,9 +390,11 @@ let
|
|||||||
env = { };
|
env = { };
|
||||||
extraShellText = "";
|
extraShellText = "";
|
||||||
bootstrap = "";
|
bootstrap = "";
|
||||||
|
banner = defaultShellBanner;
|
||||||
},
|
},
|
||||||
checkSpecs ? { },
|
checkSpecs ? { },
|
||||||
rawHookEntries ? { },
|
rawHookEntries ? { },
|
||||||
|
lefthookConfig ? { },
|
||||||
extraPackages ? [ ],
|
extraPackages ? [ ],
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
@@ -309,26 +415,44 @@ let
|
|||||||
// formatting.programs;
|
// formatting.programs;
|
||||||
settings.formatter = { } // formatting.settings;
|
settings.formatter = { } // formatting.settings;
|
||||||
};
|
};
|
||||||
|
treefmtWrapper = treefmtEval.config.build.wrapper;
|
||||||
|
lefthookBinWrapper = pkgs.writeShellScript "lefthook-dumb-term" ''
|
||||||
|
exec env TERM=dumb ${lib.getExe pkgs.lefthook} "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
normalizedChecks = lib.mapAttrs (name: check: normalizeCheck pkgs name check) checkSpecs;
|
normalizedLefthookConfig = normalizeLefthookConfig "lefthook config" lefthookConfig;
|
||||||
hooks = mergeUniqueAttrs "hook" rawHookEntries normalizedChecks;
|
lefthookCheck = lefthookNix.lib.${system}.run {
|
||||||
|
|
||||||
pre-commit-check = git-hooks.lib.${system}.run {
|
|
||||||
inherit src;
|
inherit src;
|
||||||
hooks = {
|
config = lib.foldl' lib.recursiveUpdate { } (
|
||||||
treefmt = {
|
[
|
||||||
enable = true;
|
{
|
||||||
entry = "${treefmtEval.config.build.wrapper}/bin/treefmt --ci";
|
output = [
|
||||||
pass_filenames = true;
|
"failure"
|
||||||
};
|
"summary"
|
||||||
gitlint.enable = true;
|
];
|
||||||
gitleaks = {
|
}
|
||||||
enable = true;
|
(parallelHookStageConfig "pre-commit")
|
||||||
entry = "${pkgs.gitleaks}/bin/gitleaks protect --staged";
|
(parallelHookStageConfig "pre-push")
|
||||||
pass_filenames = false;
|
(lib.setAttrByPath [ "pre-commit" "commands" "treefmt" ] {
|
||||||
};
|
run = "${treefmtWrapper}/bin/treefmt --no-cache {staged_files}";
|
||||||
}
|
stage_fixed = true;
|
||||||
// hooks;
|
})
|
||||||
|
(lib.setAttrByPath [ "pre-commit" "commands" "gitleaks" ] {
|
||||||
|
run = "${pkgs.gitleaks}/bin/gitleaks protect --staged";
|
||||||
|
})
|
||||||
|
(lib.setAttrByPath [ "commit-msg" "commands" "gitlint" ] {
|
||||||
|
run = "${pkgs.gitlint}/bin/gitlint --staged --msg-filename {1}";
|
||||||
|
})
|
||||||
|
]
|
||||||
|
++ lib.mapAttrsToList (name: check: checkToLefthookConfig pkgs name check) checkSpecs
|
||||||
|
++ lib.mapAttrsToList hookToLefthookConfig rawHookEntries
|
||||||
|
++ [ normalizedLefthookConfig ]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
selectedCheckOutputs = {
|
||||||
|
formatting-check = treefmtEval.config.build.check src;
|
||||||
|
hook-check = lefthookCheck;
|
||||||
|
lefthook-check = lefthookCheck;
|
||||||
};
|
};
|
||||||
|
|
||||||
toolNames = builtins.map (tool: tool.name) tools;
|
toolNames = builtins.map (tool: tool.name) tools;
|
||||||
@@ -345,45 +469,119 @@ let
|
|||||||
) shellConfig.env
|
) shellConfig.env
|
||||||
);
|
);
|
||||||
|
|
||||||
toolBannerScript = lib.concatMapStrings (
|
banner = normalizeShellBanner (shellConfig.banner or { });
|
||||||
tool:
|
|
||||||
if tool.kind == "strict" then
|
shellBannerScript =
|
||||||
|
if banner.style == "pretty" then
|
||||||
''
|
''
|
||||||
repo_lib_probe_tool \
|
repo_lib_print_pretty_header \
|
||||||
${lib.escapeShellArg tool.name} \
|
${lib.escapeShellArg banner.borderColor} \
|
||||||
${lib.escapeShellArg tool.banner.color} \
|
${lib.escapeShellArg banner.titleColor} \
|
||||||
${lib.escapeShellArg (if tool.required then "1" else "0")} \
|
${lib.escapeShellArg banner.icon} \
|
||||||
${lib.escapeShellArg (toString tool.version.line)} \
|
${lib.escapeShellArg banner.title} \
|
||||||
${lib.escapeShellArg (toString tool.version.group)} \
|
${lib.escapeShellArg banner.subtitleColor} \
|
||||||
${lib.escapeShellArg (tool.version.regex or "")} \
|
${lib.escapeShellArg banner.subtitle}
|
||||||
${lib.escapeShellArg tool.executable} \
|
''
|
||||||
${lib.escapeShellArgs tool.version.args}
|
+ lib.concatMapStrings (
|
||||||
|
tool:
|
||||||
|
if tool.kind == "strict" then
|
||||||
|
''
|
||||||
|
repo_lib_print_pretty_tool \
|
||||||
|
${lib.escapeShellArg banner.borderColor} \
|
||||||
|
${lib.escapeShellArg tool.name} \
|
||||||
|
${lib.escapeShellArg tool.banner.color} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.icon == null then "" else tool.banner.icon)} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.iconColor == null then "" else tool.banner.iconColor)} \
|
||||||
|
${lib.escapeShellArg (if tool.required then "1" else "0")} \
|
||||||
|
${lib.escapeShellArg (toString tool.version.line)} \
|
||||||
|
${lib.escapeShellArg (toString tool.version.group)} \
|
||||||
|
${lib.escapeShellArg (if tool.version.regex == null then "" else tool.version.regex)} \
|
||||||
|
${lib.escapeShellArg (if tool.version.match == null then "" else tool.version.match)} \
|
||||||
|
${lib.escapeShellArg tool.executable} \
|
||||||
|
${lib.escapeShellArgs tool.version.args}
|
||||||
|
''
|
||||||
|
else
|
||||||
|
''
|
||||||
|
repo_lib_print_pretty_legacy_tool \
|
||||||
|
${lib.escapeShellArg banner.borderColor} \
|
||||||
|
${lib.escapeShellArg tool.name} \
|
||||||
|
${lib.escapeShellArg tool.banner.color} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.icon == null then "" else tool.banner.icon)} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.iconColor == null then "" else tool.banner.iconColor)} \
|
||||||
|
${lib.escapeShellArg (if tool.required then "1" else "0")} \
|
||||||
|
${lib.escapeShellArg tool.command} \
|
||||||
|
${lib.escapeShellArg tool.versionCommand}
|
||||||
|
''
|
||||||
|
) tools
|
||||||
|
+ ''
|
||||||
|
repo_lib_print_pretty_footer \
|
||||||
|
${lib.escapeShellArg banner.borderColor}
|
||||||
''
|
''
|
||||||
else
|
else
|
||||||
''
|
''
|
||||||
repo_lib_probe_legacy_tool \
|
repo_lib_print_simple_header \
|
||||||
${lib.escapeShellArg tool.name} \
|
${lib.escapeShellArg banner.titleColor} \
|
||||||
${lib.escapeShellArg tool.banner.color} \
|
${lib.escapeShellArg banner.icon} \
|
||||||
${lib.escapeShellArg (if tool.required then "1" else "0")} \
|
${lib.escapeShellArg banner.title} \
|
||||||
${lib.escapeShellArg tool.command} \
|
${lib.escapeShellArg banner.subtitleColor} \
|
||||||
${lib.escapeShellArg tool.versionCommand}
|
${lib.escapeShellArg banner.subtitle}
|
||||||
''
|
''
|
||||||
) tools;
|
+ lib.concatMapStrings (
|
||||||
|
tool:
|
||||||
|
if tool.kind == "strict" then
|
||||||
|
''
|
||||||
|
repo_lib_print_simple_tool \
|
||||||
|
${lib.escapeShellArg tool.name} \
|
||||||
|
${lib.escapeShellArg tool.banner.color} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.icon == null then "" else tool.banner.icon)} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.iconColor == null then "" else tool.banner.iconColor)} \
|
||||||
|
${lib.escapeShellArg (if tool.required then "1" else "0")} \
|
||||||
|
${lib.escapeShellArg (toString tool.version.line)} \
|
||||||
|
${lib.escapeShellArg (toString tool.version.group)} \
|
||||||
|
${lib.escapeShellArg (if tool.version.regex == null then "" else tool.version.regex)} \
|
||||||
|
${lib.escapeShellArg (if tool.version.match == null then "" else tool.version.match)} \
|
||||||
|
${lib.escapeShellArg tool.executable} \
|
||||||
|
${lib.escapeShellArgs tool.version.args}
|
||||||
|
''
|
||||||
|
else
|
||||||
|
''
|
||||||
|
repo_lib_print_simple_legacy_tool \
|
||||||
|
${lib.escapeShellArg tool.name} \
|
||||||
|
${lib.escapeShellArg tool.banner.color} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.icon == null then "" else tool.banner.icon)} \
|
||||||
|
${lib.escapeShellArg (if tool.banner.iconColor == null then "" else tool.banner.iconColor)} \
|
||||||
|
${lib.escapeShellArg (if tool.required then "1" else "0")} \
|
||||||
|
${lib.escapeShellArg tool.command} \
|
||||||
|
${lib.escapeShellArg tool.versionCommand}
|
||||||
|
''
|
||||||
|
) tools
|
||||||
|
+ ''
|
||||||
|
printf "\n"
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit pre-commit-check;
|
checks = selectedCheckOutputs;
|
||||||
formatter = treefmtEval.config.build.wrapper;
|
formatter = treefmtWrapper;
|
||||||
shell = pkgs.mkShell {
|
shell = pkgs.mkShell {
|
||||||
packages = lib.unique (selectedStandardPackages ++ extraPackages ++ toolPackages);
|
LEFTHOOK_BIN = builtins.toString lefthookBinWrapper;
|
||||||
buildInputs = pre-commit-check.enabledPackages;
|
packages = lib.unique (
|
||||||
|
selectedStandardPackages
|
||||||
|
++ extraPackages
|
||||||
|
++ toolPackages
|
||||||
|
++ [
|
||||||
|
pkgs.lefthook
|
||||||
|
treefmtWrapper
|
||||||
|
]
|
||||||
|
);
|
||||||
shellHook = buildShellHook {
|
shellHook = buildShellHook {
|
||||||
preCommitShellHook = pre-commit-check.shellHook;
|
hooksShellHook = lefthookCheck.shellHook;
|
||||||
inherit toolLabelWidth shellEnvScript toolBannerScript;
|
inherit toolLabelWidth shellEnvScript shellBannerScript;
|
||||||
bootstrap = shellConfig.bootstrap;
|
bootstrap = shellConfig.bootstrap;
|
||||||
extraShellText = shellConfig.extraShellText;
|
extraShellText = shellConfig.extraShellText;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
// selectedCheckOutputs;
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
systems = {
|
systems = {
|
||||||
@@ -411,6 +609,24 @@ rec {
|
|||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fromCommand =
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
command,
|
||||||
|
version ? { },
|
||||||
|
banner ? { },
|
||||||
|
required ? true,
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
name
|
||||||
|
command
|
||||||
|
version
|
||||||
|
banner
|
||||||
|
required
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
simple =
|
simple =
|
||||||
name: package: args:
|
name: package: args:
|
||||||
fromPackage {
|
fromPackage {
|
||||||
@@ -429,12 +645,14 @@ rec {
|
|||||||
extraShellText = "";
|
extraShellText = "";
|
||||||
allowImpureBootstrap = false;
|
allowImpureBootstrap = false;
|
||||||
bootstrap = "";
|
bootstrap = "";
|
||||||
|
banner = { };
|
||||||
};
|
};
|
||||||
formatting = {
|
formatting = {
|
||||||
programs = { };
|
programs = { };
|
||||||
settings = { };
|
settings = { };
|
||||||
};
|
};
|
||||||
checks = { };
|
checks = { };
|
||||||
|
lefthook = { };
|
||||||
release = null;
|
release = null;
|
||||||
} rawConfig;
|
} rawConfig;
|
||||||
release =
|
release =
|
||||||
@@ -452,7 +670,13 @@ rec {
|
|||||||
if merged.shell.bootstrap != "" && !merged.shell.allowImpureBootstrap then
|
if merged.shell.bootstrap != "" && !merged.shell.allowImpureBootstrap then
|
||||||
throw "repo-lib: config.shell.bootstrap requires config.shell.allowImpureBootstrap = true"
|
throw "repo-lib: config.shell.bootstrap requires config.shell.allowImpureBootstrap = true"
|
||||||
else
|
else
|
||||||
merged // { inherit release; };
|
merged
|
||||||
|
// {
|
||||||
|
inherit release;
|
||||||
|
shell = merged.shell // {
|
||||||
|
banner = normalizeShellBanner merged.shell.banner;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
mkDevShell =
|
mkDevShell =
|
||||||
{
|
{
|
||||||
@@ -463,6 +687,7 @@ rec {
|
|||||||
preToolHook ? "",
|
preToolHook ? "",
|
||||||
extraShellHook ? "",
|
extraShellHook ? "",
|
||||||
additionalHooks ? { },
|
additionalHooks ? { },
|
||||||
|
lefthook ? { },
|
||||||
tools ? [ ],
|
tools ? [ ],
|
||||||
includeStandardPackages ? true,
|
includeStandardPackages ? true,
|
||||||
formatters ? { },
|
formatters ? { },
|
||||||
@@ -487,6 +712,7 @@ rec {
|
|||||||
extraShellText = extraShellHook;
|
extraShellText = extraShellHook;
|
||||||
allowImpureBootstrap = true;
|
allowImpureBootstrap = true;
|
||||||
bootstrap = preToolHook;
|
bootstrap = preToolHook;
|
||||||
|
banner = defaultShellBanner;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
if duplicateToolNames != [ ] then
|
if duplicateToolNames != [ ] then
|
||||||
@@ -501,6 +727,7 @@ rec {
|
|||||||
;
|
;
|
||||||
formatting = normalizedFormatting;
|
formatting = normalizedFormatting;
|
||||||
rawHookEntries = additionalHooks;
|
rawHookEntries = additionalHooks;
|
||||||
|
lefthookConfig = lefthook;
|
||||||
shellConfig = shellConfig;
|
shellConfig = shellConfig;
|
||||||
tools = legacyTools;
|
tools = legacyTools;
|
||||||
extraPackages =
|
extraPackages =
|
||||||
@@ -580,6 +807,7 @@ rec {
|
|||||||
tools = [ ];
|
tools = [ ];
|
||||||
shell = { };
|
shell = { };
|
||||||
checks = { };
|
checks = { };
|
||||||
|
lefthook = { };
|
||||||
packages = { };
|
packages = { };
|
||||||
apps = { };
|
apps = { };
|
||||||
}
|
}
|
||||||
@@ -592,6 +820,9 @@ rec {
|
|||||||
strictTools = builtins.map (tool: normalizeStrictTool pkgs tool) perSystemResult.tools;
|
strictTools = builtins.map (tool: normalizeStrictTool pkgs tool) perSystemResult.tools;
|
||||||
duplicateToolNames = duplicateStrings (builtins.map (tool: tool.name) strictTools);
|
duplicateToolNames = duplicateStrings (builtins.map (tool: tool.name) strictTools);
|
||||||
mergedChecks = mergeUniqueAttrs "check" normalizedConfig.checks perSystemResult.checks;
|
mergedChecks = mergeUniqueAttrs "check" normalizedConfig.checks perSystemResult.checks;
|
||||||
|
mergedLefthookConfig =
|
||||||
|
lib.recursiveUpdate (normalizeLefthookConfig "config.lefthook" normalizedConfig.lefthook)
|
||||||
|
(normalizeLefthookConfig "perSystem.lefthook" (perSystemResult.lefthook or { }));
|
||||||
shellConfig = lib.recursiveUpdate normalizedConfig.shell (perSystemResult.shell or { });
|
shellConfig = lib.recursiveUpdate normalizedConfig.shell (perSystemResult.shell or { });
|
||||||
env =
|
env =
|
||||||
if duplicateToolNames != [ ] then
|
if duplicateToolNames != [ ] then
|
||||||
@@ -607,6 +838,7 @@ rec {
|
|||||||
formatting = normalizedConfig.formatting;
|
formatting = normalizedConfig.formatting;
|
||||||
tools = strictTools;
|
tools = strictTools;
|
||||||
checkSpecs = mergedChecks;
|
checkSpecs = mergedChecks;
|
||||||
|
lefthookConfig = mergedLefthookConfig;
|
||||||
shellConfig = shellConfig;
|
shellConfig = shellConfig;
|
||||||
extraPackages = perSystemResult.shell.packages or [ ];
|
extraPackages = perSystemResult.shell.packages or [ ];
|
||||||
};
|
};
|
||||||
@@ -638,9 +870,7 @@ rec {
|
|||||||
default = systemResults.${system}.env.shell;
|
default = systemResults.${system}.env.shell;
|
||||||
});
|
});
|
||||||
|
|
||||||
checks = lib.genAttrs systems (system: {
|
checks = lib.genAttrs systems (system: systemResults.${system}.env.checks);
|
||||||
inherit (systemResults.${system}.env) pre-commit-check;
|
|
||||||
});
|
|
||||||
|
|
||||||
formatter = lib.genAttrs systems (system: systemResults.${system}.env.formatter);
|
formatter = lib.genAttrs systems (system: systemResults.${system}.env.formatter);
|
||||||
packages = lib.genAttrs systems (system: systemResults.${system}.packages);
|
packages = lib.genAttrs systems (system: systemResults.${system}.packages);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
${pre-commit-check.shellHook}
|
@HOOKS_SHELL_HOOK@
|
||||||
|
|
||||||
if [ -t 1 ]; then
|
if [ -t 1 ]; then
|
||||||
command -v tput >/dev/null 2>&1 && tput clear || printf '\033c'
|
command -v tput >/dev/null 2>&1 && tput clear || printf '\033c'
|
||||||
@@ -16,107 +16,326 @@ BOLD=$'\033[1m'
|
|||||||
UNDERLINE=$'\033[4m'
|
UNDERLINE=$'\033[4m'
|
||||||
RESET=$'\033[0m'
|
RESET=$'\033[0m'
|
||||||
|
|
||||||
repo_lib_probe_tool() {
|
REPO_LIB_TOOL_VERSION=""
|
||||||
local name="$1"
|
REPO_LIB_TOOL_ERROR=""
|
||||||
local color_name="$2"
|
|
||||||
local required="$3"
|
repo_lib_capture_tool() {
|
||||||
local line_no="$4"
|
local required="$1"
|
||||||
local group_no="$5"
|
local line_no="$2"
|
||||||
local regex="$6"
|
local group_no="$3"
|
||||||
local executable="$7"
|
local regex="$4"
|
||||||
shift 7
|
local match_regex="$5"
|
||||||
|
local executable="$6"
|
||||||
|
shift 6
|
||||||
|
|
||||||
local color="${!color_name:-$YELLOW}"
|
|
||||||
local output=""
|
local output=""
|
||||||
local selected=""
|
local selected=""
|
||||||
local version=""
|
local version=""
|
||||||
|
|
||||||
|
REPO_LIB_TOOL_VERSION=""
|
||||||
|
REPO_LIB_TOOL_ERROR=""
|
||||||
|
|
||||||
if ! output="$("$executable" "$@" 2>&1)"; then
|
if ! output="$("$executable" "$@" 2>&1)"; then
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "probe failed"
|
REPO_LIB_TOOL_ERROR="probe failed"
|
||||||
printf "%s\n" "$output" >&2
|
printf "%s\n" "$output" >&2
|
||||||
if [ "$required" = "1" ]; then
|
return 1
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
selected="$(printf '%s\n' "$output" | sed -n "${line_no}p")"
|
if [ -n "$match_regex" ]; then
|
||||||
|
selected="$(printf '%s\n' "$output" | grep -E -m 1 "$match_regex" || true)"
|
||||||
|
else
|
||||||
|
selected="$(printf '%s\n' "$output" | sed -n "${line_no}p")"
|
||||||
|
fi
|
||||||
selected="$(printf '%s' "$selected" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
|
selected="$(printf '%s' "$selected" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
|
||||||
|
|
||||||
if [ -n "$regex" ]; then
|
if [ -n "$regex" ]; then
|
||||||
if [[ "$selected" =~ $regex ]]; then
|
if [[ "$selected" =~ $regex ]]; then
|
||||||
version="${BASH_REMATCH[$group_no]}"
|
version="${BASH_REMATCH[$group_no]}"
|
||||||
else
|
else
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "version parse failed"
|
REPO_LIB_TOOL_ERROR="version parse failed"
|
||||||
printf "%s\n" "$output" >&2
|
printf "%s\n" "$output" >&2
|
||||||
if [ "$required" = "1" ]; then
|
return 1
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
version="$selected"
|
version="$selected"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$version" ]; then
|
if [ -z "$version" ]; then
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "empty version"
|
REPO_LIB_TOOL_ERROR="empty version"
|
||||||
printf "%s\n" "$output" >&2
|
printf "%s\n" "$output" >&2
|
||||||
if [ "$required" = "1" ]; then
|
return 1
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET %s%s$RESET\n" "${name}:" "$color" "$version"
|
REPO_LIB_TOOL_VERSION="$version"
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
repo_lib_probe_legacy_tool() {
|
repo_lib_capture_legacy_tool() {
|
||||||
local name="$1"
|
local required="$1"
|
||||||
local color_name="$2"
|
local command_name="$2"
|
||||||
local required="$3"
|
local version_command="$3"
|
||||||
local command_name="$4"
|
|
||||||
local version_command="$5"
|
|
||||||
|
|
||||||
local color="${!color_name:-$YELLOW}"
|
|
||||||
local output=""
|
local output=""
|
||||||
local version=""
|
local version=""
|
||||||
|
|
||||||
|
REPO_LIB_TOOL_VERSION=""
|
||||||
|
REPO_LIB_TOOL_ERROR=""
|
||||||
|
|
||||||
if ! command -v "$command_name" >/dev/null 2>&1; then
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
||||||
if [ "$required" = "1" ]; then
|
REPO_LIB_TOOL_ERROR="missing command"
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "missing command"
|
return 1
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! output="$(sh -c "$command_name $version_command" 2>&1)"; then
|
if ! output="$(sh -c "$command_name $version_command" 2>&1)"; then
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "probe failed"
|
REPO_LIB_TOOL_ERROR="probe failed"
|
||||||
printf "%s\n" "$output" >&2
|
printf "%s\n" "$output" >&2
|
||||||
if [ "$required" = "1" ]; then
|
return 1
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
version="$(printf '%s\n' "$output" | head -n 1 | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
|
version="$(printf '%s\n' "$output" | head -n 1 | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
|
||||||
if [ -z "$version" ]; then
|
if [ -z "$version" ]; then
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "empty version"
|
REPO_LIB_TOOL_ERROR="empty version"
|
||||||
printf "%s\n" "$output" >&2
|
printf "%s\n" "$output" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REPO_LIB_TOOL_VERSION="$version"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_simple_header() {
|
||||||
|
local title_color_name="$1"
|
||||||
|
local icon="$2"
|
||||||
|
local title="$3"
|
||||||
|
local subtitle_color_name="$4"
|
||||||
|
local subtitle="$5"
|
||||||
|
|
||||||
|
local title_color="${!title_color_name:-$GREEN}"
|
||||||
|
local subtitle_color="${!subtitle_color_name:-$GRAY}"
|
||||||
|
|
||||||
|
printf "\n%s" "$title_color"
|
||||||
|
if [ -n "$icon" ]; then
|
||||||
|
printf "%s " "$icon"
|
||||||
|
fi
|
||||||
|
printf "%s%s" "$title" "$RESET"
|
||||||
|
if [ -n "$subtitle" ]; then
|
||||||
|
printf " %s%s%s" "$subtitle_color" "$subtitle" "$RESET"
|
||||||
|
fi
|
||||||
|
printf "\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_simple_tool() {
|
||||||
|
local name="$1"
|
||||||
|
local color_name="$2"
|
||||||
|
local icon="$3"
|
||||||
|
local icon_color_name="$4"
|
||||||
|
local required="$5"
|
||||||
|
local line_no="$6"
|
||||||
|
local group_no="$7"
|
||||||
|
local regex="$8"
|
||||||
|
local match_regex="$9"
|
||||||
|
local executable="${10}"
|
||||||
|
shift 10
|
||||||
|
|
||||||
|
local color="${!color_name:-$YELLOW}"
|
||||||
|
local effective_icon_color_name="$icon_color_name"
|
||||||
|
local icon_color=""
|
||||||
|
|
||||||
|
if [ -z "$effective_icon_color_name" ]; then
|
||||||
|
effective_icon_color_name="$color_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if repo_lib_capture_tool "$required" "$line_no" "$group_no" "$regex" "$match_regex" "$executable" "$@"; then
|
||||||
|
icon_color="${!effective_icon_color_name:-$color}"
|
||||||
|
printf " "
|
||||||
|
if [ -n "$icon" ]; then
|
||||||
|
printf "%s%s%s " "$icon_color" "$icon" "$RESET"
|
||||||
|
fi
|
||||||
|
printf "$CYAN %-@TOOL_LABEL_WIDTH@s$RESET %s%s$RESET\n" "${name}:" "$color" "$REPO_LIB_TOOL_VERSION"
|
||||||
|
else
|
||||||
|
printf " "
|
||||||
|
if [ -n "$icon" ]; then
|
||||||
|
printf "%s%s%s " "$RED" "$icon" "$RESET"
|
||||||
|
fi
|
||||||
|
printf "$CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "$REPO_LIB_TOOL_ERROR"
|
||||||
if [ "$required" = "1" ]; then
|
if [ "$required" = "1" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
return 0
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_simple_legacy_tool() {
|
||||||
|
local name="$1"
|
||||||
|
local color_name="$2"
|
||||||
|
local icon="$3"
|
||||||
|
local icon_color_name="$4"
|
||||||
|
local required="$5"
|
||||||
|
local command_name="$6"
|
||||||
|
local version_command="$7"
|
||||||
|
|
||||||
|
local color="${!color_name:-$YELLOW}"
|
||||||
|
local effective_icon_color_name="$icon_color_name"
|
||||||
|
local icon_color=""
|
||||||
|
|
||||||
|
if [ -z "$effective_icon_color_name" ]; then
|
||||||
|
effective_icon_color_name="$color_name"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf " $CYAN %-@TOOL_LABEL_WIDTH@s$RESET %s%s$RESET\n" "${name}:" "$color" "$version"
|
if repo_lib_capture_legacy_tool "$required" "$command_name" "$version_command"; then
|
||||||
|
icon_color="${!effective_icon_color_name:-$color}"
|
||||||
|
printf " "
|
||||||
|
if [ -n "$icon" ]; then
|
||||||
|
printf "%s%s%s " "$icon_color" "$icon" "$RESET"
|
||||||
|
fi
|
||||||
|
printf "$CYAN %-@TOOL_LABEL_WIDTH@s$RESET %s%s$RESET\n" "${name}:" "$color" "$REPO_LIB_TOOL_VERSION"
|
||||||
|
else
|
||||||
|
printf " "
|
||||||
|
if [ -n "$icon" ]; then
|
||||||
|
printf "%s%s%s " "$RED" "$icon" "$RESET"
|
||||||
|
fi
|
||||||
|
printf "$CYAN %-@TOOL_LABEL_WIDTH@s$RESET $RED%s$RESET\n" "${name}:" "$REPO_LIB_TOOL_ERROR"
|
||||||
|
if [ "$required" = "1" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_pretty_header() {
|
||||||
|
local border_color_name="$1"
|
||||||
|
local title_color_name="$2"
|
||||||
|
local icon="$3"
|
||||||
|
local title="$4"
|
||||||
|
local subtitle_color_name="$5"
|
||||||
|
local subtitle="$6"
|
||||||
|
|
||||||
|
local border_color="${!border_color_name:-$BLUE}"
|
||||||
|
local title_color="${!title_color_name:-$GREEN}"
|
||||||
|
local subtitle_color="${!subtitle_color_name:-$GRAY}"
|
||||||
|
|
||||||
|
printf "\n%s╭─%s %s" "$border_color" "$RESET" "$title_color"
|
||||||
|
if [ -n "$icon" ]; then
|
||||||
|
printf "%s " "$icon"
|
||||||
|
fi
|
||||||
|
printf "%s%s" "$title" "$RESET"
|
||||||
|
if [ -n "$subtitle" ]; then
|
||||||
|
printf " %s%s%s" "$subtitle_color" "$subtitle" "$RESET"
|
||||||
|
fi
|
||||||
|
printf "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_pretty_row() {
|
||||||
|
local border_color_name="$1"
|
||||||
|
local icon="$2"
|
||||||
|
local icon_color_name="$3"
|
||||||
|
local label="$4"
|
||||||
|
local value="$5"
|
||||||
|
local value_color_name="$6"
|
||||||
|
|
||||||
|
local border_color="${!border_color_name:-$BLUE}"
|
||||||
|
local icon_color="${!icon_color_name:-$WHITE}"
|
||||||
|
local value_color="${!value_color_name:-$YELLOW}"
|
||||||
|
|
||||||
|
if [ -z "$icon" ]; then
|
||||||
|
icon="•"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s│%s %s%s%s ${WHITE}%-@TOOL_LABEL_WIDTH@s${RESET} %s%s${RESET}\n" \
|
||||||
|
"$border_color" "$RESET" "$icon_color" "$icon" "$RESET" "$label" "$value_color" "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_pretty_tool() {
|
||||||
|
local border_color_name="$1"
|
||||||
|
local name="$2"
|
||||||
|
local color_name="$3"
|
||||||
|
local icon="$4"
|
||||||
|
local icon_color_name="$5"
|
||||||
|
local required="$6"
|
||||||
|
local line_no="$7"
|
||||||
|
local group_no="$8"
|
||||||
|
local regex="$9"
|
||||||
|
local match_regex="${10}"
|
||||||
|
local executable="${11}"
|
||||||
|
shift 11
|
||||||
|
|
||||||
|
local effective_icon_color_name="$icon_color_name"
|
||||||
|
local value_color_name="$color_name"
|
||||||
|
local value=""
|
||||||
|
|
||||||
|
if [ -z "$effective_icon_color_name" ]; then
|
||||||
|
effective_icon_color_name="$color_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if repo_lib_capture_tool "$required" "$line_no" "$group_no" "$regex" "$match_regex" "$executable" "$@"; then
|
||||||
|
value="$REPO_LIB_TOOL_VERSION"
|
||||||
|
else
|
||||||
|
value="$REPO_LIB_TOOL_ERROR"
|
||||||
|
effective_icon_color_name="RED"
|
||||||
|
value_color_name="RED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_lib_print_pretty_row \
|
||||||
|
"$border_color_name" \
|
||||||
|
"$icon" \
|
||||||
|
"$effective_icon_color_name" \
|
||||||
|
"$name" \
|
||||||
|
"$value" \
|
||||||
|
"$value_color_name"
|
||||||
|
|
||||||
|
if [ "$value_color_name" = "RED" ] && [ "$required" = "1" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_pretty_legacy_tool() {
|
||||||
|
local border_color_name="$1"
|
||||||
|
local name="$2"
|
||||||
|
local color_name="$3"
|
||||||
|
local icon="$4"
|
||||||
|
local icon_color_name="$5"
|
||||||
|
local required="$6"
|
||||||
|
local command_name="$7"
|
||||||
|
local version_command="$8"
|
||||||
|
|
||||||
|
local effective_icon_color_name="$icon_color_name"
|
||||||
|
local value_color_name="$color_name"
|
||||||
|
local value=""
|
||||||
|
|
||||||
|
if [ -z "$effective_icon_color_name" ]; then
|
||||||
|
effective_icon_color_name="$color_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if repo_lib_capture_legacy_tool "$required" "$command_name" "$version_command"; then
|
||||||
|
value="$REPO_LIB_TOOL_VERSION"
|
||||||
|
else
|
||||||
|
value="$REPO_LIB_TOOL_ERROR"
|
||||||
|
effective_icon_color_name="RED"
|
||||||
|
value_color_name="RED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_lib_print_pretty_row \
|
||||||
|
"$border_color_name" \
|
||||||
|
"$icon" \
|
||||||
|
"$effective_icon_color_name" \
|
||||||
|
"$name" \
|
||||||
|
"$value" \
|
||||||
|
"$value_color_name"
|
||||||
|
|
||||||
|
if [ "$value_color_name" = "RED" ] && [ "$required" = "1" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
repo_lib_print_pretty_footer() {
|
||||||
|
local border_color_name="$1"
|
||||||
|
local border_color="${!border_color_name:-$BLUE}"
|
||||||
|
|
||||||
|
printf "%s╰─%s\n\n" "$border_color" "$RESET"
|
||||||
}
|
}
|
||||||
|
|
||||||
@SHELL_ENV_SCRIPT@
|
@SHELL_ENV_SCRIPT@
|
||||||
|
|
||||||
@BOOTSTRAP@
|
@BOOTSTRAP@
|
||||||
|
|
||||||
printf "\n$GREEN 🚀 Dev shell ready$RESET\n\n"
|
@SHELL_BANNER_SCRIPT@
|
||||||
@TOOL_BANNER_SCRIPT@
|
|
||||||
printf "\n"
|
|
||||||
|
|
||||||
@EXTRA_SHELL_TEXT@
|
@EXTRA_SHELL_TEXT@
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ repo-lib.lib.mkRepo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
checks = { };
|
checks = { };
|
||||||
|
lefthook = { };
|
||||||
|
|
||||||
release = null; # or attrset below
|
release = null; # or attrset below
|
||||||
};
|
};
|
||||||
@@ -43,6 +44,7 @@ repo-lib.lib.mkRepo {
|
|||||||
tools = [ ];
|
tools = [ ];
|
||||||
shell.packages = [ ];
|
shell.packages = [ ];
|
||||||
checks = { };
|
checks = { };
|
||||||
|
lefthook = { };
|
||||||
packages = { };
|
packages = { };
|
||||||
apps = { };
|
apps = { };
|
||||||
};
|
};
|
||||||
@@ -52,7 +54,8 @@ repo-lib.lib.mkRepo {
|
|||||||
Generated outputs:
|
Generated outputs:
|
||||||
|
|
||||||
- `devShells.${system}.default`
|
- `devShells.${system}.default`
|
||||||
- `checks.${system}.pre-commit-check`
|
- `checks.${system}.hook-check`
|
||||||
|
- `checks.${system}.lefthook-check`
|
||||||
- `formatter.${system}`
|
- `formatter.${system}`
|
||||||
- `packages.${system}.release` when `config.release != null`
|
- `packages.${system}.release` when `config.release != null`
|
||||||
- merged `packages` and `apps` from `perSystem`
|
- merged `packages` and `apps` from `perSystem`
|
||||||
@@ -112,7 +115,36 @@ Defaults:
|
|||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
- Only `pre-commit` and `pre-push` are supported.
|
- Only `pre-commit` and `pre-push` are supported.
|
||||||
- The command is wrapped as a script and connected into `git-hooks.nix`.
|
- The command is wrapped as a script and connected into `lefthook.nix`.
|
||||||
|
- `pre-commit` and `pre-push` commands are configured to run in parallel.
|
||||||
|
|
||||||
|
## Raw Lefthook config
|
||||||
|
|
||||||
|
Use `config.lefthook` or `perSystem.lefthook` for advanced Lefthook features that the built-in `checks` abstraction does not carry.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
checks.tests = {
|
||||||
|
command = "go test ./...";
|
||||||
|
stage = "pre-push";
|
||||||
|
};
|
||||||
|
|
||||||
|
lefthook.pre-push.commands.tests.stage_fixed = true;
|
||||||
|
|
||||||
|
lefthook.commit-msg.commands.commitlint = {
|
||||||
|
run = "pnpm commitlint --edit {1}";
|
||||||
|
stage_fixed = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
|
||||||
|
- These attrsets are passed through to `lefthook.nix`.
|
||||||
|
- They are merged after generated checks, so they can extend generated commands.
|
||||||
|
- Prefer `checks` for the simple common case and `lefthook` for advanced fields such as `stage_fixed`, `files`, `glob`, `exclude`, `jobs`, or `scripts`.
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
|
||||||
@@ -136,15 +168,26 @@ Preferred shape in `perSystem.tools`:
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For a tool that should come from the host `PATH` instead of `nixpkgs`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
(repo-lib.lib.tools.fromCommand {
|
||||||
|
name = "Nix";
|
||||||
|
command = "nix";
|
||||||
|
version.args = [ "--version" ];
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
Helper:
|
Helper:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
repo-lib.lib.tools.simple "Nix" pkgs.nix [ "--version" ]
|
repo-lib.lib.tools.simple "Go" pkgs.go [ "version" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
Tool behavior:
|
Tool behavior:
|
||||||
|
|
||||||
- Tool packages are added to the shell automatically.
|
- Tool packages are added to the shell automatically.
|
||||||
|
- Command-backed tools are probed from the existing `PATH` and are not added to the shell automatically.
|
||||||
- Banner probing uses absolute executable paths.
|
- Banner probing uses absolute executable paths.
|
||||||
- `required = true` by default.
|
- `required = true` by default.
|
||||||
- Required tool probe failure aborts shell startup.
|
- Required tool probe failure aborts shell startup.
|
||||||
@@ -257,6 +300,7 @@ If the user asks for a webhook after the tag exists remotely:
|
|||||||
- `extraPackages`
|
- `extraPackages`
|
||||||
- `preToolHook`
|
- `preToolHook`
|
||||||
- `extraShellHook`
|
- `extraShellHook`
|
||||||
|
- `lefthook`
|
||||||
- `additionalHooks`
|
- `additionalHooks`
|
||||||
- old `tools = [ { name; bin; versionCmd; color; } ]`
|
- old `tools = [ { name; bin; versionCmd; color; } ]`
|
||||||
- `features.oxfmt`
|
- `features.oxfmt`
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
watch_file flake.nix
|
||||||
use flake
|
use flake
|
||||||
|
|||||||
1
template/.gitignore
vendored
1
template/.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.direnv/
|
.direnv/
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
lefthook.yml
|
||||||
|
|
||||||
bazel-*
|
bazel-*
|
||||||
build/
|
build/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=v3.0.0";
|
repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v3.4.0";
|
||||||
repo-lib.inputs.nixpkgs.follows = "nixpkgs";
|
repo-lib.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
formatting = {
|
formatting = {
|
||||||
|
# nixfmt is enabled by default and wired into lefthook.
|
||||||
programs = {
|
programs = {
|
||||||
# shfmt.enable = true;
|
# shfmt.enable = true;
|
||||||
# gofmt.enable = true;
|
# gofmt.enable = true;
|
||||||
@@ -50,14 +51,40 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
checks.tests = {
|
# These checks become lefthook commands in the generated `lefthook.yml`.
|
||||||
command = "echo 'No tests defined yet.'";
|
# repo-lib runs `pre-commit` and `pre-push` hook commands in parallel.
|
||||||
stage = "pre-push";
|
# It also sets `output = [ "failure" "summary" ]` by default.
|
||||||
passFilenames = false;
|
checks = {
|
||||||
|
tests = {
|
||||||
|
command = "echo 'No tests defined yet.'";
|
||||||
|
stage = "pre-push";
|
||||||
|
passFilenames = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# fmt = {
|
||||||
|
# command = "nix fmt";
|
||||||
|
# stage = "pre-commit";
|
||||||
|
# passFilenames = false;
|
||||||
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# For advanced Lefthook fields like `stage_fixed`, use raw passthrough.
|
||||||
|
# repo-lib merges this after generated checks.
|
||||||
|
# lefthook.pre-push.commands.tests.stage_fixed = true;
|
||||||
|
# lefthook.commit-msg.commands.commitlint = {
|
||||||
|
# run = "pnpm commitlint --edit {1}";
|
||||||
|
# stage_fixed = true;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# repo-lib also installs built-in hooks for:
|
||||||
|
# - treefmt / nixfmt on `pre-commit`
|
||||||
|
# - gitleaks on `pre-commit`
|
||||||
|
# - gitlint on `commit-msg`
|
||||||
|
|
||||||
|
# release = null;
|
||||||
release = {
|
release = {
|
||||||
steps = [
|
steps = [
|
||||||
|
# Write a generated version file during release.
|
||||||
# {
|
# {
|
||||||
# writeFile = {
|
# writeFile = {
|
||||||
# path = "src/version.ts";
|
# path = "src/version.ts";
|
||||||
@@ -66,6 +93,8 @@
|
|||||||
# '';
|
# '';
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
# Replace a version string while preserving surrounding captures.
|
||||||
# {
|
# {
|
||||||
# replace = {
|
# replace = {
|
||||||
# path = "README.md";
|
# path = "README.md";
|
||||||
@@ -73,6 +102,16 @@
|
|||||||
# replacement = ''\1$FULL_VERSION\2'';
|
# replacement = ''\1$FULL_VERSION\2'';
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
# Run any extra release step with declared runtime inputs.
|
||||||
|
# {
|
||||||
|
# run = {
|
||||||
|
# runtimeInputs = [ pkgs.git ];
|
||||||
|
# script = ''
|
||||||
|
# git status --short
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
# }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -85,10 +124,17 @@
|
|||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
tools = [
|
tools = [
|
||||||
(repo-lib.lib.tools.fromPackage {
|
(repo-lib.lib.tools.fromCommand {
|
||||||
name = "Nix";
|
name = "Nix";
|
||||||
package = pkgs.nix;
|
command = "nix";
|
||||||
version.args = [ "--version" ];
|
version = {
|
||||||
|
args = [ "--version" ];
|
||||||
|
group = 1;
|
||||||
|
};
|
||||||
|
banner = {
|
||||||
|
color = "BLUE";
|
||||||
|
icon = "";
|
||||||
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
# (repo-lib.lib.tools.fromPackage {
|
# (repo-lib.lib.tools.fromPackage {
|
||||||
@@ -106,9 +152,16 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
# checks.lint = {
|
# checks.lint = {
|
||||||
# command = "go test ./...";
|
# command = "bun test";
|
||||||
# stage = "pre-push";
|
# stage = "pre-push";
|
||||||
# runtimeInputs = [ pkgs.go ];
|
# passFilenames = false;
|
||||||
|
# runtimeInputs = [ pkgs.bun ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# checks.generated = {
|
||||||
|
# command = "git diff --exit-code";
|
||||||
|
# stage = "pre-commit";
|
||||||
|
# passFilenames = false;
|
||||||
# };
|
# };
|
||||||
|
|
||||||
# packages.my-tool = pkgs.writeShellApplication {
|
# packages.my-tool = pkgs.writeShellApplication {
|
||||||
|
|||||||
335
tests/release.sh
335
tests/release.sh
@@ -6,6 +6,11 @@ ROOT_DIR="${REPO_LIB_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|||||||
RELEASE_TEMPLATE="$ROOT_DIR/packages/release/release.sh"
|
RELEASE_TEMPLATE="$ROOT_DIR/packages/release/release.sh"
|
||||||
NIXPKGS_FLAKE_PATH="${NIXPKGS_FLAKE_PATH:-}"
|
NIXPKGS_FLAKE_PATH="${NIXPKGS_FLAKE_PATH:-}"
|
||||||
CURRENT_LOG=""
|
CURRENT_LOG=""
|
||||||
|
QC_SEEN_TAGS=()
|
||||||
|
|
||||||
|
if [[ -z "$NIXPKGS_FLAKE_PATH" ]]; then
|
||||||
|
NIXPKGS_FLAKE_PATH="$(nix eval --raw --impure --expr "(builtins.getFlake (toString ${ROOT_DIR})).inputs.nixpkgs.outPath")"
|
||||||
|
fi
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
echo "[test] FAIL: $*" >&2
|
echo "[test] FAIL: $*" >&2
|
||||||
@@ -30,7 +35,7 @@ assert_contains() {
|
|||||||
local needle="$1"
|
local needle="$1"
|
||||||
local haystack_file="$2"
|
local haystack_file="$2"
|
||||||
local message="$3"
|
local message="$3"
|
||||||
if ! grep -Fq "$needle" "$haystack_file"; then
|
if ! grep -Fq -- "$needle" "$haystack_file"; then
|
||||||
fail "$message (missing '$needle')"
|
fail "$message (missing '$needle')"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -70,6 +75,8 @@ setup_repo() {
|
|||||||
run_capture_ok "setup_repo: git init failed" git -C "$repo_dir" init
|
run_capture_ok "setup_repo: git init failed" git -C "$repo_dir" init
|
||||||
run_capture_ok "setup_repo: git config user.name failed" git -C "$repo_dir" config user.name "Release Test"
|
run_capture_ok "setup_repo: git config user.name failed" git -C "$repo_dir" config user.name "Release Test"
|
||||||
run_capture_ok "setup_repo: git config user.email failed" git -C "$repo_dir" config user.email "release-test@example.com"
|
run_capture_ok "setup_repo: git config user.email failed" git -C "$repo_dir" config user.email "release-test@example.com"
|
||||||
|
run_capture_ok "setup_repo: git config commit.gpgsign failed" git -C "$repo_dir" config commit.gpgsign false
|
||||||
|
run_capture_ok "setup_repo: git config tag.gpgsign failed" git -C "$repo_dir" config tag.gpgsign false
|
||||||
|
|
||||||
cat >"$repo_dir/flake.nix" <<'EOF'
|
cat >"$repo_dir/flake.nix" <<'EOF'
|
||||||
{
|
{
|
||||||
@@ -213,6 +220,92 @@ write_mk_repo_flake() {
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_mk_repo_command_tool_flake() {
|
||||||
|
local repo_dir="$1"
|
||||||
|
cat >"$repo_dir/flake.nix" <<EOF
|
||||||
|
{
|
||||||
|
description = "mkRepo command-backed tool";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "path:${NIXPKGS_FLAKE_PATH}";
|
||||||
|
repo-lib.url = "path:${ROOT_DIR}";
|
||||||
|
repo-lib.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, repo-lib, ... }:
|
||||||
|
repo-lib.lib.mkRepo {
|
||||||
|
inherit self nixpkgs;
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
config.release = {
|
||||||
|
steps = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
tools = [
|
||||||
|
(repo-lib.lib.tools.fromCommand {
|
||||||
|
name = "Nix";
|
||||||
|
command = "nix";
|
||||||
|
version.args = [ "--version" ];
|
||||||
|
banner = {
|
||||||
|
color = "BLUE";
|
||||||
|
icon = "";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
shell.packages = [
|
||||||
|
self.packages.\${system}.release
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
write_mk_repo_lefthook_flake() {
|
||||||
|
local repo_dir="$1"
|
||||||
|
cat >"$repo_dir/flake.nix" <<EOF
|
||||||
|
{
|
||||||
|
description = "mkRepo raw lefthook config";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "path:${NIXPKGS_FLAKE_PATH}";
|
||||||
|
repo-lib.url = "path:${ROOT_DIR}";
|
||||||
|
repo-lib.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, repo-lib, ... }:
|
||||||
|
repo-lib.lib.mkRepo {
|
||||||
|
inherit self nixpkgs;
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
config = {
|
||||||
|
checks.tests = {
|
||||||
|
command = "echo test";
|
||||||
|
stage = "pre-push";
|
||||||
|
passFilenames = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
lefthook.pre-push.commands.tests.stage_fixed = true;
|
||||||
|
|
||||||
|
release.steps = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
init_git_repo() {
|
||||||
|
local repo_dir="$1"
|
||||||
|
|
||||||
|
run_capture_ok "init_git_repo: git init failed" git -C "$repo_dir" init
|
||||||
|
run_capture_ok "init_git_repo: git config user.name failed" git -C "$repo_dir" config user.name "Repo Lib Test"
|
||||||
|
run_capture_ok "init_git_repo: git config user.email failed" git -C "$repo_dir" config user.email "repo-lib-test@example.com"
|
||||||
|
run_capture_ok "init_git_repo: git add failed" git -C "$repo_dir" add flake.nix
|
||||||
|
run_capture_ok "init_git_repo: git commit failed" git -C "$repo_dir" commit -m "init"
|
||||||
|
}
|
||||||
|
|
||||||
write_tool_failure_flake() {
|
write_tool_failure_flake() {
|
||||||
local repo_dir="$1"
|
local repo_dir="$1"
|
||||||
cat >"$repo_dir/flake.nix" <<EOF
|
cat >"$repo_dir/flake.nix" <<EOF
|
||||||
@@ -297,7 +390,7 @@ write_release_replace_backref_flake() {
|
|||||||
replace = {
|
replace = {
|
||||||
path = "template/flake.nix";
|
path = "template/flake.nix";
|
||||||
regex = ''^([[:space:]]*repo-lib\.url = ")[^"]*(";)$'';
|
regex = ''^([[:space:]]*repo-lib\.url = ")[^"]*(";)$'';
|
||||||
replacement = ''\1git+https://example.invalid/repo-lib?ref=$FULL_TAG\2'';
|
replacement = ''\1git+https://example.invalid/repo-lib?ref=refs/tags/\$FULL_TAG\2'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -365,7 +458,7 @@ write_legacy_flake() {
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit (env) pre-commit-check;
|
inherit (env) lefthook-check;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -392,7 +485,7 @@ EOF
|
|||||||
write_template_fixture() {
|
write_template_fixture() {
|
||||||
local repo_dir="$1"
|
local repo_dir="$1"
|
||||||
sed \
|
sed \
|
||||||
-e "s|git+https://git.dgren.dev/eric/nix-flake-lib?ref=v[0-9.]*|path:${ROOT_DIR}|" \
|
-e "s|git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v[0-9.]*|path:${ROOT_DIR}|" \
|
||||||
-e "s|github:nixos/nixpkgs?ref=nixos-unstable|path:${NIXPKGS_FLAKE_PATH}|" \
|
-e "s|github:nixos/nixpkgs?ref=nixos-unstable|path:${NIXPKGS_FLAKE_PATH}|" \
|
||||||
"$ROOT_DIR/template/flake.nix" >"$repo_dir/flake.nix"
|
"$ROOT_DIR/template/flake.nix" >"$repo_dir/flake.nix"
|
||||||
}
|
}
|
||||||
@@ -496,6 +589,18 @@ qc_oracle_init() {
|
|||||||
QC_STATE_BASE="1.0.0"
|
QC_STATE_BASE="1.0.0"
|
||||||
QC_STATE_CHANNEL="stable"
|
QC_STATE_CHANNEL="stable"
|
||||||
QC_STATE_PRE=""
|
QC_STATE_PRE=""
|
||||||
|
QC_SEEN_TAGS=()
|
||||||
|
}
|
||||||
|
|
||||||
|
qc_seen_tag() {
|
||||||
|
local tag="$1"
|
||||||
|
local existing
|
||||||
|
for existing in "${QC_SEEN_TAGS[@]:-}"; do
|
||||||
|
if [[ "$existing" == "$tag" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
qc_oracle_current_full() {
|
qc_oracle_current_full() {
|
||||||
@@ -576,12 +681,16 @@ qc_oracle_apply() {
|
|||||||
if [[ $cmp_status -eq 0 || $cmp_status -eq 2 ]]; then
|
if [[ $cmp_status -eq 0 || $cmp_status -eq 2 ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if qc_seen_tag "v$QC_FULL_VERSION"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
QC_STATE_BASE="$QC_BASE_VERSION"
|
QC_STATE_BASE="$QC_BASE_VERSION"
|
||||||
QC_STATE_CHANNEL="$QC_CHANNEL"
|
QC_STATE_CHANNEL="$QC_CHANNEL"
|
||||||
QC_STATE_PRE="$QC_PRERELEASE_NUM"
|
QC_STATE_PRE="$QC_PRERELEASE_NUM"
|
||||||
QC_EXPECT_SUCCESS=1
|
QC_EXPECT_SUCCESS=1
|
||||||
QC_EXPECT_VERSION="$QC_FULL_VERSION"
|
QC_EXPECT_VERSION="$QC_FULL_VERSION"
|
||||||
|
QC_SEEN_TAGS+=("v$QC_FULL_VERSION")
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -649,12 +758,16 @@ qc_oracle_apply() {
|
|||||||
if [[ $QC_FULL_VERSION == "$current_full" ]]; then
|
if [[ $QC_FULL_VERSION == "$current_full" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if qc_seen_tag "v$QC_FULL_VERSION"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
QC_STATE_BASE="$QC_BASE_VERSION"
|
QC_STATE_BASE="$QC_BASE_VERSION"
|
||||||
QC_STATE_CHANNEL="$QC_CHANNEL"
|
QC_STATE_CHANNEL="$QC_CHANNEL"
|
||||||
QC_STATE_PRE="$QC_PRERELEASE_NUM"
|
QC_STATE_PRE="$QC_PRERELEASE_NUM"
|
||||||
QC_EXPECT_SUCCESS=1
|
QC_EXPECT_SUCCESS=1
|
||||||
QC_EXPECT_VERSION="$QC_FULL_VERSION"
|
QC_EXPECT_VERSION="$QC_FULL_VERSION"
|
||||||
|
QC_SEEN_TAGS+=("v$QC_FULL_VERSION")
|
||||||
}
|
}
|
||||||
|
|
||||||
run_randomized_quickcheck_cases() {
|
run_randomized_quickcheck_cases() {
|
||||||
@@ -798,6 +911,38 @@ run_set_prerelease_then_full_case() {
|
|||||||
echo "[test] PASS: $case_name" >&2
|
echo "[test] PASS: $case_name" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_stable_then_beta_cannot_reuse_same_base_case() {
|
||||||
|
local case_name="stable release cannot go back to same-base beta"
|
||||||
|
|
||||||
|
local workdir
|
||||||
|
workdir="$(mktemp -d)"
|
||||||
|
local repo_dir="$workdir/repo"
|
||||||
|
local remote_dir="$workdir/remote.git"
|
||||||
|
CURRENT_LOG="$workdir/case.log"
|
||||||
|
|
||||||
|
prepare_case_repo "$repo_dir" "$remote_dir"
|
||||||
|
|
||||||
|
run_capture_ok "$case_name: initial beta release failed" run_release "$repo_dir" beta
|
||||||
|
run_capture_ok "$case_name: stable promotion failed" run_release "$repo_dir" full
|
||||||
|
run_capture_ok "$case_name: second beta release failed" run_release "$repo_dir" beta
|
||||||
|
|
||||||
|
local got_version
|
||||||
|
got_version="$(version_from_file "$repo_dir")"
|
||||||
|
assert_eq "1.0.2-beta.1" "$got_version" "$case_name: VERSION mismatch"
|
||||||
|
|
||||||
|
if ! git -C "$repo_dir" tag --list | grep -qx "v1.0.1"; then
|
||||||
|
fail "$case_name: expected stable tag v1.0.1 was not created"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git -C "$repo_dir" tag --list | grep -qx "v1.0.2-beta.1"; then
|
||||||
|
fail "$case_name: expected tag v1.0.2-beta.1 was not created"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$workdir"
|
||||||
|
CURRENT_LOG=""
|
||||||
|
echo "[test] PASS: $case_name" >&2
|
||||||
|
}
|
||||||
|
|
||||||
run_set_stable_then_full_noop_case() {
|
run_set_stable_then_full_noop_case() {
|
||||||
local case_name="set stable then full fails with no-op"
|
local case_name="set stable then full fails with no-op"
|
||||||
|
|
||||||
@@ -985,6 +1130,65 @@ EOF
|
|||||||
echo "[test] PASS: $case_name" >&2
|
echo "[test] PASS: $case_name" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_version_metadata_case() {
|
||||||
|
local case_name="release metadata is preserved and exported"
|
||||||
|
local release_steps
|
||||||
|
|
||||||
|
read -r -d '' release_steps <<'EOF' || true
|
||||||
|
if [[ "$(version_meta_get desktop_backend_change_scope)" != "bindings" ]]; then
|
||||||
|
echo "metadata getter mismatch" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ "${VERSION_META_DESKTOP_BACKEND_CHANGE_SCOPE:-}" != "bindings" ]]; then
|
||||||
|
echo "metadata export mismatch" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ "${VERSION_META_DESKTOP_RELEASE_MODE:-}" != "binary" ]]; then
|
||||||
|
echo "metadata export mismatch" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
version_meta_set desktop_release_mode codepush
|
||||||
|
version_meta_set desktop_binary_version_min 1.0.0
|
||||||
|
version_meta_set desktop_binary_version_max "$FULL_VERSION"
|
||||||
|
version_meta_set desktop_backend_compat_id compat-123
|
||||||
|
version_meta_unset desktop_unused
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local workdir
|
||||||
|
workdir="$(mktemp -d)"
|
||||||
|
local repo_dir="$workdir/repo"
|
||||||
|
local remote_dir="$workdir/remote.git"
|
||||||
|
CURRENT_LOG="$workdir/case.log"
|
||||||
|
|
||||||
|
prepare_case_repo_with_release_script "$repo_dir" "$remote_dir" "$release_steps" ":"
|
||||||
|
cat >"$repo_dir/VERSION" <<'EOF'
|
||||||
|
1.0.0
|
||||||
|
stable
|
||||||
|
0
|
||||||
|
desktop_backend_change_scope=bindings
|
||||||
|
desktop_release_mode=binary
|
||||||
|
desktop_unused=temporary
|
||||||
|
EOF
|
||||||
|
run_capture_ok "$case_name: setup commit failed" git -C "$repo_dir" add VERSION
|
||||||
|
run_capture_ok "$case_name: setup commit failed" git -C "$repo_dir" commit -m "chore: seed metadata"
|
||||||
|
run_capture_ok "$case_name: release command failed" run_release "$repo_dir" patch
|
||||||
|
|
||||||
|
assert_eq "1.0.1" "$(version_from_file "$repo_dir")" "$case_name: VERSION mismatch"
|
||||||
|
assert_contains "desktop_backend_change_scope=bindings" "$repo_dir/VERSION" "$case_name: missing preserved scope"
|
||||||
|
assert_contains "desktop_release_mode=codepush" "$repo_dir/VERSION" "$case_name: missing updated mode"
|
||||||
|
assert_contains "desktop_binary_version_min=1.0.0" "$repo_dir/VERSION" "$case_name: missing min version"
|
||||||
|
assert_contains "desktop_binary_version_max=1.0.1" "$repo_dir/VERSION" "$case_name: missing max version"
|
||||||
|
assert_contains "desktop_backend_compat_id=compat-123" "$repo_dir/VERSION" "$case_name: missing compat id"
|
||||||
|
if grep -Fq "desktop_unused=temporary" "$repo_dir/VERSION"; then
|
||||||
|
fail "$case_name: unset metadata key was preserved"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "$workdir"
|
||||||
|
CURRENT_LOG=""
|
||||||
|
echo "[test] PASS: $case_name" >&2
|
||||||
|
}
|
||||||
|
|
||||||
run_mk_repo_case() {
|
run_mk_repo_case() {
|
||||||
local case_name="mkRepo exposes outputs and auto-installs tools"
|
local case_name="mkRepo exposes outputs and auto-installs tools"
|
||||||
local workdir
|
local workdir
|
||||||
@@ -994,13 +1198,105 @@ run_mk_repo_case() {
|
|||||||
write_mk_repo_flake "$repo_dir"
|
write_mk_repo_flake "$repo_dir"
|
||||||
CURRENT_LOG="$workdir/mk-repo.log"
|
CURRENT_LOG="$workdir/mk-repo.log"
|
||||||
|
|
||||||
run_capture_ok "$case_name: flake show failed" nix flake show --json "$repo_dir"
|
run_capture_ok "$case_name: flake show failed" nix flake show --json --no-write-lock-file "$repo_dir"
|
||||||
assert_contains '"pre-commit-check"' "$CURRENT_LOG" "$case_name: missing pre-commit-check"
|
assert_contains '"lefthook-check"' "$CURRENT_LOG" "$case_name: missing lefthook-check"
|
||||||
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
||||||
assert_contains '"example"' "$CURRENT_LOG" "$case_name: missing merged package"
|
assert_contains '"example"' "$CURRENT_LOG" "$case_name: missing merged package"
|
||||||
|
|
||||||
run_capture_ok "$case_name: tool package should be available in shell" nix develop "$repo_dir" -c hello --version
|
run_capture_ok "$case_name: tool package should be available in shell" bash -c 'cd "$1" && nix develop --no-write-lock-file . -c hello --version' _ "$repo_dir"
|
||||||
run_capture_ok "$case_name: release package should be available in shell" nix develop "$repo_dir" -c sh -c 'command -v release >/dev/null'
|
run_capture_ok "$case_name: release package should be available in shell" bash -c 'cd "$1" && nix develop --no-write-lock-file . -c sh -c "command -v release >/dev/null"' _ "$repo_dir"
|
||||||
|
|
||||||
|
rm -rf "$workdir"
|
||||||
|
CURRENT_LOG=""
|
||||||
|
echo "[test] PASS: $case_name" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
run_mk_repo_command_tool_case() {
|
||||||
|
local case_name="mkRepo supports command-backed tools from PATH"
|
||||||
|
local workdir
|
||||||
|
workdir="$(mktemp -d)"
|
||||||
|
local repo_dir="$workdir/mk-repo-command-tool"
|
||||||
|
mkdir -p "$repo_dir"
|
||||||
|
write_mk_repo_command_tool_flake "$repo_dir"
|
||||||
|
CURRENT_LOG="$workdir/mk-repo-command-tool.log"
|
||||||
|
|
||||||
|
run_capture_ok "$case_name: flake show failed" nix flake show --json --no-write-lock-file "$repo_dir"
|
||||||
|
assert_contains '"lefthook-check"' "$CURRENT_LOG" "$case_name: missing lefthook-check"
|
||||||
|
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
||||||
|
|
||||||
|
run_capture_ok "$case_name: system nix should be available in shell" bash -c 'cd "$1" && nix develop --no-write-lock-file . -c nix --version' _ "$repo_dir"
|
||||||
|
assert_contains "" "$CURRENT_LOG" "$case_name: missing tool icon in banner"
|
||||||
|
run_capture_ok "$case_name: release package should be available in shell" bash -c 'cd "$1" && nix develop --no-write-lock-file . -c sh -c "command -v release >/dev/null"' _ "$repo_dir"
|
||||||
|
|
||||||
|
rm -rf "$workdir"
|
||||||
|
CURRENT_LOG=""
|
||||||
|
echo "[test] PASS: $case_name" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
run_mk_repo_lefthook_case() {
|
||||||
|
local case_name="mkRepo exposes raw lefthook config for advanced hook fields"
|
||||||
|
local workdir
|
||||||
|
workdir="$(mktemp -d)"
|
||||||
|
local repo_dir="$workdir/mk-repo-lefthook"
|
||||||
|
local system
|
||||||
|
local derivation_json="$workdir/lefthook-run.drv.json"
|
||||||
|
local lefthook_yml_drv
|
||||||
|
local lefthook_yml_json="$workdir/lefthook-yml.drv.json"
|
||||||
|
mkdir -p "$repo_dir"
|
||||||
|
write_mk_repo_lefthook_flake "$repo_dir"
|
||||||
|
CURRENT_LOG="$workdir/mk-repo-lefthook.log"
|
||||||
|
|
||||||
|
system="$(nix eval --raw --impure --expr 'builtins.currentSystem')"
|
||||||
|
run_capture_ok "$case_name: flake show failed" nix flake show --json --no-write-lock-file "$repo_dir"
|
||||||
|
run_capture_ok "$case_name: lefthook derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$repo_dir#checks.${system}.lefthook-check" "$derivation_json"
|
||||||
|
|
||||||
|
lefthook_yml_drv="$(perl -0ne 'print "/nix/store/$1\n" if /"([a-z0-9]{32}-lefthook\.yml\.drv)"/' "$derivation_json")"
|
||||||
|
if [[ -z "$lefthook_yml_drv" ]]; then
|
||||||
|
fail "$case_name: could not locate lefthook.yml derivation"
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_capture_ok "$case_name: lefthook.yml derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$lefthook_yml_drv" "$lefthook_yml_json"
|
||||||
|
assert_contains '\"pre-push\":{\"commands\":{\"tests\":{' "$lefthook_yml_json" "$case_name: generated check missing from pre-push"
|
||||||
|
assert_contains 'repo-lib-check-tests' "$lefthook_yml_json" "$case_name: generated check command missing from lefthook config"
|
||||||
|
assert_contains '\"output\":[\"failure\",\"summary\"]' "$lefthook_yml_json" "$case_name: lefthook output config missing"
|
||||||
|
assert_contains '\"stage_fixed\":true' "$lefthook_yml_json" "$case_name: stage_fixed missing from lefthook config"
|
||||||
|
|
||||||
|
rm -rf "$workdir"
|
||||||
|
CURRENT_LOG=""
|
||||||
|
echo "[test] PASS: $case_name" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
run_mk_repo_treefmt_hook_case() {
|
||||||
|
local case_name="mkRepo configures treefmt and lefthook for dev shell hooks"
|
||||||
|
local workdir
|
||||||
|
workdir="$(mktemp -d)"
|
||||||
|
local repo_dir="$workdir/mk-repo-treefmt"
|
||||||
|
local system
|
||||||
|
local derivation_json="$workdir/treefmt-hook.drv.json"
|
||||||
|
local lefthook_yml_drv
|
||||||
|
local lefthook_yml_json="$workdir/treefmt-hook-yml.drv.json"
|
||||||
|
mkdir -p "$repo_dir"
|
||||||
|
write_mk_repo_flake "$repo_dir"
|
||||||
|
CURRENT_LOG="$workdir/mk-repo-treefmt.log"
|
||||||
|
|
||||||
|
init_git_repo "$repo_dir"
|
||||||
|
|
||||||
|
run_capture_ok "$case_name: treefmt should be available in shell" bash -c 'cd "$1" && nix develop --no-write-lock-file . -c sh -c '"'"'printf "%s\n" "$LEFTHOOK_BIN" && command -v treefmt'"'"'' _ "$repo_dir"
|
||||||
|
assert_contains 'lefthook-dumb-term' "$CURRENT_LOG" "$case_name: LEFTHOOK_BIN wrapper missing"
|
||||||
|
assert_contains '/bin/treefmt' "$CURRENT_LOG" "$case_name: treefmt missing from shell"
|
||||||
|
|
||||||
|
system="$(nix eval --raw --impure --expr 'builtins.currentSystem')"
|
||||||
|
run_capture_ok "$case_name: formatting check derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$repo_dir#checks.${system}.formatting-check" "$workdir/formatting-check.drv.json"
|
||||||
|
run_capture_ok "$case_name: lefthook derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$repo_dir#checks.${system}.lefthook-check" "$derivation_json"
|
||||||
|
|
||||||
|
lefthook_yml_drv="$(perl -0ne 'print "/nix/store/$1\n" if /"([a-z0-9]{32}-lefthook\.yml\.drv)"/' "$derivation_json")"
|
||||||
|
if [[ -z "$lefthook_yml_drv" ]]; then
|
||||||
|
fail "$case_name: could not locate lefthook.yml derivation"
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_capture_ok "$case_name: lefthook.yml derivation show failed" bash -c 'nix derivation show "$1" >"$2"' _ "$lefthook_yml_drv" "$lefthook_yml_json"
|
||||||
|
assert_contains '--no-cache {staged_files}' "$lefthook_yml_json" "$case_name: treefmt hook missing staged-file format command"
|
||||||
|
assert_contains '\"stage_fixed\":true' "$lefthook_yml_json" "$case_name: treefmt hook should re-stage formatted files"
|
||||||
|
|
||||||
rm -rf "$workdir"
|
rm -rf "$workdir"
|
||||||
CURRENT_LOG=""
|
CURRENT_LOG=""
|
||||||
@@ -1016,7 +1312,7 @@ run_mk_repo_tool_failure_case() {
|
|||||||
write_tool_failure_flake "$repo_dir"
|
write_tool_failure_flake "$repo_dir"
|
||||||
CURRENT_LOG="$workdir/tool-failure.log"
|
CURRENT_LOG="$workdir/tool-failure.log"
|
||||||
|
|
||||||
run_expect_failure "$case_name: shell startup should fail" nix develop "$repo_dir" -c true
|
run_expect_failure "$case_name: shell startup should fail" bash -c 'cd "$1" && nix develop . -c true' _ "$repo_dir"
|
||||||
assert_contains "probe failed" "$CURRENT_LOG" "$case_name: failure reason missing"
|
assert_contains "probe failed" "$CURRENT_LOG" "$case_name: failure reason missing"
|
||||||
|
|
||||||
rm -rf "$workdir"
|
rm -rf "$workdir"
|
||||||
@@ -1051,7 +1347,7 @@ run_legacy_api_eval_case() {
|
|||||||
CURRENT_LOG="$workdir/legacy.log"
|
CURRENT_LOG="$workdir/legacy.log"
|
||||||
|
|
||||||
run_capture_ok "$case_name: flake show failed" nix flake show --json "$repo_dir"
|
run_capture_ok "$case_name: flake show failed" nix flake show --json "$repo_dir"
|
||||||
assert_contains '"pre-commit-check"' "$CURRENT_LOG" "$case_name: missing pre-commit-check"
|
assert_contains '"lefthook-check"' "$CURRENT_LOG" "$case_name: missing lefthook-check"
|
||||||
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
||||||
|
|
||||||
rm -rf "$workdir"
|
rm -rf "$workdir"
|
||||||
@@ -1069,7 +1365,7 @@ run_template_eval_case() {
|
|||||||
CURRENT_LOG="$workdir/template.log"
|
CURRENT_LOG="$workdir/template.log"
|
||||||
|
|
||||||
run_capture_ok "$case_name: flake show failed" nix flake show --json "$repo_dir"
|
run_capture_ok "$case_name: flake show failed" nix flake show --json "$repo_dir"
|
||||||
assert_contains '"pre-commit-check"' "$CURRENT_LOG" "$case_name: missing pre-commit-check"
|
assert_contains '"lefthook-check"' "$CURRENT_LOG" "$case_name: missing lefthook-check"
|
||||||
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
assert_contains '"release"' "$CURRENT_LOG" "$case_name: missing release package"
|
||||||
|
|
||||||
rm -rf "$workdir"
|
rm -rf "$workdir"
|
||||||
@@ -1090,7 +1386,7 @@ run_release_replace_backref_case() {
|
|||||||
cat >"$repo_dir/template/flake.nix" <<'EOF'
|
cat >"$repo_dir/template/flake.nix" <<'EOF'
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=v0.0.0";
|
repo-lib.url = "git+https://git.dgren.dev/eric/nix-flake-lib?ref=refs/tags/v0.0.0";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
@@ -1098,10 +1394,10 @@ EOF
|
|||||||
run_capture_ok "$case_name: setup commit failed" git -C "$repo_dir" add flake.nix template/flake.nix
|
run_capture_ok "$case_name: setup commit failed" git -C "$repo_dir" add flake.nix template/flake.nix
|
||||||
run_capture_ok "$case_name: setup commit failed" git -C "$repo_dir" commit -m "chore: add replace fixture"
|
run_capture_ok "$case_name: setup commit failed" git -C "$repo_dir" commit -m "chore: add replace fixture"
|
||||||
|
|
||||||
run_capture_ok "$case_name: nix run release failed" bash -c 'cd "$1" && nix run .#release -- patch' _ "$repo_dir"
|
run_capture_ok "$case_name: nix run release failed" bash -c 'cd "$1" && nix run --no-write-lock-file .#release -- patch' _ "$repo_dir"
|
||||||
|
|
||||||
assert_contains 'repo-lib.url = "git+https://example.invalid/repo-lib?ref=v1.0.1";' "$repo_dir/template/flake.nix" "$case_name: replacement did not preserve captures"
|
assert_contains 'repo-lib.url = "git+https://example.invalid/repo-lib?ref=refs/tags/v1.0.1";' "$repo_dir/template/flake.nix" "$case_name: replacement did not preserve captures"
|
||||||
if grep -Fq '\1git+https://example.invalid/repo-lib?ref=v1.0.1\2' "$repo_dir/template/flake.nix"; then
|
if grep -Fq '\1git+https://example.invalid/repo-lib?ref=refs/tags/v1.0.1\2' "$repo_dir/template/flake.nix"; then
|
||||||
fail "$case_name: replacement left literal backreferences in output"
|
fail "$case_name: replacement left literal backreferences in output"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1113,16 +1409,23 @@ EOF
|
|||||||
run_case "channel-only from stable bumps patch" "beta" "1.0.1-beta.1"
|
run_case "channel-only from stable bumps patch" "beta" "1.0.1-beta.1"
|
||||||
run_case "explicit minor bump keeps requested bump" "minor beta" "1.1.0-beta.1"
|
run_case "explicit minor bump keeps requested bump" "minor beta" "1.1.0-beta.1"
|
||||||
run_set_prerelease_then_full_case
|
run_set_prerelease_then_full_case
|
||||||
|
run_stable_then_beta_cannot_reuse_same_base_case
|
||||||
run_set_stable_then_full_noop_case
|
run_set_stable_then_full_noop_case
|
||||||
run_set_stable_from_prerelease_requires_full_case
|
run_set_stable_from_prerelease_requires_full_case
|
||||||
run_patch_stable_from_prerelease_requires_full_case
|
run_patch_stable_from_prerelease_requires_full_case
|
||||||
run_structured_release_steps_case
|
run_structured_release_steps_case
|
||||||
|
run_version_metadata_case
|
||||||
run_mk_repo_case
|
run_mk_repo_case
|
||||||
|
run_mk_repo_command_tool_case
|
||||||
|
run_mk_repo_lefthook_case
|
||||||
|
run_mk_repo_treefmt_hook_case
|
||||||
run_mk_repo_tool_failure_case
|
run_mk_repo_tool_failure_case
|
||||||
run_impure_bootstrap_validation_case
|
run_impure_bootstrap_validation_case
|
||||||
run_legacy_api_eval_case
|
run_legacy_api_eval_case
|
||||||
run_template_eval_case
|
run_template_eval_case
|
||||||
run_release_replace_backref_case
|
run_release_replace_backref_case
|
||||||
run_randomized_quickcheck_cases
|
if [[ "${QUICKCHECK:-0}" == "1" ]]; then
|
||||||
|
run_randomized_quickcheck_cases
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[test] All release tests passed" >&2
|
echo "[test] All release tests passed" >&2
|
||||||
|
|||||||
Reference in New Issue
Block a user