Skip to content

Commit 08ed099

Browse files
committed
change var syntax
1 parent 8adc65f commit 08ed099

File tree

5 files changed

+89
-116
lines changed

5 files changed

+89
-116
lines changed

README.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ Here is an example:
2626
```yaml
2727
common:
2828
labels:
29-
gitsha: $GITHUB_SHA
29+
gitsha: ${{GITHUB_SHA}}
3030

3131
deploys:
3232
- name: my-app-deploy
3333
region: us-central1
3434
instance_group: my-app-instance-group
3535
instance_template_base: my-app-instance-template-base
36-
instance_template: my-app-$GITHUB_RUN_NUMBER-$GITHUB_SHA
36+
instance_template: my-app-${{GITHUB_RUN_NUMBER}}-${{GITHUB_SHA}}
3737
cloud_init: cloud-init.yml # see example dir
3838
labels: # will also have gitsha from common section
39-
version: $APP_VERSION
39+
version: ${{APP_VERSION}}
4040
tags:
4141
- my-tag123
4242
update_policy:
@@ -89,23 +89,14 @@ delete_instance_templates_after: false
8989

9090
### Variables
9191

92-
#### Variables in `deploy.yml`
93-
94-
Environment variables can be used in `deploy.yml`. The syntax is `$FOO` or `${FOO}` and supports
95-
substring extraction, i.e. `${GITHUB_SHA:0:7}`:
92+
Environment variables can be used in `deploy.yml`, `startup_script`, `shutdown_script` and `cloud_init` files.
93+
The syntax is `${{FOO}}` and supports substring extraction, i.e. `${{GITHUB_SHA:0:7}}`:
9694

9795
```
98-
${VAR:position} - Extracts substring from $VAR at "position"
99-
${VAR:position:length} - Extracts "length" characters of substring from $VAR at "position"
96+
${{VAR:position}} - Extracts substring from $VAR at "position"
97+
${{VAR:position:length}} - Extracts "length" characters of substring from $VAR at "position"
10098
```
10199

102-
#### Variables in `startup_script`, `shutdown_script` or `cloud_init`
103-
104-
Environment variables or `deploys.*.vars` can be used in the `startup_script`, `shutdown_script` or `cloud_init`, see [example](example/cloud-init.yml).
105-
The syntax is `${{FOO}}`.
106-
107-
#### Github ENV variables
108-
109100
Github sets a bunch of [default environment variables](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-environment-variables#default-environment-variables).
110101

111102

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ runs:
2121
shell: bash
2222
run: |
2323
cd /tmp
24-
export GCE_DEPLOY_VERSION=4.1.1
24+
export GCE_DEPLOY_VERSION=5.0.0
2525
wget --quiet https://github.com/mattes/gce-deploy-action/releases/download/v${GCE_DEPLOY_VERSION}/gce-deploy-action.linux.amd64
2626
sudo mv gce-deploy-action.linux.amd64 /usr/local/bin/gce-deploy-action
2727
sudo chmod +x /usr/local/bin/gce-deploy-action

config.go

Lines changed: 29 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,14 @@ func ParseConfig(b io.Reader) (*Config, error) {
218218
for i := range c.Deploys {
219219
dy := &c.Deploys[i]
220220

221-
dy.Name = expandShellRe(dy.Name, getEnv(nil))
221+
dy.Name = expandVars(dy.Name, getEnv(nil))
222222
if dy.Name == "" {
223223
return nil, fmt.Errorf("deploy item #%v needs name", i+1)
224224
}
225225

226-
dy.Project = expandShellRe(dy.Project, getEnv(nil))
226+
dy.Project = expandVars(dy.Project, getEnv(nil))
227227

228-
dy.GoogleApplicationCredentials = expandShellRe(dy.GoogleApplicationCredentials, getEnv(nil))
228+
dy.GoogleApplicationCredentials = expandVars(dy.GoogleApplicationCredentials, getEnv(nil))
229229

230230
f, err := ioutil.ReadFile(dy.GoogleApplicationCredentials)
231231
if err == nil {
@@ -234,55 +234,55 @@ func ParseConfig(b io.Reader) (*Config, error) {
234234
dy.googleApplicationCredentialsData = dy.GoogleApplicationCredentials
235235
}
236236

237-
dy.Region = expandShellRe(dy.Region, getEnv(nil))
237+
dy.Region = expandVars(dy.Region, getEnv(nil))
238238
if dy.Region == "" {
239239
return nil, fmt.Errorf("deploy '%v' needs region", dy.Name)
240240
}
241241

242-
dy.InstanceGroup = expandShellRe(dy.InstanceGroup, getEnv(nil))
242+
dy.InstanceGroup = expandVars(dy.InstanceGroup, getEnv(nil))
243243
if dy.InstanceGroup == "" {
244244
return nil, fmt.Errorf("deploy '%v' needs instance_group", dy.Name)
245245
}
246246

247-
dy.InstanceTemplateBase = expandShellRe(dy.InstanceTemplateBase, getEnv(nil))
247+
dy.InstanceTemplateBase = expandVars(dy.InstanceTemplateBase, getEnv(nil))
248248
if dy.InstanceTemplateBase == "" {
249249
return nil, fmt.Errorf("deploy '%v' needs instance_template_base", dy.Name)
250250
}
251251

252-
dy.InstanceTemplate = expandShellRe(dy.InstanceTemplate, getEnv(nil))
252+
dy.InstanceTemplate = expandVars(dy.InstanceTemplate, getEnv(nil))
253253
if dy.InstanceTemplate == "" {
254254
return nil, fmt.Errorf("deploy '%v' needs instance_template", dy.Name)
255255
}
256256

257-
dy.StartupScriptPath = expandShellRe(dy.StartupScriptPath, getEnv(nil))
257+
dy.StartupScriptPath = expandVars(dy.StartupScriptPath, getEnv(nil))
258258

259-
dy.ShutdownScriptPath = expandShellRe(dy.ShutdownScriptPath, getEnv(nil))
259+
dy.ShutdownScriptPath = expandVars(dy.ShutdownScriptPath, getEnv(nil))
260260

261-
dy.CloudInitPath = expandShellRe(dy.CloudInitPath, getEnv(nil))
261+
dy.CloudInitPath = expandVars(dy.CloudInitPath, getEnv(nil))
262262

263263
for k, v := range dy.Vars {
264-
dy.Vars[k] = expandShellRe(v, getEnv(nil))
264+
dy.Vars[k] = expandVars(v, getEnv(nil))
265265
}
266266

267267
for k, v := range dy.Labels {
268-
dy.Labels[k] = expandShellRe(v, getEnv(nil))
268+
dy.Labels[k] = expandVars(v, getEnv(nil))
269269
}
270270

271271
for k, v := range dy.Metadata {
272-
dy.Metadata[k] = expandShellRe(v, getEnv(nil))
272+
dy.Metadata[k] = expandVars(v, getEnv(nil))
273273
}
274274

275275
for j := range dy.Tags {
276-
dy.Tags[j] = expandShellRe(dy.Tags[j], getEnv(nil))
276+
dy.Tags[j] = expandVars(dy.Tags[j], getEnv(nil))
277277
}
278278

279279
// expand vars in update policy
280-
dy.UpdatePolicy.Type = expandShellRe(dy.UpdatePolicy.Type, getEnv(nil))
281-
dy.UpdatePolicy.MinimalAction = expandShellRe(dy.UpdatePolicy.MinimalAction, getEnv(nil))
282-
dy.UpdatePolicy.ReplacementMethod = expandShellRe(dy.UpdatePolicy.ReplacementMethod, getEnv(nil))
283-
dy.UpdatePolicy.MinReadySec = expandShellRe(dy.UpdatePolicy.MinReadySec, getEnv(nil))
284-
dy.UpdatePolicy.MaxSurge = expandShellRe(dy.UpdatePolicy.MaxSurge, getEnv(nil))
285-
dy.UpdatePolicy.MaxUnavailable = expandShellRe(dy.UpdatePolicy.MaxUnavailable, getEnv(nil))
280+
dy.UpdatePolicy.Type = expandVars(dy.UpdatePolicy.Type, getEnv(nil))
281+
dy.UpdatePolicy.MinimalAction = expandVars(dy.UpdatePolicy.MinimalAction, getEnv(nil))
282+
dy.UpdatePolicy.ReplacementMethod = expandVars(dy.UpdatePolicy.ReplacementMethod, getEnv(nil))
283+
dy.UpdatePolicy.MinReadySec = expandVars(dy.UpdatePolicy.MinReadySec, getEnv(nil))
284+
dy.UpdatePolicy.MaxSurge = expandVars(dy.UpdatePolicy.MaxSurge, getEnv(nil))
285+
dy.UpdatePolicy.MaxUnavailable = expandVars(dy.UpdatePolicy.MaxUnavailable, getEnv(nil))
286286

287287
if strings.TrimSpace(dy.UpdatePolicy.Type) == "" {
288288
dy.UpdatePolicy.Type = "PROACTIVE"
@@ -357,23 +357,23 @@ func ParseConfig(b io.Reader) (*Config, error) {
357357
if err != nil {
358358
return nil, fmt.Errorf("startup_script: %v", err)
359359
}
360-
dy.startupScript = expandCurlyRe(string(f), getEnv(dy.Vars))
360+
dy.startupScript = expandVars(string(f), getEnv(dy.Vars))
361361
}
362362

363363
if dy.ShutdownScriptPath != "" {
364364
f, err := downloadOrReadFile(dy.ShutdownScriptPath)
365365
if err != nil {
366366
return nil, fmt.Errorf("shutdown_script: %v", err)
367367
}
368-
dy.shutdownScript = expandCurlyRe(string(f), getEnv(dy.Vars))
368+
dy.shutdownScript = expandVars(string(f), getEnv(dy.Vars))
369369
}
370370

371371
if dy.CloudInitPath != "" {
372372
f, err := downloadOrReadFile(dy.CloudInitPath)
373373
if err != nil {
374374
return nil, fmt.Errorf("cloud_init: %v", err)
375375
}
376-
dy.cloudInit = expandCurlyRe(string(f), getEnv(dy.Vars))
376+
dy.cloudInit = expandVars(string(f), getEnv(dy.Vars))
377377
}
378378
}
379379

@@ -396,25 +396,24 @@ func getEnv(locals map[string]string) map[string]string {
396396
}
397397

398398
var (
399-
shellVarRe = regexp.MustCompile(`\\?\${?([a-zA-Z]([a-zA-Z0-9-_]+[a-zA-Z0-9]|[a-zA-Z0-9]*)(:\d(:\d)?)?)}?`)
400-
curlyVarRe = regexp.MustCompile(`\\?\$\{\{ *[a-zA-Z0-9_-]+ *\}\}`)
399+
variableRe = regexp.MustCompile(`\\?\$\{\{ *([a-zA-Z]([a-zA-Z0-9-_]+[a-zA-Z0-9]|[a-zA-Z0-9]*)(:\d(:\d)?)?) *\}\}`)
401400
)
402401

403-
// expandShellRe replaces $VAR and ${VAR}
404-
func expandShellRe(str string, vars map[string]string) string {
405-
return shellVarRe.ReplaceAllStringFunc(str, func(x string) string {
406-
402+
// expandVars replaces ${{VAR}}
403+
func expandVars(str string, vars map[string]string) string {
404+
return variableRe.ReplaceAllStringFunc(str, func(x string) string {
407405
if strings.HasPrefix(x, `\$`) {
408406
return x
409407
}
410408

411409
x = strings.Trim(x, "${}")
410+
x = strings.TrimSpace(x)
412411

413412
if !strings.Contains(x, ":") {
414413
return vars[strings.ToLower(x)]
415414
}
416415

417-
// parse ${string:position[:length]} and truncate string
416+
// parse ${{string:position[:length]}} and truncate string
418417
parts := strings.Split(x, ":")
419418
switch len(parts) {
420419
default:
@@ -448,21 +447,6 @@ func expandShellRe(str string, vars map[string]string) string {
448447
})
449448
}
450449

451-
// expandCurlyRe replaces ${{VAR}}
452-
func expandCurlyRe(str string, vars map[string]string) string {
453-
return curlyVarRe.ReplaceAllStringFunc(str, func(x string) string {
454-
455-
if strings.HasPrefix(x, `\$`) {
456-
return x
457-
}
458-
459-
x = strings.Trim(x, "${}")
460-
x = strings.TrimSpace(x)
461-
462-
return vars[strings.ToLower(x)]
463-
})
464-
}
465-
466450
func downloadOrReadFile(path string) ([]byte, error) {
467451
path = strings.TrimSpace(path)
468452

config_test.go

Lines changed: 49 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,31 @@ func TestParseConfig(t *testing.T) {
2222
config := `
2323
delete_instance_templates_after: 14h
2424
deploys:
25-
- name: name-$BAR-${BAR}
26-
project: project-$BAR-${BAR}
27-
creds: google-application-credentials-$BAR-${BAR}
28-
region: region-$BAR-${BAR}
29-
instance_group: instance-group-$BAR-${BAR}
30-
instance_template_base: instance-template-base-$BAR-${BAR}
31-
instance_template: instance-template-$BAR-${BAR}
25+
- name: name-${{BAR}}
26+
project: project-${{BAR}}
27+
creds: google-application-credentials-${{BAR}}
28+
region: region-${{BAR}}
29+
instance_group: instance-group-${{BAR}}
30+
instance_template_base: instance-template-base-${{BAR}}
31+
instance_template: instance-template-${{BAR}}
3232
startup_script: ` + tmpFile.Name() + `
3333
shutdown_script: ` + tmpFile.Name() + `
3434
cloud_init: ` + tmpFile.Name() + `
3535
vars:
36-
scriptvarkey: scriptvarvalue-$BAR-${BAR}
36+
scriptvarkey: scriptvarvalue-${{BAR}}
3737
labels:
38-
labelkey: labelvalue-$BAR-${BAR}
38+
labelkey: labelvalue-${{BAR}}
3939
metadata:
40-
metadatakey: metadatavalue-$BAR-${BAR}
40+
metadatakey: metadatavalue-${{BAR}}
4141
tags:
42-
- tagvalue-$BAR-${BAR}
42+
- tagvalue-${{BAR}}
4343
update_policy:
44-
type: type-$BAR-${BAR}
45-
minimal_action: minimal-action-$BAR-${BAR}
46-
replacement_method: replacement-method-$BAR-${BAR}
47-
min_ready_sec: $MIN_READY_SEC
48-
max_surge: $MAX_SURGE
49-
max_unavailable: $MAX_UNAVAILABLE
44+
type: type-${{BAR}}
45+
minimal_action: minimal-action-${{BAR}}
46+
replacement_method: replacement-method-${{BAR}}
47+
min_ready_sec: ${{MIN_READY_SEC}}
48+
max_surge: ${{MAX_SURGE}}
49+
max_unavailable: ${{MAX_UNAVAILABLE}}
5050
`
5151

5252
environ = append(environ, "BAR=FOO")
@@ -65,27 +65,27 @@ deploys:
6565
require.Len(t, c.Deploys[0].Metadata, 1)
6666
require.Len(t, c.Deploys[0].Tags, 1)
6767

68-
assert.Equal(t, "name-FOO-FOO", c.Deploys[0].Name)
69-
assert.Equal(t, "project-FOO-FOO", c.Deploys[0].Project)
70-
assert.Equal(t, "google-application-credentials-FOO-FOO", c.Deploys[0].GoogleApplicationCredentials)
71-
assert.Equal(t, "region-FOO-FOO", c.Deploys[0].Region)
72-
assert.Equal(t, "instance-group-FOO-FOO", c.Deploys[0].InstanceGroup)
73-
assert.Equal(t, "instance-template-base-FOO-FOO", c.Deploys[0].InstanceTemplateBase)
74-
assert.Equal(t, "instance-template-FOO-FOO", c.Deploys[0].InstanceTemplate)
68+
assert.Equal(t, "name-FOO", c.Deploys[0].Name)
69+
assert.Equal(t, "project-FOO", c.Deploys[0].Project)
70+
assert.Equal(t, "google-application-credentials-FOO", c.Deploys[0].GoogleApplicationCredentials)
71+
assert.Equal(t, "region-FOO", c.Deploys[0].Region)
72+
assert.Equal(t, "instance-group-FOO", c.Deploys[0].InstanceGroup)
73+
assert.Equal(t, "instance-template-base-FOO", c.Deploys[0].InstanceTemplateBase)
74+
assert.Equal(t, "instance-template-FOO", c.Deploys[0].InstanceTemplate)
7575
assert.Equal(t, tmpFile.Name(), c.Deploys[0].StartupScriptPath)
76-
assert.Equal(t, "Foo: $BAR FOO scriptvarvalue-FOO-FOO", c.Deploys[0].startupScript)
76+
assert.Equal(t, "Foo: $BAR FOO scriptvarvalue-FOO", c.Deploys[0].startupScript)
7777
assert.Equal(t, tmpFile.Name(), c.Deploys[0].ShutdownScriptPath)
78-
assert.Equal(t, "Foo: $BAR FOO scriptvarvalue-FOO-FOO", c.Deploys[0].shutdownScript)
78+
assert.Equal(t, "Foo: $BAR FOO scriptvarvalue-FOO", c.Deploys[0].shutdownScript)
7979
assert.Equal(t, tmpFile.Name(), c.Deploys[0].CloudInitPath)
80-
assert.Equal(t, "Foo: $BAR FOO scriptvarvalue-FOO-FOO", c.Deploys[0].cloudInit)
81-
assert.Equal(t, "scriptvarvalue-FOO-FOO", c.Deploys[0].Vars["scriptvarkey"])
82-
assert.Equal(t, "labelvalue-FOO-FOO", c.Deploys[0].Labels["labelkey"])
83-
assert.Equal(t, "metadatavalue-FOO-FOO", c.Deploys[0].Metadata["metadatakey"])
84-
assert.Equal(t, "tagvalue-FOO-FOO", c.Deploys[0].Tags[0])
85-
86-
assert.Equal(t, "type-FOO-FOO", c.Deploys[0].UpdatePolicy.Type)
87-
assert.Equal(t, "minimal-action-FOO-FOO", c.Deploys[0].UpdatePolicy.MinimalAction)
88-
assert.Equal(t, "replacement-method-FOO-FOO", c.Deploys[0].UpdatePolicy.ReplacementMethod)
80+
assert.Equal(t, "Foo: $BAR FOO scriptvarvalue-FOO", c.Deploys[0].cloudInit)
81+
assert.Equal(t, "scriptvarvalue-FOO", c.Deploys[0].Vars["scriptvarkey"])
82+
assert.Equal(t, "labelvalue-FOO", c.Deploys[0].Labels["labelkey"])
83+
assert.Equal(t, "metadatavalue-FOO", c.Deploys[0].Metadata["metadatakey"])
84+
assert.Equal(t, "tagvalue-FOO", c.Deploys[0].Tags[0])
85+
86+
assert.Equal(t, "type-FOO", c.Deploys[0].UpdatePolicy.Type)
87+
assert.Equal(t, "minimal-action-FOO", c.Deploys[0].UpdatePolicy.MinimalAction)
88+
assert.Equal(t, "replacement-method-FOO", c.Deploys[0].UpdatePolicy.ReplacementMethod)
8989
assert.Equal(t, "2", c.Deploys[0].UpdatePolicy.MinReadySec)
9090
assert.Equal(t, 2, c.Deploys[0].UpdatePolicy.minReadySec)
9191
assert.Equal(t, "15%", c.Deploys[0].UpdatePolicy.MaxSurge)
@@ -205,39 +205,37 @@ deploys:
205205
require.NoError(t, err)
206206
}
207207

208-
func TestExpandShellRe(t *testing.T) {
209-
in := `$foo $FOO ${foo} a${foo}b \$foo \${foo} a\${foo}b $foo-$foo $foo-${foo} $fo $f`
208+
func TestExpandVars(t *testing.T) {
209+
in := `f fo foo $f $fo $foo ${f} ${fo} ${foo} \${{f}} \${{fo}} \${{foo}} ${{f}} ${{fo}} ${{foo}} ${{ f }} ${{ fo }} ${{ foo }} a${{f}}b a${{fo}}b a${{foo}}b a\${{f}}b a\${{fo}}b a\${{foo}}b`
210210

211211
vars := map[string]string{
212212
"f": "b",
213213
"fo": "ba",
214214
"foo": "bar",
215215
}
216216

217-
out := expandShellRe(in, vars)
218-
assert.Equal(t, `bar bar bar abarb \$foo \${foo} a\${foo}b bar-bar bar-bar ba b`, out)
217+
out := expandVars(in, vars)
218+
assert.Equal(t, `f fo foo $f $fo $foo ${f} ${fo} ${foo} \${{f}} \${{fo}} \${{foo}} b ba bar b ba bar abb abab abarb a\${{f}}b a\${{fo}}b a\${{foo}}b`, out)
219219
}
220220

221-
func TestShellReTruncate(t *testing.T) {
222-
in := `${foo:0} ${foo:1} ${foo:7} ${foo:7:3} ${foo:1:1}`
221+
func TestVariableCaseInsensitive(t *testing.T) {
222+
in := `${{foo}} ${{FOO}}`
223223

224224
vars := map[string]string{
225-
"foo": "abcABC123ABCabc",
225+
"foo": "bar",
226226
}
227227

228-
out := expandShellRe(in, vars)
229-
assert.Equal(t, `abcABC123ABCabc bcABC123ABCabc 23ABCabc 23A b`, out)
228+
out := expandVars(in, vars)
229+
assert.Equal(t, `bar bar`, out)
230230
}
231231

232-
func TestExpandCurlyRe(t *testing.T) {
233-
in := `$foo $FOO $(foo) $(FOO) ${{foo}} ${{FOO}} ${{ foo }} ${{ FOO }} ${{ foo }} ${{ FOO }} a${{foo}}b \${{foo}} a\${{foo}}b ${{foo}}-${{foo}} ${{fo}} ${{f}}`
232+
func TestVariableTruncate(t *testing.T) {
233+
in := `${{foo:0}} ${{foo:1}} ${{foo:7}} ${{foo:7:3}} ${{foo:1:1}}`
234234

235235
vars := map[string]string{
236-
"f": "b",
237-
"fo": "ba",
238-
"foo": "bar",
236+
"foo": "abcABC123ABCabc",
239237
}
240238

241-
out := expandCurlyRe(in, vars)
242-
assert.Equal(t, `$foo $FOO $(foo) $(FOO) bar bar bar bar bar bar abarb \${{foo}} a\${{foo}}b bar-bar ba b`, out)
239+
out := expandVars(in, vars)
240+
assert.Equal(t, `abcABC123ABCabc bcABC123ABCabc 23ABCabc 23A b`, out)
243241
}

example/deploy.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ deploys:
44
region: us-central1
55
instance_group: github-action-instance-group-1
66
instance_template_base: github-action-instance-template-test-1
7-
instance_template: github-action-instance-template-$GITHUB_RUN_NUMBER-${GITHUB_SHA:0:7}
7+
instance_template: github-action-instance-template-${{GITHUB_RUN_NUMBER}}-${{GITHUB_SHA:0:7}}
88
cloud_init: cloud-init.yml
99
vars:
1010
string_var: "The current directory is:"
1111
labels:
12-
github_sha: $GITHUB_SHA
12+
github_sha: ${{GITHUB_SHA}}
1313
tags:
1414
- no-network
1515
- app123
1616
metadata:
17-
github_run_number: $GITHUB_RUN_NUMBER
17+
github_run_number: ${{GITHUB_RUN_NUMBER}}
1818
update_policy:
1919
min_ready_sec: 20
2020

0 commit comments

Comments
 (0)