-
-
Notifications
You must be signed in to change notification settings - Fork 368
/
Copy pathinline.ts
139 lines (120 loc) · 4.96 KB
/
inline.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import * as fs from "fs"
import { debug } from "../../debug"
import _require from "require-from-string"
import { DangerResults, DangerRuntimeContainer } from "../../dsl/DangerResults"
import { DangerContext } from "../../runner/Dangerfile"
import { DangerRunner } from "./runner"
import compile from "./utils/transpiler"
import cleanDangerfile from "./utils/cleanDangerfile"
import resultsForCaughtError from "./utils/resultsForCaughtError"
const d = debug("inline_runner")
/**
* Executes a Dangerfile at a specific path, with a context.
* The values inside a Danger context are applied as globals to the Dangerfiles runtime.
*
* @param {DangerContext} dangerfileContext the global danger context
*/
export async function createDangerfileRuntimeEnvironment(dangerfileContext: DangerContext): Promise<DangerContext> {
return dangerfileContext
}
const runAllScheduledTasks = async (results: DangerRuntimeContainer) => {
if (results.scheduled) {
d(`Scheduler waiting on: ${results.scheduled.length} tasks`)
await Promise.all(
results.scheduled.map((fnOrPromise: any) => {
if (fnOrPromise instanceof Promise) {
return fnOrPromise
}
if (fnOrPromise.length === 1) {
// callback-based function
return new Promise(res => fnOrPromise(res))
}
return fnOrPromise()
})
)
d(`Finished scheduled tasks`)
}
}
/**
* Executes a Dangerfile at a specific path, with a context.
* The values inside a Danger context are applied as globals to the Dangerfiles runtime.
*
* @param {string} filename the file path for the dangerfile
* @param {string} originalContents optional, the JS pre-compiled
* @param {DangerContext} environment the results of createDangerfileRuntimeEnvironment
* @param {any | undefined} injectedObjectToExport an optional object for passing into default exports
* @param {func | undefined} moduleHandler an optional func for handling module resolution
* @returns {DangerResults} the results of the run
*/
export const runDangerfileEnvironment = async (
filenames: string[],
originalContents: (string | undefined)[] | undefined,
environment: DangerContext,
injectedObjectToExport?: any,
moduleHandler?: (module: any, filename: string) => string | Promise<any>
): Promise<DangerResults> => {
// We need to change the local runtime to support running JavaScript
// and TypeScript through babel first. This is a simple implementation
// and if we need more nuance, then we can look at other options
const customModuleHandler = (module: any, filename: string) => {
if (!filename.includes("node_modules")) {
d("Handling custom module: ", filename)
}
const contents = fs.readFileSync(filename, "utf8")
const compiled = compile(contents, filename)
module._compile(compiled, filename)
}
const customRequire = moduleHandler || customModuleHandler
// Tell all these filetypes to ge the custom compilation
require.extensions[".ts"] = customRequire
require.extensions[".tsx"] = customRequire
require.extensions[".js"] = customRequire
require.extensions[".jsx"] = customRequire
// Loop through all files and their potential contents, they edit
// results inside the env, so no need to keep track ourselves
for (const filename of filenames) {
const index = filenames.indexOf(filename)
const originalContent = (originalContents && originalContents[index]) || fs.readFileSync(filename, "utf8")
let content = cleanDangerfile(originalContent)
let compiled = compile(content, filename)
try {
// Move all the DSL attributes into the global scope
for (let key in environment) {
if (environment.hasOwnProperty(key)) {
let element = environment[key]
global[key] = element
}
}
d("Started parsing Dangerfile: ", filename)
const optionalExport = _require(compiled, filename, {})
if (typeof optionalExport.default === "function") {
d("Running default export from Dangerfile", filename)
await optionalExport.default(injectedObjectToExport)
}
d("Finished running dangerfile: ", filename)
// Don't stop all current async code from breaking,
// however new code (without Peril support) can run
// without the scheduler
await runAllScheduledTasks(environment.results)
} catch (error) {
console.log("Unable to evaluate the Dangerfile\n", error)
d("Got a parse error: ", error)
// Call the internal functions to fail the build
const errorResults = resultsForCaughtError(filename, content, error)
environment.markdown(errorResults.markdowns[0].message)
environment.fail(errorResults.fails[0].message)
}
}
const results = environment.results
return {
fails: results.fails,
warnings: results.warnings,
messages: results.messages,
markdowns: results.markdowns,
}
}
const defaultExport: DangerRunner = {
createDangerfileRuntimeEnvironment,
runDangerfileEnvironment,
}
export default defaultExport