-
Notifications
You must be signed in to change notification settings - Fork 169
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add base dir structure for reading workflow settings, some cleanup * Add a basic workflow_settings reader * Progress with loading YAML via require * Working YAML reader for workflow settings * Tidying * Cleanup bits * Fix relative path for requiring workflow settings * Fix import orders and lint errors * Stop exporting getWorkflowSettings * Move TSLint comment locations * Add explicit include for new compilation_sql BUILD file to cli/api * Fix compilation sql visibility
- Loading branch information
Showing
16 changed files
with
322 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
load("//tools:ts_library.bzl", "ts_library") | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
ts_library( | ||
name = "compilation_sql", | ||
srcs = [ | ||
"index.ts", | ||
], | ||
deps = [ | ||
"//protos:ts", | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { expect } from "chai"; | ||
import * as fs from "fs-extra"; | ||
import * as path from "path"; | ||
import { CompilerFunction, NodeVM } from "vm2"; | ||
|
||
import { decode64, encode64 } from "df/common/protos"; | ||
import { compile } from "df/core/compilers"; | ||
import { dataform } from "df/protos/ts"; | ||
import { suite, test } from "df/testing"; | ||
import { TmpDirFixture } from "df/testing/fixtures"; | ||
import { asPlainObject } from "df/tests/utils"; | ||
|
||
const VALID_WORKFLOW_SETTINGS_YAML = ` | ||
warehouse: bigquery | ||
defaultDatabase: dataform | ||
`; | ||
|
||
const VALID_DATAFORM_JSON = ` | ||
{ | ||
"warehouse": "bigquery", | ||
"defaultDatabase": "dataform" | ||
} | ||
`; | ||
|
||
suite("@dataform/core", ({ afterEach }) => { | ||
const tmpDirFixture = new TmpDirFixture(afterEach); | ||
|
||
suite("workflow settings", () => { | ||
test(`main succeeds when a valid workflow_settings.yaml is present`, () => { | ||
const projectDir = tmpDirFixture.createNewTmpDir(); | ||
// tslint:disable-next-line: tsr-detect-non-literal-fs-filename | ||
fs.writeFileSync( | ||
path.join(projectDir, "workflow_settings.yaml"), | ||
VALID_WORKFLOW_SETTINGS_YAML | ||
); | ||
const coreExecutionRequest = dataform.CoreExecutionRequest.create({ | ||
compile: { compileConfig: { projectDir } } | ||
}); | ||
|
||
const result = runMainInVm(coreExecutionRequest); | ||
|
||
expect(asPlainObject(result.compile.compiledGraph.projectConfig)).deep.equals( | ||
asPlainObject({ | ||
warehouse: "bigquery", | ||
defaultDatabase: "dataform" | ||
}) | ||
); | ||
}); | ||
|
||
// dataform.json for workflow settings is deprecated, but still currently supported. | ||
test(`main succeeds when a valid dataform.json is present`, () => { | ||
const projectDir = tmpDirFixture.createNewTmpDir(); | ||
// tslint:disable-next-line: tsr-detect-non-literal-fs-filename | ||
fs.writeFileSync(path.join(projectDir, "dataform.json"), VALID_DATAFORM_JSON); | ||
const coreExecutionRequest = dataform.CoreExecutionRequest.create({ | ||
compile: { compileConfig: { projectDir } } | ||
}); | ||
|
||
const result = runMainInVm(coreExecutionRequest); | ||
|
||
expect(asPlainObject(result.compile.compiledGraph.projectConfig)).deep.equals( | ||
asPlainObject({ | ||
warehouse: "bigquery", | ||
defaultDatabase: "dataform" | ||
}) | ||
); | ||
}); | ||
|
||
test(`main fails when no workflow settings file is present`, () => { | ||
const projectDir = tmpDirFixture.createNewTmpDir(); | ||
const coreExecutionRequest = dataform.CoreExecutionRequest.create({ | ||
compile: { compileConfig: { projectDir } } | ||
}); | ||
|
||
expect(() => runMainInVm(coreExecutionRequest)).to.throw( | ||
"Failed to resolve workflow_settings.yaml" | ||
); | ||
}); | ||
|
||
test(`main fails when both workflow settings and dataform.json files are present`, () => { | ||
const projectDir = tmpDirFixture.createNewTmpDir(); | ||
// tslint:disable-next-line: tsr-detect-non-literal-fs-filename | ||
fs.writeFileSync(path.join(projectDir, "dataform.json"), VALID_DATAFORM_JSON); | ||
// tslint:disable-next-line: tsr-detect-non-literal-fs-filename | ||
fs.writeFileSync( | ||
path.join(projectDir, "workflow_settings.yaml"), | ||
VALID_WORKFLOW_SETTINGS_YAML | ||
); | ||
const coreExecutionRequest = dataform.CoreExecutionRequest.create({ | ||
compile: { compileConfig: { projectDir } } | ||
}); | ||
|
||
expect(() => runMainInVm(coreExecutionRequest)).to.throw( | ||
"dataform.json has been deprecated and cannot be defined alongside workflow_settings.yaml" | ||
); | ||
}); | ||
|
||
test(`main fails when workflow_settings.yaml is an invalid yaml file`, () => { | ||
const projectDir = tmpDirFixture.createNewTmpDir(); | ||
// tslint:disable-next-line: tsr-detect-non-literal-fs-filename | ||
fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), "&*19132sdS:asd:"); | ||
const coreExecutionRequest = dataform.CoreExecutionRequest.create({ | ||
compile: { compileConfig: { projectDir } } | ||
}); | ||
|
||
expect(() => runMainInVm(coreExecutionRequest)).to.throw( | ||
"workflow_settings.yaml contains invalid fields" | ||
); | ||
}); | ||
|
||
test(`main fails when dataform.json is an invalid json file`, () => { | ||
const projectDir = tmpDirFixture.createNewTmpDir(); | ||
// tslint:disable-next-line: tsr-detect-non-literal-fs-filename | ||
fs.writeFileSync(path.join(projectDir, "dataform.json"), '{keyWithNoQuotes: "validValue"}'); | ||
const coreExecutionRequest = dataform.CoreExecutionRequest.create({ | ||
compile: { compileConfig: { projectDir } } | ||
}); | ||
|
||
expect(() => runMainInVm(coreExecutionRequest)).to.throw( | ||
"Unexpected token k in JSON at position 1" | ||
); | ||
}); | ||
}); | ||
}); | ||
|
||
// A VM is needed when running main because Node functions like `require` are overridden. | ||
function runMainInVm(coreExecutionRequest: dataform.CoreExecutionRequest) { | ||
const projectDir = coreExecutionRequest.compile.compileConfig.projectDir; | ||
|
||
// Copy over the build Dataform Core that is set up as a node_modules directory. | ||
fs.copySync(`${process.cwd()}/core/node_modules`, `${projectDir}/node_modules`); | ||
|
||
const compiler = compile as CompilerFunction; | ||
// Then use vm2's native compiler integration to apply the compiler to files. | ||
const nodeVm = new NodeVM({ | ||
// Inheriting the console makes console.logs show when tests are running, which is useful for | ||
// debugging. | ||
console: "inherit", | ||
wrapper: "none", | ||
require: { | ||
builtin: ["path"], | ||
context: "sandbox", | ||
external: true, | ||
root: projectDir, | ||
resolve: (moduleName, parentDirName) => | ||
path.join(parentDirName, path.relative(parentDirName, projectDir), moduleName) | ||
}, | ||
sourceExtensions: ["js", "sql", "sqlx", "yaml"], | ||
compiler | ||
}); | ||
|
||
const encodedCoreExecutionRequest = encode64(dataform.CoreExecutionRequest, coreExecutionRequest); | ||
const vmIndexFileName = path.resolve(path.join(projectDir, "index.js")); | ||
const encodedCoreExecutionResponse = nodeVm.run( | ||
`return require("@dataform/core").main("${encodedCoreExecutionRequest}")`, | ||
vmIndexFileName | ||
); | ||
return decode64(dataform.CoreExecutionResponse, encodedCoreExecutionResponse); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { dataform } from "df/protos/ts"; | ||
|
||
export function readWorkflowSettings(): dataform.ProjectConfig { | ||
const workflowSettingsYaml = maybeRequire("workflow_settings.yaml"); | ||
// `dataform.json` is deprecated; new versions of Dataform Core prefer `workflow_settings.yaml`. | ||
const dataformJson = maybeRequire("dataform.json"); | ||
|
||
if (workflowSettingsYaml && dataformJson) { | ||
throw Error( | ||
"dataform.json has been deprecated and cannot be defined alongside workflow_settings.yaml" | ||
); | ||
} | ||
|
||
if (workflowSettingsYaml) { | ||
const workflowSettingsAsJson = workflowSettingsYaml.asJson(); | ||
verifyWorkflowSettingsAsJson(workflowSettingsAsJson); | ||
return dataform.ProjectConfig.create(workflowSettingsAsJson); | ||
} | ||
|
||
if (dataformJson) { | ||
verifyWorkflowSettingsAsJson(dataformJson); | ||
return dataform.ProjectConfig.create(dataformJson); | ||
} | ||
|
||
throw Error("Failed to resolve workflow_settings.yaml"); | ||
} | ||
|
||
function verifyWorkflowSettingsAsJson(workflowSettingsAsJson?: object) { | ||
// TODO(ekrekr): Implement a protobuf field validator. Protobufjs's verify method is not fit for | ||
// purpose. | ||
if (!workflowSettingsAsJson) { | ||
throw Error("workflow_settings.yaml contains invalid fields"); | ||
} | ||
} | ||
|
||
function maybeRequire(file: string): any { | ||
try { | ||
// tslint:disable-next-line: tsr-detect-non-literal-require | ||
return require(file); | ||
} catch (e) { | ||
if (e instanceof SyntaxError) { | ||
throw e; | ||
} | ||
return undefined; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ ts_library( | |
) | ||
|
||
externals = [ | ||
"js-yaml", | ||
"protobufjs", | ||
"tarjan-graph", | ||
"semver", | ||
|
Oops, something went wrong.