Skip to content

Commit

Permalink
internal/e2e: stop creating GitHub repositories
Browse files Browse the repository at this point in the history
Following the TODO I left for myself a few weeks ago,
we no longer need to create one GitHub repository per testscript
as we now support publishing modules under subdirectories via GitHub.

The first main advantage is that we no longer require a $GITHUB_TOKEN
secret to create such repos, simplifying the setup to run the tests.

The second advantage is the tests are now faster,
as they skip the setup and cleanup steps to create and delete repos,
which are full round-trip GitHub API operations.

The third, and perhaps most important advantage,
is that we no longer add any extra module dependency beyond what
the root cuelang.org/go module already requires.
This perhaps drops the need for ./internal/e2e to be a separate module;
a follow-up change will attempt un-doing that.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: Ie869485aa93a0f1f980649f4ea57bd279a8a737c
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1178251
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.io>
TryBot-Result: CUEcueckoo <cueckoo@gmail.com>
  • Loading branch information
mvdan committed Mar 13, 2024
1 parent d48dcbe commit ba698de
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 88 deletions.
1 change: 0 additions & 1 deletion .github/workflows/trybot.yml
Expand Up @@ -184,7 +184,6 @@ jobs:
Dispatch-Trailer: {"type":"')))) && (matrix.go-version == '1.22.x' && matrix.runner == 'ubuntu-22.04')
name: End-to-end test
env:
GITHUB_TOKEN: ${{ secrets.E2E_GITHUB_TOKEN }}
CUE_LOGINS: ${{ secrets.E2E_CUE_LOGINS }}
run: |-
cd internal/e2e
Expand Down
3 changes: 1 addition & 2 deletions internal/ci/github/trybot.cue
Expand Up @@ -142,8 +142,7 @@ workflows: trybot: _repo.bashWorkflow & {
// on the entire cue-labs-modules-testing org. Note that porcuepine is also an org admin,
// since otherwise the repo admin access to create and delete repos does not work.
env: {
GITHUB_TOKEN: "${{ secrets.E2E_GITHUB_TOKEN }}"
CUE_LOGINS: "${{ secrets.E2E_CUE_LOGINS }}"
CUE_LOGINS: "${{ secrets.E2E_CUE_LOGINS }}"
}
// Our regular tests run with both `go test ./...` and `go test -race ./...`.
// The end-to-end tests should only be run once, given the slowness and API rate limits.
Expand Down
2 changes: 0 additions & 2 deletions internal/e2e/go.mod
Expand Up @@ -4,7 +4,6 @@ go 1.21

require (
cuelang.org/go v0.0.0-00010101000000-000000000000
github.com/google/go-github/v56 v56.0.0
github.com/rogpeppe/go-internal v1.12.0
)

Expand All @@ -13,7 +12,6 @@ require (
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/emicklei/proto v1.10.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
Expand Down
5 changes: 0 additions & 5 deletions internal/e2e/go.sum
Expand Up @@ -11,14 +11,9 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v56 v56.0.0 h1:TysL7dMa/r7wsQi44BjqlwaHvwlFlqkK8CtBWCX3gb4=
github.com/google/go-github/v56 v56.0.0/go.mod h1:D8cdcX98YWJvi7TLo7zM4/h8ZTx6u6fwGEkCdisopo0=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
Expand Down
92 changes: 26 additions & 66 deletions internal/e2e/script_test.go
Expand Up @@ -16,18 +16,16 @@ package e2e_test

import (
"bytes"
"context"
cryptorand "crypto/rand"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"testing"
"time"

"github.com/google/go-github/v56/github"
"github.com/rogpeppe/go-internal/testscript"
)

Expand Down Expand Up @@ -73,13 +71,15 @@ func TestMain(m *testing.M) {
}

var (
// githubOrg is a GitHub organization where the "CUE Module Publisher"
// GitHub App has been installed on all repositories.
// This is necessary since we will create a new repository per test,
// and there's no way to easily install the app on each repo via the API.
githubOrg = envOr("GITHUB_ORG", "cue-labs-modules-testing")
// githubKeep leaves the newly created repo around when set to true.
githubKeep = envOr("GITHUB_KEEP", "false")
// githubPublicRepo is a GitHub public repository
// with the "cue.works authz" GitHub App installed.
// The repository can be entirely empty, as it's only needed for authz.
githubPublicRepo = envOr("GITHUB_PUBLIC_REPO", "github.com/cue-labs-modules-testing/e2e-public")

// githubPublicRepo is a GitHub private repository
// with the "cue.works authz" GitHub App installed.
// The repository can be entirely empty, as it's only needed for authz.
githubPrivateRepo = envOr("GITHUB_PRIVATE_REPO", "github.com/cue-labs-modules-testing/e2e-private")

// gcloudRegistry is an existing Google Cloud Artifact Registry repository
// to publish module versions to via "cue mod publish",
Expand Down Expand Up @@ -115,64 +115,24 @@ func TestScript(t *testing.T) {
return nil
},
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
// create-github-repo creates a unique repository under githubOrg
// and sets $MODULE to its resulting module path.
// TODO(mvdan): once we support nested modules,
// such as github.com/owner/repo/subpath@v1.2.3,
// we could rely on an existing github.com/owner/repo repository on GitHub
// and use unique subpaths for each test run,
// meaning that the e2e tests would no longer need a GitHub token.
"create-github-repo": func(ts *testscript.TestScript, neg bool, args []string) {
if neg {
ts.Fatalf("usage: create-github-repo [field=value...]")
}

// githubToken should have read and write access to repository
// administration and contents within githubOrg,
// to be able to create repositories under the org and git push to them.
// Not a global, since we only want to require GITHUB_TOKEN when needed.
githubToken := envMust(t, "GITHUB_TOKEN")

repoName := testModuleName(ts)
client := github.NewClient(nil).WithAuthToken(githubToken)
ctx := context.TODO()

repo := &github.Repository{
Name: github.String(repoName),
// github-repo-module sets $MODULE to a unique nested module under the given repository path.
"github-repo-module": func(ts *testscript.TestScript, neg bool, args []string) {
if neg || len(args) != 1 {
ts.Fatalf("usage: with-github-repo <public|private>")
}
for _, arg := range args {
field, value, ok := strings.Cut(arg, "=")
if !ok {
ts.Fatalf("invalid field=value arg: %q", arg)
}
switch field {
case "private":
b, err := strconv.ParseBool(value)
ts.Check(err)
repo.Private = addr(b)
default:
ts.Fatalf("unsupported field: %q", field)
}
moduleName := testModuleName(ts)
var repo string
switch args[0] {
case "public":
repo = githubPublicRepo
case "private":
repo = githubPrivateRepo
default:
ts.Fatalf("usage: with-github-repo <public|private>")
}
_, _, err := client.Repositories.Create(ctx, githubOrg, repo)
ts.Check(err)

// Unless GITHUB_KEEP=true is set, delete the repo when we finish.
//
// TODO: It might be useful to leave the repo around when the test fails.
// We would need testscript.TestScript to expose T.Failed for this.
ts.Defer(func() {
if githubKeep == "true" {
return
}
_, err := client.Repositories.Delete(ctx, githubOrg, repoName)
ts.Check(err)
})

module := fmt.Sprintf("github.com/%s/%s", githubOrg, repoName)
module := path.Join(repo, moduleName)
ts.Setenv("MODULE", module)
ts.Setenv("GITHUB_TOKEN", githubToken) // needed for "git push"
ts.Logf("created github repo: https://%s", module)
ts.Logf("using module path %s", module)
},
// env-fill rewrites its argument files to replace any environment variable
// references with their values, using the same algorithm as cmpenv.
Expand Down Expand Up @@ -252,6 +212,6 @@ func testModuleName(ts *testscript.TestScript) string {
if _, err := cryptorand.Read(randomTrailer[:]); err != nil {
panic(err) // should typically not happen
}
return fmt.Sprintf("e2e-%s-%s-%x", ts.Name(),
return fmt.Sprintf("%s-%s-%x", ts.Name(),
time.Now().UTC().Format("2006.01.02-15.04.05"), randomTrailer)
}
1 change: 0 additions & 1 deletion internal/e2e/testdata/script/gcloud_upload.txtar
Expand Up @@ -12,7 +12,6 @@ env MODVER=${MODULE}@v0
cd publish

exec cue mod init ${MODVER}

exec cue mod publish ${VERSION}

cd ../depend
Expand Down
10 changes: 4 additions & 6 deletions internal/e2e/testdata/script/github_app_private.txtar
@@ -1,17 +1,15 @@
# Create a private GitHub repository in an organization
# where the registry account owning $CUE_REGISTRY_TOKEN
# has read-write access to all GitHub repositories.
# Publish a CUE module under a private GitHub repository namespace
# where the $CUE_LOGINS tokens have full read-write access.
# Publish a version for this new repository with `cue mod publish`,
# and then fetch the module as a dependency via cmd/cue.

create-github-repo private=true
github-repo-module private
env VERSION=v0.0.1
env MODVER=${MODULE}@v0

cd publish

exec cue mod init ${MODVER}

exec cue mod publish ${VERSION}

cd ../depend
Expand All @@ -23,7 +21,7 @@ exec cue export
cmp stdout export.golden

# TODO(mvdan): Use another registry token without access to this private repo
# and check that they cannot list the module's versions or download any of them.
# and check that they cannot list, fetch, or publish any versions.

-- publish/foo.cue --
package publish
Expand Down
11 changes: 6 additions & 5 deletions internal/e2e/testdata/script/github_app_public.txtar
@@ -1,17 +1,15 @@
# Create a public GitHub repository in an organization
# where the registry account owning $CUE_REGISTRY_TOKEN
# has read-write access to all GitHub repositories.
# Publish a CUE module under a public GitHub repository namespace
# where the $CUE_LOGINS tokens have full read-write access.
# Publish a version for this new repository with `cue mod publish`,
# and then fetch the module as a dependency via cmd/cue.

create-github-repo
github-repo-module public
env VERSION=v0.0.1
env MODVER=${MODULE}@v0

cd publish

exec cue mod init ${MODVER}

exec cue mod publish ${VERSION}

cd ../depend
Expand All @@ -22,6 +20,9 @@ exec cue mod tidy
exec cue export
cmp stdout export.golden

# TODO(mvdan): Use another registry token without access to this private repo
# and check that they can list and fetch, but not publish, any versions.

-- publish/foo.cue --
package publish

Expand Down

0 comments on commit ba698de

Please sign in to comment.