Yeet those builds out!
1# Yeetfile API
2
3Yeet uses [goja](https://pkg.go.dev/github.com/dop251/goja#section-readme) to execute JavaScript. As such, it does not have access to NPM or other external JavaScript libraries. You also cannot import code/data from other files. These are not planned for inclusion into yeet. If functionality is required, it should be added to yeet itself.
4
5To make it useful, yeet exposes a bunch of helper objects full of tools. These tools fall in a few categories, each has its own section.
6
7## `$`
8
9`$` lets you construct shell commands using [tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). This lets you build whatever shell commands you want by mixing Go and JavaScript values freely.
10
11Example:
12
13```js
14$`CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -s -w -extldflags "-static" -X "within.website/x.Version=${git.tag()}"`;
15```
16
17## `deb`
18
19Helpers for building Debian packages.
20
21### `deb.build`
22
23Builds a Debian package with a descriptor object. See the native packages section for more information. The important part of this is your `build` function. The `build` function is what will turn your package source code into an executable in `out` somehow.
24
25The resulting Debian package path will be returned as a string.
26
27Usage:
28
29`deb.build(package);`
30
31```js
32["amd64", "arm64"].forEach((goarch) =>
33 deb.build({
34 name: "yeet",
35 description: "Yeet out actions with maximum haste!",
36 homepage: "https://techaro.lol",
37 license: "MIT",
38 goarch,
39
40 build: ({ bin }) => {
41 go.build("-o", `${bin}/yeet`, "./cmd/yeet");
42 },
43 }),
44);
45```
46
47## `docker`
48
49Aliases for `docker` commands.
50
51### `docker.build`
52
53An alias for the `docker build` command. Builds a docker image in the current working directory's Dockerfile.
54
55Usage:
56
57`docker.build(tag);`
58
59```js
60docker.build("ghcr.io/xe/site/bin");
61docker.push("ghcr.io/xe/site/bin");
62```
63
64### `docker.push`
65
66Pushes a docker image to a registry. Analogous to `docker push` in the CLI.
67
68Usage:
69
70`docker.push(tag);`
71
72```js
73docker.build("ghcr.io/xe/site/bin");
74docker.push("ghcr.io/xe/site/bin");
75```
76
77## `file`
78
79### `file.install`
80
81Copies from a file from one place to another whilst preserving the file mode, analogous to `install -d` on Linux. Automatically creates directories in the `dest` path if they don't exist already.
82
83Usage:
84
85`file.install(src, dest);`
86
87```js
88file.install("LICENSE", `${doc}/LICENSE`);
89```
90
91## `git`
92
93Helpers for the Git version control system.
94
95### `git.repoRoot`
96
97Returns the repository root as a string.
98
99`git.repoRoot();`
100
101```js
102const repoRoot = git.repoRoot();
103
104file.copy(`${repoRoot}/LICENSE`, `${doc}/LICENSE`);
105```
106
107### `git.tag`
108
109Returns the output of `git describe --tags`. Useful for getting the "current version" of the repo, where the current version will likely be different forward in time than it is backwards in time.
110
111Usage:
112
113`git.tag();`
114
115```js
116const version = git.tag();
117```
118
119## `gitea`
120
121Helpers for integrating with Gitea servers.
122
123### `gitea.uploadPackage`
124
125Uploads a binary package to Gitea, silently failing if the package is not a `.deb` or `.rpm` file. Gitea configuration is done with flags or the configuration file.
126
127Usage:
128
129`gitea.uploadPackage(owner, distro, component, fname)`
130
131```js
132gitea.uploadPackage(
133 "Techaro",
134 "yeet",
135 "unstable",
136 "./var/yeet-0.0.8.x86_64.rpm",
137);
138```
139
140## `go`
141
142Helpers for the Go programming language.
143
144### `go.build`
145
146Runs `go build` in the current working directory with any extra arguments passed in. This is useful for building and installing Go programs in an RPM build context.
147
148Usage:
149
150`go.build(args);`
151
152```js
153go.build("-o", `${out}/usr/bin/`);
154```
155
156### `go.install`
157
158Runs `go install`. Not useful for cross-compilation.
159
160Usage:
161
162`go.install();`
163
164```js
165go.install();
166```
167
168## `log`
169
170Logging functions.
171
172### `log.println`
173
174Prints log data to standard output.
175
176Usage:
177
178`log.println(...);`
179
180```js
181log.println(`built package ${pkgPath}`);
182```
183
184## `rpm`
185
186Helpers for building RPM packages and docker images out of a constellation of RPM packages.
187
188### `rpm.build`
189
190Builds an RPM package with a descriptor object. See the RPM packages section for more information. The important part of this is your `build` function. The `build` function is what will turn your package source code into an executable in `out` somehow. Everything in `out` corresponds 1:1 with paths in the resulting RPM.
191
192The resulting RPM path will be returned as a string.
193
194Usage:
195
196`rpm.build(package);`
197
198```js
199["amd64", "arm64"].forEach((goarch) =>
200 rpm.build({
201 name: "yeet",
202 description: "Yeet out actions with maximum haste!",
203 homepage: "https://techaro.lol",
204 license: "MIT",
205 goarch,
206
207 build: ({ bin }) => {
208 go.build("-o", `${bin}/yeet`, "./cmd/yeet");
209 },
210 }),
211);
212```
213
214## `yeet`
215
216This contains various "other" functions that don't have a good place to put them.
217
218### `yeet.cwd`
219
220The current working directory. This is a constant value and is not updated at runtime.
221
222Usage:
223
224```js
225log.println(yeet.cwd);
226```
227
228### `yeet.dateTag`
229
230A constant string representing the time that yeet was started in UTC. It is formatted in terms of `YYYYmmDDhhMM`. This is not updated at runtime. You can use it for a "unique" value per invocation of yeet (assuming you aren't a time traveler).
231
232Usage:
233
234```js
235docker.build(`ghcr.io/xe/site/bin:${git.tag()}-${yeet.dateTag}`);
236```
237
238### `yeet.getenv`
239
240Gets an environment variable and returns it as a string, optionally returning an empty string if the variable is not found.
241
242Usage:
243
244`yeet.getenv(name);`
245
246```js
247const someValue = yeet.getenv("SOME_VALUE");
248```
249
250### `yeet.run` / `yeet.runcmd`
251
252Runs an arbitrary command and returns any output as a string.
253
254Usage:
255
256`yeet.run(cmd, arg1, arg2, ...);`
257
258```js
259yeet.run(
260 "protoc",
261 "--proto-path=.",
262 `--proto-path=${git.repoRoot()}/proto`,
263 "foo.proto",
264);
265```
266
267### `yeet.setenv`
268
269Sets an environment variable for the process yeet is running in and all children.
270
271Usage:
272
273`yeet.setenv(key, val);`
274
275```js
276yeet.setenv("GOOS", "linux");
277```
278
279### `yeet.goos` / `yeet.goarch`
280
281The GOOS/GOARCH value that yeet was built for. This typically corresponds with the OS and CPU architecture that yeet is running on.
282
283## Building native packages
284
285When using the `deb.build`, `rpm.build`, or `tarball.build` functions, you can create native packages from arbitrary yeet expressions. This allows you to cross-compile native packages from a macOS or other Linux system. As an example, here is how the yeet packages are built:
286
287```js
288["amd64", "arm64"].forEach((goarch) =>
289 [deb, rpm, tarball].forEach((method) =>
290 method.build({
291 name: "yeet",
292 description: "Yeet out scripts with maximum haste!",
293 homepage: "https://techaro.lol",
294 license: "MIT",
295 goarch,
296
297 build: ({ bin }) => {
298 go.build("-o", `${bin}/yeet`, "./cmd/yeet");
299 },
300 }),
301 ),
302);
303```
304
305### Build settings
306
307The following settings are supported:
308
309| Name | Example | Description |
310| :-------------- | :----------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
311| `name` | `xeiaso.net-yeet` | The name of the package. This should be unique across the system. |
312| `version` | `1.0.0` | The version of the package, if not set then it will be inferred from the git version. |
313| `description` | `Yeet out scripts with haste!` | The human-readable description of the package. |
314| `homepage` | `https://xeiaso.net` | The URL for the homepage of the package. |
315| `group` | `Network` | If set, the RPM group that this package belongs to. |
316| `license` | `MIT` | The license that the contents of this package is under. |
317| `goarch` | `amd64` / `arm64` | The GOARCH value corresponding to the architecture that the RPM is being built for. If you want to build a `noarch` package, put `any` here. |
318| `replaces` | `["foo", "bar"]` | Any packages that this package conflicts with or replaces. |
319| `depends` | `["foo", "bar"]` | Any packages that this package depends on (such as C libraries for CGo code). |
320| `emptyDirs` | `["/var/lib/yeet"]` | Any empty directories that should be created when the package is installed. |
321| `configFiles` | `{"./.env.example": "/var/lib/yeet/.env"}` | Any configuration files that should be copied over on install, but managed by administrators after installation. |
322| `documentation` | `{"./README.md": "README.md"}` | Any documentation files that should be copied to the `doc` folder of a tarball or be put in `/usr/share/doc` in an OS package. Try to include enough documentation that users can troubleshoot the program completely offline. |
323| `files` | `{}` | Any other static files that should be copied in-place to a path in the target filesystem. |
324
325Packages MUST define a `build` function and tarball packages MAY define a `mkFilename` function.
326
327### `build` function
328
329Every package definition MUST contain a `build` function that describes how to build the software. The build function takes one argument and returns nothing. If the build fails, throw an Exception with `throw`.
330
331The signature of `build` roughly follows this TypeScript type:
332
333```ts
334interface BuildInput {
335 // output folder, usually the package root
336 out: string;
337 // binary folder, ${out}/bin for tarballs or ${out}/usr/bin for OS packages
338 bin: string;
339 // documentation folder, ${out}/doc for tarballs or ${out}/usr/share/${pkg.name}/doc for OS packages
340 doc: string;
341 // configuration folder, ${out}/run for tarballs or ${out}/etc/${pkg.name} for OS packages
342 etc: string;
343 // systemd unit folder, ${out}/run for tarballs or ${out}/usr/lib/systemd/system for OS packages
344 systemd: string;
345}
346
347function build({...}: BuildInput) => {
348 // ...
349};
350```
351
352### `mkFilename` function
353
354When building a tarball, you MAY define a `mkFilename` function to customize the generated filename. If no `mkFilename` function is specified, the filename defaults to:
355
356```js
357const mkFilename = ({name, version, platform, goarch}) =
358 `${name}-${version}-${platform}-${goarch}`;
359```
360
361For example, to reduce the filename to the name and the version:
362
363```js
364tarball.build({
365 // ...
366 mkFilename: ({ name, version }) => `${name}-${version}`,
367 // ...
368});
369```