-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
127 lines (105 loc) · 3.04 KB
/
index.js
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
const {Toolkit} = require('actions-toolkit')
const crypto = require('crypto')
const fs = require('fs')
const {promisify} = require('util')
const randomBytes = promisify(crypto.randomBytes)
const writeFile = promisify(fs.writeFile)
const readFile = promisify(fs.readFile)
const randomId = async () => (await randomBytes(16)).toString('hex')
Toolkit.run(async tools => {
const versions = tools.arguments._.map(String)
const builds = versions.map(vsn => runBuild(tools, vsn))
const buildResults = await Promise.all(builds)
await Promise.all(buildResults.map(reportBuildResult.bind(null, tools)))
let allBuildsOk = true
for (const buildResult of buildResults) {
if (buildResult.ok) {
tools.log.success(`Build ${buildResult.version} succeeded.`)
} else {
tools.log.error(`Build ${buildResult.version} failed.`)
allBuildsOk = false
}
}
if (allBuildsOk) {
tools.exit.success('Matrix build succeeded.')
} else {
tools.exit.failure('Matrix build failed.')
}
})
/*
* Report a build result, either logging it when there is no token, or creating
* a check run.
*/
async function reportBuildResult(
tools,
{logFile, version, ok, startedAt, completedAt}
) {
const log = (await readFile(logFile)).toString()
if (process.env.GITHUB_TOKEN == null) {
console.log(log)
return
}
const result = await tools.github.checks.create({
...tools.context.repo,
name: `actions/node-matrix-node-${version}`,
head_sha: tools.context.sha,
status: 'completed',
conclusion: ok ? 'success' : 'failure',
started_at: startedAt.toISOString(),
completed_at: completedAt.toISOString(),
output: {
title: `\`npm test\` with Node ${version}`,
summary: ok ? ':tada:' : ':x:',
text: `\`\`\`
${log}
\`\`\``
}
})
if (result.status != 201) {
tools.log.debug(result)
tools.exit.failure(`Check run creation failed with status ${result.status}`)
}
}
/**
* Spawn a child process that runs a custom Node.js-version-specific Dockerfile.
*/
async function runBuild(tools, version) {
const dockerfile = `Dockerfile.${await randomId()}`
const logFile = `/tmp/${dockerfile}.log`
const log = await createOpenWriteStream(logFile)
await writeFile(dockerfile, generateDockerfile(version))
let ok = false
const startedAt = new Date()
try {
const {code} = await tools.runInWorkspace(
'docker',
['build', '-f', dockerfile, '.'],
{stdio: [0, log, log]}
)
ok = code === 0
} catch (err) {
tools.log.error(err)
ok = false
} finally {
tools.log.info(`Removing temp ${dockerfile}`)
await tools.runInWorkspace('rm', dockerfile)
}
const completedAt = new Date()
return {version, logFile, ok, startedAt, completedAt}
}
function generateDockerfile(version) {
return `FROM node:${version}
WORKDIR /src
COPY . .
RUN node --version
RUN npm --version
RUN npm ci
RUN npm test
`
}
function createOpenWriteStream(path) {
const stream = fs.createWriteStream(path)
return new Promise(resolve => {
stream.on('open', () => resolve(stream))
})
}