Skip to content

Commit

Permalink
internal/e2e: add a test for a private github repo
Browse files Browse the repository at this point in the history
Since the GitHub App setup with registry.cue.works only knows
how to publish module versions in a public way,
any git tag created on a private github repo with the app installed
does not get published as a module version in the registry.

Tweaked our builtins so we can set the Repo.Private field
as well as allowing negating and configuring the timeout in cue-mod-wait.

Signed-off-by: Daniel Martí <[email protected]>
Change-Id: Ide73065b6aeebfaefb5d464a8e446c54a14410fe
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1171965
Reviewed-by: Roger Peppe <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
Unity-Result: CUE porcuepine <[email protected]>
  • Loading branch information
mvdan committed Nov 9, 2023
1 parent 95a88a5 commit 4d2ba88
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 7 deletions.
44 changes: 37 additions & 7 deletions internal/e2e/script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -101,8 +102,8 @@ func TestScript(t *testing.T) {
// create-github-repo creates a unique repository under githubOrg
// and sets $MODULE to its resulting module path.
"create-github-repo": func(ts *testscript.TestScript, neg bool, args []string) {
if neg || len(args) > 0 {
ts.Fatalf("usage: create-github-repo")
if neg {
ts.Fatalf("usage: create-github-repo [field=value...]")
}

// githubToken should have read and write access to repository
Expand All @@ -118,6 +119,20 @@ func TestScript(t *testing.T) {
repo := &github.Repository{
Name: github.String(repoName),
}
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)
}
}
_, _, err := client.Repositories.Create(ctx, githubOrg, repo)
ts.Check(err)

Expand All @@ -133,8 +148,10 @@ func TestScript(t *testing.T) {
ts.Check(err)
})

ts.Setenv("MODULE", fmt.Sprintf("github.com/%s/%s", githubOrg, repoName))
module := fmt.Sprintf("github.com/%s/%s", githubOrg, repoName)
ts.Setenv("MODULE", module)
ts.Setenv("GITHUB_TOKEN", githubToken) // needed for "git push"
ts.Logf("created github repo: https://%s", module)
},
// env-fill rewrites its argument files to replace any environment variable
// references with their values, using the same algorithm as cmpenv.
Expand All @@ -152,23 +169,34 @@ func TestScript(t *testing.T) {
// cue-mod-wait waits for a CUE module to exist in a registry for up to 20s.
// Since this is easily done via an HTTP HEAD request, an OCI client isn't necessary.
"cue-mod-wait": func(ts *testscript.TestScript, neg bool, args []string) {
if neg || len(args) > 0 {
ts.Fatalf("usage: cue-mod-wait")
if len(args) > 1 {
ts.Fatalf("usage: [!] cue-mod-wait [timeout]")
}
manifest := tsExpand(ts, "https://${CUE_REGISTRY}/v2/${MODULE}/manifests/${VERSION}")
timeout := 20 * time.Second
if len(args) > 0 {
var err error
timeout, err = time.ParseDuration(args[0])
ts.Check(err)
}
retries := retry.Strategy{
Delay: 10 * time.Millisecond,
MaxDelay: time.Second,
MaxDuration: 20 * time.Second,
MaxDuration: timeout,
}
for it := retries.Start(); it.Next(nil); {
resp, err := http.Head(manifest)
ts.Check(err)
if resp.StatusCode == http.StatusOK {
if neg {
ts.Fatalf("%s was unexpectedly published", manifest)
}
return
}
}
ts.Fatalf("timed out waiting for module")
if !neg {
ts.Fatalf("timed out waiting for %s", manifest)
}
},
// gcloud-auth-docker configures gcloud so that it uses the host's existing configuration,
// and sets CUE_REGISTRY and CUE_REGISTRY_HOST according to gcloudRegistry.
Expand Down Expand Up @@ -200,6 +228,8 @@ func TestScript(t *testing.T) {
testscript.Run(t, p)
}

func addr[T any](t T) *T { return &t }

func envOr(name, fallback string) string {
if s := os.Getenv(name); s != "" {
return s
Expand Down
57 changes: 57 additions & 0 deletions internal/e2e/testdata/script/github_app_private.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Create a private GitHub repository in an org with the GitHub App
# "CUE Module Publisher" installed for all repositories.
# Push a git tag with a simple CUE module, and check that the app
# does not publish a version that is publicly accessible.

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

cd publish

# TODO: replace by "cue mod init" once it supports versioned module names.
# cue mod init ${MODVER}
env-fill cue.mod/module.cue

exec git init --initial-branch main
exec git config user.name 'modules_e2e'
exec git config user.email 'modules_e2e@bot'
exec git remote add origin https://${GITHUB_TOKEN}@${MODULE}

exec git add foo.cue cue.mod
exec git commit -m 'first commit'
exec git tag cue-${VERSION}

exec git push origin main cue-${VERSION}

# The app publishing method gives no feedback right now,
# so we instead check that the module version isn't published on the registry within a timeout.
# From previous test runs, it takes between 5 and 8 seconds between pushing a git tag
# on a public repo and the module version being published on the registry,
# so 20 seconds is likely more than enough here to ensure it won't be published.
! cue-mod-wait 20s

cd ../depend

# Double check that cmd/cue cannot download the dependency either.
env-fill cue.mod/module.cue out_foo.cue
! exec cue export
stderr 'cannot resolve dependencies'

-- publish/cue.mod/module.cue --
module: "${MODVER}"
-- publish/foo.cue --
package publish

foo: "foo value"

-- depend/cue.mod/module.cue --
module: "depend.localhost"

deps: "${MODVER}": v: "${VERSION}"
-- depend/out_foo.cue --
package depend

import mt "${MODVER}:publish"

out: mt.foo

0 comments on commit 4d2ba88

Please sign in to comment.