-
Notifications
You must be signed in to change notification settings - Fork 250
/
Copy pathsetup-terraform.js
204 lines (162 loc) · 5.92 KB
/
setup-terraform.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Node.js core
const fs = require('fs').promises;
const os = require('os');
const path = require('path');
// External
const core = require('@actions/core');
const tc = require('@actions/tool-cache');
const io = require('@actions/io');
const fetch = require('node-fetch');
const semver = require('semver');
// Find latest version given list of all available
function findLatest (allVersions) {
core.debug('Parsing version list for latest version');
let latest = '0.0.0';
for (const version in allVersions.versions) {
// is "version" greater than "latest"
latest = semver.gt(version, latest) ? version : latest;
}
return allVersions.versions[latest];
}
// Find specific version given list of all available
function findSpecific (allVersions, version) {
core.debug(`Parsing version list for version ${version}`);
const versionObj = allVersions.versions[version];
if (!versionObj) {
throw new Error(`Could not find Terraform version ${version} in version list`);
}
return versionObj;
}
async function downloadMetadata () {
core.debug('Downloading version metadata');
return fetch('https://releases.hashicorp.com/terraform/index.json')
.then(res => res.json())
.catch(err => {
core.setFailed(`Failed to fetch version metadata. ${err}`);
});
}
// arch in [arm, x32, x64...] (https://nodejs.org/api/os.html#os_os_arch)
// return value in [amd64, 386, arm]
function mapArch (arch) {
const mappings = {
x32: '386',
x64: 'amd64'
};
return mappings[arch] || arch;
}
// os in [darwin, linux, win32...] (https://nodejs.org/api/os.html#os_os_platform)
// return value in [darwin, linux, windows]
function mapOS (os) {
const mappings = {
win32: 'windows'
};
return mappings[os] || os;
}
// Get build for an operating system and architecture
function getBuild (versionObj, os, arch) {
core.debug(`Getting build for Terraform version ${versionObj.version}, os ${os}, and arch ${arch}`);
const buildObj = versionObj.builds.length &&
versionObj.builds.find(build =>
build.arch === mapArch(arch) &&
build.os === mapOS(os)
);
if (!buildObj) {
throw new Error(`Terraform version ${versionObj.version} not available for ${os} and ${arch}`);
}
return buildObj;
}
async function downloadCLI (url) {
core.debug(`Downloading Terraform CLI from ${url}`);
const pathToCLIZip = await tc.downloadTool(url);
core.debug('Extracting Terraform CLI zip file');
const pathToCLI = await tc.extractZip(pathToCLIZip);
core.debug(`Terraform CLI path is ${pathToCLI}.`);
if (!pathToCLIZip || !pathToCLI) {
throw new Error(`Unable to download Terraform from ${url}`);
}
return pathToCLI;
}
async function installWrapper (pathToCLI) {
let source, target;
// If we're on Windows, then the executable ends with .exe
const exeSuffix = os.platform().startsWith('win') ? '.exe' : '';
// Rename terraform(.exe) to terraform-bin(.exe)
try {
source = [pathToCLI, `terraform${exeSuffix}`].join(path.sep);
target = [pathToCLI, `terraform-bin${exeSuffix}`].join(path.sep);
core.debug(`Moving ${source} to ${target}.`);
await io.mv(source, target);
} catch (e) {
core.error(`Unable to move ${source} to ${target}.`);
throw e;
}
// Install our wrapper as terraform
try {
source = path.resolve([__dirname, '..', 'wrapper', 'dist', 'index.js'].join(path.sep));
target = [pathToCLI, 'terraform'].join(path.sep);
core.debug(`Copying ${source} to ${target}.`);
await io.cp(source, target);
} catch (e) {
core.error(`Unable to copy ${source} to ${target}.`);
throw e;
}
// Export a new environment variable, so our wrapper can locate the binary
core.exportVariable('TERRAFORM_CLI_PATH', pathToCLI);
}
// Add credentials to CLI Configuration File
// https://www.terraform.io/docs/commands/cli-config.html
async function addCredentials (credentialsHostname, credentialsToken, osPlat) {
// format HCL block
// eslint-disable
const creds = `
credentials "${credentialsHostname}" {
token = "${credentialsToken}"
}`.trim();
// eslint-enable
// default to OS-specific path
let credsFile = osPlat === 'win32'
? `${process.env.APPDATA}/terraform.rc`
: `${process.env.HOME}/.terraformrc`;
// override with TF_CLI_CONFIG_FILE environment variable
credsFile = process.env.TF_CLI_CONFIG_FILE ? process.env.TF_CLI_CONFIG_FILE : credsFile;
// get containing folder
const credsFolder = path.dirname(credsFile);
core.debug(`Creating ${credsFolder}`);
await io.mkdirP(credsFolder);
core.debug(`Adding credentials to ${credsFile}`);
await fs.writeFile(credsFile, creds);
}
async function run () {
try {
// Gather GitHub Actions inputs
const version = core.getInput('terraform_version');
const credentialsHostname = core.getInput('cli_config_credentials_hostname');
const credentialsToken = core.getInput('cli_config_credentials_token');
const wrapper = core.getInput('terraform_wrapper') === 'true';
// Gather OS details
const osPlat = os.platform();
const osArch = os.arch();
// Download metadata about all versions of Terraform CLI
const versionMetadata = await downloadMetadata();
// Find latest or a specific version like 0.1.0
const versionObj = version.toLowerCase() === 'latest' ? findLatest(versionMetadata) : findSpecific(versionMetadata, version);
// Get the build available for this runner's OS and a 64 bit architecture
const buildObj = getBuild(versionObj, osPlat, osArch);
// Download requested version
const pathToCLI = await downloadCLI(buildObj.url);
// Install our wrapper
if (wrapper) {
await installWrapper(pathToCLI);
}
// Add to path
core.addPath(pathToCLI);
// Add credentials to file if they are provided
if (credentialsHostname && credentialsToken) {
await addCredentials(credentialsHostname, credentialsToken, osPlat);
}
} catch (error) {
core.error(error);
throw new Error(error);
}
}
module.exports = run;