-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.ts
146 lines (137 loc) · 5.61 KB
/
main.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
140
141
142
143
144
145
146
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as github from '@actions/github';
import * as io from '@actions/io';
import * as fs from 'fs';
import * as yaml from 'js-yaml';
import { GitHub } from '@actions/github/lib/utils';
import { join as pathJoin, resolve as pathResolve } from 'path';
import { Config } from './types';
function createOctokit() {
const token = core.getInput('token');
if (token) {
return github.getOctokit(token);
} else {
core.warning(
'No token set, you may experience rate limiting. Set "token: ${{ github.token }}" if you have problems.',
);
return new GitHub();
}
}
const cwd = process.cwd();
export async function run(): Promise<void> {
try {
const { owner, repo } = github.context.repo;
const { ref } = github.context;
const configPath = pathJoin('.github', core.getInput('config'));
const outputFiles = pathResolve(cwd, core.getInput('outputFiles'));
const templatePaths = core.getInput('templatePaths').split(',');
core.debug(
`Configuration: ${JSON.stringify({
configPath,
outputFiles,
templatePaths,
})}`,
);
// Retrieve workflow configuration
const octokit = createOctokit();
core.debug(`Retrieving content from repo ${repo} (${ref}) in expected path ${configPath}`);
const contentResponse = await octokit.rest.repos.getContent({
owner,
ref,
repo,
path: configPath,
});
let config: Config;
if ('content' in contentResponse.data) {
const content = Buffer.from(contentResponse.data.content, 'base64').toString('utf8');
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
config = yaml.load(content) as Config;
} else {
throw new Error(`Unable to load config from ${configPath}`);
}
// Show config, current folder and templates
core.debug(`Config content loaded from ${configPath} via octokit:\n ${JSON.stringify(config)}`);
if (core.isDebug()) {
core.debug('Current working directory:');
await exec.exec('pwd');
core.debug('Current working directory contents:');
await exec.exec('ls -allh');
for (const templatePath of templatePaths) {
const templateResolvedPath = pathResolve(cwd, templatePath);
core.debug(`Template directory ${templateResolvedPath} contents:`);
await exec.exec(`ls -allh ${templateResolvedPath}`);
}
core.debug('Output folder contents:');
await exec.exec(`ls -allh ${outputFiles}`);
}
// Create temporary directory
const tmpDir = pathResolve(cwd, '.github', 'tmp');
await io.mkdirP(tmpDir);
core.debug(`Created temporary directory in ${tmpDir}`);
// Generate YTT templates for global workflows
const templateCommandParams = () =>
templatePaths.reduce<string[]>(
(commandParams, templatePath) => commandParams.concat('-f', pathResolve(cwd, templatePath)),
[],
);
const globalExtraParams: string[] = templateCommandParams();
config.global.workflows.forEach((workflow) => {
globalExtraParams.push('--file-mark');
globalExtraParams.push(`${workflow}:exclusive-for-output=true`);
});
if (config.global.values) {
const globalValuesPath = pathJoin(tmpDir, 'global.yml');
core.debug(`Generating global values in ${globalValuesPath}...`);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment
const serializedValues = yaml.dump(config.global.values);
fs.writeFileSync(globalValuesPath, serializedValues);
globalExtraParams.push('--data-values-file');
globalExtraParams.push(globalValuesPath);
}
await exec.exec('ytt', ['--output-files', outputFiles].concat(globalExtraParams), {
listeners: {
stdout: (data: Buffer) => core.debug(data.toString()),
stderr: (error: Buffer) => core.error(error.toString()),
},
});
// Generate YTT templates for scoped workflows
for (const scope of config.scoped) {
const scopeValuesPath = pathJoin(tmpDir, `${scope.name}.yml`);
core.debug(`Generating ${scope.name} scope values in ${scopeValuesPath}...`);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment
const serializedValues: string = yaml.dump(scope.values);
core.debug(`Serialized values:\n${serializedValues}`);
fs.writeFileSync(scopeValuesPath, serializedValues);
for (const workflow of scope.workflows) {
const workflowBits = workflow.split('.');
const scopeWorkflowName = workflowBits
.slice(0, -1)
.concat(scope.name, workflowBits.slice(-1))
.join('.');
const scopeWorkflowPath = pathJoin(outputFiles, scopeWorkflowName);
core.debug(`Process workflow ${workflow} into ${scopeWorkflowPath} ...`);
await exec.exec(
'ytt',
[
'--data-values-file',
scopeValuesPath,
'--file-mark',
`${workflow}:exclusive-for-output=true`,
].concat(templateCommandParams()),
{
listeners: {
stdout: (data: Buffer) => fs.writeFileSync(scopeWorkflowPath, data),
stderr: (error: Buffer) => core.error(error.toString()),
},
},
);
}
}
// Delete temporary directory
await io.rmRF(tmpDir);
core.debug(`Deleted temporary directory in ${tmpDir}`);
} catch (error) {
core.setFailed((error as Error).message);
}
}