chore: add git remote topology module + docs
modules/git/remotes.nix declares upstream/fork/extras schema. extras is a typed submodule list so order is preserved and future fields (pushUrl, mirror) can extend without breaking callers. docs/remotes.md walks the three canonical topologies (upstream-only / github-fork / multi-remote with private host). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8cc59b3024
commit
6adc82e8f3
2 changed files with 194 additions and 0 deletions
80
docs/remotes.md
Normal file
80
docs/remotes.md
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Remote topology
|
||||||
|
|
||||||
|
`lnbits-sensei.git.remotes` (declared in `modules/git/remotes.nix`)
|
||||||
|
abstracts how the local LNbits checkout is wired to its git remotes.
|
||||||
|
Three patterns cover almost every workflow.
|
||||||
|
|
||||||
|
## 1. Upstream-only
|
||||||
|
|
||||||
|
You read upstream, never push. Good for a read-only dev box, a CI
|
||||||
|
runner, or initial exploration before you've decided to contribute.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
lnbits-sensei.git.remotes = {
|
||||||
|
upstream = "https://github.com/lnbits/lnbits";
|
||||||
|
fork = null;
|
||||||
|
extras = [ ];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
What you get:
|
||||||
|
|
||||||
|
- `upstream` remote pointing at canonical lnbits/lnbits.
|
||||||
|
- No `fork` remote — the bootstrap script skips it when `fork` is null.
|
||||||
|
- No extras.
|
||||||
|
|
||||||
|
## 2. GitHub fork for PRs
|
||||||
|
|
||||||
|
You maintain a personal fork on GitHub and use it as your push target
|
||||||
|
for PRs landing in upstream. `upstream` stays pull-only.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
lnbits-sensei.git.remotes = {
|
||||||
|
upstream = "https://github.com/lnbits/lnbits";
|
||||||
|
fork = "git@github.com:<you>/lnbits.git";
|
||||||
|
extras = [ ];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
What you get:
|
||||||
|
|
||||||
|
- `upstream` for fetching releases / rebasing onto main.
|
||||||
|
- `fork` as the default push target.
|
||||||
|
- The upstream-PR helper (later pass) knows to push branches to `fork`
|
||||||
|
and open the compare URL against `upstream`.
|
||||||
|
|
||||||
|
## 3. Multi-remote with a private host
|
||||||
|
|
||||||
|
You also push to a private forgejo / gitea / codeberg mirror — for
|
||||||
|
internal review, a deployment pipeline, or just an off-GitHub backup.
|
||||||
|
The upstream + public-fork flow stays intact; the extras layer on top.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
lnbits-sensei.git.remotes = {
|
||||||
|
upstream = "https://github.com/lnbits/lnbits";
|
||||||
|
fork = "git@github.com:<you>/lnbits.git";
|
||||||
|
extras = [
|
||||||
|
{ name = "internal"; url = "git@<your-forgejo>:<org>/lnbits.git"; }
|
||||||
|
{ name = "mirror"; url = "git@codeberg.org:<you>/lnbits.git"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
What you get:
|
||||||
|
|
||||||
|
- Same as pattern 2, plus the named extras as additional remotes.
|
||||||
|
- Each extra becomes a `git remote add <name> <url>` on bootstrap;
|
||||||
|
pushing to them is opt-in (never the default push target).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `extras` is a list of `{ name; url; }` submodules — order is
|
||||||
|
preserved, and future fields (`pushUrl`, `mirror`) can be added
|
||||||
|
without breaking existing configs.
|
||||||
|
- The module is schema-only. The dev-env bootstrap script (later pass)
|
||||||
|
is what actually runs `git remote add` against a real checkout. It
|
||||||
|
is idempotent: re-running after editing `extras` reconciles the
|
||||||
|
on-disk remotes with the declared set.
|
||||||
|
- `fork = null` is the right value when you have no GitHub fork —
|
||||||
|
don't point it at a placeholder URL, the bootstrap script keys on
|
||||||
|
null to skip the `fork` remote entirely.
|
||||||
114
modules/git/remotes.nix
Normal file
114
modules/git/remotes.nix
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
# lnbits-sensei — git remote topology.
|
||||||
|
#
|
||||||
|
# Abstracts how a local LNbits checkout is wired to its remotes. Three
|
||||||
|
# patterns are supported out of the box (see docs/remotes.md for the
|
||||||
|
# full prose):
|
||||||
|
#
|
||||||
|
# 1. Upstream-only — you read upstream, never push. `fork` = null,
|
||||||
|
# `extras` = [].
|
||||||
|
#
|
||||||
|
# lnbits-sensei.git.remotes = {
|
||||||
|
# upstream = "https://github.com/lnbits/lnbits";
|
||||||
|
# fork = null;
|
||||||
|
# extras = [ ];
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# 2. GitHub fork for PRs — you maintain a fork on GitHub and send
|
||||||
|
# PRs upstream. The fork remote is your push target; `upstream` is
|
||||||
|
# pull-only.
|
||||||
|
#
|
||||||
|
# lnbits-sensei.git.remotes = {
|
||||||
|
# upstream = "https://github.com/lnbits/lnbits";
|
||||||
|
# fork = "git@github.com:<you>/lnbits.git";
|
||||||
|
# extras = [ ];
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# 3. Multi-remote with private host — you also push to a private
|
||||||
|
# forgejo/gitea/codeberg for internal review or deployment, while
|
||||||
|
# keeping the upstream + public-fork flow intact.
|
||||||
|
#
|
||||||
|
# lnbits-sensei.git.remotes = {
|
||||||
|
# upstream = "https://github.com/lnbits/lnbits";
|
||||||
|
# fork = "git@github.com:<you>/lnbits.git";
|
||||||
|
# extras = [
|
||||||
|
# { name = "internal"; url = "git@<your-forgejo>:<org>/lnbits.git"; }
|
||||||
|
# { name = "mirror"; url = "git@codeberg.org:<you>/lnbits.git"; }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# Modules that materialize remotes on disk (dev-env bootstrap, the
|
||||||
|
# upstream-PR helper) read this attrset and translate to `git remote
|
||||||
|
# add` / `git remote set-url` operations idempotently.
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
|
||||||
|
# One entry in `extras`. Kept as a typed submodule rather than an
|
||||||
|
# `attrsOf str` so the order is preserved (relevant for any UI that
|
||||||
|
# surfaces remotes in declaration order) and so future fields
|
||||||
|
# (`pushUrl`, `mirror`, …) can be added without breaking callers.
|
||||||
|
extraRemoteType = types.submodule {
|
||||||
|
options = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Git remote name (the `<name>` in `git remote add <name> <url>`).";
|
||||||
|
example = "internal";
|
||||||
|
};
|
||||||
|
url = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Git remote URL (ssh or https).";
|
||||||
|
example = "git@codeberg.org:<you>/lnbits.git";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.lnbits-sensei.git.remotes = {
|
||||||
|
upstream = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "https://github.com/lnbits/lnbits";
|
||||||
|
description = ''
|
||||||
|
Canonical upstream URL. Read-only in practice — even when you
|
||||||
|
have push rights, prefer routing changes through `fork` so the
|
||||||
|
upstream-PR helper does the right thing.
|
||||||
|
'';
|
||||||
|
example = "https://github.com/lnbits/lnbits";
|
||||||
|
};
|
||||||
|
|
||||||
|
fork = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Personal GitHub fork URL used as the push target for upstream
|
||||||
|
PRs. Null when you don't intend to send PRs upstream; the
|
||||||
|
skeleton then skips adding a `fork` remote on bootstrap.
|
||||||
|
'';
|
||||||
|
example = "git@github.com:<you>/lnbits.git";
|
||||||
|
};
|
||||||
|
|
||||||
|
extras = mkOption {
|
||||||
|
type = types.listOf extraRemoteType;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Additional remotes — private forgejo, internal gitea, codeberg
|
||||||
|
mirror, etc. Each entry becomes a `git remote add <name> <url>`
|
||||||
|
on bootstrap.
|
||||||
|
'';
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
[
|
||||||
|
{ name = "internal"; url = "git@<your-forgejo>:<org>/lnbits.git"; }
|
||||||
|
{ name = "mirror"; url = "git@codeberg.org:<you>/lnbits.git"; }
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# No config body — this module declares schema only. The dev-env
|
||||||
|
# bootstrap script (later pass) consumes these values to materialize
|
||||||
|
# remotes on a real checkout.
|
||||||
|
}
|
||||||
Reference in a new issue