Skip to content

Commit

Permalink
Merge pull request #4 from emicklei/run-section-as-file
Browse files Browse the repository at this point in the history
run all commands at once using temporary shell script
  • Loading branch information
emicklei authored Aug 23, 2018
2 parents 512dcc6 + f623d90 commit 7021ea3
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 12 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ Each change is a single YAML file with one or more shell commands that change in
- gcloud iam service-accounts delete loadrunner

A change must have at least a `do` section and optionally an `undo` section.
The `do` section typically has a list of gcloud commands that create resources. Each line will be executed as a shell command so any available tool can be used.
The `do` section typically has a list of gcloud commands that create resources but any available tool can be used.
All lines will be executed at once using a single temporary shell script so you can use shell variables to simplify each section.
The `undo` section typically has an ordered list of gcloud commands that deletes the same resources (in reverse order if relevant).
Each command can use the following environment variables: `$PROJECT`,`$REGION`,`$ZONE` and any additional environment variables populated from the target configuration (see `env` section in the configuration below).
Each command in each section can use the following environment variables: `$PROJECT`,`$REGION`,`$ZONE` and any additional environment variables populated from the target configuration (see `env` section in the configuration below).

Information about the last applied change to a project is stored as a Google Storage Bucket object.

Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func newApp() *cli.App {
},
{
Name: "up",
Usage: "Runs the do section of all pending migrations in order, one after the other.",
Usage: "Runs the do section of all pending migrations in order, one after the other. If a migration file is specified then stop after applying that one.",
Action: func(c *cli.Context) error {
defer started(c, "up = apply pending migrations")()
return cmdMigrationsUp(c)
Expand Down
32 changes: 23 additions & 9 deletions migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strings"
Expand Down Expand Up @@ -60,20 +61,33 @@ func (m Migration) ToYAML() ([]byte, error) {
}

// ExecuteAll the commands for this migration.
// We create a temporary executable file with all commands.
// This allows for using shell variables in multiple commands.
func ExecuteAll(commands []string, envs []string) error {
if len(commands) == 0 {
return nil
}
for i, each := range commands {
log.Println(each)
cmd := exec.Command("sh", "-c", each)
cmd.Env = append(os.Environ(), envs...) // extend, not replace
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("%d: failed to run :%v", i, err)
tempScript := path.Join(os.TempDir(), "gmig.sh")
content := new(bytes.Buffer)
fmt.Fprintln(content, `#!/bin/bash
set -e -v`)
for _, each := range commands {
fmt.Fprintln(content, each)
}
if err := ioutil.WriteFile(tempScript, content.Bytes(), os.ModePerm); err != nil {
return fmt.Errorf("failed to write temporary migration section: %v", err)
}
defer func() {
if err := os.Remove(tempScript); err != nil {
log.Printf("warning: failed to remove temporary migration execution script:%s\n", tempScript)
}
}()
cmd := exec.Command("sh", "-c", tempScript)
cmd.Env = append(os.Environ(), envs...) // extend, not replace
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to run migration section: %v", err)
}
return nil
}
Expand Down

0 comments on commit 7021ea3

Please sign in to comment.