@sous-io/sous 0.2.16 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/markdown/commands.md +59 -13
- package/docs/markdown/repositories-authoring.md +75 -13
- package/docs/markdown/repositories-consuming.md +44 -2
- package/docs/markdown/repositories-file-formats.md +22 -1
- package/docs/markdown/repositories-providers.md +20 -10
- package/package.json +1 -1
- package/recipes/core/sous-skills/sous.recipe.yaml +8 -1
- package/src/commands/repo/release.ts +41 -0
- package/src/commands/repo/submit.ts +245 -35
- package/src/commands/repo/unlink.ts +333 -20
- package/src/commands/subscription/update.ts +215 -0
- package/src/lib/repos/formats/common.ts +20 -0
- package/src/lib/repos/formats/links-map.ts +5 -3
- package/src/lib/repos/formats/recipe-manifest.ts +7 -0
- package/src/lib/repos/formats/repo-manifest.ts +8 -0
- package/src/lib/repos/git-clone.ts +71 -0
- package/src/lib/repos/links.ts +2 -1
- package/src/lib/repos/locked-recipes.ts +22 -0
- package/src/lib/repos/providers/base.ts +33 -1
- package/src/lib/repos/providers/github.ts +275 -3
- package/src/lib/repos/providers/provider.ts +119 -3
- package/src/lib/repos/release/changelog.ts +448 -0
- package/src/lib/repos/release/git-state.ts +101 -15
- package/src/lib/repos/release/index.ts +2 -0
- package/src/lib/repos/release/submissions.ts +214 -0
- package/src/lib/repos/release/submit-checkout.ts +271 -0
- package/src/lib/repos/release/submit-questions.ts +153 -0
- package/src/lib/repos/release/submit-service.ts +581 -174
- package/src/lib/repos/resolver.ts +25 -2
- package/src/lib/repos/seed.ts +64 -5
- package/src/lib/repos/store/hash.ts +68 -8
- package/src/lib/repos/subscription-service.ts +744 -20
- package/src/lib/repos/update-plan.ts +234 -0
|
@@ -17,7 +17,8 @@ Every command that works on a project takes these four. `SOUS_CONFIG`, `SOUS_DIR
|
|
|
17
17
|
a flag beats its variable, and both beat walk-up discovery. See [Discovery and overrides](config-discovery.md).
|
|
18
18
|
|
|
19
19
|
?> `repo init`, `repo release` and `repo submit` take none of these. They run inside a recipe repository, which
|
|
20
|
-
has no `.sous/` directory to discover. All three still take `--non-interactive`.
|
|
20
|
+
has no `.sous/` directory to discover. All three still take `--non-interactive`. `repo submit` may also be run
|
|
21
|
+
from a project, which it finds by walking up from the working directory.
|
|
21
22
|
|
|
22
23
|
## Flags that answer questions
|
|
23
24
|
|
|
@@ -230,9 +231,22 @@ Example: `sous repo link sous-recipes ~/Projects/sous-recipes`, or `sous repo li
|
|
|
230
231
|
--generate-branch --latest --yes`
|
|
231
232
|
|
|
232
233
|
### `sous repo unlink REPO`
|
|
233
|
-
Stops reading a repository from a working copy
|
|
234
|
-
it appears in `sous.links.json` (see
|
|
235
|
-
|
|
234
|
+
Stops reading a repository from a working copy, goes back to the versions the lockfile pins, and rebuilds the
|
|
235
|
+
project; `REPO` is the short name as it appears in `sous.links.json` (see
|
|
236
|
+
[File formats](repositories-file-formats.md)). On its own it also fetches the repository's index, with a short
|
|
237
|
+
timeout, and reports any newer published version the ranges allow, without moving anything; when the index
|
|
238
|
+
cannot be fetched in time it says it could not check. The checkout stays where it is unless `--remove` is passed.
|
|
239
|
+
Takes `--dry-run`, `--no-build`, `--answer` and `--answers-file`.
|
|
240
|
+
|
|
241
|
+
- `--global`: remove the machine-wide link, not this project's.
|
|
242
|
+
- `--update`: move this repository's pins to the newest versions their ranges allow before rebuilding. It runs
|
|
243
|
+
the same code as `sous subscription update REPO`.
|
|
244
|
+
- `--remove`: delete the checkout as well, but only one sous cloned itself; a checkout linked by path is refused
|
|
245
|
+
with an error. Uncommitted changes, commits no remote has and stashes are listed first and asked about.
|
|
246
|
+
- `-y, --yes`: answer every question this command asks: deleting a checkout that holds work, the update plan,
|
|
247
|
+
and the trust question for a repository a newer version needs (also `--force`, `--trust`).
|
|
248
|
+
|
|
249
|
+
Example: `sous repo unlink sous-recipes --update`
|
|
236
250
|
|
|
237
251
|
### `sous repo init [DIRECTORY]`
|
|
238
252
|
Creates a new recipe repository in a directory, defaulting to the current one; `--dry-run` prints the files it
|
|
@@ -254,17 +268,32 @@ and `git config user.email`), because it commits and cuts annotated tags. Takes
|
|
|
254
268
|
- `--no-bump`: raise nothing; a changed recipe that was never raised is then an error.
|
|
255
269
|
- `--include-unchanged`: release every recipe in scope, changed or not.
|
|
256
270
|
- `--tag`, `--push`: tag even on a non-default branch, and push the commit and this run's tags.
|
|
257
|
-
- `--check`: only validate. It fails on a problem the release would refuse, and
|
|
258
|
-
|
|
271
|
+
- `--check`: only validate. It fails on a problem the release would refuse, and on a change to a recipe that
|
|
272
|
+
takes no proposals (see [`submissions`](repositories-file-formats.md#the-submissions-block)), and reports,
|
|
273
|
+
without failing, how merging would rewrite the committed index.
|
|
259
274
|
- `--ci`: the merge preset. Never bump, never ask, and fail on anything unbumped. It still needs `--yes` to
|
|
260
275
|
accept the plan it prints, so a merge job runs `sous repo release --ci --yes --push`.
|
|
261
276
|
|
|
262
277
|
Example: `sous repo release --recipe workflow/task-files --bump minor --push`
|
|
263
278
|
|
|
264
|
-
### `sous repo submit`
|
|
265
|
-
Proposes
|
|
266
|
-
|
|
267
|
-
|
|
279
|
+
### `sous repo submit [REPO]`
|
|
280
|
+
Proposes a recipe repository's changes to its maintainers, and follows the proposal through: it opens one,
|
|
281
|
+
updates it when there is more to send, reports where it stands, and starts the next one once it was merged. Run
|
|
282
|
+
inside a recipe repository it works there; run inside a project, `REPO` names a linked repository and the
|
|
283
|
+
submission runs in its checkout (with no `REPO`, the only linked repository is used, and several are a
|
|
284
|
+
question). Takes `-y, --yes` and `--dry-run`.
|
|
285
|
+
|
|
286
|
+
- `--title <text>`, `--body <text>`: the proposal's title and description. Both are required for a new
|
|
287
|
+
proposal, and asked for at a terminal when missing; on an open proposal they are optional and replace its own.
|
|
288
|
+
The body is followed by a changelog sous generates.
|
|
289
|
+
- `--branch <name>`: work with this branch instead of the one checked out. A branch that does not exist is
|
|
290
|
+
created from the current commit.
|
|
291
|
+
- `--status`: only report where the branch's proposal stands; nothing is checked, written or sent.
|
|
292
|
+
- `--commit`: commit uncommitted changes for you, after listing them and asking once, with the title, the
|
|
293
|
+
description and the changelog as the message.
|
|
294
|
+
- `--draft`: open a new proposal as a draft.
|
|
295
|
+
|
|
296
|
+
Example: `sous repo submit --title "Add a linting recipe" --body "Adds lint rules for shell scripts." --draft`
|
|
268
297
|
|
|
269
298
|
## subscription
|
|
270
299
|
|
|
@@ -290,6 +319,20 @@ Example: `sous subscription add workflow/task-files@^1.2.0 --answer apiUrl=https
|
|
|
290
319
|
Removes a subscription and everything only it brought in, then rebuilds so those files are gone. Also spelled
|
|
291
320
|
`sous unsubscribe`. Takes `--dry-run` and `--no-build`. Example: `sous subscription remove workflow/task-files`
|
|
292
321
|
|
|
322
|
+
### `sous subscription update [REF]`
|
|
323
|
+
Moves the lockfile's pins to the newest published versions their ranges allow, then rebuilds the project. With
|
|
324
|
+
no `REF` it covers every subscription; a `REF` naming a repository, a namespace or a recipe narrows it, and
|
|
325
|
+
everything outside it stays where it is pinned. It fetches every trusted repository's index first, never widens
|
|
326
|
+
a range, moves dependencies with the closure, and changes only the lockfile, never the subscriptions. It prints
|
|
327
|
+
the plan and asks once; with nothing to update it says so and asks nothing. See
|
|
328
|
+
[Moving to newer versions](repositories-consuming.md#moving-to-newer-versions). Takes `--no-build`, `--answer`
|
|
329
|
+
and `--answers-file`, and `--dry-run`, which fetches the indexes but downloads no recipe and writes nothing.
|
|
330
|
+
|
|
331
|
+
- `-y, --yes`: accept the plan, and trust any repository a newer version needs (also `--force`, `--trust`).
|
|
332
|
+
- `--accept-first`: when `REF` matches several things, take the first one listed.
|
|
333
|
+
|
|
334
|
+
Example: `sous subscription update workflow/task-files`
|
|
335
|
+
|
|
293
336
|
### `sous subscription list`
|
|
294
337
|
Lists the subscriptions this project declares, switched-off ones included, with the range each resolves within,
|
|
295
338
|
the versions the lockfile pins, the latest version each of those recipes has published, where it came from and
|
|
@@ -301,7 +344,8 @@ only the subscriptions that have pinned something. Example: `sous subscription l
|
|
|
301
344
|
|
|
302
345
|
`namespace` reads the cached indexes and the lockfile, so it works offline. A trusted repository whose index has
|
|
303
346
|
never been fetched is named at the end of a listing, not left out. Both commands take the
|
|
304
|
-
[browsing flags](#flags-that-browse); with `--installed` the recipe count is the number installed.
|
|
347
|
+
[browsing flags](#flags-that-browse); with `--installed` the recipe count is the number installed. The core version this installation of sous
|
|
348
|
+
ships is listed even while the cached index does not publish it yet.
|
|
305
349
|
|
|
306
350
|
### `sous namespace list`
|
|
307
351
|
Lists every namespace the trusted repositories publish, how many recipes each holds, and how much of it this
|
|
@@ -338,8 +382,10 @@ Prints what `.sous/sous.lock.json` pins: the recipe, the version, the repository
|
|
|
338
382
|
### `sous lock rebuild`
|
|
339
383
|
Recomputes the whole lockfile from the subscriptions the config declares and the cached indexes, starting from
|
|
340
384
|
empty, so an entry nothing holds any more is dropped rather than carried through: the repair for a file that
|
|
341
|
-
drifted through a hand edit or a bad merge. It asks nothing, grants no trust and downloads nothing.
|
|
342
|
-
|
|
385
|
+
drifted through a hand edit or a bad merge. It asks nothing, grants no trust and downloads nothing. The core
|
|
386
|
+
version this installation of sous ships resolves even when the cached index has not published it yet, exactly
|
|
387
|
+
as it does in a build. To move pins to versions published since the last fetch, use `sous subscription update`.
|
|
388
|
+
Takes `--dry-run`. Example: `sous lock rebuild --dry-run`
|
|
343
389
|
|
|
344
390
|
## vars
|
|
345
391
|
|
|
@@ -4,8 +4,9 @@ The guide to publishing recipes of your own: creating a repository, writing a re
|
|
|
4
4
|
needs, cutting a release, editing a published repository in place, and proposing a change to somebody else's.
|
|
5
5
|
[Repository file formats](repositories-file-formats.md) holds the schemas; this page is the workflow.
|
|
6
6
|
|
|
7
|
-
?> A recipe repository is not a sous project. It has no `.sous/` directory, and `sous repo init
|
|
8
|
-
release`
|
|
7
|
+
?> A recipe repository is not a sous project. It has no `.sous/` directory, and `sous repo init` and `sous repo
|
|
8
|
+
release` do not look for one. Run them from inside the repository itself. `sous repo submit` runs there too, and
|
|
9
|
+
may also be run from a project that links the repository.
|
|
9
10
|
|
|
10
11
|
## Create a repository
|
|
11
12
|
|
|
@@ -196,8 +197,9 @@ third case is what a merge looks like to continuous integration: the bump is don
|
|
|
196
197
|
`--namespace <ns>` and `--recipe <ns/name>` narrow the run and both repeat; `--bump <level>` is `patch` (the
|
|
197
198
|
default), `minor`, `major` or `prerelease`; `--no-bump` raises nothing; `--include-unchanged` releases every
|
|
198
199
|
recipe in scope, changed or not; `--check` only reads, validating, failing on any problem the release would
|
|
199
|
-
refuse
|
|
200
|
-
|
|
200
|
+
refuse and on a change to a recipe whose [`submissions`](repositories-file-formats.md#the-submissions-block)
|
|
201
|
+
block says it takes no proposals, and reporting how merging would rewrite the committed index without failing
|
|
202
|
+
on it, since that index is the release's output; and `--ci` is the merge preset: never bump, accept the plan, never ask, fail on anything unbumped. Every flag
|
|
201
203
|
this command takes, `--tag`, `--push` and `--non-interactive` among them, is in the
|
|
202
204
|
[command reference](commands.md#sous-repo-release).
|
|
203
205
|
|
|
@@ -235,7 +237,8 @@ missing from the index is rebuilt from it whenever the index is regenerated, whi
|
|
|
235
237
|
publishes something. A bump edits the manifest in place, so comments, field order and layout survive; a folded
|
|
236
238
|
block of YAML prose may be re-wrapped and the space before a trailing comment collapsed to one.
|
|
237
239
|
|
|
238
|
-
!> A release commits the version bumps and the index, and nothing else
|
|
240
|
+
!> A release commits the version bumps and the index, and nothing else; the only other commit sous ever makes
|
|
241
|
+
for you is `sous repo submit --commit`. It refuses to run while anything else is
|
|
239
242
|
uncommitted, because a tag names one commit and the index records what each recipe folder holds right now. It also
|
|
240
243
|
refuses when git does not know who is committing: set `git config user.name` and `git config user.email` first, or
|
|
241
244
|
give that identity to the account a continuous integration job runs as (the scaffolded workflow already does).
|
|
@@ -286,8 +289,29 @@ and freshness checks no longer apply to it. Builds say so every time.
|
|
|
286
289
|
Run 'sous repo unlink my-recipes' to go back to published versions.
|
|
287
290
|
```
|
|
288
291
|
|
|
289
|
-
|
|
290
|
-
|
|
292
|
+
### Unlink, and pick up your release
|
|
293
|
+
|
|
294
|
+
Linking never touches the lockfile, so `sous repo unlink my-recipes` goes back to exactly the versions pinned
|
|
295
|
+
before the link, and rebuilds the project so its outputs match them. It also fetches the repository's index,
|
|
296
|
+
with a short timeout, and says whether a newer version the ranges allow has been published since; it moves
|
|
297
|
+
nothing, and when the index cannot be fetched in time it says it could not check. Unlinking a name linked in
|
|
298
|
+
the other scope says which scope holds it.
|
|
299
|
+
|
|
300
|
+
Once your change is released, one of these moves the project onto it:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
sous repo unlink my-recipes --update # unlink, move this repository's pins, then rebuild
|
|
304
|
+
sous subscription update my-recipes # the same move, when nothing is linked any more
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
`--update` runs exactly the code `sous subscription update my-recipes` runs: every pin the repository supplies
|
|
308
|
+
moves to the newest version its range allows, after one plan and one question. See
|
|
309
|
+
[Moving to newer versions](repositories-consuming.md#moving-to-newer-versions).
|
|
310
|
+
|
|
311
|
+
The checkout stays where it is unless you pass `--remove`, because `sous repo submit` uses a leftover checkout to
|
|
312
|
+
revise a proposal that is still open. `--remove` deletes it only when sous cloned it; a checkout you linked by
|
|
313
|
+
path is yours, and sous refuses with an error. Before deleting, sous lists anything in the checkout that exists
|
|
314
|
+
nowhere else (uncommitted changes, commits no remote has, and stashes) and asks; `--yes` answers ahead.
|
|
291
315
|
|
|
292
316
|
### How a checkout compares with upstream
|
|
293
317
|
|
|
@@ -344,22 +368,60 @@ changing its branch says it affects all of them.
|
|
|
344
368
|
|
|
345
369
|
## Contribute to someone else's repository
|
|
346
370
|
|
|
347
|
-
`sous repo submit` proposes
|
|
348
|
-
writes to a repository directly.
|
|
349
|
-
|
|
371
|
+
`sous repo submit` proposes a change to a repository's maintainers and follows it through; it never publishes
|
|
372
|
+
and never writes to a repository directly. Run it inside the recipe repository you changed, or from a project
|
|
373
|
+
that links it: `sous repo submit sous-recipes` runs in the linked checkout, and with no argument the project's
|
|
374
|
+
only linked repository is used (several are a question). A repository you have since unlinked is still
|
|
375
|
+
submitted from the checkout sous cloned for it, with a note saying so; with no checkout at all there is no
|
|
376
|
+
working copy to propose from, and `submit` says so.
|
|
377
|
+
|
|
378
|
+
It prints each step as it runs them:
|
|
350
379
|
|
|
351
380
|
1. **Preflight.** An `origin` remote exists, sous recognizes its provider, that provider's command line tool
|
|
352
|
-
(`gh` or `glab`) is installed and signed in, and everything is committed.
|
|
381
|
+
(`gh` or `glab`) is installed and signed in, and everything is committed. `--commit` lifts that last rule:
|
|
382
|
+
sous lists what is uncommitted, asks once (`--yes` answers), checks git knows who is committing before
|
|
383
|
+
writing anything, and commits it all with the proposal's title, description and changelog as the message.
|
|
353
384
|
2. **Validation.** The repository validates, and your change leaves `sous.index.json` as it found it, so a
|
|
354
385
|
proposal never fails the maintainer's own checks and wastes their review. The index is written by the
|
|
355
386
|
repository's own release after a merge; whether it agrees with the release tags is checked there, by
|
|
356
387
|
`sous repo release --check` on a full clone, not by `submit`. That is what lets `submit` run from the shallow
|
|
357
388
|
checkout `sous repo link` makes, which holds almost none of the tags. The comparison is made against the
|
|
358
389
|
copy of the default branch your checkout holds (`origin/main`, for example); when it holds none, `submit`
|
|
359
|
-
says the check was skipped.
|
|
390
|
+
says the check was skipped. A change that touches a recipe whose
|
|
391
|
+
[`submissions`](repositories-file-formats.md#the-submissions-block) block says it takes no proposals is
|
|
392
|
+
warned about, with where to send it instead, and proposed only if you carry on.
|
|
360
393
|
3. **Delegation.** Sous asks the provider whether you can push to the repository itself, forks it onto your
|
|
361
394
|
account when you cannot, pushes the branch, and asks the provider to open the proposal. A change sitting on
|
|
362
|
-
the default branch is moved to `sous/submit-<YYYYMMDD>-<HHMM
|
|
395
|
+
the default branch is moved to `sous/submit-<YYYYMMDD>-<HHMM>`, or to the branch `--branch` names.
|
|
396
|
+
|
|
397
|
+
**A title and a description are yours to write.** A new proposal needs both: pass `--title` and `--body`, or
|
|
398
|
+
answer the two questions at a terminal (Tab opens your editor for a longer description). Sous never borrows a
|
|
399
|
+
commit message. The body is your description followed by a changelog sous generates by comparing the manifests
|
|
400
|
+
your change carries with the default branch:
|
|
401
|
+
|
|
402
|
+
- recipes added, and recipes retired (a renamed recipe shows as one of each);
|
|
403
|
+
- version changes;
|
|
404
|
+
- recipes whose files changed without a version raise, which merging will release as the next patch;
|
|
405
|
+
- namespaces added or removed;
|
|
406
|
+
- variables added, removed or changed, with a warning that removing a variable or tightening its validation is
|
|
407
|
+
usually a major change.
|
|
408
|
+
|
|
409
|
+
The changelog explains; it never refuses. Only what the repository's own checks would reject stops a submission.
|
|
410
|
+
|
|
411
|
+
**One command for the proposal's whole life.** Every run looks up the proposal for the current branch (or the
|
|
412
|
+
one `--branch` names), by the fork's owner as well as the branch when you work through a fork, and then:
|
|
413
|
+
|
|
414
|
+
| The branch's proposal | What `submit` does |
|
|
415
|
+
|-----------------------|--------------------|
|
|
416
|
+
| none | Opens one |
|
|
417
|
+
| open, with new commits | Pushes them, which updates it; a given `--title` or `--body` replaces its own |
|
|
418
|
+
| open, with nothing new | Reports where it stands: review, checks, whether it can merge |
|
|
419
|
+
| merged | Says so, then continues on a new branch: you name one, sous generates one, or you cancel. `--yes` generates one |
|
|
420
|
+
| closed without merging | Says so, and opens a fresh one for the branch |
|
|
421
|
+
|
|
422
|
+
When the branch on the remote holds commits yours lacks (a maintainer pushed to it), git refuses the push and
|
|
423
|
+
`submit` passes git's own explanation through and stops. It never forces a push. `--status` only reports, and
|
|
424
|
+
`--dry-run` works everything out and writes and sends nothing.
|
|
363
425
|
|
|
364
426
|
Each step is the provider's own business, and what each one can do depends on the host; see
|
|
365
427
|
[Providers](repositories-providers.md#proposing-a-change). Sous sequences the steps and reports what came back. A
|
|
@@ -220,7 +220,48 @@ build` instead. The `Latest version` column beside it is read from the cache, or
|
|
|
220
220
|
`sous repo list` shows each trusted repository with its provider, origin, whether it is linked, its
|
|
221
221
|
recipe count and its URL; `--verbose` adds a `Namespaces:` line under each row. `sous lock show`
|
|
222
222
|
prints the other half: every version your lockfile pins, where it came from and who holds it. When
|
|
223
|
-
that file has drifted, `sous lock rebuild` recomputes it from your subscriptions
|
|
223
|
+
that file has drifted, `sous lock rebuild` recomputes it from your subscriptions and the cached
|
|
224
|
+
indexes, fetching nothing.
|
|
225
|
+
|
|
226
|
+
## Moving to newer versions
|
|
227
|
+
|
|
228
|
+
A build holds the versions the lockfile pins, so a newer release reaches the project only when
|
|
229
|
+
something moves the pin. `sous subscription update` is that step:
|
|
230
|
+
|
|
231
|
+
```term
|
|
232
|
+
$ sous subscription update workflow/qa-variables
|
|
233
|
+
Updating the recipe 'qa-recipes:workflow/qa-variables' changes the lockfile:
|
|
234
|
+
|
|
235
|
+
• Adding workflow/qa-helper version 1.0.0
|
|
236
|
+
• Updating workflow/qa-variables from version 0.1.0 to version 0.2.0
|
|
237
|
+
|
|
238
|
+
Update the lockfile? (y/N)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
It fetches every trusted repository's index first, so a version published a minute ago counts.
|
|
242
|
+
With no reference it covers every subscription; a reference names a repository, a namespace or a
|
|
243
|
+
recipe, at any level of qualification, and everything outside it stays exactly where it is pinned.
|
|
244
|
+
What it will and will not do:
|
|
245
|
+
|
|
246
|
+
- A pin moves only within the range its subscription declares, or the range the recipe depending
|
|
247
|
+
on it declares; a range is never widened. Prereleases count only for a subscription that opted
|
|
248
|
+
into them.
|
|
249
|
+
- Dependencies move with the closure: a dependency a newer version adds is pinned, and one it
|
|
250
|
+
dropped leaves the lockfile unless something else still holds it.
|
|
251
|
+
- Only the lockfile changes. Your subscriptions stay exactly as they are written.
|
|
252
|
+
- It prints the plan and asks once; `--yes` accepts it, and a run with no terminal and no `--yes`
|
|
253
|
+
fails naming the flag. With nothing to update it says so and asks nothing.
|
|
254
|
+
- A repository a newer version needs that the project does not trust goes through the usual trust
|
|
255
|
+
question, and new questions the newer versions ask are asked the way subscribing asks them.
|
|
256
|
+
- A repository whose index cannot be fetched is skipped and named, and its pins stay put.
|
|
257
|
+
- A linked repository's pins move too, and the plan notes that builds keep reading the checkout
|
|
258
|
+
until it is unlinked.
|
|
259
|
+
- The built-in `core` subscription never moves: its range is exactly the running sous version, so
|
|
260
|
+
upgrading sous is what moves it.
|
|
261
|
+
|
|
262
|
+
It rebuilds the project afterwards. `--dry-run` fetches the indexes and prints the plan, and
|
|
263
|
+
downloads no recipe and writes nothing, so the dependencies and questions of a version this machine
|
|
264
|
+
does not hold yet are named rather than listed. `--no-build` skips the rebuild.
|
|
224
265
|
|
|
225
266
|
## Remove a subscription
|
|
226
267
|
|
|
@@ -290,7 +331,8 @@ lapsed (`store.freshnessSeconds`, five minutes by default), or when a command fo
|
|
|
290
331
|
check never breaks a build, because the cached index is used instead. Always-pull changes what
|
|
291
332
|
happens after that check, not how often it happens: a repository or subscription marked
|
|
292
333
|
`alwaysPull` takes a newer in-range version rather than the locked one; set it with
|
|
293
|
-
`--always-pull`, or on either entry in the config.
|
|
334
|
+
`--always-pull`, or on either entry in the config. Without it, `sous subscription update` is how a
|
|
335
|
+
pin moves; see [Moving to newer versions](#moving-to-newer-versions).
|
|
294
336
|
|
|
295
337
|
Every other repository the lockfile pins from is checked on the same window, only to tell you what
|
|
296
338
|
is newer. A build lists each recipe with a newer version inside the range declared for it, beside
|
|
@@ -54,6 +54,7 @@ recipes: # every recipe folder, relative to the repos
|
|
|
54
54
|
| `description`, `contribute` | no | A summary for anyone reading the repository, and where to send a contribution when a provider cannot support `sous repo submit` |
|
|
55
55
|
| `namespaces` | yes | Keyed by namespace name; each entry takes an optional `description` |
|
|
56
56
|
| `recipes` | yes | Relative paths, each holding a recipe manifest; a path listed twice is an error |
|
|
57
|
+
| `submissions` | no | Whether the repository's recipes take proposed changes; see [The submissions block](#the-submissions-block) |
|
|
57
58
|
|
|
58
59
|
## `sous.recipe.yaml`: the recipe manifest
|
|
59
60
|
|
|
@@ -77,11 +78,30 @@ contents: # what a subscriber actually receives
|
|
|
77
78
|
| `description` | no | Copied into the index at release time; shown by `sous recipe list` and `sous repo search` |
|
|
78
79
|
| `depends`, `subscribes` | no | Build dependencies and co-subscriptions; within either list, no entry may repeat |
|
|
79
80
|
| `contents`, `variables` | no | Contents default to an empty list, which is what a curated bundle publishes; a duplicated variable name, or two definitions claiming one `env`, is an error |
|
|
81
|
+
| `submissions` | no | Whether this recipe takes proposed changes, winning over the repository's block; see [The submissions block](#the-submissions-block) |
|
|
80
82
|
|
|
81
83
|
`contents[].kind` is `skills`, `memories`, `prompts` or `config`. The first three are written to the
|
|
82
84
|
destinations named by [`recipeOutputs`](#recipeoutputs-where-the-files-land); `config` entries become config
|
|
83
85
|
layers instead. `include` needs at least one glob, and both lists are recipe-relative.
|
|
84
86
|
|
|
87
|
+
### The submissions block
|
|
88
|
+
|
|
89
|
+
Both manifests accept a `submissions` block. On `sous.repo.yaml` it covers every recipe in the repository; on
|
|
90
|
+
`sous.recipe.yaml` it covers that recipe, and wins over the repository's.
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
submissions:
|
|
94
|
+
allowed: false # defaults to true
|
|
95
|
+
instead: Propose changes in sous-io/sous, under recipes/core/sous-skills/.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
It exists for a recipe whose files are copied in from somewhere else: an edit merged into the copy is
|
|
99
|
+
overwritten by the next copy, and a version it tagged can collide with the one the real source publishes.
|
|
100
|
+
`sous repo submit` warns before proposing a change that touches such a recipe, prints the `instead` text, and
|
|
101
|
+
proposes it if the contributor carries on. `sous repo release --check` fails a pull request that changes one,
|
|
102
|
+
because a pull request can be opened without `submit`, and the check is the one gate every change passes. A
|
|
103
|
+
release itself is never restricted, so whatever publishes the recipe still releases it.
|
|
104
|
+
|
|
85
105
|
### Dependencies named by location
|
|
86
106
|
|
|
87
107
|
`depends` and `subscribes` share one grammar in two spellings: `workflow/qa-helper` is a sibling in this
|
|
@@ -232,7 +252,8 @@ freshness checks; entries are keyed by the repository's configured short name.
|
|
|
232
252
|
```
|
|
233
253
|
|
|
234
254
|
`path` is absolute; `origin` is `clone` when sous cloned the working copy itself and `path` when it was
|
|
235
|
-
pointed at an existing checkout
|
|
255
|
+
pointed at an existing checkout. Unlinking removes the entry and leaves the checkout in place, unless
|
|
256
|
+
`sous repo unlink --remove` is asked to delete one sous cloned; it never deletes a `path` checkout. Both the
|
|
236
257
|
project's `.sous/sous.links.json` and `$SOUS_HOME/sous.links.json` are read, and the project's entries win.
|
|
237
258
|
|
|
238
259
|
## Configuration keys
|
|
@@ -21,8 +21,12 @@ Nothing there clones a whole repository. A provider that can also carry a contri
|
|
|
21
21
|
the **write path**: report whether its command line tool is installed and signed in, say whether
|
|
22
22
|
you may push to the repository itself, fork it onto your account, and open the proposal.
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
A provider may also answer the **proposals** path, which is what lets a submission follow a proposal
|
|
25
|
+
after it is opened: find the proposal a branch was pushed for, report where it stands, and replace its
|
|
26
|
+
title or body.
|
|
27
|
+
|
|
28
|
+
Each provider declares which of the three features, `fetch`, `submit` and `proposals`, it genuinely
|
|
29
|
+
answers, and sous consults that declaration rather than a provider's name. Asking for something outside a
|
|
26
30
|
provider's features is refused with a sentence naming it and what it cannot do, never a crash.
|
|
27
31
|
|
|
28
32
|
## How a URL is matched
|
|
@@ -184,11 +188,15 @@ finds the index but cannot clone has only the second half missing.
|
|
|
184
188
|
your repository, then hands the host-specific mechanics to the provider that owns its `origin`
|
|
185
189
|
remote. Providers differ, and sous says so rather than pretending otherwise:
|
|
186
190
|
|
|
187
|
-
| Provider | Tool | Push permission | Forking | Proposal |
|
|
188
|
-
|
|
189
|
-
| `github` | `gh` | read from GitHub, so a contributor without it is forked automatically | `gh repo fork`, with a `fork` remote added for you | pull request |
|
|
190
|
-
| `gitlab` | `glab` | sous cannot tell, so it pushes to `origin` and says so | not done for you | merge request |
|
|
191
|
-
| `local` | none | not applicable | not applicable | not applicable |
|
|
191
|
+
| Provider | Tool | Push permission | Forking | Proposal | Following it up |
|
|
192
|
+
|---|---|---|---|---|---|
|
|
193
|
+
| `github` | `gh` | read from GitHub, so a contributor without it is forked automatically | `gh repo fork`, with a `fork` remote added for you | pull request | `gh pr list`, `gh pr view` and `gh pr edit`, matching a fork's pull request by its owner |
|
|
194
|
+
| `gitlab` | `glab` | sous cannot tell, so it pushes to `origin` and says so | not done for you | merge request | not done: every run opens a merge request, and `--status` is refused |
|
|
195
|
+
| `local` | none | not applicable | not applicable | not applicable | not applicable |
|
|
196
|
+
|
|
197
|
+
**GitLab cannot follow a proposal up yet.** It does not declare `proposals`, so a submission cannot
|
|
198
|
+
look for a merge request that is already open; it says so, pushes, and opens one. When the branch
|
|
199
|
+
already has one, the push updates it and GitLab may refuse the second.
|
|
192
200
|
|
|
193
201
|
**GitLab reports "cannot tell" rather than guessing.** Sous has no cheap, reliable way to ask
|
|
194
202
|
whether you may push, and a wrong guess would send you down a fork path this provider cannot
|
|
@@ -297,14 +305,16 @@ subclass overrides it. Each member is documented where it lives, in
|
|
|
297
305
|
The subclass supplies the rest:
|
|
298
306
|
|
|
299
307
|
- `id`, the identifier a repository entry and a locator scheme use;
|
|
300
|
-
- `features`, the ones it genuinely answers (`fetch
|
|
301
|
-
are
|
|
308
|
+
- `features`, the ones it genuinely answers (`fetch`; `submit` only if all four write calls are
|
|
309
|
+
real; `proposals` only if `findProposal`, `proposalStatus` and `updateProposal` are);
|
|
302
310
|
- `matches(url)` and `canonicalize(url)`, the URL half;
|
|
303
311
|
- `fetchIndex(repo, options)` and `fetchRecipeTree(repo, recipePath, tag, destDir, options)`, the
|
|
304
312
|
read half;
|
|
305
313
|
- `cli` and `proposalNoun` when it submits, so messages can name the tool and call a proposal
|
|
306
314
|
what the host calls it;
|
|
307
|
-
- overrides of the four write-path calls when it submits
|
|
315
|
+
- overrides of the four write-path calls when it submits, and of the three proposals calls when
|
|
316
|
+
it can follow a proposal up. Each answers with plain data (a proposal's id, address, state,
|
|
317
|
+
title, review and check counts), never with a host's own vocabulary.
|
|
308
318
|
|
|
309
319
|
Every call takes an options object carrying the testing seams (`cwd`, `env`, `fetchImpl`, `run`),
|
|
310
320
|
which is why no provider reaches for `spawn` or the global `fetch` directly and no test in this
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ formatVersion: 1
|
|
|
11
11
|
|
|
12
12
|
namespace: core
|
|
13
13
|
name: sous-skills
|
|
14
|
-
version: 0.2.
|
|
14
|
+
version: 0.2.18
|
|
15
15
|
|
|
16
16
|
description: >-
|
|
17
17
|
The skills that teach an agent what sous is and how it works: which files sous
|
|
@@ -19,6 +19,13 @@ description: >-
|
|
|
19
19
|
debugged, the .tpl. template convention and LiquidJS syntax, what an agent
|
|
20
20
|
skill is, and how to create one.
|
|
21
21
|
|
|
22
|
+
# The copy in sous-io/sous-recipes is overwritten by every sous release, so a
|
|
23
|
+
# change proposed there would be lost, and a version it tagged would collide
|
|
24
|
+
# with the one the release publishes.
|
|
25
|
+
submissions:
|
|
26
|
+
allowed: false
|
|
27
|
+
instead: Propose changes in sous-io/sous, under recipes/core/sous-skills/.
|
|
28
|
+
|
|
22
29
|
contents:
|
|
23
30
|
- kind: skills
|
|
24
31
|
include:
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
anythingToCommit,
|
|
12
12
|
buildIndex,
|
|
13
13
|
buildReleasePlan,
|
|
14
|
+
checkSubmissions,
|
|
14
15
|
bumpRecipeVersion,
|
|
15
16
|
commitPaths,
|
|
16
17
|
createAnnotatedTag,
|
|
@@ -391,6 +392,46 @@ export default class RepoRelease extends Command {
|
|
|
391
392
|
log(" records for every version it publishes.");
|
|
392
393
|
}
|
|
393
394
|
reportPending(result, "These versions have no tag yet; they publish when this merges:");
|
|
395
|
+
|
|
396
|
+
// A pull request can be opened without `sous repo submit`, so this check is
|
|
397
|
+
// the one gate every change passes. The release itself is not restricted:
|
|
398
|
+
// whatever publishes such a recipe still releases it.
|
|
399
|
+
section("Checking the recipes that take no proposals");
|
|
400
|
+
const submissions = await checkSubmissions(validation);
|
|
401
|
+
if (submissions.refusing.length > 0) {
|
|
402
|
+
const problems: ValidationProblem[] = submissions.refusing.map((recipe) => ({
|
|
403
|
+
level: "error",
|
|
404
|
+
where: recipe.path,
|
|
405
|
+
message:
|
|
406
|
+
`this change touches '${recipe.key}', which does not take proposed changes ` +
|
|
407
|
+
`(${recipe.declaredBy === "recipe" ? "its own manifest" : "the repository manifest"} ` +
|
|
408
|
+
`says so). Merging it would break whatever publishes the recipe.` +
|
|
409
|
+
(recipe.instead === undefined ? "" : ` Instead: ${recipe.instead}`),
|
|
410
|
+
}));
|
|
411
|
+
reportProblems(problems);
|
|
412
|
+
displayErrorBlock(
|
|
413
|
+
`This change cannot be merged: it touches ` +
|
|
414
|
+
`${describeCount(problems.length, "recipe")} that ${problems.length === 1 ? "does" : "do"} ` +
|
|
415
|
+
`not take proposed changes, listed above.\n` +
|
|
416
|
+
` Take those edits out of the change, and send them where each recipe asks.`
|
|
417
|
+
);
|
|
418
|
+
return this.exit(1);
|
|
419
|
+
}
|
|
420
|
+
if (submissions.comparedWith.kind === "branch") {
|
|
421
|
+
log(
|
|
422
|
+
` Compared with the branch '${submissions.comparedWith.branch}': this change touches no ` +
|
|
423
|
+
`recipe that declines proposals.`
|
|
424
|
+
);
|
|
425
|
+
} else if (submissions.comparedWith.kind === "tags") {
|
|
426
|
+
log(" Compared with each recipe's last release tag: nothing that declines proposals changed.");
|
|
427
|
+
} else if (submissions.comparedWith.kind === "none declined") {
|
|
428
|
+
log(" No recipe in this repository declines proposed changes.");
|
|
429
|
+
} else {
|
|
430
|
+
note(
|
|
431
|
+
"This checkout holds neither a copy of the default branch nor a release tag of any " +
|
|
432
|
+
"recipe that declines proposed changes, so there was nothing to compare with."
|
|
433
|
+
);
|
|
434
|
+
}
|
|
394
435
|
footer();
|
|
395
436
|
}
|
|
396
437
|
|