Merge pull request #38 from marccampbell/optional-docker-pull
Add flag to skip pulling images already present
This commit is contained in:
commit
8186f00560
|
@ -43,6 +43,7 @@ type RunnerConfig struct {
|
|||
EventName string // name of event to run
|
||||
EventPath string // path to JSON file to use for event.json in containers, relative to WorkingDir
|
||||
ReuseContainers bool // reuse containers to maintain state
|
||||
ForcePull bool // force pulling of the image, if already present
|
||||
}
|
||||
|
||||
type environmentApplier interface {
|
||||
|
|
|
@ -49,10 +49,25 @@ func (runner *runnerImpl) addImageExecutor(action *model.Action, executors *[]co
|
|||
|
||||
case *model.UsesDockerImage:
|
||||
image = uses.Image
|
||||
*executors = append(*executors, container.NewDockerPullExecutor(container.NewDockerPullExecutorInput{
|
||||
DockerExecutorInput: in,
|
||||
Image: image,
|
||||
}))
|
||||
|
||||
pull := runner.config.ForcePull
|
||||
if !pull {
|
||||
imageExists, err := container.ImageExistsLocally(runner.config.Ctx, image)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to determine if image already exists for image %q", image)
|
||||
}
|
||||
|
||||
if imageExists {
|
||||
pull = false
|
||||
}
|
||||
}
|
||||
|
||||
if pull {
|
||||
*executors = append(*executors, container.NewDockerPullExecutor(container.NewDockerPullExecutorInput{
|
||||
DockerExecutorInput: in,
|
||||
Image: image,
|
||||
}))
|
||||
}
|
||||
|
||||
case *model.UsesPath:
|
||||
contextDir := filepath.Join(runner.config.WorkingDir, uses.String())
|
||||
|
|
|
@ -31,6 +31,7 @@ func Execute(ctx context.Context, version string) {
|
|||
rootCmd.Flags().StringP("action", "a", "", "run action")
|
||||
rootCmd.Flags().BoolVarP(&runnerConfig.ReuseContainers, "reuse", "r", false, "reuse action containers to maintain state")
|
||||
rootCmd.Flags().StringVarP(&runnerConfig.EventPath, "event", "e", "", "path to event JSON file")
|
||||
rootCmd.Flags().BoolVarP(&runnerConfig.ForcePull, "pull", "p", false, "pull docker image(s) if already present")
|
||||
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
|
||||
rootCmd.PersistentFlags().BoolVarP(&runnerConfig.Dryrun, "dryrun", "n", false, "dryrun mode")
|
||||
rootCmd.PersistentFlags().StringVarP(&runnerConfig.WorkflowPath, "file", "f", "./.github/main.workflow", "path to workflow file")
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
|
||||
// ImageExistsLocally returns a boolean indicating if an image with the
|
||||
// requested name (and tag) exist in the local docker image store
|
||||
func ImageExistsLocally(ctx context.Context, imageName string) (bool, error) {
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
cli.NegotiateAPIVersion(ctx)
|
||||
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("reference", imageName)
|
||||
|
||||
imageListOptions := types.ImageListOptions{
|
||||
Filters: filters,
|
||||
}
|
||||
|
||||
images, err := cli.ImageList(ctx, imageListOptions)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return len(images) > 0, nil
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
|
||||
func TestImageExistsLocally(t *testing.T) {
|
||||
// to help make this test reliable and not flaky, we need to have
|
||||
// an image that will exist, and onew that won't exist
|
||||
|
||||
exists, err := ImageExistsLocally(context.TODO(), "library/alpine:this-random-tag-will-never-exist")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, false, exists)
|
||||
|
||||
// pull an image
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||
assert.Nil(t, err)
|
||||
cli.NegotiateAPIVersion(context.TODO())
|
||||
|
||||
// Chose alpine latest because it's so small
|
||||
// maybe we should build an image instead so that tests aren't reliable on dockerhub
|
||||
reader, err := cli.ImagePull(context.TODO(), "alpine:latest", types.ImagePullOptions{})
|
||||
assert.Nil(t, err)
|
||||
defer reader.Close()
|
||||
_, err = ioutil.ReadAll(reader)
|
||||
assert.Nil(t, err)
|
||||
|
||||
exists, err = ImageExistsLocally(context.TODO(), "alpine:latest")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, exists)
|
||||
}
|
Loading…
Reference in New Issue