Skip to content

Commit

Permalink
all: add tests for the GitHub workflow process
Browse files Browse the repository at this point in the history
Re-running go generate is a step that invariably happens _after_ having
verified that tests pass. This is unfortunate in the case of the GitHub
workflow schema that is vendored at:

github.com/SchemaStore/schemastore/src/schemas/json/github-workflow.cue

because it has been the cause of a number of bugs in the past (in a good
way).

This change adds the updateTxtarTests command to the internal/ci CUE
tool to update three txtar-based tests:

* encoding/jsonschema - checking the we can imported the source
  JSONSchema
* internal/core/adt (the eval part) - checking that we can evaluate the
  workflows defined in internal/ci against the imported schema
* cmd/cue/cmd - verifying that we can run the step of generating the
  yaml workflow definitions from a cue cmd flow definition

It's still the case that if you:

* change the workflow definitions in internal/ci, or
* pin to a later version of the GitHub workflow schema

you must run:

    go generate ./internal/ci

to update the generated workflow definitions, but now this will also
update the source files in various txtar test archives.

If a GitHub-related txtar test fails in such a way that you need to
update the golden files in that archive, this indicates you will also
need to re-run the go generate ./internal/ci to re-generate the yaml
workflow definitions.

Change-Id: I310c4f58cfd91965766279d7ad06fee54b7842cb
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8112
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
  • Loading branch information
myitcv committed Feb 3, 2021
1 parent 2338b59 commit 09cd07b
Show file tree
Hide file tree
Showing 8 changed files with 6,043 additions and 54 deletions.
1,453 changes: 1,453 additions & 0 deletions cmd/cue/cmd/testdata/script/cmd_github.txt

Large diffs are not rendered by default.

2,365 changes: 2,365 additions & 0 deletions cue/testdata/eval/github.txtar

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion encoding/jsonschema/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import (
_ "cuelang.org/go/pkg"
)

var update = flag.Bool("update", false, "update the test files")
var update = flag.Bool("update", os.Getenv("CUE_UPDATE") != "", "update the test files")

// TestDecode reads the testdata/*.txtar files, converts the contained
// JSON schema to CUE and compares it against the output.
Expand Down
2,001 changes: 2,001 additions & 0 deletions encoding/jsonschema/testdata/github.txtar

Large diffs are not rendered by default.

123 changes: 100 additions & 23 deletions internal/ci/ci_tool.cue
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,112 @@
package ci

import (
"encoding/yaml"
"path"

"encoding/yaml"

"tool/exec"
"tool/file"
"tool/os"
)

// genworkflows regenerates the GitHub workflow Yaml definitions.
//
// See internal/ci/gen.go for details on how this step fits into the sequence
// of generating our CI workflow definitions, and updating various txtar tests
// with files from that process.
//
// Until we have a resolution for cuelang.org/issue/704 and
// cuelang.org/issue/708 this must be run from the internal/ci package. At
// which point we can switch to using _#modroot.
//
// This also explains why the ../../ relative path specification below appear
// wrong in the context of the containing directory internal/ci/vendor.
command: genworkflows: {
goos: _#goos

for w in workflows {
"\(w.file)": file.Create & {
_dir: path.FromSlash("../../.github/workflows", path.Unix)
filename: path.Join([_dir, w.file], goos.GOOS)
contents: """
# Generated by internal/ci/ci_tool.cue; do not edit
\(yaml.Marshal(w.schema))
"""
}
}
}

// updateTxtarTests ensures certain txtar tests are updated with the
// relevant files that make up the process of generating our CI
// workflows.
//
// See internal/ci/gen.go for details on how this step fits into the sequence
// of generating our CI workflow definitions, and updating various txtar tests
// with files from that process.
//
// Until we have a resolution for cuelang.org/issue/704 and
// cuelang.org/issue/708 this must be run from the internal/ci package. At
// which point we can switch to using _#modroot.
//
// This also explains why the ../../ relative path specification below appear
// wrong in the context of the containing directory internal/ci/vendor.
command: updateTxtarTests: {
goos: _#goos

readJSONSchema: file.Read & {
_path: path.FromSlash("../../cue.mod/pkg/github.com/SchemaStore/schemastore/src/schemas/json/github-workflow.cue", path.Unix)
filename: path.Join([_path], goos.GOOS)
contents: string
}
cueDefInternalCI: exec.Run & {
cmd: "go run cuelang.org/go/cmd/cue def cuelang.org/go/internal/ci"
stdout: string
}
// updateEvalTxtarTest updates the cue/testdata/eval testscript which exercises
// the evaluation of the workflows defined in internal/ci (which by definition
// means resolving and using the vendored GitHub Workflow schema)
updateEvalTxtarTest: {
_relpath: path.FromSlash("../../cue/testdata/eval/github.txtar", path.Unix)
_path: path.Join([_relpath], goos.GOOS)

githubSchema: exec.Run & {
stdin: readJSONSchema.contents
cmd: "go run cuelang.org/go/internal/ci/updatetxtar - \(_path) cue.mod/pkg/github.com/SchemaStore/schemastore/src/schemas/json/github-workflow.cue"
}
defWorkflows: exec.Run & {
$after: githubSchema
stdin: cueDefInternalCI.stdout
cmd: "go run cuelang.org/go/internal/ci/updatetxtar - \(_path) workflows.cue"
}
}
// When we have a solution for cuelang.org/issue/709 we can make this a
// file.Glob
readToolsFile: file.Read & {
filename: "ci_tool.cue"
contents: string
}
updateCmdCueCmdTxtarTest: {
_relpath: path.FromSlash("../../cmd/cue/cmd/testdata/script/cmd_github.txt", path.Unix)
_path: path.Join([_relpath], goos.GOOS)

githubSchema: exec.Run & {
stdin: readJSONSchema.contents
cmd: "go run cuelang.org/go/internal/ci/updatetxtar - \(_path) cue.mod/pkg/github.com/SchemaStore/schemastore/src/schemas/json/github-workflow.cue"
}
defWorkflows: exec.Run & {
$after: githubSchema
stdin: cueDefInternalCI.stdout
cmd: "go run cuelang.org/go/internal/ci/updatetxtar - \(_path) internal/ci/workflows.cue"
}
toolsFile: exec.Run & {
stdin: readToolsFile.contents
cmd: "go run cuelang.org/go/internal/ci/updatetxtar - \(_path) internal/ci/\(readToolsFile.filename)"
}
}
}

// _#modroot is a common helper to get the module root
//
// TODO: use once we have a solution to cuelang.org/issue/704.
Expand All @@ -38,26 +136,5 @@ _#modroot: exec.Run & {
// or via a tag in the case you want to manually run the CUE
// command.
_#goos: os.Getenv & {
GOOS: *"unix" | string @tag(os)
}

// genworkflows regenerates the GitHub workflow Yaml definitions
//
// Until we have a resolution for cuelang.org/issue/704 this must be
// run from the internal/ci package. At which point we can switch to using
// _#modroot and move the associated go:generate directive into
// internal/ci alongside this command definition.
command: genworkflows: task: {
goos: _#goos
for w in workflows {
"\(w.file)": file.Create & {
_dir: path.FromSlash("../../.github/workflows", "unix")
filename: path.Join([_dir, w.file], goos.GOOS)
contents: """
# Generated by internal/ci/ci_tool.cue; do not edit
\(yaml.Marshal(w.schema))
"""
}
}
GOOS: *path.Unix | string @tag(os)
}
1 change: 1 addition & 0 deletions internal/ci/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ package ci

//go:generate go run cuelang.org/go/cmd/cue cmd vendorgithubschema ./vendor
//go:generate go run cuelang.org/go/cmd/cue cmd genworkflows
//go:generate go run cuelang.org/go/cmd/cue cmd updateTxtarTests
74 changes: 74 additions & 0 deletions internal/ci/updatetxtar/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2021 The CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"flag"
"io"
"io/ioutil"
"log"
"os"

"github.com/rogpeppe/go-internal/txtar"
)

// Usage:
// updateTxtar source target filename
//
// updateTxtar writes the contents of source (could be - for stdin) to a file
// (identified by filename) within the txtar archive at target.

func main() {
log.SetFlags(0)
flag.Parse()
if flag.NArg() != 3 {
log.Fatal("Usage:\n\tupdateTxtar source target filename")
}
source := flag.Arg(0)
target := flag.Arg(1)
fn := flag.Arg(2)
a, err := txtar.ParseFile(target)
if err != nil {
log.Fatal(err)
}
var file *txtar.File
for i, f := range a.Files {
if f.Name == fn {
file = &a.Files[i]
break
}
}
if file == nil {
a.Files = append(a.Files, txtar.File{Name: fn})
file = &a.Files[len(a.Files)-1]
}
var sourceReader io.Reader
if source == "-" {
sourceReader = os.Stdin
} else {
sourceReader, err = os.Open(source)
if err != nil {
log.Fatal(err)
}
}
contents, err := ioutil.ReadAll(sourceReader)
if err != nil {
log.Fatal(err)
}
file.Data = contents
if err := ioutil.WriteFile(target, txtar.Format(a), 0666); err != nil {
log.Fatal(err)
}
}
78 changes: 48 additions & 30 deletions internal/ci/vendor/vendor_tool.cue
Original file line number Diff line number Diff line change
Expand Up @@ -23,51 +23,69 @@ import (
"tool/os"
)

// _#modroot is a common helper to get the module root
//
// TODO: use once we have a solution to cuelang.org/issue/704.
// This will then allow us to remove the use of .. below.
_#modroot: exec.Run & {
cmd: "go list -m -f {{.Dir}}"
stdout: string
}

// Until we have the ability to inject contextual information
// we need to pass in GOOS explicitly. Either by environment
// variable (which we get for free when this is used via go generate)
// or via a tag in the case you want to manually run the CUE
// command.
_#goos: os.Getenv & {
GOOS: *"unix" | string @tag(os)
}

// vendorgithubschema vendors a "cue import"-ed version of the JSONSchema that
// defines GitHub workflows into the main module's cue.mod/pkg.
//
// Until we have a resolution for cuelang.org/issue/704 this must be
// run from the internal/ci package. At which point we can switch to using
// _#modroot and move the associated go:generate directive into
// internal/ci alongside this command definition.
// See internal/ci/gen.go for details on how this step fits into the sequence
// of generating our CI workflow definitions, and updating various txtar tests
// with files from that process.
//
// Until we have a resolution for cuelang.org/issue/704 and
// cuelang.org/issue/708 this must be run from the internal/ci package. At
// which point we can switch to using _#modroot.
//
// This also explains why the ../../ relative path specification below
// appear wrong in the context of the containing directory internal/ci/vendor.
// This also explains why the ../../ relative path specification below appear
// wrong in the context of the containing directory internal/ci/vendor.
command: vendorgithubschema: {
goos: _#goos
get: http.Get & {
goos: _#goos
getJSONSchema: http.Get & {
request: body: ""

// Tip link for humans:
// https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/github-workflow.json
url: "https://raw.githubusercontent.com/SchemaStore/schemastore/6fe4707b9d1c5d45cfc8d5b6d56968e65d2bdc38/src/schemas/json/github-workflow.json"
}
convert: exec.Run & {
stdin: get.response.body
// Write the JSON schema to an encoding/jsonschema txtar test
// that verifies (at go test time) that we can import this
// JSON schema definition, independently of having to re-run
// go generate (which is expensive and yet another command
// to have to remember to run)
updateEncodingJSONSchemaTxtarTest: exec.Run & {
_relpath: path.FromSlash("../../encoding/jsonschema/testdata/github.txtar", "unix")
_path: path.Join([_relpath], goos.GOOS)
stdin: getJSONSchema.response.body
cmd: "go run cuelang.org/go/internal/ci/updatetxtar - \(_path) workflow.json"
}
importJSONSchema: exec.Run & {
stdin: getJSONSchema.response.body
cmd: "go run cuelang.org/go/cmd/cue import -f -p json -l #Workflow: jsonschema: - -o -"
stdout: string
}
write: file.Create & {
// vendorGitHubWorkflowSchema writes the imported schema to the cue.mod/pkg
// hierarchy for the GitHub workflow package. This vendored
// package is then referenced in the internal/ci package
// when defining workflows.
vendorGitHubWorkflowSchema: file.Create & {
_path: path.FromSlash("../../cue.mod/pkg/github.com/SchemaStore/schemastore/src/schemas/json/github-workflow.cue", "unix")
filename: path.Join([_path], goos.GOOS)
contents: convert.stdout
contents: importJSONSchema.stdout
}
}

// _#modroot is a common helper to get the module root
//
// TODO: use once we have a solution to cuelang.org/issue/704.
// This will then allow us to remove the use of .. below.
_#modroot: exec.Run & {
cmd: "go list -m -f {{.Dir}}"
stdout: string
}

// Until we have the ability to inject contextual information
// we need to pass in GOOS explicitly. Either by environment
// variable (which we get for free when this is used via go generate)
// or via a tag in the case you want to manually run the CUE
// command.
_#goos: os.Getenv & {
GOOS: *"unix" | string @tag(os)
}

0 comments on commit 09cd07b

Please sign in to comment.