Skip to content

Commit

Permalink
[v2] First Public Release of V2
Browse files Browse the repository at this point in the history
Ginkgo V2 is an extensive effort to clean up the Ginkgo codebase and
introduce several new highly-requested features.

This first public release represents a significant clean up of the
codebase, deprecation of several pieces of functionality that wil not
be making it into V2, and the beginnings of some new functionality.

Details of changes so far are in the `docs/MIGRATING_TO_V2.md` file.

More extensive discussion of V2 is in #711 and the google doc linked
there.
  • Loading branch information
onsi committed Apr 7, 2021
1 parent e4cff82 commit 753fe71
Show file tree
Hide file tree
Showing 325 changed files with 15,578 additions and 16,127 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.DS_Store
TODO
TODO.md
tmp/**/*
*.coverprofile
.vscode
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.0.0

See [https://github.com/onsi/ginkgo/blob/v2/docs/MIGRATING_TO_V2.md](https://github.com/onsi/ginkgo/blob/v2/docs/MIGRATING_TO_V2.md)

## 1.16.1

### Fixes
Expand All @@ -13,7 +17,6 @@

- Add slim-sprig template functions to bootstrap/generate (#775) [9162b86]

### Fixes
- Fix accidental reference to 1488 (#784) [9fb7fe4]

## 1.15.2
Expand Down
213 changes: 213 additions & 0 deletions config/cli_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package config

import (
"os"
"runtime"
"time"
)

type GinkgoCLIConfigType struct {
//for build, run, and watch
Recurse bool
SkipPackage string
RequireSuite bool
NumCompilers int

//for run and watch only
Nodes int
Parallel bool
AfterRunHook string
Timeout time.Duration
OutputDir string
KeepSeparateCoverprofiles bool

//for run only
KeepGoing bool
UntilItFails bool
RandomizeSuites bool

//for watch only
Depth int
WatchRegExp string
}

func (g GinkgoCLIConfigType) ComputedNodes() int {
if g.Nodes > 0 {
return g.Nodes
}

n := 1
if g.Parallel {
n = runtime.NumCPU()
if n > 4 {
n = n - 1
}
}
return n
}

func NewDefaultGinkgoCLIConfig() GinkgoCLIConfigType {
return GinkgoCLIConfigType{
Timeout: time.Hour * 24,
Depth: 1,
WatchRegExp: `\.go$`,
}
}

type deprecatedGinkgoCLIConfig struct {
Stream bool
Notify bool
}

var GinkgoCLISharedFlags = GinkgoFlags{
{KeyPath: "C.Recurse", Name: "r", SectionKey: "multiple-suites",
Usage: "If set, ginkgo finds and runs test suites under the current directory recursively."},
{KeyPath: "C.SkipPackage", Name: "skip-package", SectionKey: "multiple-suites", DeprecatedName: "skipPackage", DeprecatedDocLink: "changed-command-line-flags",
UsageArgument: "comma-separated list of packages",
Usage: "A comma-separated list of package names to be skipped. If any part of the package's path matches, that package is ignored."},
{KeyPath: "C.RequireSuite", Name: "require-suite", SectionKey: "failure", DeprecatedName: "requireSuite", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, Ginkgo fails if there are ginkgo tests in a directory but no invocation of RunSpecs."},
{KeyPath: "C.NumCompilers", Name: "compilers", SectionKey: "multiple-suites", UsageDefaultValue: "0 (will autodetect)",
Usage: "When running multiple packages, the number of concurrent compilations to perform."},
}

var GinkgoCLIRunAndWatchFlags = GinkgoFlags{
{KeyPath: "C.Nodes", Name: "nodes", SectionKey: "parallel", UsageDefaultValue: "1 (run in series)",
Usage: "The number of parallel test nodes to run."},
{KeyPath: "C.Parallel", Name: "p", SectionKey: "parallel",
Usage: "If set, ginkgo will run in parallel with an auto-detected number of nodes."},
{KeyPath: "C.AfterRunHook", Name: "after-run-hook", SectionKey: "misc", DeprecatedName: "afterSuiteHook", DeprecatedDocLink: "changed-command-line-flags",
Usage: "Command to run when a test suite completes."},
{KeyPath: "C.Timeout", Name: "timeout", SectionKey: "debug", UsageDefaultValue: "24h",
Usage: "Test suite fails if it does not complete within the specified timeout."},
{KeyPath: "C.OutputDir", Name: "output-dir", SectionKey: "output", UsageArgument: "directory", DeprecatedName: "outputdir", DeprecatedDocLink: "changed-profiling-support",
Usage: "A location to place all generated profiles and reports."},
{KeyPath: "C.KeepSeparateCoverprofiles", Name: "keep-separate-coverprofiles", SectionKey: "code-and-coverage-analysis",
Usage: "If set, Ginkgo does not merge coverprofiles into one monolithic coverprofile. The coverprofiles will remain in their respective package direcotries or in -output-dir if set."},

{KeyPath: "Dcli.Stream", DeprecatedName: "stream", DeprecatedDocLink: "removed--stream"},
{KeyPath: "Dcli.Notify", DeprecatedName: "notify", DeprecatedDocLink: "removed--notify"},
}

var GinkgoCLIRunFlags = GinkgoFlags{
{KeyPath: "C.KeepGoing", Name: "keep-going", SectionKey: "multiple-suites", DeprecatedName: "keepGoing", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, failures from earlier test suites do not prevent later test suites from running."},
{KeyPath: "C.UntilItFails", Name: "until-it-fails", SectionKey: "debug", DeprecatedName: "untilItFails", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will keep rerunning test suites until a failure occurs."},
{KeyPath: "C.RandomizeSuites", Name: "randomize-suites", SectionKey: "order", DeprecatedName: "randomizeSuites", DeprecatedDocLink: "changed-command-line-flags",
Usage: "If set, ginkgo will randomize the order in which test suites run."},
}

var GinkgoCLIWatchFlags = GinkgoFlags{
{KeyPath: "C.Depth", Name: "depth", SectionKey: "watch",
Usage: "Ginkgo will watch dependencies down to this depth in the dependency tree."},
{KeyPath: "C.WatchRegExp", Name: "watch-regexp", SectionKey: "watch", DeprecatedName: "watchRegExp", DeprecatedDocLink: "changed-command-line-flags",
UsageArgument: "Regular Expression",
UsageDefaultValue: `\.go$`,
Usage: "Only files matching this regular expression will be watched for changes."},
}

func VetAndInitializeCLIAndGoConfig(cliConfig GinkgoCLIConfigType, goFlagsConfig GoFlagsConfigType) (GinkgoCLIConfigType, GoFlagsConfigType, []error) {
errors := []error{}

//initialize the output directory
if cliConfig.OutputDir != "" {
err := os.MkdirAll(cliConfig.OutputDir, 0777)
if err != nil {
errors = append(errors, err)
}
}

//ensure cover mode is configured appropriately
if goFlagsConfig.CoverMode != "" || goFlagsConfig.CoverPkg != "" || goFlagsConfig.CoverProfile != "" {
goFlagsConfig.Cover = true
}
if goFlagsConfig.Cover && goFlagsConfig.CoverProfile == "" {
goFlagsConfig.CoverProfile = "coverprofile.out"
}

return cliConfig, goFlagsConfig, errors
}

func GenerateTestRunArgs(ginkgoConfig GinkgoConfigType, reporterConfig DefaultReporterConfigType, goFlagsConfig GoFlagsConfigType) ([]string, error) {
var flags GinkgoFlags
flags = GinkgoConfigFlags.WithPrefix("ginkgo")
flags = flags.CopyAppend(GinkgoParallelConfigFlags.WithPrefix("ginkgo")...)
flags = flags.CopyAppend(ReporterConfigFlags.WithPrefix("ginkgo")...)
flags = flags.CopyAppend(GoRunFlags.WithPrefix("test")...)
bindings := map[string]interface{}{
"G": &ginkgoConfig,
"R": &reporterConfig,
"Go": &goFlagsConfig,
}

return GenerateFlagArgs(flags, bindings)
}

func BuildRunCommandFlagSet(ginkgoConfig *GinkgoConfigType, reporterConfig *DefaultReporterConfigType, cliConfig *GinkgoCLIConfigType, goFlagsConfig *GoFlagsConfigType) (GinkgoFlagSet, error) {
flags := GinkgoConfigFlags
flags = flags.CopyAppend(ReporterConfigFlags...)
flags = flags.CopyAppend(GinkgoCLISharedFlags...)
flags = flags.CopyAppend(GinkgoCLIRunAndWatchFlags...)
flags = flags.CopyAppend(GinkgoCLIRunFlags...)
flags = flags.CopyAppend(GoBuildFlags...)
flags = flags.CopyAppend(GoRunFlags...)

bindings := map[string]interface{}{
"G": ginkgoConfig,
"R": reporterConfig,
"C": cliConfig,
"Go": goFlagsConfig,
"D": &deprecatedConfigsType{},
"Dcli": &deprecatedGinkgoCLIConfig{},
}

return NewGinkgoFlagSet(flags, bindings, FlagSections)
}

func BuildWatchCommandFlagSet(ginkgoConfig *GinkgoConfigType, reporterConfig *DefaultReporterConfigType, cliConfig *GinkgoCLIConfigType, goFlagsConfig *GoFlagsConfigType) (GinkgoFlagSet, error) {
flags := GinkgoConfigFlags
flags = flags.CopyAppend(ReporterConfigFlags...)
flags = flags.CopyAppend(GinkgoCLISharedFlags...)
flags = flags.CopyAppend(GinkgoCLIRunAndWatchFlags...)
flags = flags.CopyAppend(GinkgoCLIWatchFlags...)
flags = flags.CopyAppend(GoBuildFlags...)
flags = flags.CopyAppend(GoRunFlags...)

bindings := map[string]interface{}{
"G": ginkgoConfig,
"R": reporterConfig,
"C": cliConfig,
"Go": goFlagsConfig,
"D": &deprecatedConfigsType{},
"Dcli": &deprecatedGinkgoCLIConfig{},
}

return NewGinkgoFlagSet(flags, bindings, FlagSections)
}

func BuildBuildCommandFlagSet(cliConfig *GinkgoCLIConfigType, goFlagsConfig *GoFlagsConfigType) (GinkgoFlagSet, error) {
flags := GinkgoCLISharedFlags
flags = flags.CopyAppend(GoBuildFlags...)

bindings := map[string]interface{}{
"C": cliConfig,
"Go": goFlagsConfig,
"D": &deprecatedConfigsType{},
"DCli": &deprecatedGinkgoCLIConfig{},
}

flagSections := make(GinkgoFlagSections, len(FlagSections))
copy(flagSections, FlagSections)
for i := range flagSections {
if flagSections[i].Key == "multiple-suites" {
flagSections[i].Heading = "Building Multiple Suites"
}
if flagSections[i].Key == "go-build" {
flagSections[i] = GinkgoFlagSection{Key: "go-build", Style: "{{/}}", Heading: "Go Build Flags",
Description: "These flags are inherited from go build."}
}
}

return NewGinkgoFlagSet(flags, bindings, flagSections)
}
148 changes: 148 additions & 0 deletions config/cli_go_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package config

// A subset of Go flags are exposed by Ginkgo. Some are avaiable at compile time (e.g. ginkgo build) and others only at run time (e.g. ginkgo run - which has both build and run time flags).
// More details can be found at:
// https://docs.google.com/spreadsheets/d/1zkp-DS4hU4sAJl5eHh1UmgwxCPQhf3s5a8fbiOI8tJU/

type GoFlagsConfigType struct {
//build-time flags for code-and-performance analysis
Race bool
Cover bool
CoverMode string
CoverPkg string
Vet string

//run-time flags for code-and-performance analysis
BlockProfile string
BlockProfileRate int
CoverProfile string
CPUProfile string
MemProfile string
MemProfileRate int
MutexProfile string
MutexProfileFraction int
Trace string

//build-time flags for building
A bool
ASMFlags string
BuildMode string
Compiler string
GCCGoFlags string
GCFlags string
InstallSuffix string
LDFlags string
LinkShared bool
Mod bool
N bool
ModFile string
ModCacheRW bool
MSan bool
PkgDir string
Tags string
TrimPath bool
ToolExec string
Work bool
X bool
}

func NewDefaultGoFlagsConfig() GoFlagsConfigType {
return GoFlagsConfigType{}
}

var GoBuildFlags = GinkgoFlags{
{KeyPath: "Go.Race", Name: "race", SectionKey: "code-and-coverage-analysis",
Usage: "enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, linux/ppc64le and linux/arm64 (only for 48-bit VMA)."},
{KeyPath: "Go.Vet", Name: "vet", UsageArgument: "list", SectionKey: "code-and-coverage-analysis",
Usage: `Configure the invocation of "go vet" during "go test" to use the comma-separated list of vet checks. If list is empty, "go test" runs "go vet" with a curated list of checks believed to be always worth addressing. If list is "off", "go test" does not run "go vet" at all. Available checks can be found by running 'go doc cmd/vet'`},
{KeyPath: "Go.Cover", Name: "cover", SectionKey: "code-and-coverage-analysis",
Usage: "Enable coverage analysis. Note that because coverage works by annotating the source code before compilation, compilation and test failures with coverage enabled may report line numbers that don't correspond to the original sources."},
{KeyPath: "Go.CoverMode", Name: "covermode", UsageArgument: "set,count,atomic", SectionKey: "code-and-coverage-analysis",
Usage: `Set the mode for coverage analysis for the package[s] being tested. 'set': does this statement run? 'count': how many times does this statement run? 'atomic': like count, but correct in multithreaded tests and more expensive (must use atomic with -race). Sets -cover`},
{KeyPath: "Go.CoverPkg", Name: "coverpkg", UsageArgument: "pattern1,pattern2,pattern3", SectionKey: "code-and-coverage-analysis",
Usage: "Apply coverage analysis in each test to packages matching the patterns. The default is for each test to analyze only the package being tested. See 'go help packages' for a description of package patterns. Sets -cover."},

{KeyPath: "Go.A", Name: "a", SectionKey: "go-build",
Usage: "force rebuilding of packages that are already up-to-date."},
{KeyPath: "Go.ASMFlags", Name: "asmflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build",
Usage: "arguments to pass on each go tool asm invocation."},
{KeyPath: "Go.BuildMode", Name: "buildmode", UsageArgument: "mode", SectionKey: "go-build",
Usage: "build mode to use. See 'go help buildmode' for more."},
{KeyPath: "Go.Compiler", Name: "compiler", UsageArgument: "name", SectionKey: "go-build",
Usage: "name of compiler to use, as in runtime.Compiler (gccgo or gc)."},
{KeyPath: "Go.GCCGoFlags", Name: "gccgoflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build",
Usage: "arguments to pass on each gccgo compiler/linker invocation."},
{KeyPath: "Go.GCFlags", Name: "gcflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build",
Usage: "arguments to pass on each go tool compile invocation."},
{KeyPath: "Go.InstallSuffix", Name: "installsuffix", SectionKey: "go-build",
Usage: "a suffix to use in the name of the package installation directory, in order to keep output separate from default builds. If using the -race flag, the install suffix is automatically set to raceor, if set explicitly, has _race appended to it. Likewise for the -msan flag. Using a -buildmode option that requires non-default compile flags has a similar effect."},
{KeyPath: "Go.LDFlags", Name: "ldflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build",
Usage: "arguments to pass on each go tool link invocation."},
{KeyPath: "Go.LinkShared", Name: "linkshared", SectionKey: "go-build",
Usage: "build code that will be linked against shared libraries previously created with -buildmode=shared."},
{KeyPath: "Go.Mod", Name: "mod", UsageArgument: "mode (readonly, vender, or mod)", SectionKey: "go-build",
Usage: "module download mode to use: readonly, vendor, or mod. See 'go help modules' for more."},
{KeyPath: "Go.ModCacheRW", Name: "modcacherw", SectionKey: "go-build",
Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."},
{KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build",
Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`},
{KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build",
Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."},
{KeyPath: "Go.N", Name: "n", SectionKey: "go-build",
Usage: "print the commands but do not run them."},
{KeyPath: "Go.PkgDir", Name: "pkgdir", UsageArgument: "dir", SectionKey: "go-build",
Usage: "install and load all packages from dir instead of the usual locations. For example, when building with a non-standard configuration, use -pkgdir to keep generated packages in a separate location."},
{KeyPath: "Go.Tags", Name: "tags", UsageArgument: "tag,list", SectionKey: "go-build",
Usage: "a comma-separated list of build tags to consider satisfied during the build. For more information about build tags, see the description of build constraints in the documentation for the go/build package. (Earlier versions of Go used a space-separated list, and that form is deprecated but still recognized.)"},
{KeyPath: "Go.TrimPath", Name: "trimpath", SectionKey: "go-build",
Usage: `remove all file system paths from the resulting executable. Instead of absolute file system paths, the recorded file names will begin with either "go" (for the standard library), or a module path@version (when using modules), or a plain import path (when using GOPATH).`},
{KeyPath: "Go.ToolExec", Name: "toolexec", UsageArgument: "'cmd args'", SectionKey: "go-build",
Usage: "a program to use to invoke toolchain programs like vet and asm. For example, instead of running asm, the go command will run cmd args /path/to/asm <arguments for asm>'."},
{KeyPath: "Go.Work", Name: "work", SectionKey: "go-build",
Usage: "print the name of the temporary work directory and do not delete it when exiting."},
{KeyPath: "Go.X", Name: "x", SectionKey: "go-build",
Usage: "print the commands."},
}

var GoRunFlags = GinkgoFlags{
{KeyPath: "Go.CoverProfile", Name: "coverprofile", UsageArgument: "file", SectionKey: "code-and-coverage-analysis",
Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover.`},
{KeyPath: "Go.BlockProfile", Name: "blockprofile", UsageArgument: "rile", SectionKey: "performance-analysis",
Usage: `Write a goroutine blocking profile to the specified file when all tests are complete. Preserves test binary.`},
{KeyPath: "Go.BlockProfileRate", Name: "blockprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis",
Usage: `Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with rate. See 'go doc runtime.SetBlockProfileRate'. The profiler aims to sample, on average, one blocking event every n nanoseconds the program spends blocked. By default, if -test.blockprofile is set without this flag, all blocking events are recorded, equivalent to -test.blockprofilerate=1.`},
{KeyPath: "Go.CPUProfile", Name: "cpuprofile", UsageArgument: "file", SectionKey: "performance-analysis",
Usage: `Write a CPU profile to the specified file before exiting. Preserves test binary.`},
{KeyPath: "Go.MemProfile", Name: "memprofile", UsageArgument: "file", SectionKey: "performance-analysis",
Usage: `Write an allocation profile to the file after all tests have passed. Preserves test binary.`},
{KeyPath: "Go.MemProfileRate", Name: "memprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis",
Usage: `Enable more precise (and expensive) memory allocation profiles by setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1.`},
{KeyPath: "Go.MutexProfile", Name: "mutexprofile", UsageArgument: "file", SectionKey: "performance-analysis",
Usage: `Write a mutex contention profile to the specified file when all tests are complete. Preserves test binary.`},
{KeyPath: "Go.MutexProfileFraction", Name: "mutexprofilefraction", UsageArgument: "n", SectionKey: "performance-analysis",
Usage: `if >= 0, calls runtime.SetMutexProfileFraction() Sample 1 in n stack traces of goroutines holding a contended mutex.`},
{KeyPath: "Go.Trace", Name: "execution-trace", UsageArgument: "file", ExportAs: "trace", SectionKey: "performance-analysis",
Usage: `Write an execution trace to the specified file before exiting.`},
}

func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfigType, destination string, packageToBuild string) ([]string, error) {
// if the user has set the CoverProfile run-time flag make sure to set the build-time cover flag to make sure
// the built test binary can generate a coverprofile
if goFlagsConfig.CoverProfile != "" {
goFlagsConfig.Cover = true
}

args := []string{"test", "-c", "-o", destination, packageToBuild}
goArgs, err := GenerateFlagArgs(
GoBuildFlags,
map[string]interface{}{
"Go": &goFlagsConfig,
},
)

if err != nil {
return []string{}, err
}
args = append(args, goArgs...)
return args, nil
}
Loading

0 comments on commit 753fe71

Please sign in to comment.