aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.go.mod.sri2
-rw-r--r--cmd/tshello/main.go52
-rw-r--r--cmd/yeet/.gitignore1
-rw-r--r--cmd/yeet/README.md380
-rw-r--r--cmd/yeet/internal/mkrpm/mkrpm.go173
-rw-r--r--cmd/yeet/main.go81
-rw-r--r--cmd/yeet/yeetfile.js13
-rw-r--r--flake.nix2
-rw-r--r--go.mod42
-rw-r--r--go.sum173
-rw-r--r--internal/yeet/yeet.go2
11 files changed, 847 insertions, 74 deletions
diff --git a/.go.mod.sri b/.go.mod.sri
index 1d6815a..496d3dc 100644
--- a/.go.mod.sri
+++ b/.go.mod.sri
@@ -1 +1 @@
-sha256-O3pH0hQ/WmXWO3bO/xQqX2kRfFEdTLeB4q9g+uVkJX4=
+sha256-wXchFhghtSn4JAS4spJhTcwM1axDIaQuCEBs29XXxkA=
diff --git a/cmd/tshello/main.go b/cmd/tshello/main.go
deleted file mode 100644
index 59c688f..0000000
--- a/cmd/tshello/main.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// The tshello server demonstrates how to use Tailscale as a library.
-package main
-
-import (
- "flag"
- "fmt"
- "html"
- "log"
- "net/http"
- "strings"
-
- "tailscale.com/tsnet"
-)
-
-var (
- addr = flag.String("addr", ":80", "address to listen on")
- hostname = flag.String("hostname", "tshello", "hostname to use on the tailnet")
-)
-
-func main() {
- flag.Parse()
- s := new(tsnet.Server)
- defer s.Close()
- ln, err := s.Listen("tcp", *addr)
- if err != nil {
- log.Fatal(err)
- }
- defer ln.Close()
-
- lc, err := s.LocalClient()
- if err != nil {
- log.Fatal(err)
- }
-
- log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- who, err := lc.WhoIs(r.Context(), r.RemoteAddr)
- if err != nil {
- http.Error(w, err.Error(), 500)
- return
- }
- fmt.Fprintf(w, "<html><body><h1>Hello, world!</h1>\n")
- fmt.Fprintf(w, "<p>You are <b>%s</b> from <b>%s</b> (%s)</p>",
- html.EscapeString(who.UserProfile.LoginName),
- html.EscapeString(firstLabel(who.Node.ComputedName)),
- r.RemoteAddr)
- })))
-}
-
-func firstLabel(s string) string {
- s, _, _ = strings.Cut(s, ".")
- return s
-}
diff --git a/cmd/yeet/.gitignore b/cmd/yeet/.gitignore
new file mode 100644
index 0000000..e7a9c13
--- /dev/null
+++ b/cmd/yeet/.gitignore
@@ -0,0 +1 @@
+*.rpm
diff --git a/cmd/yeet/README.md b/cmd/yeet/README.md
new file mode 100644
index 0000000..4e61d6f
--- /dev/null
+++ b/cmd/yeet/README.md
@@ -0,0 +1,380 @@
+# yeet
+
+Yeet out actions with maximum haste! Declare your build instructions as small JavaScript snippets and let er rip!
+
+## Usage
+
+To install the current program with `go install`:
+
+```js
+// yeetfile.js
+go.install();
+```
+
+## Available functions
+
+Yeet 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.
+
+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.
+
+### `docker`
+
+Aliases for `docker` commands.
+
+#### `docker.build`
+
+An alias for the `docker build` command. Builds a docker image in the current working directory's Dockerfile.
+
+Usage:
+
+`docker.build(tag);`
+
+```js
+docker.build("ghcr.io/xe/site/bin");
+docker.push("ghcr.io/xe/site/bin");
+```
+
+#### `docker.load`
+
+Loads an exported docker image by path into the local docker daemon. This is most useful when combined with tools like `nix.build`.
+
+Usage:
+
+`docker.load(path)`
+
+```js
+nix.build(".#docker.xedn");
+docker.load("./result");
+docker.push("registry.fly.io/xedn:latest");
+fly.deploy();
+```
+
+#### `docker.push`
+
+Pushes a docker image to a registry. Analogous to `docker push` in the CLI.
+
+Usage:
+
+`docker.push(tag);`
+
+```js
+docker.build("ghcr.io/xe/site/bin");
+docker.push("ghcr.io/xe/site/bin");
+```
+
+### `file`
+
+Helpers for filesystem access.
+
+#### `file.copy`
+
+Copies a file from one place to another. Analogous to the `cp` command on Linux. Automatically creates directories in the `dest` path if they don't exist.
+
+Usage:
+
+`file.copy(src, dest);`
+
+```js
+file.copy("LICENSE", `${out}/usr/share/doc/LICENSE`);
+```
+
+#### `file.read`
+
+Reads a file into memory and returns it as a string.
+
+Usage:
+
+`file.read(path);`
+
+```js
+const version = file.read("VERSION");
+```
+
+#### `file.write`
+
+Writes the contents of the `data` string to a file with mode `0660`.
+
+Usage:
+
+`file.write(path, data);`
+
+```js
+file.write("VERSION", git.tag());
+```
+
+### `fly`
+
+Automation for [flyctl](https://github.com/superfly/flyctl). Soon this will also let you manage Machines with the [Machines API](https://docs.machines.dev).
+
+#### `fly.deploy`
+
+Runs the `fly deploy` command for you.
+
+Usage:
+
+`fly.deploy();`
+
+```js
+docker.build("registry.fly.io/foobar");
+docker.push("registry.fly.io/foobar");
+fly.deploy();
+```
+
+### `git`
+
+Helpers for the Git version control system.
+
+#### `git.repoRoot`
+
+Returns the repository root as a string.
+
+`git.repoRoot();`
+
+```js
+const repoRoot = git.repoRoot();
+
+file.copy(`${repoRoot}/LICENSE`, `${out}/usr/share/doc/yeet/LICENSE`);
+```
+
+#### `git.tag`
+
+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();`
+
+```js
+const version = git.tag();
+```
+
+### `go`
+
+Helpers for the Go programming language.
+
+#### `go.build`
+
+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);`
+
+```js
+go.build("-o", `${out}/usr/bin/`);
+```
+
+#### `go.install`
+
+Runs `go install`. Not useful for cross-compilation.
+
+Usage:
+
+`go.install();`
+
+```js
+go.install();
+```
+
+### `nix`
+
+Automation for running Nix ecosystem tooling.
+
+#### `nix.build`
+
+Runs `nix build` against a given flakeref.
+
+Usage:
+
+`nix.build(flakeref);`
+
+```js
+nix.build(".#docker");
+docker.load("./result");
+```
+
+#### `nix.eval`
+
+A tagged template that helps you build Nix expressions safely from JavaScript and then evaluates them. See my [nixexpr blogpost](https://xeiaso.net/blog/nixexpr/) for more information about how this works.
+
+Usage:
+
+```js
+const glibcPath = nix.eval`let pkgs = import <nixpkgs>; in pkgs.glibc`;
+```
+
+#### `nix.expr`
+
+A tagged template that helps you build Nix expressions safely from JavaScript. See my [nixexpr blogpost](https://xeiaso.net/blog/nixexpr/) for more information about how this works.
+
+Usage:
+
+```js
+go.build();
+const fname = slug.build("todayinmarch2020");
+
+const url = slug.push(fname);
+const hash = nix.hashURL(url);
+
+const expr = nix.expr`{ stdenv }:
+
+stdenv.mkDerivation {
+ name = "todayinmarch2020";
+ src = builtins.fetchurl {
+ url = ${url};
+ sha256 = ${hash};
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ tar xf $src
+ mkdir -p $out/bin
+ cp bin/main $out/bin/todayinmarch2020
+ '';
+}
+`;
+
+file.write(`${repoRoot}/pkgs/x/todayinmarch2020.nix`, expr);
+```
+
+#### `nix.hashURL`
+
+Hashes the contents of a given URL and returns the `sha256` SRI form. Useful when composing Nix expressions with the `nix.expr` tagged template.
+
+Usage:
+
+`nix.hashURL(url);`
+
+```js
+const hash = nix.hashURL("https://whatever.com/some_file.tgz");
+```
+
+### `rpm`
+
+Helpers for building RPM packages and docker images out of a constellation of RPM packages.
+
+#### `rpm.build`
+
+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);`
+
+```js
+["amd64", "arm64"].forEach((goarch) =>
+ rpm.build({
+ name: "yeet",
+ description: "Yeet out actions with maximum haste!",
+ homepage: "https://within.website",
+ license: "CC0",
+ goarch,
+
+ build: (out) => {
+ go.build("-o", `${out}/usr/bin/`);
+ },
+ })
+);
+```
+
+### `yeet`
+
+This contains various "other" functions that don't have a good place to put them.
+
+#### `yeet.cwd`
+
+The current working directory. This is a constant value and is not updated at runtime.
+
+Usage:
+
+```js
+log.println(yeet.cwd);
+```
+
+#### `yeet.dateTag`
+
+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:
+
+```js
+docker.build(`ghcr.io/xe/site/bin:${git.tag()}-${yeet.dateTag}`);
+```
+
+#### `yeet.run` / `yeet.runcmd`
+
+Runs an arbitrary command and returns any output as a string.
+
+Usage:
+
+`yeet.run(cmd, arg1, arg2, ...);`
+
+```js
+yeet.run(
+ "protoc",
+ "--proto-path=.",
+ `--proto-path=${git.repoRoot()}/proto`,
+ "foo.proto"
+);
+```
+
+#### `yeet.setenv`
+
+Sets an environment variable for the process yeet is running in and all children.
+
+Usage:
+
+`yeet.setenv(key, val);`
+
+```js
+yeet.setenv("GOOS", "linux");
+```
+
+#### `yeet.goos` / `yeet.goarch`
+
+The GOOS/GOARCH value that yeet was built for. This typically corresponds with the OS and CPU architecture that yeet is running on.
+
+## Building RPM Packages
+
+When using the `rpm.build` function, you can create RPM packages from arbitrary yeet expressions. This allows you to create RPM packages from a macOS or other Linux system. As an example, here is how the yeet RPMs are built:
+
+```js
+["amd64", "arm64"].forEach((goarch) =>
+ rpm.build({
+ name: "yeet",
+ description: "Yeet out actions with maximum haste!",
+ homepage: "https://within.website",
+ license: "CC0",
+ goarch: goarch,
+
+ build: (out) => {
+ go.build("-o", `${out}/usr/bin/`);
+ },
+ })
+);
+```
+
+### Build settings
+
+The following settings are supported:
+
+| Name | Example | Description |
+| :------------ | :----------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
+| `name` | `xeiaso.net-yeet` | The unique name of the package. |
+| `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. |
+
+## Support
+
+For support, please [subscribe to me on Patreon](https://patreon.com/cadey) and ask in the `#yeet` channel. You may open GitHub issues if you wish, but I do not often look at them.
diff --git a/cmd/yeet/internal/mkrpm/mkrpm.go b/cmd/yeet/internal/mkrpm/mkrpm.go
new file mode 100644
index 0000000..71c48fd
--- /dev/null
+++ b/cmd/yeet/internal/mkrpm/mkrpm.go
@@ -0,0 +1,173 @@
+package mkrpm
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "log/slog"
+ "os"
+ "path/filepath"
+ "runtime"
+
+ "github.com/Songmu/gitconfig"
+ "github.com/goreleaser/nfpm/v2"
+ "github.com/goreleaser/nfpm/v2/files"
+ _ "github.com/goreleaser/nfpm/v2/rpm"
+ "within.website/x/internal/yeet"
+)
+
+var (
+ userName = flag.String("git-user-name", gitUserName(), "user name in Git")
+ userEmail = flag.String("git-user-email", gitUserEmail(), "user email in Git")
+)
+
+const (
+ fallbackName = "Mimi Yasomi"
+ fallbackEmail = "mimi@xeserv.us"
+)
+
+func gitUserName() string {
+ name, err := gitconfig.User()
+ if err != nil {
+ return fallbackName
+ }
+
+ return name
+}
+
+func gitUserEmail() string {
+ email, err := gitconfig.Email()
+ if err != nil {
+ return fallbackEmail
+ }
+
+ return email
+}
+
+func gitVersion() string {
+ vers, err := yeet.GitTag(context.Background())
+ if err != nil {
+ panic(err)
+ }
+ return vers[1:]
+}
+
+type Package struct {
+ Name string `json:"name"`
+ Version string `json:"version"`
+ Description string `json:"description"`
+ Homepage string `json:"homepage"`
+ Group string `json:"group"`
+ License string `json:"license"`
+ Goarch string `json:"goarch"`
+ Replaces []string `json:"replaces"`
+ Depends []string `json:"depends"`
+ Recommends []string `json:"recommends"`
+
+ EmptyDirs []string `json:"emptyDirs"` // rpm destination path
+ ConfigFiles map[string]string `json:"configFiles"` // repo-relative source path, rpm destination path
+
+ Build func(out string) `json:"build"`
+}
+
+func Build(p Package) (foutpath string, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ switch r.(type) {
+ case error:
+ err = r.(error)
+ default:
+ err = fmt.Errorf("mkrpm: error while building: %v", r)
+ }
+ }
+ }()
+
+ if p.Version == "" {
+ p.Version = gitVersion()
+ }
+
+ dir, err := os.MkdirTemp("", "yeet-mkrpm")
+ if err != nil {
+ return "", fmt.Errorf("mkrpm: can't make temporary directory")
+ }
+ defer os.RemoveAll(dir)
+
+ defer func() {
+ os.Setenv("GOARCH", runtime.GOARCH)
+ os.Setenv("GOOS", runtime.GOOS)
+ }()
+ os.Setenv("GOARCH", p.Goarch)
+ os.Setenv("GOOS", "linux")
+
+ p.Build(dir)
+
+ var contents files.Contents
+
+ for _, d := range p.EmptyDirs {
+ if d == "" {
+ continue
+ }
+
+ contents = append(contents, &files.Content{Type: files.TypeDir, Destination: d})
+ }
+
+ for repoPath, rpmPath := range p.ConfigFiles {
+ contents = append(contents, &files.Content{Type: files.TypeConfig, Source: repoPath, Destination: rpmPath})
+ }
+
+ if err := filepath.Walk(dir, func(path string, stat os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if stat.IsDir() {
+ return nil
+ }
+
+ contents = append(contents, &files.Content{Type: files.TypeFile, Source: path, Destination: path[len(dir)+1:]})
+
+ return nil
+ }); err != nil {
+ return "", fmt.Errorf("mkrpm: can't walk output directory: %w", err)
+ }
+
+ info := nfpm.WithDefaults(&nfpm.Info{
+ Name: p.Name,
+ Version: p.Version,
+ Arch: p.Goarch,
+ Platform: "linux",
+ Description: p.Description,
+ Maintainer: fmt.Sprintf("%s <%s>", *userName, *userEmail),
+ Homepage: p.Homepage,
+ License: p.License,
+ Overridables: nfpm.Overridables{
+ Contents: contents,
+ Depends: p.Depends,
+ Recommends: p.Recommends,
+ Replaces: p.Replaces,
+ Conflicts: p.Replaces,
+ },
+ })
+
+ info.Overridables.RPM.Group = p.Group
+
+ pkg, err := nfpm.Get("rpm")
+ if err != nil {
+ return "", fmt.Errorf("mkrpm: can't get RPM packager: %w", err)
+ }
+
+ foutpath = fmt.Sprintf("%s-%s-%s.rpm", p.Name, p.Version, p.Goarch)
+ fout, err := os.Create(foutpath)
+ if err != nil {
+ return "", fmt.Errorf("mkrpm: can't create output file: %w", err)
+ }
+ defer fout.Close()
+
+ if err := pkg.Package(info, fout); err != nil {
+ return "", fmt.Errorf("mkrpm: can't build package: %w", err)
+ }
+
+ slog.Debug("built package", "name", p.Name, "version", p.Version, "path", foutpath)
+
+ return foutpath, err
+}
diff --git a/cmd/yeet/main.go b/cmd/yeet/main.go
index b143597..dd18d33 100644
--- a/cmd/yeet/main.go
+++ b/cmd/yeet/main.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"flag"
"fmt"
+ "io"
"log"
"log/slog"
"os"
@@ -15,6 +16,7 @@ import (
"strings"
"github.com/dop251/goja"
+ "within.website/x/cmd/yeet/internal/mkrpm"
"within.website/x/internal"
"within.website/x/internal/appsluggr"
"within.website/x/internal/kahless"
@@ -23,8 +25,8 @@ import (
)
var (
- fname = flag.String("fname", "yeetfile.js", "filename for the yeetfile")
- flyctl = flag.String("flyctl-path", flyctlPath(), "path to flyctl binary")
+ fname = flag.String("fname", "yeetfile.js", "filename for the yeetfile")
+ flyctl = flag.String("flyctl-path", flyctlPath(), "path to flyctl binary")
protocPath = flag.String("protoc-path", "protoc", "path to protoc binary")
)
@@ -46,7 +48,7 @@ func flyctlPath() string {
func runcmd(cmdName string, args ...string) string {
ctx := context.Background()
- slog.Info("running command", "cmd", cmdName, "args", args)
+ slog.Debug("running command", "cmd", cmdName, "args", args)
result, err := yeet.Output(ctx, cmdName, args...)
if err != nil {
@@ -74,10 +76,6 @@ func dockerload(fname string) {
yeet.DockerLoadResult(context.Background(), fname)
}
-func dockertag(org, repo, image string) string {
- return yeet.DockerTag(context.Background(), org, repo, image)
-}
-
func dockerbuild(tag string, args ...string) {
yeet.DockerBuild(context.Background(), yeet.WD, tag, args...)
}
@@ -150,11 +148,11 @@ func hostname() string {
}
type protocInput struct {
- Input string `json:"input"`
+ Input string `json:"input"`
Output string `json:"output"`
- Kinds []struct {
+ Kinds []struct {
Kind string `json:"kind"`
- Opt string `json:"opt"`
+ Opt string `json:"opt"`
} `json:"kinds"`
}
@@ -182,15 +180,52 @@ func main() {
"build": dockerbuild,
"load": dockerload,
"push": dockerpush,
- "tag": dockertag,
})
vm.Set("file", map[string]any{
+ "read": func(fname string) string {
+ data, err := os.ReadFile(fname)
+ if err != nil {
+ panic(err)
+ }
+ return string(data)
+ },
"write": func(fname, data string) {
if err := os.WriteFile(fname, []byte(data), 0660); err != nil {
panic(err)
}
},
+ "copy": func(from, to string) {
+ st, err := os.Stat(from)
+ if err != nil {
+ panic(err)
+ }
+
+ fin, err := os.Open(from)
+ if err != nil {
+ panic(err)
+ }
+ defer fin.Close()
+
+ dir := filepath.Dir(to)
+ os.MkdirAll(dir, 0777)
+
+ fout, err := os.OpenFile(to, os.O_CREATE, st.Mode())
+ if err != nil {
+ panic(err)
+ }
+ defer fout.Close()
+
+ n, err := io.Copy(fout, fin)
+ if err != nil {
+ panic(err)
+ }
+
+ if n != st.Size() {
+ slog.Error("wrong number of bytes written", "from", from, "to", to, "want", st.Size(), "got", n)
+ panic("copy failed")
+ }
+ },
})
vm.Set("fly", map[string]any{
@@ -201,17 +236,17 @@ func main() {
"repoRoot": func() string {
return runcmd("git", "rev-parse", "--show-toplevel")
},
+ "tag": gittag,
})
vm.Set("go", map[string]any{
- "build": func() { runcmd("go", "build") },
+ "build": func(args ...string) {
+ args = append([]string{"build"}, args...)
+ runcmd("go", args...)
+ },
"install": func() { runcmd("go", "install") },
})
- vm.Set("git", map[string]any{
- "tag": gittag,
- })
-
vm.Set("log", map[string]any{
"info": lg.Println,
"println": fmt.Println,
@@ -219,9 +254,19 @@ func main() {
vm.Set("nix", map[string]any{
"build": nixbuild,
- "hashURL": func(fileURL string) string { return strings.TrimSpace(runcmd("nix-prefetch-url", fileURL)) },
- "expr": buildNixExpr,
"eval": evalNixExpr,
+ "expr": buildNixExpr,
+ "hashURL": func(fileURL string) string { return strings.TrimSpace(runcmd("nix-prefetch-url", fileURL)) },
+ })
+
+ vm.Set("rpm", map[string]any{
+ "build": func(p mkrpm.Package) string {
+ foutpath, err := mkrpm.Build(p)
+ if err != nil {
+ panic(err)
+ }
+ return foutpath
+ },
})
vm.Set("slug", map[string]any{
diff --git a/cmd/yeet/yeetfile.js b/cmd/yeet/yeetfile.js
index 312fd4f..ebf7acf 100644
--- a/cmd/yeet/yeetfile.js
+++ b/cmd/yeet/yeetfile.js
@@ -1,2 +1,13 @@
-yeet.setenv("CGO_ENABLED", "0");
go.install();
+
+["amd64", "arm64"].forEach(goarch => rpm.build({
+ name: "yeet",
+ description: "Yeet out actions with maximum haste!",
+ homepage: "https://within.website",
+ license: "CC0",
+ goarch,
+
+ build: (out) => {
+ go.build("-o", `${out}/usr/bin/`);
+ },
+})); \ No newline at end of file
diff --git a/flake.nix b/flake.nix
index 07b4321..bf5d0ba 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,4 +1,4 @@
-# nix-direnv cache busting line: sha256-O3pH0hQ/WmXWO3bO/xQqX2kRfFEdTLeB4q9g+uVkJX4=
+# nix-direnv cache busting line: sha256-peNzrjlmFqFFgp+0UgIriHl21j1a8Y1F1zIu7RO5NaY=
{
description = "/x/perimental code";
diff --git a/go.mod b/go.mod
index e264cca..6f24445 100644
--- a/go.mod
+++ b/go.mod
@@ -9,6 +9,7 @@ require (
entgo.io/ent v0.13.1
github.com/Marcel-ICMC/graw v0.0.0-20230411090719-e24cd8592d25
github.com/McKael/madon/v2 v2.4.0
+ github.com/Songmu/gitconfig v0.2.0
github.com/aws/aws-sdk-go v1.51.13
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0
github.com/bwmarrin/discordgo v0.27.1
@@ -26,6 +27,7 @@ require (
github.com/google/go-github v17.0.0+incompatible
github.com/google/subcommands v1.2.0
github.com/google/uuid v1.6.0
+ github.com/goreleaser/nfpm/v2 v2.33.1
github.com/hullerob/go.farbfeld v0.0.0-20181222022525-3661193c725f
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
github.com/joho/godotenv v1.5.1
@@ -62,7 +64,14 @@ require (
require (
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
+ dario.cat/mergo v1.0.0 // indirect
+ github.com/AlekSi/pointer v1.2.0 // indirect
github.com/Khan/genqlient v0.6.0 // indirect
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/semver/v3 v3.2.1 // indirect
+ github.com/Masterminds/sprig/v3 v3.2.3 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/PuerkitoBio/rehttp v1.3.0 // indirect
github.com/agext/levenshtein v1.2.1 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
@@ -74,34 +83,61 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 // indirect
github.com/bytedance/sonic v1.11.3 // indirect
+ github.com/cavaliergopher/cpio v1.0.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
+ github.com/cli/go-gh v0.1.0 // indirect
+ github.com/cloudflare/circl v1.3.7 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
+ github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
+ github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanw/esbuild v0.19.11 // indirect
github.com/fasthttp/router v1.5.0 // indirect
+ github.com/fatih/color v1.15.0 // indirect
+ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
+ github.com/go-git/go-billy/v5 v5.5.0 // indirect
+ github.com/go-git/go-git/v5 v5.11.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-shiori/dom v0.0.0-20210627111528-4e4722cd0d65 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
+ github.com/gobwas/glob v0.2.3 // indirect
+ github.com/goccy/go-yaml v1.9.5 // indirect
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
+ github.com/google/rpmpack v0.5.0 // indirect
+ github.com/goreleaser/chglog v0.5.0 // indirect
+ github.com/goreleaser/fileglob v1.3.0 // indirect
github.com/gorilla/csrf v1.7.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/grbit/go-json v0.11.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
+ github.com/huandu/xstrings v1.4.0 // indirect
+ github.com/imdario/mergo v0.3.16 // indirect
+ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
+ github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
+ github.com/klauspost/pgzip v1.2.6 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.58 // indirect
+ github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
+ github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/safchain/ethtool v0.3.0 // indirect
github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 // indirect
+ github.com/sergi/go-diff v1.3.1 // indirect
+ github.com/shopspring/decimal v1.3.1 // indirect
+ github.com/skeema/knownhosts v1.2.1 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
github.com/superfly/graphql v0.2.4 // indirect
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
@@ -109,13 +145,19 @@ require (
github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect
github.com/turnage/redditproto v0.0.0-20151223012412-afedf1b6eddb // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+ github.com/ulikunitz/xz v0.5.11 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.52.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/vektah/gqlparser/v2 v2.5.1 // indirect
+ github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/zclconf/go-cty v1.8.0 // indirect
+ gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
golang.org/x/arch v0.6.0 // indirect
+ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
+ gopkg.in/warnings.v0 v0.1.2 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.41.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
diff --git a/go.sum b/go.sum
index 63298e1..a7c9b80 100644
--- a/go.sum
+++ b/go.sum
@@ -57,6 +57,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
entgo.io/ent v0.13.1 h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=
entgo.io/ent v0.13.1/go.mod h1:qCEmo+biw3ccBn9OyL4ZK5dfpwg++l1Gxwac5B1206A=
@@ -64,21 +66,44 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc=
filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA=
+github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
+github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
+github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Khan/genqlient v0.6.0 h1:Bwb1170ekuNIVIwTJEqvO8y7RxBxXu639VJOkKSrwAk=
github.com/Khan/genqlient v0.6.0/go.mod h1:rvChwWVTqXhiapdhLDV4bp9tz/Xvtewwkon4DpWWCRM=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Marcel-ICMC/graw v0.0.0-20230411090719-e24cd8592d25 h1:2y0Jf51U3toefyF80qgCNfd8qZEjkmWSvBX/DNhM6Mw=
github.com/Marcel-ICMC/graw v0.0.0-20230411090719-e24cd8592d25/go.mod h1:Tc1Bv6CivnFGhW5kjO2ZN9/PMlGJ6O4cVFYkaTNWSY8=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/McKael/madon/v2 v2.4.0 h1:u5bwEs7r3ek2L1KFOZ27wzHY1vY9bnG4oQDzcrbJyK4=
github.com/McKael/madon/v2 v2.4.0/go.mod h1:fSjqeQzvbKPjWQOv0VV3SPKvPCmj6Y+meOqkvQbXEnU=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
+github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
+github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
+github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
+github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
+github.com/ProtonMail/gopenpgp/v2 v2.7.1/go.mod h1:/BU5gfAVwqyd8EfC3Eu7zmuhwYQpKs+cGD8M//iiaxs=
github.com/PuerkitoBio/rehttp v1.3.0 h1:w54Pb72MQn2eJrSdPsvGqXlAfiK1+NMTGDrOJJ4YvSU=
github.com/PuerkitoBio/rehttp v1.3.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s=
+github.com/Songmu/gitconfig v0.2.0 h1:pX2++u4KUq+K2k/ZCzGXLtkD3ceCqIdi0tDyb+IbSyo=
+github.com/Songmu/gitconfig v0.2.0/go.mod h1:cB5bYJer+pl7W8g6RHFwL/0X6aJROVrYuHlvc7PT+hE=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
@@ -102,6 +127,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go v1.51.13 h1:j6lgtz9E/XFRiYYnGNrAfWvyyTsuYvWvo2RCt0zqAIs=
github.com/aws/aws-sdk-go v1.51.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn