vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Give workflows and jobs a name and description
1cde8b9ea2ba1483beb90f19cde0f58aede2a661 · Keenan Nemetz · 8d ago · parent 30de4a44
Give workflows and jobs a name and description The workflows page showed the file path and job IDs, so a reader had to open the YAML comments to learn what a workflow was for. Add optional top-level and job-level name and description fields, default them to the file stem and job ID, pin them with a queued run, and show them on the workflows and run pages. Also document what the workflow format still cannot express, and state that CI jobs are independent and unordered: only a local run uses the declaration order. Part of: #138
ci/workflow_test.go +30
| @@ -8,11 +8,15 @@ import ( | |||
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | 10 | const validCI = `version: 1 | |
| 11 | name: Verify main | ||
| 12 | description: Build, test and lint every push to main. | ||
| 11 | 13 | on: | |
| 12 | 14 | push: | |
| 13 | 15 | branches: [main, "release/*"] | |
| 14 | 16 | jobs: | |
| 15 | 17 | test: | |
| 18 | name: Unit tests | ||
| 19 | description: Runs the test suite. | ||
| 16 | 20 | image: alpine:3.22 | |
| 17 | 21 | steps: | |
| 18 | 22 | - name: build | |
| @@ -30,6 +34,12 @@ func TestValidWorkflowParses(t *testing.T) { | |||
| 30 | 34 | if len(wf.Jobs) != 1 || wf.Jobs[0].ID != "test" { | |
| 31 | 35 | t.Fatalf("jobs = %+v", wf.Jobs) | |
| 32 | 36 | } | |
| 37 | if wf.Name != "Verify main" || wf.Description != "Build, test and lint every push to main." { | ||
| 38 | t.Fatalf("workflow metadata = %q / %q", wf.Name, wf.Description) | ||
| 39 | } | ||
| 40 | if wf.Jobs[0].Name != "Unit tests" || wf.Jobs[0].Description != "Runs the test suite." { | ||
| 41 | t.Fatalf("job metadata = %q / %q", wf.Jobs[0].Name, wf.Jobs[0].Description) | ||
| 42 | } | ||
| 33 | 43 | if got := len(wf.Jobs[0].Steps); got != 2 { | |
| 34 | 44 | t.Fatalf("steps = %d, want 2", got) | |
| 35 | 45 | } | |
| @@ -51,6 +61,24 @@ func TestValidWorkflowParses(t *testing.T) { | |||
| 51 | 61 | } | |
| 52 | 62 | } | |
| 53 | 63 | ||
| 64 | func TestNamesDefaultToTheFileAndJobID(t *testing.T) { | ||
| 65 | t.Parallel() | ||
| 66 | wf, problems := Parse(".vole/workflows/verify.yaml", | ||
| 67 | "version: 1\njobs:\n test:\n image: alpine:3.22\n steps:\n - run: echo hi\n") | ||
| 68 | if len(problems) > 0 { | ||
| 69 | t.Fatalf("rejected: %v", problems) | ||
| 70 | } | ||
| 71 | if wf.Name != "verify" { | ||
| 72 | t.Fatalf("default workflow name = %q, want the file base name", wf.Name) | ||
| 73 | } | ||
| 74 | if wf.Description != "" || wf.Jobs[0].Description != "" { | ||
| 75 | t.Fatalf("an absent description became %q / %q", wf.Description, wf.Jobs[0].Description) | ||
| 76 | } | ||
| 77 | if wf.Jobs[0].Name != "test" { | ||
| 78 | t.Fatalf("default job name = %q, want the job ID", wf.Jobs[0].Name) | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 54 | 82 | func TestBranchesDefaultToAll(t *testing.T) { | |
| 55 | 83 | t.Parallel() | |
| 56 | 84 | wf, problems := Parse("w.yaml", "version: 1\njobs:\n j:\n image: alpine:3.22\n steps:\n - run: echo hi\n") | |
| @@ -83,6 +111,8 @@ func TestInvalidWorkflowsRejected(t *testing.T) { | |||
| 83 | 111 | {"typo key", "version: 1\njobs:\n j:\n run-on: x\n image: alpine:3.22\n steps:\n - run: echo\n", "is not a known key"}, | |
| 84 | 112 | {"empty", "", "empty"}, | |
| 85 | 113 | {"bad glob", "version: 1\non:\n push:\n branches: [\"a b\"]\njobs:\n j:\n image: alpine:3.22\n steps:\n - run: echo\n", "not a branch pattern"}, | |
| 114 | {"multiline description", "version: 1\ndescription: \"one\\ntwo\"\njobs:\n j:\n image: alpine:3.22\n steps:\n - run: echo\n", "must be one line"}, | ||
| 115 | {"long job description", "version: 1\njobs:\n j:\n image: alpine:3.22\n description: \"" + strings.Repeat("x", MaxDescriptionBytes+1) + "\"\n steps:\n - run: echo\n", "limit"}, | ||
| 86 | 116 | } | |
| 87 | 117 | for _, tc := range cases { | |
| 88 | 118 | t.Run(tc.name, func(t *testing.T) { | |