Skip to content

Commit bb61649

Browse files
authored
#14: --remove-image option (#15)
#14: --remove-image option
1 parent 330816f commit bb61649

File tree

8 files changed

+139
-3
lines changed

8 files changed

+139
-3
lines changed

pkg/action/env.container.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const (
2929

3030
// Environment specific flags.
3131
containerFlagUseVolumeWD = "use-volume-wd"
32+
containerFlagRemoveImage = "remove-image"
3233
)
3334

3435
type containerEnv struct {
@@ -38,7 +39,8 @@ type containerEnv struct {
3839
nameprv ContainerNameProvider
3940

4041
// Runtime flags
41-
useVolWD bool
42+
useVolWD bool
43+
removeImg bool
4244
}
4345

4446
// ContainerNameProvider provides an ability to generate a random container name
@@ -77,13 +79,25 @@ func (c *containerEnv) FlagsDefinition() OptionsList {
7779
Type: jsonschema.Boolean,
7880
Default: false,
7981
},
82+
&Option{
83+
Name: containerFlagRemoveImage,
84+
Title: "Remove Image",
85+
Description: "Remove an image after execution of action",
86+
Type: jsonschema.Boolean,
87+
Default: false,
88+
},
8089
}
8190
}
8291

8392
func (c *containerEnv) UseFlags(flags TypeOpts) error {
8493
if v, ok := flags[containerFlagUseVolumeWD]; ok {
8594
c.useVolWD = v.(bool)
8695
}
96+
97+
if v, ok := flags[containerFlagRemoveImage]; ok {
98+
c.removeImg = v.(bool)
99+
}
100+
87101
return nil
88102
}
89103

@@ -224,6 +238,16 @@ func (c *containerEnv) Execute(ctx context.Context, a *Action) (err error) {
224238
return err
225239
}
226240
}
241+
242+
if c.removeImg {
243+
err = c.imageRemove(ctx, a)
244+
if err != nil {
245+
log.Err("Image remove returned an error: %v", err)
246+
} else {
247+
cli.Println("Image %q was successfully removed", a.ActionDef().Image)
248+
}
249+
}
250+
227251
return nil
228252
}
229253

@@ -245,6 +269,15 @@ func (c *containerEnv) Close() error {
245269
return c.driver.Close()
246270
}
247271

272+
func (c *containerEnv) imageRemove(ctx context.Context, a *Action) error {
273+
_, err := c.driver.ImageRemove(ctx, a.ActionDef().Image, types.ImageRemoveOptions{
274+
Force: false,
275+
PruneChildren: false,
276+
})
277+
278+
return err
279+
}
280+
248281
func (c *containerEnv) imageEnsure(ctx context.Context, a *Action) error {
249282
streams := a.GetInput().IO
250283
image := a.ActionDef().Image

pkg/action/env.container_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,70 @@ func Test_ContainerExec_imageEnsure(t *testing.T) {
199199
}
200200
}
201201

202+
func Test_ContainerExec_imageRemove(t *testing.T) {
203+
t.Parallel()
204+
205+
actLoc := testContainerAction(&DefAction{
206+
Image: "build:local",
207+
Build: &types.BuildDefinition{
208+
Context: ".",
209+
},
210+
})
211+
err := actLoc.EnsureLoaded()
212+
assert.NoError(t, err)
213+
type testCase struct {
214+
name string
215+
action *DefAction
216+
expBuild *types.BuildDefinition
217+
ret []interface{}
218+
}
219+
220+
tts := []testCase{
221+
{
222+
"image removed",
223+
actLoc.ActionDef(),
224+
nil,
225+
[]interface{}{&types.ImageRemoveResponse{Status: types.ImageRemoved}, nil},
226+
},
227+
{
228+
"failed to remove",
229+
&DefAction{Image: "failed"},
230+
nil,
231+
[]interface{}{nil, fmt.Errorf("failed to remove")},
232+
},
233+
}
234+
235+
for _, tt := range tts {
236+
tt := tt
237+
238+
t.Run(tt.name, func(t *testing.T) {
239+
t.Parallel()
240+
assert, ctrl, d, r := prepareContainerTestSuite(t)
241+
ctx := context.Background()
242+
243+
defer ctrl.Finish()
244+
defer r.driver.Close()
245+
246+
act := testContainerAction(tt.action)
247+
act.input = Input{
248+
IO: cli.NoopStreams(),
249+
}
250+
251+
err := act.EnsureLoaded()
252+
assert.NoError(err)
253+
254+
a := act.ActionDef()
255+
imgOpts := types.ImageRemoveOptions{Force: false, PruneChildren: false}
256+
d.EXPECT().
257+
ImageRemove(ctx, a.Image, gomock.Eq(imgOpts)).
258+
Return(tt.ret...)
259+
err = r.imageRemove(ctx, act)
260+
261+
assert.Equal(err, tt.ret[1])
262+
})
263+
}
264+
}
265+
202266
func Test_ContainerExec_containerCreate(t *testing.T) {
203267
t.Parallel()
204268
assert, ctrl, d, r := prepareContainerTestSuite(t)
@@ -678,6 +742,10 @@ func callContainerDriverMockFn(d *mockdriver.MockContainerRunner, step mockCallI
678742
call = d.EXPECT().
679743
ContainerStart(gomock.Any(), step.args[0], step.args[1]).
680744
Return(step.ret...)
745+
case "ImageRemove":
746+
call = d.EXPECT().
747+
ImageRemove(gomock.Any(), step.args[0], step.args[1]).
748+
Return(step.ret...)
681749
}
682750
if step.minTimes > 1 {
683751
call.MinTimes(step.minTimes)

pkg/action/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (p inputProcessor) Process(ctx LoadContext, b []byte) ([]byte, error) {
193193
}
194194
}
195195
if hasDash && strings.Contains(err.Error(), "bad character U+002D '-'") {
196-
return nil, fmt.Errorf(`Unexpected '-' symbol in a template variable.
196+
return nil, fmt.Errorf(`unexpected '-' symbol in a template variable.
197197
Action definition is correct, but dashes are not allowed in templates, replace "-" with "_" in {{ }} blocks`)
198198
}
199199
return nil, err

pkg/action/loader_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func Test_InputProcessor(t *testing.T) {
5656

5757
s = "{{ .opt-str }}"
5858
res, err = proc.Process(ctx, []byte(s))
59-
assert.ErrorContains(t, err, "Unexpected '-' symbol in a template variable.")
59+
assert.ErrorContains(t, err, "unexpected '-' symbol in a template variable.")
6060
assert.Equal(t, "", string(res))
6161

6262
s = "{{ .arg2 }},{{ .optUnd }}"

pkg/driver/docker.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ func (d *dockerDriver) ImageEnsure(ctx context.Context, image types.ImageOptions
8686
return &types.ImageStatusResponse{Status: types.ImagePull, Progress: reader}, nil
8787
}
8888

89+
func (d *dockerDriver) ImageRemove(ctx context.Context, image string, options types.ImageRemoveOptions) (*types.ImageRemoveResponse, error) {
90+
_, err := d.cli.ImageRemove(ctx, image, dockertypes.ImageRemoveOptions(options))
91+
92+
if err != nil {
93+
return nil, err
94+
}
95+
96+
return &types.ImageRemoveResponse{Status: types.ImageRemoved}, nil
97+
}
98+
8999
func (d *dockerDriver) CopyToContainer(ctx context.Context, cid string, path string, content io.Reader, opts types.CopyToContainerOptions) error {
90100
return d.cli.CopyToContainer(ctx, cid, path, content, dockertypes.CopyToContainerOptions(opts))
91101
}

pkg/driver/driver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
// ContainerRunner defines common interface for container environments.
1414
type ContainerRunner interface {
1515
ImageEnsure(ctx context.Context, opts types.ImageOptions) (*types.ImageStatusResponse, error)
16+
ImageRemove(ctx context.Context, image string, opts types.ImageRemoveOptions) (*types.ImageRemoveResponse, error)
1617
CopyToContainer(ctx context.Context, cid string, path string, content io.Reader, opts types.CopyToContainerOptions) error
1718
CopyFromContainer(ctx context.Context, cid, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
1819
ContainerStatPath(ctx context.Context, cid string, path string) (types.ContainerPathStat, error)

pkg/driver/mocks/driver.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/types/container.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ type ImageOptions struct {
6262
Build *BuildDefinition
6363
}
6464

65+
// ImageRemoveOptions stores options for removing an image.
66+
type ImageRemoveOptions = types.ImageRemoveOptions
67+
6568
// ImageStatus defines image status on local machine.
6669
type ImageStatus int64
6770

@@ -70,6 +73,7 @@ const (
7073
ImageUnexpectedError // ImageUnexpectedError - image can't be pulled or retrieved.
7174
ImagePull // ImagePull - image is being pulled from the registry.
7275
ImageBuild // ImageBuild - image is being built.
76+
ImageRemoved // ImageRemoved - image was removed
7377
)
7478

7579
// ContainerListOptions stores options to request container list.
@@ -90,6 +94,11 @@ type ImageStatusResponse struct {
9094
Progress io.ReadCloser
9195
}
9296

97+
// ImageRemoveResponse stores response when removing the image.
98+
type ImageRemoveResponse struct {
99+
Status ImageStatus
100+
}
101+
93102
// ContainerPathStat is a type alias for container path stat result.
94103
type ContainerPathStat = types.ContainerPathStat
95104

0 commit comments

Comments
 (0)