aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-09-28 17:37:30 +0900
committerOphestra <cat@gensokyo.uk>2026-09-28 19:57:13 +0900
commit75bf6b0f0a1ce00a4ce1d710bbd84d5ff20e058a (patch)
tree13f66c45250143a0eac246185a3eb4e9bd3e85fd
parentaae629a16bdce3931c508f498db7055b2301d156 (diff)
cmd/workflows: migrate workflowswip-ci-json
This represents the workflow documents via compound literals, and removes the ugly and footgun-heavy yaml documents. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--.gitea/workflows/test.yml130
-rw-r--r--cmd/workflows/doc.go10
-rw-r--r--cmd/workflows/main.go149
-rw-r--r--cmd/workflows/test.go227
4 files changed, 387 insertions, 129 deletions
diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml
index d1fc7ef8..0c29eb9e 100644
--- a/.gitea/workflows/test.yml
+++ b/.gitea/workflows/test.yml
@@ -1,129 +1 @@
-name: Test
-
-on:
- - push
-
-jobs:
- hakurei:
- name: Hakurei
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Run NixOS test
- run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.hakurei
-
- - name: Upload test output
- uses: actions/upload-artifact@v3
- with:
- name: "hakurei-vm-output"
- path: result/*
- retention-days: 1
-
- race:
- name: Hakurei (race detector)
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Run NixOS test
- run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.race
-
- - name: Upload test output
- uses: actions/upload-artifact@v3
- with:
- name: "hakurei-race-vm-output"
- path: result/*
- retention-days: 1
-
- sandbox:
- name: Sandbox
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Run NixOS test
- run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox
-
- - name: Upload test output
- uses: actions/upload-artifact@v3
- with:
- name: "sandbox-vm-output"
- path: result/*
- retention-days: 1
-
- sandbox-race:
- name: Sandbox (race detector)
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Run NixOS test
- run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox-race
-
- - name: Upload test output
- uses: actions/upload-artifact@v3
- with:
- name: "sandbox-race-vm-output"
- path: result/*
- retention-days: 1
-
- sharefs:
- name: ShareFS
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Run NixOS test
- run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sharefs
-
- - name: Upload test output
- uses: actions/upload-artifact@v3
- with:
- name: "sharefs-vm-output"
- path: result/*
- retention-days: 1
-
- check:
- name: Flake checks
- needs:
- - hakurei
- - race
- - sandbox
- - sandbox-race
- - sharefs
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Run checks
- run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check ./test
-
- dist:
- name: Create distribution
- runs-on: nix
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Build for test
- id: build-test
- run: >-
- export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
- sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' test/package.nix &&
- nix build --print-out-paths --print-build-logs ./test#dist &&
- mv test/{package.nix.old,package.nix} &&
- echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
-
- - name: Upload test build
- uses: actions/upload-artifact@v3
- with:
- name: "hakurei-${{ steps.build-test.outputs.rev }}"
- path: result/*
- retention-days: 1
+{"name":"Test","on":["push"],"jobs":{"hakurei":{"name":"Hakurei","runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Run NixOS test","run":"nix build --out-link result --print-out-paths --print-build-logs ./test#checks.x86_64-linux.hakurei"},{"name":"Upload test output","uses":"actions/upload-artifact@v3","with":{"name":"hakurei-vm-output","path":"result/*","retention-days":1}}]},"race":{"name":"Hakurei (race detector)","runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Run NixOS test","run":"nix build --out-link result --print-out-paths --print-build-logs ./test#checks.x86_64-linux.race"},{"name":"Upload test output","uses":"actions/upload-artifact@v3","with":{"name":"hakurei-race-vm-output","path":"result/*","retention-days":1}}]},"sandbox":{"name":"Sandbox","runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Run NixOS test","run":"nix build --out-link result --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox"},{"name":"Upload test output","uses":"actions/upload-artifact@v3","with":{"name":"sandbox-vm-output","path":"result/*","retention-days":1}}]},"sandbox-race":{"name":"Sandbox (race detector)","runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Run NixOS test","run":"nix build --out-link result --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox-race"},{"name":"Upload test output","uses":"actions/upload-artifact@v3","with":{"name":"sandbox-race-vm-output","path":"result/*","retention-days":1}}]},"sharefs":{"name":"ShareFS","runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Run NixOS test","run":"nix build --out-link result --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sharefs"},{"name":"Upload test output","uses":"actions/upload-artifact@v3","with":{"name":"sharefs-vm-output","path":"result/*","retention-days":1}}]},"check":{"name":"Flake checks","needs":["hakurei","race","sandbox","sandbox-race","sharefs"],"runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Run checks","run":"nix --print-build-logs --experimental-features 'nix-command flakes' flake check ./test"}]},"dist":{"name":"Create distribution","runs-on":"nix","steps":[{"name":"Checkout","uses":"actions/checkout@v4"},{"name":"Build for test","id":"build-test","run":"export HAKUREI_REV=\"$(git rev-parse --short HEAD)\" \u0026\u0026 sed -i.old 's/version = /version = \"0.0.0-'$HAKUREI_REV'\"; # version = /' test/package.nix \u0026\u0026 nix build --print-out-paths --print-build-logs ./test#dist \u0026\u0026 mv test/{package.nix.old,package.nix} \u0026\u0026 echo \"rev=$HAKUREI_REV\" \u003e\u003e $GITHUB_OUTPUT"},{"name":"Upload test build","uses":"actions/upload-artifact@v3","with":{"name":"hakurei-${{ steps.build-test.outputs.rev }}","path":"result/*","retention-days":1}}]}}}
diff --git a/cmd/workflows/doc.go b/cmd/workflows/doc.go
new file mode 100644
index 00000000..110d635a
--- /dev/null
+++ b/cmd/workflows/doc.go
@@ -0,0 +1,10 @@
+//go:build !workflows
+
+// The workflows program manages the .gitea directory to avoid having to write
+// yaml. It is never invoked directly or built for the distribution tarball.
+//
+// This program is an internal detail of the hakurei project and is not usable
+// on its own. It is not covered by the compatibility promise.
+package main
+
+//go:generate go run -tags=workflows .
diff --git a/cmd/workflows/main.go b/cmd/workflows/main.go
new file mode 100644
index 00000000..46f7e054
--- /dev/null
+++ b/cmd/workflows/main.go
@@ -0,0 +1,149 @@
+//go:build workflows
+
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "os"
+ "path/filepath"
+ "sync"
+)
+
+// KV represents a string to value pair.
+type KV[T any] struct {
+ K string
+ V T
+}
+
+// A Map represents an ordered set of key-value pairs.
+type Map[T any] []KV[T]
+
+// MarshalJSON encodes m as a key-value pair in JSON.
+func (m *Map[T]) MarshalJSON() ([]byte, error) {
+ if m == nil || len(*m) == 0 {
+ return []byte("{}"), nil
+ }
+
+ buf := bytes.NewBuffer(make([]byte, 0, len(*m)<<5))
+ buf.WriteByte('{')
+
+ last := len(*m) - 1
+ for i, pair := range *m {
+ p, err := json.Marshal(pair.K)
+ if err != nil {
+ return nil, fmt.Errorf("key %q: %w", pair.K, err)
+ }
+ buf.Write(p)
+ buf.WriteByte(':')
+
+ p, err = json.Marshal(pair.V)
+ if err != nil {
+ return nil, fmt.Errorf("value of key %q: %w", pair.K, err)
+ }
+ buf.Write(p)
+
+ if i < last {
+ buf.WriteByte(',')
+ }
+ }
+
+ buf.WriteByte('}')
+ return buf.Bytes(), nil
+}
+
+// A Step is a task ran as part of a [Job].
+type Step struct {
+ // A name for the step.
+ Name string `json:"name,omitempty"`
+ // Selects an action to run as part of a step in the job.
+ Uses string `json:"uses,omitempty"`
+ // A unique identifier for the step.
+ ID string `json:"id,omitempty"`
+ // Prevent a step from running unless a condition is met.
+ If string `json:"if,omitempty"`
+ // Runs command-line programs that do not exceed 21,000 characters using the
+ // operating system's shell.
+ Run string `json:"run,omitempty"`
+ // Key-value pairs of input parameters defined by the action.
+ With Map[any] `json:"with,omitempty"`
+}
+
+// A Job is an entry in a [Workflow] document.
+type Job struct {
+ // Set a name for the job.
+ Name string `json:"name,omitempty"`
+ // Identifies any jobs that must complete successfully before this job will
+ // run.
+ Needs []string `json:"needs,omitempty"`
+ // Define the type of machine to run the job on.
+ On string `json:"runs-on,omitempty"`
+ // A sequence of tasks.
+ Steps []Step `json:"steps,omitempty"`
+}
+
+// Workflow describes a workflow document.
+type Workflow struct {
+ // The name of the workflow.
+ Name string `json:"name,omitempty"`
+ // The name for workflow runs generated from the workflow.
+ RunName string `json:"run-name,omitempty"`
+ // Define which events can cause the workflow to run.
+ On any `json:"on"`
+
+ // Named jobs part of the workflow run.
+ Jobs Map[Job] `json:"jobs,omitempty"`
+}
+
+// workflowsDir is the relative pathname of the workflows directory.
+const workflowsDir = "../../.gitea/workflows"
+
+// writeFile writes the action to the .gitea directory.
+func (w *Workflow) writeFile(name string) error {
+ f, err := os.OpenFile(
+ filepath.Join(workflowsDir, name+".yml"),
+ os.O_CREATE|os.O_EXCL|os.O_WRONLY,
+ 0444,
+ )
+ if err != nil {
+ return err
+ }
+
+ err = json.NewEncoder(f).Encode(w)
+ if closeErr := f.Close(); err == nil {
+ err = closeErr
+ }
+ return err
+}
+
+// removeOnce synchronises removal of stale workflow files.
+var removeOnce sync.Once
+
+// removeWorkflows removes existing workflow files once.
+func removeWorkflows() {
+ removeOnce.Do(func() {
+ if err := os.RemoveAll(workflowsDir); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ if err := os.Mkdir(workflowsDir, 0755); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ })
+}
+
+// mustWriteFile is like writeFile, but terminates the program if a non-nil
+// error is returned.
+func (w *Workflow) mustWriteFile(name string) (_ struct{}) {
+ removeWorkflows()
+
+ if err := w.writeFile(name); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ return
+}
+
+func main() {}
diff --git a/cmd/workflows/test.go b/cmd/workflows/test.go
new file mode 100644
index 00000000..1bbb04f9
--- /dev/null
+++ b/cmd/workflows/test.go
@@ -0,0 +1,227 @@
+//go:build workflows
+
+package main
+
+var _ = (&Workflow{
+ Name: "Test",
+ On: []any{"push"},
+
+ Jobs: Map[Job]{
+ {K: "hakurei", V: Job{
+ Name: "Hakurei",
+ On: "nix",
+
+ Steps: []Step{
+ {
+ Name: "Checkout",
+ Uses: "actions/checkout@v4",
+ },
+
+ {
+ Name: "Run NixOS test",
+ Run: "nix build " +
+ "--out-link result " +
+ "--print-out-paths " +
+ "--print-build-logs " +
+ "./test#checks.x86_64-linux.hakurei",
+ },
+
+ {
+ Name: "Upload test output",
+ Uses: "actions/upload-artifact@v3",
+
+ With: Map[any]{
+ {K: "name", V: "hakurei-vm-output"},
+ {K: "path", V: "result/*"},
+
+ {K: "retention-days", V: 1},
+ },
+ },
+ },
+ }},
+
+ {K: "race", V: Job{
+ Name: "Hakurei (race detector)",
+ On: "nix",
+
+ Steps: []Step{
+ {Name: "Checkout", Uses: "actions/checkout@v4"},
+
+ {
+ Name: "Run NixOS test",
+ Run: "nix build " +
+ "--out-link result " +
+ "--print-out-paths " +
+ "--print-build-logs " +
+ "./test#checks.x86_64-linux.race",
+ },
+
+ {
+ Name: "Upload test output",
+ Uses: "actions/upload-artifact@v3",
+
+ With: Map[any]{
+ {K: "name", V: "hakurei-race-vm-output"},
+ {K: "path", V: "result/*"},
+
+ {K: "retention-days", V: 1},
+ },
+ },
+ },
+ }},
+
+ {K: "sandbox", V: Job{
+ Name: "Sandbox",
+ On: "nix",
+
+ Steps: []Step{
+ {Name: "Checkout", Uses: "actions/checkout@v4"},
+
+ {
+ Name: "Run NixOS test",
+ Run: "nix build " +
+ "--out-link result " +
+ "--print-out-paths " +
+ "--print-build-logs " +
+ "./test#checks.x86_64-linux.sandbox",
+ },
+
+ {
+ Name: "Upload test output",
+ Uses: "actions/upload-artifact@v3",
+
+ With: Map[any]{
+ {K: "name", V: "sandbox-vm-output"},
+ {K: "path", V: "result/*"},
+
+ {K: "retention-days", V: 1},
+ },
+ },
+ },
+ }},
+
+ {K: "sandbox-race", V: Job{
+ Name: "Sandbox (race detector)",
+ On: "nix",
+
+ Steps: []Step{
+ {Name: "Checkout", Uses: "actions/checkout@v4"},
+
+ {
+ Name: "Run NixOS test",
+ Run: "nix build " +
+ "--out-link result " +
+ "--print-out-paths " +
+ "--print-build-logs " +
+ "./test#checks.x86_64-linux.sandbox-race",
+ },
+
+ {
+ Name: "Upload test output",
+ Uses: "actions/upload-artifact@v3",
+
+ With: Map[any]{
+ {K: "name", V: "sandbox-race-vm-output"},
+ {K: "path", V: "result/*"},
+
+ {K: "retention-days", V: 1},
+ },
+ },
+ },
+ }},
+
+ {K: "sharefs", V: Job{
+ Name: "ShareFS",
+ On: "nix",
+
+ Steps: []Step{
+ {Name: "Checkout", Uses: "actions/checkout@v4"},
+
+ {
+ Name: "Run NixOS test",
+ Run: "nix build " +
+ "--out-link result " +
+ "--print-out-paths " +
+ "--print-build-logs " +
+ "./test#checks.x86_64-linux.sharefs",
+ },
+
+ {
+ Name: "Upload test output",
+ Uses: "actions/upload-artifact@v3",
+
+ With: Map[any]{
+ {K: "name", V: "sharefs-vm-output"},
+ {K: "path", V: "result/*"},
+
+ {K: "retention-days", V: 1},
+ },
+ },
+ },
+ }},
+
+ {K: "check", V: Job{
+ Name: "Flake checks",
+ On: "nix",
+
+ Needs: []string{
+ "hakurei",
+ "race",
+ "sandbox",
+ "sandbox-race",
+ "sharefs",
+ },
+
+ Steps: []Step{
+ {
+ Name: "Checkout",
+ Uses: "actions/checkout@v4",
+ },
+
+ {
+ Name: "Run checks",
+ Run: "nix " +
+ "--print-build-logs " +
+ "--experimental-features 'nix-command flakes' " +
+ "flake check ./test",
+ },
+ },
+ }},
+
+ {K: "dist", V: Job{
+ Name: "Create distribution",
+ On: "nix",
+
+ Steps: []Step{
+ {
+ Name: "Checkout",
+ Uses: "actions/checkout@v4",
+ },
+
+ {
+ Name: "Build for test",
+ ID: "build-test",
+ Run: "export HAKUREI_REV=\"$(git rev-parse --short HEAD)\" && " +
+ "sed -i.old " +
+ "'s/version = /version = \"0.0.0-'$HAKUREI_REV'\"; # version = /' " +
+ "test/package.nix && " +
+ "nix build --print-out-paths --print-build-logs ./test#dist && " +
+ "mv test/{package.nix.old,package.nix} && " +
+ "echo \"rev=$HAKUREI_REV\" >> $GITHUB_OUTPUT",
+ },
+
+ {
+ Name: "Upload test build",
+ Uses: "actions/upload-artifact@v3",
+
+ With: Map[any]{
+ {K: "name", V: "hakurei-${{ steps.build-test.outputs.rev }}"},
+ {K: "path", V: "result/*"},
+
+ {K: "retention-days", V: 1},
+ },
+ },
+ },
+ }},
+ },
+}).mustWriteFile("test")