Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions .dagger/modules/e2e/main.dang
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,8 @@ type E2e {
.length > 0
}

let containsModulePath(mods: [{{path: String!}}!]!, want: String!): Boolean! {
mods
.filter { mod => mod.path == want }
.length > 0
let containsModulePath(paths: [String!]!, want: String!): Boolean! {
containsPath(paths, want)
}

"""
Expand Down Expand Up @@ -112,7 +110,7 @@ type E2e {

let testDirs = mod.testDirectories(ws)
assert(
containsModulePath(testDirs.{path}, baseFixturePath),
containsModulePath(testDirs.{path}.map { dir => dir.path }, baseFixturePath),
"custom base test directory discovery did not include expected path",
)

Expand Down Expand Up @@ -157,7 +155,8 @@ type E2e {
)

let tool = go(version: "1.26.1", skipLint: skipLint, skipTest: skipTest, skipGenerate: skipGenerate)
let allModulePaths = tool.modules(ws).{path}
let allModules = tool.modules(ws)
let allModulePaths = allModules.keys
assert(
containsModulePath(allModulePaths, "fixtures/go-module-cross-include-a"),
"unfiltered modules did not include expected fixture module",
Expand All @@ -170,10 +169,18 @@ type E2e {
containsModulePath(allModulePaths, "testdata/go-module-excluded"),
"unfiltered modules did not include skipped fixture module by default",
)
assert(
allModules.get(key: "testdata/go-module-with-testdata").path == "testdata/go-module-with-testdata",
"module collection get did not return the requested module",
)
assert(
allModules.subset(keys: ["fixtures/go-module-cross-include-a"]).keys.length == 1,
"module collection subset did not narrow to the requested keys",
)

let includedModulePaths = tool
.modules(ws, include: ["fixtures/go-module-cross-include-a"])
.{path}
.keys
assert(
containsModulePath(includedModulePaths, "fixtures/go-module-cross-include-a"),
"modules include filter did not include matching module root",
Expand All @@ -185,7 +192,7 @@ type E2e {

let excludedModulePaths = tool
.modules(ws, exclude: ["fixtures/go-module-cross-include-a"])
.{path}
.keys
assert(
containsModulePath(excludedModulePaths, "fixtures/go-module-cross-include-a") == false,
"modules exclude filter included excluded module root",
Expand All @@ -197,7 +204,7 @@ type E2e {
include: ["fixtures/go-module-cross-include-*"],
exclude: ["fixtures/go-module-cross-include-b"],
)
.{path}
.keys
assert(
containsModulePath(combinedModulePaths, "fixtures/go-module-cross-include-a"),
"modules combined filters did not include matching module root",
Expand All @@ -209,7 +216,7 @@ type E2e {

let contentMatchedModulePaths = tool
.modules(ws, include: ["**/module-a-only.data"])
.{path}
.keys
assert(
containsModulePath(contentMatchedModulePaths, "fixtures/go-module-cross-include-a"),
"modules include filter did not match module directory contents",
Expand All @@ -221,7 +228,7 @@ type E2e {

let lintSkippedModulePaths = tool
.modules(ws, includeSkipLint: false)
.{path}
.keys
assert(
containsModulePath(lintSkippedModulePaths, "testdata/go-module-excluded") == false,
"modules includeSkipLint false included lint-skipped module",
Expand All @@ -241,7 +248,7 @@ type E2e {

let testSkippedModulePaths = tool
.modules(ws, includeSkipTest: false)
.{path}
.keys
assert(
containsModulePath(testSkippedModulePaths, "testdata/go-module-excluded") == false,
"modules includeSkipTest false included test-skipped module",
Expand All @@ -261,7 +268,7 @@ type E2e {

let generateSkippedModulePaths = tool
.modules(ws, includeSkipGenerate: false)
.{path}
.keys
assert(
containsModulePath(generateSkippedModulePaths, "testdata/go-module-excluded") == false,
"modules includeSkipGenerate false included generate-skipped module",
Expand Down
214 changes: 197 additions & 17 deletions go.dang
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ type Go {
pub skipGenerate: [String!]! = []

"""
Return every Go module discovered from workspace go.mod files.
Return Go modules discovered from workspace go.mod files, as a collection
keyed by module root path.
Optional include/exclude patterns filter discovered module root directories.
"""
pub modules(
Expand All @@ -90,8 +91,8 @@ type Go {
includeSkipLint: Boolean! = true,
includeSkipTest: Boolean! = true,
includeSkipGenerate: Boolean! = true,
): [GoModule!]! {
ws
): GoModules! {
let paths = ws
.directory("/", include: ["**/go.mod"])
.glob("**/go.mod")
.map { modPath =>
Expand All @@ -116,6 +117,17 @@ type Go {
(includeSkipTest or mod.skipTest(ws) == false) and
(includeSkipGenerate or mod.skipGenerate(ws) == false)
}
.map { mod => mod.path }

GoModules(
paths: paths,
version: version,
baseImage: base,
includeExtraFiles: includeExtraFiles,
skipLintPaths: skipLint,
skipTestPaths: skipTest,
skipGeneratePaths: skipGenerate,
)
}

let modulePathIncluded(
Expand Down Expand Up @@ -171,7 +183,9 @@ type Go {
Modules configured to skip lint are skipped.
"""
pub lintAll(ws: Workspace!): Void @check {
let layers = modules(ws, includeSkipLint: false).reduce(directory) { layers, mod =>
let mods = modules(ws, includeSkipLint: false)
let layers = mods.paths.reduce(directory) { layers, path =>
let mod = mods.module(path)
layers.withDirectory(
mod.path,
directory.withFile("go.mod", mod.lintExec(ws).file("go.mod")),
Expand All @@ -190,8 +204,9 @@ type Go {
Modules configured to skip tests are skipped.
"""
pub testAll(ws: Workspace!): Void @check {
let mods = modules(ws, includeSkipTest: false)
let layers = mods.reduce(directory) { layers, mod =>
let collection = modules(ws, includeSkipTest: false)
let layers = collection.paths.reduce(directory) { layers, path =>
let mod = collection.module(path)
layers.withDirectory(
mod.path,
directory.withFile("go.mod", mod.testExec(ws).file("go.mod")),
Expand All @@ -211,7 +226,8 @@ type Go {
are skipped.
"""
pub generateAll(ws: Workspace!): Changeset! @generate {
let mods = modules(ws).filter { mod =>
let collection = modules(ws)
let mods = collection.paths.map { path => collection.module(path) }.filter { mod =>
mod.skipGenerate(ws) == false and mod.hasGenerateDirectives(ws)
}

Expand All @@ -231,6 +247,38 @@ type Go {

}

"""
Go modules discovered in a workspace, keyed by module root path.
"""
type GoModules {
"""
Workspace-relative module root paths in discovery order.
"""
pub paths: [String!]! @keys

let version: String
let baseImage: Container!
let includeExtraFiles: [String!]!
let skipLintPaths: [String!]!
let skipTestPaths: [String!]!
let skipGeneratePaths: [String!]!

"""
Return the discovered Go module with the given workspace-relative root path.
"""
pub module(path: String!): GoModule! @get {
GoModule(
path: path,
version: version,
baseImage: baseImage,
includeExtraFiles: includeExtraFiles,
skipLintPaths: skipLintPaths,
skipTestPaths: skipTestPaths,
skipGeneratePaths: skipGeneratePaths,
)
}
}

"""
A Go module rooted at a workspace-relative path.
"""
Expand Down Expand Up @@ -387,6 +435,19 @@ type GoModule {
Directories in this module containing Go test files.
"""
pub testDirectories(ws: Workspace!): [GoDirectory!]! {
testDirectoryPaths(ws).map { testPath =>
GoDirectory(
path: testPath,
ws: ws,
modulePath: path,
baseImage: baseImage,
includeExtraFiles: includeExtraFiles,
skipTestPaths: skipTestPaths,
)
}
}

let testDirectoryPaths(ws: Workspace!): [String!]! {
goIncludesHelper(ws)
.withExec(
["go-includes", "--output", "/output", "--test-dirs", workspacePath],
Expand All @@ -396,16 +457,20 @@ type GoModule {
.contents
.split("\n")
.filter { testPath => testPath != "" }
.map { testPath =>
GoDirectory(
path: testPath,
ws: ws,
modulePath: path,
baseImage: baseImage,
includeExtraFiles: includeExtraFiles,
skipTestPaths: skipTestPaths,
)
}
}

"""
The test directories of this module, as a collection keyed by path.
"""
pub testDirs(ws: Workspace!): GoTestDirs! {
GoTestDirs(
paths: testDirectoryPaths(ws),
ws: ws,
modulePath: path,
baseImage: baseImage,
includeExtraFiles: includeExtraFiles,
skipTestPaths: skipTestPaths,
)
}

"""
Expand Down Expand Up @@ -601,6 +666,36 @@ type GoModule {
"""
A workspace directory containing Go test files.
"""
"""
Test directories of a Go module, keyed by workspace-relative path.
"""
type GoTestDirs {
"""
Workspace-relative test directory paths in discovery order.
"""
pub paths: [String!]! @keys

let ws: Workspace!
let modulePath: String!
let baseImage: Container!
let includeExtraFiles: [String!]!
let skipTestPaths: [String!]!

"""
Return the test directory with the given workspace-relative path.
"""
pub directory(path: String!): GoDirectory! @get {
GoDirectory(
path: path,
ws: ws,
modulePath: modulePath,
baseImage: baseImage,
includeExtraFiles: includeExtraFiles,
skipTestPaths: skipTestPaths,
)
}
}

type GoDirectory {
"""
Workspace-relative path of this directory.
Expand Down Expand Up @@ -757,4 +852,89 @@ type GoDirectory {
null
}

"""
Go test container for this directory, before a test command is added.
"""
pub testContainer(): Container! {
base
.withDirectory(".", source)
.withDirectory(".", testData)
.withWorkdir(path)
}

"""
The tests in this directory, as a collection keyed by test name.
Skipped directories produce an empty collection.
"""
pub tests(): GoTests! {
let names = if (skipTest) {
[]
} else {
testContainer()
.withExec(["sh", "-c", "go test -list '.*' . | grep '^Test' || true"])
.stdout
.split("\n")
.filter { name => name != "" }
}
GoTests(names: names, dir: self)
}

}

"""
Tests in a Go directory, keyed by test name.
"""
type GoTests {
"""
Test names in listing order.
"""
pub names: [String!]! @keys

let dir: GoDirectory!

"""
Return the test with the given name.
"""
pub test(name: String!): GoTest! @get {
GoTest(name: name, dir: dir)
}

"""
Run every test in the current subset in a single go test invocation.
"""
pub run(): Void @check {
if (names.length == 0) {
null
} else {
dir
.testContainer()
.withExec(["go", "test", "-run", "^(" + names.join("|") + ")$", "."])
.sync
null
}
}
}

"""
A single Go test.
"""
type GoTest {
"""
The test's name.
"""
pub name: String!

let dir: GoDirectory!

"""
Run this test. Batched through the collection when several tests are
selected together.
"""
pub run(): Void @check {
dir
.testContainer()
.withExec(["go", "test", "-run", "^" + name + "$", "."])
.sync
null
}
}