@izykitten/ce 0.0.3-dev.2 → 0.0.3-dev.4

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.
Files changed (3) hide show
  1. package/README.md +36 -18
  2. package/dist/ce.js +980 -103
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -31,24 +31,41 @@ Only build commands are rewritten: `build`, `buildx build` and `image build` for
31
31
 
32
32
  ## Tags from the Forgejo run
33
33
 
34
- Tags and the `TAG_PREFIX`/`CACHE_PREFIX` values can use placeholders, filled from the Forgejo Actions environment and its event file. ce makes no API calls and does not look at the checkout.
35
-
36
- | Placeholder | Value |
37
- |---|---|
38
- | `{image}` | registry host and repository, lowercased, e.g. `code.izy.sh/library/gateway` |
39
- | `{ref}` | the branch name, `pr-<number>` for a pull request, or the tag name |
40
- | `{branch}`, `{pr}`, `{tag}` | the branch, PR number or tag, set only when building that kind of ref |
41
- | `{default}` | set only when building the default branch, never for a pull request or tag |
42
- | `{revision}`, `{sha}` | the commit, in full and as its first 7 characters |
43
- | `{version}`, `{major}`, `{minor}`, `{patch}` | from a SemVer tag such as `v1.2.3` or `1.2.3-rc.1` |
44
- | `{stable}` | set only for a SemVer tag without a pre-release |
45
- | `{env.NAME}` | the environment variable `NAME`, e.g. a value from an earlier step |
34
+ Tags and the `TAG_PREFIX`/`CACHE_PREFIX` values can use placeholders, filled from the Forgejo Actions environment and its event file. ce makes no API calls, and reads nothing from the checkout but the Containerfile, for a `{arg.NAME}` that needs its default.
35
+
36
+ | Placeholder | Value |
37
+ | -------------------------------------------- | ---------------------------------------------------------------------------------- |
38
+ | `{image}` | registry host and repository, lowercased, e.g. `code.izy.sh/library/gateway` |
39
+ | `{ref}` | the branch name, `pr-<number>` for a pull request, or the tag name |
40
+ | `{branch}`, `{pr}`, `{tag}` | the branch, PR number or tag, set only when building that kind of ref |
41
+ | `{default}` | set only when building the default branch, never for a pull request or tag |
42
+ | `{revision}`, `{sha}` | the commit, in full and as its first 7 characters |
43
+ | `{version}`, `{major}`, `{minor}`, `{patch}` | from a SemVer tag such as `v1.2.3` or `1.2.3-rc.1` |
44
+ | `{stable}` | set only for a SemVer tag without a pre-release |
45
+ | `{env.NAME}` | the environment variable `NAME`, e.g. a value from an earlier step |
46
+ | `{arg.NAME}` | the build arg `NAME` as the build gets it, from `--build-arg` or the Containerfile |
46
47
 
47
48
  `{name}` must have a value (an empty variable has none): if it has none in this run, ce fails with exit 2 before anything runs. To leave a tag out instead, guard it with `{?name}`, which expands to nothing and keeps the tag only when `name` has a value. Every guard in a tag has to pass, and a tag's other values are only needed when it is kept. Names are checked in every tag, so a typo fails even in one a guard leaves out. If the guards leave out every tag, ce fails rather than build an untagged image.
48
49
 
49
- Values are made safe for a tag: any ASCII character a tag cannot have becomes `-`, so branch `ci/modernize-build` gives `ci-modernize-build`; a non-ASCII character is an error. A value never adds a tag or changes the image name. Prefixes can use `{name}` but not guards.
50
+ Values are made safe for a tag: any ASCII character a tag cannot have becomes `-`, so branch `ci/modernize-build` gives `ci-modernize-build`; a non-ASCII character is an error. A value never adds a tag or changes the image name.
50
51
 
51
- Guards decide from the run's metadata, so they need it too: outside a Forgejo Actions run, `{?default}` fails like `{default}` would. Only `{env.NAME}` works everywhere. To tell whether a branch is the default one, ce reads `repository.default_branch` from the event file, or `DEFAULT_BRANCH` when the event has none, as on a scheduled run; set `DEFAULT_BRANCH: main` in such a workflow. Pull requests and tags are never the default branch, so they need neither.
52
+ Prefixes can use guards too. A guard that does not pass leaves the prefix empty, since a prefix cannot be left out, and the prefix's other values are then not needed. `CACHE_PREFIX='{?pr}pr-{pr}'` gives each pull request a cache of its own (`pr-3`) and leaves every other build sharing the unprefixed one; with `CACHE_FROM_DEFAULT`, a PR also reads that shared one, as the prefix is empty on the default branch. The image name cannot use guards.
53
+
54
+ `{arg.NAME}` is the value the build gets for the build arg `NAME`. That is `--build-arg NAME=value`, or the environment's `NAME` for `--build-arg NAME`, as the engine reads it, so a tag can name a value worked out on the command line:
55
+
56
+ ```sh
57
+ ce docker build --build-arg VERSION="$(cat VERSION)" -t '{image}:{arg.VERSION}' .
58
+ ```
59
+
60
+ The last `--build-arg NAME` wins. One whose variable is not set is passed over by Docker, which keeps an earlier value, while podman and buildah drop the value for the Containerfile's default. An empty value (`--build-arg NAME=`) is no value.
61
+
62
+ Without a `--build-arg`, `{arg.NAME}` is the Containerfile's default, so `ARG CADDY=2.11.7` before `FROM caddy:$CADDY` can tag the image `caddy-2.11.7` with nothing on the command line. ce reads the Containerfile the engine would: the `-f` file if there is one (Docker's last), else the context's `Dockerfile` (or `dockerfile`), or with podman and buildah its `Containerfile`, then `Dockerfile`. The default is what the stage being built, `--target`'s or else the last, sets with its own `ARG NAME=…`, or the stage it is built from does; else the global `ARG NAME=…` before the first `FROM`, which a bare `ARG NAME`, or a `FROM` line, also gets. With no default anywhere, or an empty one, the build gets an empty `NAME`, so `{arg.NAME}` has no value and a guard leaves its tag out.
63
+
64
+ `$` references in a default are worked out as the engine does. Docker's BuildKit reads them from the `ARG`s before them, the `--build-arg`s and the `ENV` lines in the stage. A stage built from another gets its values, then its `ENV`s again, which win over its `ARG`s, and runs its `ONBUILD ARG` and `ONBUILD ENV` lines first. podman and buildah expand an instruction from the values before it, so `ARG A=1 V=$A` reads an earlier `A`, and an `ENV`, the base image's too, wins over an `ARG`: inside a stage, ce only works out a reference to a name an `ENV` there sets. Their stage gets the `ARG`s of the stage its `FROM` names as written, so none through `FROM $BASE`. A builtin such as `TARGETPLATFORM` is the builder's, as is `SOURCE_DATE_EPOCH` and a proxy such as `HTTP_PROXY`, which the engine may set itself, unless a `--build-arg` sets it (podman and buildah set `TARGETPLATFORM` from the platform they build, whatever a `--build-arg` says); BuildKit also takes a builtin's own `ARG` default.
65
+
66
+ The Containerfile is only read when a `{arg.NAME}` needs it. When ce cannot tell the default for certain, it fails with exit 2 and says why: when the Containerfile comes from stdin or a URL, the context is remote, podman or buildah are given several `-f` files or a `.in` one for `cpp`, or with Docker a `# syntax=` directive or `BUILDKIT_SYNTAX` picks a frontend other than `docker/dockerfile` (untagged, `:1`, or `:1.21` and later, which may be pinned by a digest; older ones work out some defaults differently); and when the default refers to a builtin, to a name it cannot know (it may be the base image's `ENV`), or uses a form like `${NAME#x}`; when an `ARG` or `ENV` name has something to expand, such as `ENV $NAME=x`, or the instruction has flags; when an instruction or stage name, or a name after a `$`, has letters other than ASCII's, or an `ARG`, `ENV` or `FROM`, or a heredoc's line, has space other than ASCII's; when a heredoc's delimiter is anything but a word, which may be quoted; when a line ends in more than one carriage return; and with podman or buildah, when the stage is built from one with an `ONBUILD ARG` or `ONBUILD ENV`, which they run only for some image formats; when a `--build-context` replaces a stage it is built from (with podman and buildah, what a `FROM` names); and when podman or buildah's `--env` or `--unsetenv`, which ce does not evaluate, may change a name a default refers to. The default branch's cache scope, with `CACHE_FROM_DEFAULT`, never uses the Containerfile, as that branch may have another one: there a `{arg.NAME}` in the cache prefix needs a `--build-arg`. With podman's `--build-arg-file`, which ce does not read, `{arg.NAME}` needs a `--build-arg NAME` of its own. ce does not see a base image's own `ONBUILD` lines, and Docker's legacy builder (`DOCKER_BUILDKIT=0`) is not modelled.
67
+
68
+ Guards decide from the run's metadata, so they need it too: outside a Forgejo Actions run, `{?default}` fails like `{default}` would. Only `{env.NAME}` and `{arg.NAME}` work everywhere. A guard that does not pass decides on its own, though: a tag with one is left out, and a prefix with one is empty, even if another guard in it could not be worked out, so `{?default}{?env.X}` outside a run with `X` empty is simply left out. To tell whether a branch is the default one, ce reads `repository.default_branch` from the event file, or `DEFAULT_BRANCH` when the event has none, as on a scheduled run; set `DEFAULT_BRANCH: main` in such a workflow. Pull requests and tags are never the default branch, so they need neither.
52
69
 
53
70
  Put templates in single quotes: `?` is a glob character in zsh.
54
71
 
@@ -57,14 +74,14 @@ A branch, PR and default-branch build:
57
74
  ```yaml
58
75
  - name: Container Build & Push
59
76
  env:
60
- CACHE_PREFIX: '{ref}'
77
+ CACHE_PREFIX: "{ref}"
61
78
  CADDY_VERSION: ${{ steps.caddy.outputs.version }}
62
79
  run: >
63
80
  bunx @izykitten/ce docker buildx build --push --cache type=gha,mode=max
64
81
  -t '{image}:{ref},{?default}latest,{?default}caddy-{env.CADDY_VERSION}' .
65
82
  ```
66
83
 
67
- With `CACHE_PREFIX='{ref}'`, each branch and pull request gets a gha cache of its own, so a new one starts cold. With `CACHE_FROM_DEFAULT=true`, or `--cache-from-default` before the engine, each gha `--cache-to` is also read from its scope on the default branch: ce expands the cache prefix as it would be there, so PR 3 reads `pr-3` and `main` and writes only `pr-3`, and with `scope=js` it reads `main-js`. The default branch comes from the event file or `DEFAULT_BRANCH`, as for `{default}`. A prefix with `{sha}` or `{revision}` cannot be worked out for it, and is an error. This only picks what is read: whether it hits depends on what the default branch last wrote.
84
+ With `CACHE_PREFIX='{ref}'`, each branch and pull request gets a gha cache of its own, so a new one starts cold. With `CACHE_FROM_DEFAULT=true`, or `--cache-from-default` before the engine, each gha `--cache-to` is also read from its scope on the default branch: ce expands the cache prefix as it would be there, so PR 3 reads `pr-3` and `main` and writes only `pr-3`, and with `scope=js` it reads `main-js`. The default branch comes from the event file or `DEFAULT_BRANCH`, as for `{default}`. A prefix that needs `{sha}` or `{revision}` there cannot be worked out for it, and is an error; one whose guards leave it empty there, like `{?pr}{sha}`, does not need them. This only picks what is read: whether it hits depends on what the default branch last wrote.
68
85
 
69
86
  The same can be written by hand, since ce only prefixes a `--cache-from` whose scope matches a `--cache-to` and passes any other on unchanged: `--cache type=gha,mode=max --cache-from type=gha,scope=main`.
70
87
 
@@ -80,7 +97,7 @@ A release on a SemVer tag, with the version aliases only for stable releases:
80
97
 
81
98
  ### Checking a template
82
99
 
83
- `--dry-run` before the engine, or `CE_DRY_RUN=true`, prints the build summary and the engine command ce would run, and exits 0 without running it or waiting for the engine. A template that fails still exits 2, so it also works as a check before pushing a workflow:
100
+ `--dry-run` before the engine, or `CE_DRY_RUN=true`, prints the build summary and the engine command ce would run, and exits 0 without running it or waiting for the engine. A template that fails still exits 2, so it also works as a check before pushing a workflow. It checks the templates, not the engine: if the engine is not on `PATH`, it warns and still exits 0, so it works on a machine without one:
84
101
 
85
102
  ```sh
86
103
  GITHUB_REF=refs/tags/v1.2.3 GITHUB_SERVER_URL=https://code.example GITHUB_REPOSITORY=org/app \
@@ -109,13 +126,14 @@ These behave the same under Node and Bun, and [test/contract.test.ts](test/contr
109
126
 
110
127
  The wording of messages is not part of that and may change.
111
128
 
112
- In 0.0.3, the `--cache-from` that `--cache` makes no longer has a gha `mode=`, which only applies to export, and a `--cache-from` given twice is passed once.
129
+ In 0.0.3, the `--cache-from` that `--cache` makes no longer has a gha `mode=`, which only applies to export, and a `--cache-from` given twice is passed once. podman and buildah are no longer run through `gosu` as `$USER` when it is on `PATH`: ce runs every engine directly, as the user ce runs as, so to drop root, run ce itself as another user, e.g. with a `USER` line in the image.
113
130
 
114
131
  Compared with the Python version:
115
132
 
116
133
  - The state file is locked with `ce-forgejo-credentials.json.pidlock`, holding the holder's PID and hostname, rather than `flock`, which Node does not have. A lock whose holder died is broken right away if the PID is gone on the same host, otherwise after two minutes. It does not exclude a Python `ce` using the same Docker config at the same moment.
117
134
  - Replacing the process with the engine uses `process.execve`. Node aborts rather than report an `execve` failure, so `ce` first checks that the engine is an executable file on `PATH`.
118
135
  - Messages are worded differently in places, and the `Usage:` line shows the absolute path of the script.
136
+ - podman and buildah are not run through `gosu`, which the runner image's `ce` does when `gosu` is on `PATH`.
119
137
  - `docker-credential-ce-forgejo` runs the helper code directly instead of `exec ce credential-helper`, so `ce` does not have to be on `PATH`.
120
138
  - JSON files keep the same structure and sorted keys. Numbers are written as JavaScript writes them (`4102444800` rather than `4102444800.0`), and non-ASCII characters are not `\u`-escaped.
121
139