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:
Ammar Bandukwala
2022-07-24 14:33:58 -05:00
committed by GitHub
parent 5578facf8f
commit 60de8d0279
8 changed files with 191 additions and 19 deletions
+7
View File
@@ -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.
+39
View File
@@ -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, " "))
}
+28
View File
@@ -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
}
+38
View File
@@ -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)
}
})
}
}