feat(dev-env): aiolabs dev environment — options, lib, config, presets
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
02504f9fd3
commit
7960f82494
6 changed files with 1689 additions and 0 deletions
369
modules/dev-env/options.nix
Normal file
369
modules/dev-env/options.nix
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption types;
|
||||
|
||||
# One entry in dev-env.projects.
|
||||
#
|
||||
# A project is a git repo with one or more worktrees (or a single clone
|
||||
# if `isClone = true`). Worktrees are derived from a bare repo at
|
||||
# `${dev-env.root}/repos/${name}.git` by default; that path is managed
|
||||
# by the bootstrap script.
|
||||
projectType = types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
forgejoRepo = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
<org>/<repo> on the configured forgejo host. Used to construct
|
||||
the `origin` remote. May be null for projects whose origin
|
||||
lives outside forgejo — in that case set `originUrl`.
|
||||
'';
|
||||
example = "aiolabs/lnbits";
|
||||
};
|
||||
|
||||
originUrl = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Override the origin remote URL. By default, origin is derived
|
||||
from the forgejo host + forgejoRepo. Set this to clone from
|
||||
an arbitrary URL (e.g. a GitHub repo that has no forgejo mirror).
|
||||
'';
|
||||
example = "https://github.com/nostr-protocol/nips";
|
||||
};
|
||||
|
||||
upstream = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
HTTPS URL of the upstream OSS repo. Set to null for projects
|
||||
with no upstream (divergent branches, original work).
|
||||
When set, the `upstream` remote is added to the bare repo and
|
||||
the `prb`/`prc`/rebase helpers know how to sync from it.
|
||||
'';
|
||||
example = "https://github.com/lnbits/lnbits";
|
||||
};
|
||||
|
||||
githubFork = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Full SSH URL of the personal github fork used for upstream PRs
|
||||
(the `github-fork` remote). If null, derived from the global
|
||||
`dev-env.github.forkUser` + the basename of `forgejoRepo`.
|
||||
'';
|
||||
example = "git@github.com:your-github-username/lnbits.git";
|
||||
};
|
||||
|
||||
category = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Sub-directory under `dev-env.root` that groups related
|
||||
projects. e.g. "bitspire" groups the bitSpire frontend +
|
||||
atm-tui. null puts the project at the top level.
|
||||
'';
|
||||
example = "bitspire";
|
||||
};
|
||||
|
||||
worktreeRoot = mkOption {
|
||||
type = types.str;
|
||||
default = if name == null then "" else name;
|
||||
defaultText = "project name";
|
||||
description = ''
|
||||
Directory name (relative to `category` or root) under which
|
||||
worktrees live. Defaults to the project name.
|
||||
'';
|
||||
};
|
||||
|
||||
worktrees = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
branch = mkOption {
|
||||
type = types.str;
|
||||
description = "Branch to check out in this worktree.";
|
||||
};
|
||||
path = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Override the worktree directory name. Defaults to the
|
||||
attribute key.
|
||||
'';
|
||||
};
|
||||
remote = mkOption {
|
||||
type = types.str;
|
||||
default = "origin";
|
||||
description = ''
|
||||
Which remote the branch tracks. Usually origin (forgejo)
|
||||
but could be "upstream" for read-only tracking worktrees.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
description = ''
|
||||
Worktrees to materialize for this project, keyed by worktree
|
||||
name. Each worktree becomes a directory at
|
||||
`''${dev-env.root}/''${category}/''${worktreeRoot}/<key>` (or under
|
||||
root if category is null).
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
dev = { branch = "dev"; };
|
||||
main = { branch = "main"; };
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
isClone = mkEnableOption ''
|
||||
Treat this project as a regular clone rather than a bare-repo
|
||||
worktree set. Used for projects that won't have multiple
|
||||
simultaneous branches checked out (e.g. atm-tui)
|
||||
'';
|
||||
|
||||
deployFlakeInput = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Name of the flake input in the deploy flake that this project
|
||||
corresponds to. Used by `dev-deploy --local` to know which
|
||||
--override-input to pass.
|
||||
'';
|
||||
example = "lnbits";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
# One entry in dev-env.tmux.sessions.
|
||||
tmuxSessionType = types.submodule {
|
||||
options = {
|
||||
cwd = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Session-default cwd, relative to `dev-env.root`. Windows can
|
||||
override with their own cwd.
|
||||
'';
|
||||
};
|
||||
windows = mkOption {
|
||||
type = types.listOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption { type = types.str; };
|
||||
cwd = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Window cwd, relative to dev-env.root.";
|
||||
};
|
||||
cmd = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Command to run in the window on creation.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.dev-env = {
|
||||
enable = mkEnableOption "dev-env multi-project development environment";
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "user";
|
||||
description = ''
|
||||
Owner of the dev tree. Drives `root`'s default and the per-user
|
||||
git-hooks / state-dir paths. Set this to your login user when
|
||||
importing dev-env standalone; on omni the host wires it to
|
||||
`settings.user`. Kept self-contained (a plain default, no
|
||||
`config.omni.*` read) so this pack is importable without omni.
|
||||
'';
|
||||
};
|
||||
|
||||
root = mkOption {
|
||||
type = types.str;
|
||||
default = "/home/${config.dev-env.user}/dev";
|
||||
defaultText = "/home/\${config.dev-env.user}/dev";
|
||||
description = ''
|
||||
Root directory for the dev environment. Bare repos live under
|
||||
`''${root}/repos/`, worktrees under `''${root}/<category>/<project>/`.
|
||||
'';
|
||||
};
|
||||
|
||||
forgejo = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "git.atitlan.io";
|
||||
description = "Forgejo server hostname.";
|
||||
};
|
||||
sshUser = mkOption {
|
||||
type = types.str;
|
||||
default = "forgejo";
|
||||
description = ''
|
||||
SSH user for git+ssh access to forgejo. Some installations use
|
||||
"git", others use "forgejo". Defaults to "forgejo" because the
|
||||
reference deployment uses that.
|
||||
'';
|
||||
};
|
||||
org = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Default forgejo org/user under which your forks live. Used as
|
||||
the namespace when a project's `forgejoRepo` is a bare name.
|
||||
'';
|
||||
example = "aiolabs";
|
||||
};
|
||||
};
|
||||
|
||||
github = {
|
||||
forkUser = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Personal github username used for upstream PR forks (the
|
||||
`github-fork` remote). When set, projects that declare an
|
||||
upstream automatically get a github-fork remote derived from
|
||||
`git@github.com:<forkUser>/<basename>.git`.
|
||||
'';
|
||||
example = "your-github-username";
|
||||
};
|
||||
};
|
||||
|
||||
projects = mkOption {
|
||||
type = types.attrsOf projectType;
|
||||
default = { };
|
||||
description = ''
|
||||
Hand-authored project list. This is merged with projects derived
|
||||
from the deploy flake (when `deploy.deriveProjectsFromInputs` is
|
||||
true). Hand entries win on key collision.
|
||||
'';
|
||||
};
|
||||
|
||||
deploy = {
|
||||
flakeInput = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Name of the omni flake input that points at the unified
|
||||
deploy flake. When set, the bootstrap script clones it to
|
||||
`''${root}/deploy/<flakeInput>` as a working copy, and
|
||||
`dev-deploy` uses it as the --flake source by default.
|
||||
'';
|
||||
example = "deploy-flake";
|
||||
};
|
||||
|
||||
targets = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = { };
|
||||
description = ''
|
||||
Map from hostname to SSH target used by `dev-deploy`. Mirrors
|
||||
the TARGETS associative array in optimize-deploys/unified/
|
||||
deploy.sh.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
host1 = "root@host1.example";
|
||||
host5 = "root@host5.example";
|
||||
host7 = "root@host7.example";
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
deriveProjectsFromInputs = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
When true and `flakeInput` is set, derive a default project
|
||||
entry for every flake input of the deploy flake whose URL is
|
||||
under the forgejo host. Hand-authored `projects` win on key
|
||||
collision.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
regtest = {
|
||||
enable = mkEnableOption ''
|
||||
Unified Bitcoin/Lightning regtest docker environment. Enables
|
||||
virtualisation.docker (via mkDefault)
|
||||
'';
|
||||
|
||||
repoUrl = mkOption {
|
||||
type = types.str;
|
||||
default = "forgejo@git.atitlan.io:aiolabs/lnbits-regtest.git";
|
||||
description = ''
|
||||
Git URL of the regtest docker-compose repo. Cloned to
|
||||
`''${root}/local/docker/regtest` by the bootstrap script.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
tmux = {
|
||||
enable = mkEnableOption "declarative tmux session launcher (dev-tm)";
|
||||
|
||||
sessions = mkOption {
|
||||
type = types.attrsOf tmuxSessionType;
|
||||
default = { };
|
||||
description = ''
|
||||
Named tmux session layouts. The `dev-tm <name>` script reads
|
||||
these from /etc/dev-env/tmux-sessions.json at runtime and
|
||||
recreates the session.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
gitHooks = {
|
||||
enable =
|
||||
mkEnableOption ''
|
||||
Shared pre-commit hook via core.hooksPath. Installs a single
|
||||
hook that scans for secrets (prv keys, hardcoded passwords,
|
||||
unencrypted sops files) in all repos under dev-env.root
|
||||
''
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
default = "${config.dev-env.root or "/tmp"}/.git-hooks";
|
||||
defaultText = ''"''${root}/.git-hooks"'';
|
||||
description = "Directory used for git core.hooksPath.";
|
||||
};
|
||||
};
|
||||
|
||||
writeDirenvHints = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
When true, the bootstrap script writes a default `.envrc`
|
||||
containing `use flake` into each worktree that has a flake.nix
|
||||
but no existing .envrc. Never clobbers existing files.
|
||||
'';
|
||||
};
|
||||
|
||||
legacyConfigFile = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = "${config.dev-env.root or "/tmp"}/.devenv.conf";
|
||||
defaultText = ''"''${root}/.devenv.conf"'';
|
||||
description = ''
|
||||
Path at which to also write a legacy `.devenv.conf` for any
|
||||
loose bash scripts still reading it. The canonical config is at
|
||||
/etc/dev-env/config.sh; this is a transitional aid. Set to null
|
||||
to disable once migration is complete.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue