-
Notifications
You must be signed in to change notification settings - Fork 0
/
deploy.ts
114 lines (97 loc) · 3.24 KB
/
deploy.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
import makeDebug from 'debug'
const debug = makeDebug('utils/deploy')
export const regexFactory = (tag = 'env') => {
return new RegExp(`\\\${{ ?(${tag})\\.([-0-9A-Z_a-z]+) ?}}`)
}
export const envVarNotFoundInEnv = (s: string) =>
`environment variable ${s} not found in given env`
export interface Options {
env?: NodeJS.ProcessEnv
}
export const stringResolvedFromEnv = (s: string, options?: Options) => {
const env = options?.env || process.env
const groups = s.match(regexFactory('env'))
if (groups) {
const [_input, _tag, v] = groups
if (!env[v]) {
throw new Error(envVarNotFoundInEnv(v))
} else {
debug(`${s} => ${env[v]}`)
return env[v]
}
} else {
return s
}
}
export const entriesResolvedFromEnv = (
entries: any[],
options?: Options
): string[] => {
return entries.map(([k, v]) => {
if (typeof v === 'object') {
const value = entriesResolvedFromEnv(Object.entries(v), options)
return `${k}=${value}`
} else if (typeof v === 'boolean') {
return `${k}=${v}`
} else if (typeof v === 'number') {
return `${k}=${v}`
} else {
return `${k}=${stringResolvedFromEnv(v, options)}`
}
})
}
export const requiredConfigValueNotSet = (s: string) =>
`${s} not set. If you want to use secrets in your configuration, you must set ${s}`
export const gcloudArgs = (config: any, options?: Options) => {
debug('input configuration %O', config)
const args = Object.entries(config).flatMap(([key, value]) => {
if (value === true) {
return [`--${key}`]
}
if (value === false) {
return [`--no-${key}`]
}
if (typeof value === 'number') {
return [`--${key}`, value]
}
switch (key) {
case 'gcp-project-num': {
// The Google Cloud Project number is required in the config to create
// the secret URL, but it's not an argument accepeted by gcloud. That's
// why we discard it here.
return []
}
case 'set-env-vars':
case 'update-labels': {
const unresolved_entries = Object.entries(value as any)
const entries = entriesResolvedFromEnv(unresolved_entries, options)
return [`--${key}`, entries.join(',')]
}
case 'set-secrets': {
const prj = stringResolvedFromEnv(config['gcp-project-num'], options)
if (!prj) {
throw new Error(requiredConfigValueNotSet('gcp-project-num'))
}
const secrets = []
for (const [k, v] of Object.entries(value as any)) {
const [unresolved_name, unresolved_version] = (v as string).split(':')
const name = stringResolvedFromEnv(unresolved_name, options)
const version = stringResolvedFromEnv(unresolved_version, options)
secrets.push(`${k}=projects/${prj}/secrets/${name}:${version}`)
}
return [`--${key}`, secrets.join(',')]
}
default: {
if (typeof value === 'object') {
throw new Error(
`key ${key} not implemented. TODO: if it's a valid gcloud config value, implement it, otherwise discard it/throw an error`
)
} else {
const v = stringResolvedFromEnv(value as any, options) as string
return [`--${key}`, v]
}
}
}
})
return args
}