Yeet uses goja 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.
To 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.
$
lets you construct shell commands using tagged templates. This lets you build whatever shell commands you want by mixing Go and JavaScript values freely.
Example:
$`CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -s -w -extldflags "-static" -X "within.website/x.Version=${git.tag()}"`;
Helpers for building Debian packages.
Builds 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.
The resulting Debian package path will be returned as a string.
Usage:
deb.build(package);
["amd64", "arm64"].forEach((goarch) =>
deb.build({
name: "yeet",
description: "Yeet out actions with maximum haste!",
homepage: "https://techaro.lol",
license: "MIT",
goarch,
build: ({ bin }) => {
go.build("-o", `${bin}/yeet`, "./cmd/yeet");
},
})
);
Aliases for docker
commands.
An alias for the docker build
command. Builds a docker image in the current working directory's Dockerfile.
Usage:
docker.build(tag);
docker.build("ghcr.io/xe/site/bin");
docker.push("ghcr.io/xe/site/bin");
Pushes a docker image to a registry. Analogous to docker push
in the CLI.
Usage:
docker.push(tag);
docker.build("ghcr.io/xe/site/bin");
docker.push("ghcr.io/xe/site/bin");
Copies 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.
Usage:
file.install(src, dest);
file.install("LICENSE", `${doc}/LICENSE`);
Helpers for the Git version control system.
Returns the repository root as a string.
git.repoRoot();
const repoRoot = git.repoRoot();
file.copy(`${repoRoot}/LICENSE`, `${doc}/LICENSE`);
Returns 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.
Usage:
git.tag();
const version = git.tag();
Helpers for integrating with Gitea servers.
Uploads 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.
Usage:
gitea.uploadPackage(owner, distro, component, fname)
gitea.uploadPackage(
"Techaro",
"yeet",
"unstable",
"./var/yeet-0.0.8.x86_64.rpm"
);
Helpers for the Go programming language.
Runs 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.
Usage:
go.build(args);
go.build("-o", `${out}/usr/bin/`);
Runs go install
. Not useful for cross-compilation.
Usage:
go.install();
go.install();
Logging functions.
Prints log data to standard output.
Usage:
log.println(...);
log.println(`built package ${pkgPath}`);
Helpers for building RPM packages and docker images out of a constellation of RPM packages.
Builds 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.
The resulting RPM path will be returned as a string.
Usage:
rpm.build(package);
["amd64", "arm64"].forEach((goarch) =>
rpm.build({
name: "yeet",
description: "Yeet out actions with maximum haste!",
homepage: "https://techaro.lol",
license: "MIT",
goarch,
build: ({ bin }) => {
go.build("-o", `${bin}/yeet`, "./cmd/yeet");
},
})
);
This contains various "other" functions that don't have a good place to put them.
The current working directory. This is a constant value and is not updated at runtime.
Usage:
log.println(yeet.cwd);
A 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).
Usage:
docker.build(`ghcr.io/xe/site/bin:${git.tag()}-${yeet.dateTag}`);
Gets an environment variable and returns it as a string, optionally returning an empty string if the variable is not found.
Usage:
yeet.getenv(name);
const someValue = yeet.getenv("SOME_VALUE");
Runs an arbitrary command and returns any output as a string.
Usage:
yeet.run(cmd, arg1, arg2, ...);
yeet.run(
"protoc",
"--proto-path=.",
`--proto-path=${git.repoRoot()}/proto`,
"foo.proto"
);
Sets an environment variable for the process yeet is running in and all children.
Usage:
yeet.setenv(key, val);
yeet.setenv("GOOS", "linux");
The GOOS/GOARCH value that yeet was built for. This typically corresponds with the OS and CPU architecture that yeet is running on.
When 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:
["amd64", "arm64"].forEach((goarch) =>
[deb, rpm, tarball].forEach((method) =>
method.build({
name: "yeet",
description: "Yeet out scripts with maximum haste!",
homepage: "https://techaro.lol",
license: "MIT",
goarch,
build: ({ bin }) => {
go.build("-o", `${bin}/yeet`, "./cmd/yeet");
},
})
)
);
The following settings are supported:
Name | Example | Description |
---|---|---|
name |
xeiaso.net-yeet |
The name of the package. This should be unique across the system. |
version |
1.0.0 |
The version of the package, if not set then it will be inferred from the git version. |
description |
Yeet out scripts with haste! |
The human-readable description of the package. |
homepage |
https://xeiaso.net |
The URL for the homepage of the package. |
group |
Network |
If set, the RPM group that this package belongs to. |
license |
MIT |
The license that the contents of this package is under. |
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. |
replaces |
["foo", "bar"] |
Any packages that this package conflicts with or replaces. |
depends |
["foo", "bar"] |
Any packages that this package depends on (such as C libraries for CGo code). |
emptyDirs |
["/var/lib/yeet"] |
Any empty directories that should be created when the package is installed. |
configFiles |
{"./.env.example": "/var/lib/yeet/.env"} |
Any configuration files that should be copied over on install, but managed by administrators after installation. |
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. |
files |
{} |
Any other static files that should be copied in-place to a path in the target filesystem. |
Packages MUST define a build
function and tarball packages MAY define a mkFilename
function.
Every 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
.
The signature of build
roughly follows this TypeScript type:
interface BuildInput {
// output folder, usually the package root
out: string;
// binary folder, ${out}/bin for tarballs or ${out}/usr/bin for OS packages
bin: string;
// documentation folder, ${out}/doc for tarballs or ${out}/usr/share/${pkg.name}/doc for OS packages
doc: string;
// configuration folder, ${out}/run for tarballs or ${out}/etc/${pkg.name} for OS packages
etc: string;
// systemd unit folder, ${out}/run for tarballs or ${out}/usr/lib/systemd/system for OS packages
systemd: string;
}
function build({...}: BuildInput) => {
// ...
};
When building a tarball, you MAY define a mkFilename
function to customize the generated filename. If no mkFilename
function is specified, the filename defaults to:
const mkFilename = ({name, version, platform, goarch}) =
`${name}-${version}-${platform}-${goarch}`;
For example, to reduce the filename to the name and the version:
tarball.build({
// ...
mkFilename: ({ name, version }) => `${name}-${version}`,
// ...
});