mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
ci: add skip directives for long tests (#3151)
This PR introduces many CI optimizations: 1. The `[ci-skip]` PR body directive to skip the Postgres and end to end tests 2. Improved caching that cuts the Go test matrix in half 3. Increasing Go test parallelism for ~20% gains 4. Enable caching in webpack (4x frontend build)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# prcontext
|
||||
|
||||
`prcontext` is a simple Go program that extracts CI directives from PRs for a
|
||||
more efficient merge cycle.
|
||||
|
||||
Right now it only supports the `[ci-skip [job ...]]` directive. Since skips are
|
||||
only possible within PRs, the full suite will still run on merge.
|
||||
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coder/flog"
|
||||
)
|
||||
|
||||
// githubContext is structured as documented here:
|
||||
// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context.
|
||||
type githubContext struct {
|
||||
EventName string `json:"event_name"`
|
||||
Event struct {
|
||||
PullRequest struct {
|
||||
Body string `json:"body"`
|
||||
} `json:"pull_request"`
|
||||
} `json:"event"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
var c githubContext
|
||||
err := json.Unmarshal([]byte(os.Getenv("GITHUB_CONTEXT")), &c)
|
||||
if err != nil {
|
||||
flog.Fatal("decode stdin: %+v", err)
|
||||
}
|
||||
flog.Info("detected event %q", c.EventName)
|
||||
if c.EventName != "pull_request" {
|
||||
flog.Info("aborting since not Pull Request")
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = fmt.Printf("::group::{PR Body}\n%s\n::endgroup::\n", c.Event.PullRequest.Body)
|
||||
|
||||
skips := parseBody(c.Event.PullRequest.Body)
|
||||
_, _ = fmt.Printf("::echo::on\n::set-output name=skips::[%s]\n", strings.Join(skips, " "))
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const ciSkipPrefix = "ci-skip"
|
||||
|
||||
var skipDirective = regexp.MustCompile(`\[` + ciSkipPrefix + ` ([\w-\/ ]+)]`)
|
||||
|
||||
func parseBody(body string) (skips []string) {
|
||||
matches := skipDirective.FindAllStringSubmatch(body, -1)
|
||||
// flog.Info("matches: %+v", matches)
|
||||
|
||||
var skipMatches []string
|
||||
for i := range matches {
|
||||
for j := range matches[i] {
|
||||
v := matches[i][j]
|
||||
// flog.Info("%q", v)
|
||||
if !strings.Contains(v, ciSkipPrefix) {
|
||||
skipMatches = append(skipMatches, strings.Split(v, " ")...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return skipMatches
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseBody_basic(t *testing.T) {
|
||||
parseBody(`
|
||||
This is a test PR.
|
||||
|
||||
[ci-skip postgres windows]
|
||||
`)
|
||||
}
|
||||
|
||||
func Test_parseBody(t *testing.T) {
|
||||
type args struct {
|
||||
body string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantSkips []string
|
||||
}{
|
||||
{"no directive", args{"test pr 123\n\n"}, nil},
|
||||
{"single dir single skip", args{"test pr [ci-skip dog] 123\n\n"}, []string{"dog"}},
|
||||
{"double dir double skip", args{"test pr [ci-skip dog] [ci-skip cat] 123\n\n"}, []string{"dog", "cat"}},
|
||||
{"single dir double skip", args{"test pr [ci-skip test/go/postgres cat] 123\n\n"}, []string{"test/go/postgres", "cat"}},
|
||||
{"confuse", args{"ci ci [ci-skip] dog [ci-skip test/go/postgres test/e2e/ubuntu-latest] 123\n\n"}, []string{"test/go/postgres", "test/e2e/ubuntu-latest"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotSkips := parseBody(tt.args.body); !reflect.DeepEqual(gotSkips, tt.wantSkips) {
|
||||
t.Errorf("parseBody() = %v, want %v", gotSkips, tt.wantSkips)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user