From ba698deda3ff8259bf80679183d3bed23e0f2b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Wed, 13 Mar 2024 13:35:01 +0000 Subject: [PATCH] internal/e2e: stop creating GitHub repositories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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í Change-Id: Ie869485aa93a0f1f980649f4ea57bd279a8a737c Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1178251 Unity-Result: CUE porcuepine Reviewed-by: Paul Jolly TryBot-Result: CUEcueckoo --- .github/workflows/trybot.yml | 1 - internal/ci/github/trybot.cue | 3 +- internal/e2e/go.mod | 2 - internal/e2e/go.sum | 5 - internal/e2e/script_test.go | 92 ++++++------------- .../e2e/testdata/script/gcloud_upload.txtar | 1 - .../testdata/script/github_app_private.txtar | 10 +- .../testdata/script/github_app_public.txtar | 11 ++- 8 files changed, 37 insertions(+), 88 deletions(-) diff --git a/.github/workflows/trybot.yml b/.github/workflows/trybot.yml index 39018253f..f4217a4fa 100644 --- a/.github/workflows/trybot.yml +++ b/.github/workflows/trybot.yml @@ -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 diff --git a/internal/ci/github/trybot.cue b/internal/ci/github/trybot.cue index 930002d2f..b95526e35 100644 --- a/internal/ci/github/trybot.cue +++ b/internal/ci/github/trybot.cue @@ -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. diff --git a/internal/e2e/go.mod b/internal/e2e/go.mod index 3e9d33534..ae15c4bca 100644 --- a/internal/e2e/go.mod +++ b/internal/e2e/go.mod @@ -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 ) @@ -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 diff --git a/internal/e2e/go.sum b/internal/e2e/go.sum index a5664aa4e..feeeaa4c8 100644 --- a/internal/e2e/go.sum +++ b/internal/e2e/go.sum @@ -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= diff --git a/internal/e2e/script_test.go b/internal/e2e/script_test.go index 643eafc21..e3c22e1f1 100644 --- a/internal/e2e/script_test.go +++ b/internal/e2e/script_test.go @@ -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" ) @@ -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", @@ -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 ") } - 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 ") } - _, _, 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. @@ -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) } diff --git a/internal/e2e/testdata/script/gcloud_upload.txtar b/internal/e2e/testdata/script/gcloud_upload.txtar index d9d281105..cacea86fe 100644 --- a/internal/e2e/testdata/script/gcloud_upload.txtar +++ b/internal/e2e/testdata/script/gcloud_upload.txtar @@ -12,7 +12,6 @@ env MODVER=${MODULE}@v0 cd publish exec cue mod init ${MODVER} - exec cue mod publish ${VERSION} cd ../depend diff --git a/internal/e2e/testdata/script/github_app_private.txtar b/internal/e2e/testdata/script/github_app_private.txtar index 997a2b642..00ffd9c42 100644 --- a/internal/e2e/testdata/script/github_app_private.txtar +++ b/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 @@ -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 diff --git a/internal/e2e/testdata/script/github_app_public.txtar b/internal/e2e/testdata/script/github_app_public.txtar index 82954a93a..772547231 100644 --- a/internal/e2e/testdata/script/github_app_public.txtar +++ b/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 @@ -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