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.
Let a job start service containers beside it
c1929d2fceb5e9e65204d5eef907d0781b9a5391 · Keenan Nemetz · 5d ago · parent 1d06b008
ci/workflow_test.go +71
| @@ -767,3 +767,74 @@ func TestSecretNamesAreEnvironmentVariableNames(t *testing.T) { | |||
| 767 | 767 | t.Fatal("the runner's own variables are not distinguished") | |
| 768 | 768 | } | |
| 769 | 769 | } | |
| 770 | |||
| 771 | func TestServicesParseInNameOrder(t *testing.T) { | ||
| 772 | t.Parallel() | ||
| 773 | wf, problems := Parse(".vole/workflows/x.yaml", `version: 1 | ||
| 774 | jobs: | ||
| 775 | test: | ||
| 776 | image: golang:1.27-bookworm | ||
| 777 | network: bridge | ||
| 778 | services: | ||
| 779 | cache: | ||
| 780 | image: redis:8 | ||
| 781 | db: | ||
| 782 | image: postgres:17 | ||
| 783 | env: | ||
| 784 | POSTGRES_PASSWORD: test | ||
| 785 | PGDATA: /tmp/pgdata | ||
| 786 | steps: | ||
| 787 | - run: go test ./... | ||
| 788 | `) | ||
| 789 | if len(problems) > 0 { | ||
| 790 | t.Fatalf("rejected: %v", problems) | ||
| 791 | } | ||
| 792 | svcs := wf.Jobs[0].Services | ||
| 793 | if len(svcs) != 2 || svcs[0].ID != "cache" || svcs[1].ID != "db" { | ||
| 794 | t.Fatalf("services = %+v, want cache then db", svcs) | ||
| 795 | } | ||
| 796 | if svcs[1].Image != "postgres:17" || svcs[1].Env["PGDATA"] != "/tmp/pgdata" { | ||
| 797 | t.Fatalf("db = %+v", svcs[1]) | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 801 | func TestServiceProblemsAreRefused(t *testing.T) { | ||
| 802 | t.Parallel() | ||
| 803 | base := `version: 1 | ||
| 804 | jobs: | ||
| 805 | test: | ||
| 806 | image: golang:1.27-bookworm | ||
| 807 | network: bridge | ||
| 808 | services: | ||
| 809 | db: | ||
| 810 | image: postgres:17 | ||
| 811 | steps: | ||
| 812 | - run: echo hi | ||
| 813 | ` | ||
| 814 | cases := []struct { | ||
| 815 | name string | ||
| 816 | src string | ||
| 817 | want string | ||
| 818 | }{ | ||
| 819 | {"no network", strings.Replace(base, " network: bridge\n", "", 1), "need network: bridge"}, | ||
| 820 | {"network none", strings.Replace(base, "network: bridge", "network: none", 1), "need network: bridge"}, | ||
| 821 | {"no image", strings.Replace(base, " image: postgres:17\n", "", 1), "image is required"}, | ||
| 822 | {"image file", strings.Replace(base, "image: postgres:17", "image: file:db", 1), "reserved for image-file"}, | ||
| 823 | {"bad name", strings.Replace(base, " db:", " DB:", 1), "service name is"}, | ||
| 824 | {"bad env name", strings.Replace(base, " steps:", " env:\n BAD NAME: x\n steps:", 1), "not a variable name"}, | ||
| 825 | {"multiline env", strings.Replace(base, " steps:", " env:\n X: \"one\\ntwo\"\n steps:", 1), "one line"}, | ||
| 826 | {"unknown key", strings.Replace(base, " image: postgres:17", " image: postgres:17\n ports: [5432]", 1), "not a known key"}, | ||
| 827 | } | ||
| 828 | for _, tc := range cases { | ||
| 829 | t.Run(tc.name, func(t *testing.T) { | ||
| 830 | _, problems := Parse(".vole/workflows/x.yaml", tc.src) | ||
| 831 | if len(problems) == 0 { | ||
| 832 | t.Fatalf("accepted invalid services:\n%s", tc.src) | ||
| 833 | } | ||
| 834 | joined := strings.Join(problems, "\n") | ||
| 835 | if !strings.Contains(joined, tc.want) { | ||
| 836 | t.Fatalf("problems do not mention %q:\n%s", tc.want, joined) | ||
| 837 | } | ||
| 838 | }) | ||
| 839 | } | ||
| 840 | } | ||