forked from arschles/deisrel
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(main.go,actions): create a docker image tagging command
- Loading branch information
Aaron Schlesinger
committed
Jun 28, 2016
1 parent
2c4ec68
commit 09dba8a
Showing
28 changed files
with
938 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package docker | ||
|
||
import ( | ||
"github.com/codegangsta/cli" | ||
"github.com/deis/deisrel/actions" | ||
"github.com/deis/deisrel/docker" | ||
"github.com/google/go-github/github" | ||
) | ||
|
||
// Command returns the entire set of subcommands for the 'deisrel docker ...' command | ||
func Command(ghClient *github.Client, dockerCl docker.Client) cli.Command { | ||
return cli.Command{ | ||
Name: "docker", | ||
Subcommands: []cli.Command{ | ||
cli.Command{ | ||
Name: "retag", | ||
Description: "This command pulls specific Docker images for each corresponding repository's Git SHA, then retags each one to a uniform release tag", | ||
Usage: "Retag each specific Docker image from a repo-specific Git SHA to a uniform release tag", | ||
Flags: []cli.Flag{ | ||
cli.BoolFlag{ | ||
Name: actions.YesFlag, | ||
Usage: "If true, skip the prompt to confirm that newly-tagged images will be pushed", | ||
}, | ||
cli.StringFlag{ | ||
Name: actions.ShaFilepathFlag, | ||
Value: "", | ||
Usage: "the file path which to read in the shas to release", | ||
}, | ||
cli.StringFlag{ | ||
Name: newOrgFlag, | ||
Usage: "The Docker registry organization for the new tagged images (default: deis)", | ||
}, | ||
cli.StringFlag{ | ||
Name: actions.RefFlag, | ||
Value: "master", | ||
Usage: "Optional ref to add to GitHub repo request (can be SHA, branch or tag)", | ||
}, | ||
}, | ||
Action: retagCmd(ghClient, dockerCl), | ||
}, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package docker | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/codegangsta/cli" | ||
"github.com/deis/deisrel/actions" | ||
"github.com/deis/deisrel/docker" | ||
"github.com/deis/deisrel/git" | ||
"github.com/google/go-github/github" | ||
) | ||
|
||
const ( | ||
newOrgFlag = "new-org" | ||
defaultNewOrg = "deis" | ||
) | ||
|
||
func getAllReposAndShas(ghClient *github.Client, shaFilePath, ref string) ([]git.RepoAndSha, error) { | ||
var allReposAndShas []git.RepoAndSha | ||
if shaFilePath != "" { | ||
reposFromFile, err := git.GetShasFromFilepath(shaFilePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("getting git SHAs from %s (%s)", shaFilePath, err) | ||
} | ||
allReposAndShas = reposFromFile | ||
} | ||
|
||
reposAndShas, err := git.GetSHAs(ghClient, git.RepoNames(), git.NoTransform, ref) | ||
if err != nil { | ||
return nil, fmt.Errorf("getting all SHAs from HEAD on each repository (%s)", err) | ||
} | ||
allReposAndShas = reposAndShas | ||
return allReposAndShas, nil | ||
} | ||
|
||
func ensureImages(dockerCl docker.Client, images []*docker.Image) { | ||
imgsCh, errCh, doneCh := docker.PullImages(dockerCl, images) | ||
for { | ||
select { | ||
case img := <-imgsCh: | ||
fmt.Printf("pulled %s\n", img.String()) | ||
case err := <-errCh: | ||
fmt.Printf("error pulling %s (%s)\n", err.Img.String(), err.Err) | ||
case <-doneCh: | ||
return | ||
} | ||
} | ||
} | ||
|
||
func retagAll(dockerCl docker.Client, imageTagPairs []docker.ImageTagPair) { | ||
pairsCh, errCh, doneCh := docker.RetagImages(dockerCl, imageTagPairs) | ||
for { | ||
select { | ||
case pair := <-pairsCh: | ||
fmt.Printf("re-tagged %s to %s\n", pair.Source.String(), pair.Target.String()) | ||
case err := <-errCh: | ||
fmt.Printf("error re-tagging %s to %s (%s)\n", err.SourceImage.String(), err.TargetImage.String(), err.Err) | ||
case <-doneCh: | ||
return | ||
} | ||
} | ||
} | ||
|
||
func pushTargets(dockerCl docker.Client, imageTagPairs []docker.ImageTagPair) { | ||
images := make([]*docker.Image, len(imageTagPairs)) | ||
for i, imageTagPair := range imageTagPairs { | ||
images[i] = imageTagPair.Target | ||
} | ||
if err := docker.PushImages(dockerCl, images); err != nil { | ||
log.Printf("Error pushing (%s)", err) | ||
return | ||
} | ||
} | ||
|
||
func retagCmd(ghClient *github.Client, dockerCl docker.Client) func(c *cli.Context) error { | ||
return func(c *cli.Context) error { | ||
newTag := c.Args().Get(0) | ||
if newTag == "" { | ||
log.Fatal("This command should have 1 argument to specify the new tag to use") | ||
} | ||
newOrg := c.String(newOrgFlag) | ||
if newOrg == "" { | ||
newOrg = defaultNewOrg | ||
} | ||
// only prompt to push new images if the yes flag was false | ||
shaFilepath := c.String(actions.ShaFilepathFlag) | ||
ref := c.String(actions.RefFlag) | ||
promptPush := !c.Bool(actions.YesFlag) | ||
|
||
allReposAndShas, err := getAllReposAndShas(ghClient, shaFilepath, ref) | ||
if err != nil { | ||
log.Fatalf("Error getting all git SHAs (%s)", err) | ||
} | ||
|
||
repoAndShaList := git.NewRepoAndShaListFromSlice(allReposAndShas) | ||
repoAndShaList.Sort() | ||
images, err := docker.ParseImagesFromRepoAndShaList(docker.DeisCIDockerOrg, repoAndShaList) | ||
if err != nil { | ||
log.Fatalf("Error parsing docker images (%s)", err) | ||
} | ||
|
||
fmt.Printf("Pulling %d images\n", len(images)) | ||
ensureImages(dockerCl, images) | ||
fmt.Println("Re-tagging images...") | ||
imageTagPairs := docker.CreateImageTagPairsFromTransform(images, func(img docker.Image) *docker.Image { | ||
img.SetRepo(newOrg) | ||
img.SetTag(newTag) | ||
return &img | ||
}) | ||
retagAll(dockerCl, imageTagPairs) | ||
fmt.Println("done") | ||
|
||
if promptPush { | ||
fmt.Println("Pushing new tags") | ||
pushTargets(dockerCl, imageTagPairs) | ||
} else { | ||
fmt.Println("Not pushing newly tagged images") | ||
} | ||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package docker | ||
|
||
// Client is the interface to interact with the docker daemon. | ||
type Client interface { | ||
Push(*Image) error | ||
Pull(*Image) error | ||
Retag(*Image, *Image) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package docker | ||
|
||
import ( | ||
"os/exec" | ||
) | ||
|
||
type cmdClient struct{} | ||
|
||
// NewCmdClient creates a new Client that does all of its operations by shelling out to the docker CLI | ||
func NewCmdClient() Client { | ||
return &cmdClient{} | ||
} | ||
|
||
func (c *cmdClient) Push(img *Image) error { | ||
cmd := exec.Command("docker", "push", img.String()) | ||
return cmd.Run() | ||
} | ||
|
||
func (c *cmdClient) Pull(img *Image) error { | ||
cmd := exec.Command("docker", "pull", img.String()) | ||
return cmd.Run() | ||
} | ||
|
||
func (c *cmdClient) Retag(src *Image, tar *Image) error { | ||
cmd := exec.Command("docker", "tag", src.String(), tar.String()) | ||
return cmd.Run() | ||
} |
Oops, something went wrong.