diff --git a/docs/content/en/schemas/v2alpha2.json b/docs/content/en/schemas/v2alpha2.json index 803b21b0527..b4464f57f6a 100755 --- a/docs/content/en/schemas/v2alpha2.json +++ b/docs/content/en/schemas/v2alpha2.json @@ -1652,6 +1652,11 @@ }, "LocalBuild": { "properties": { + "concurrency": { + "type": "integer", + "description": "how many artifacts can be built concurrently. 0 means \"no-limit\" Defaults to 1.", + "x-intellij-html-description": "how many artifacts can be built concurrently. 0 means "no-limit" Defaults to 1." + }, "push": { "type": "boolean", "description": "should images be pushed to a registry. If not specified, images are pushed only if the current Kubernetes context connects to a remote cluster.", @@ -1673,7 +1678,8 @@ "preferredOrder": [ "push", "useDockerCLI", - "useBuildkit" + "useBuildkit", + "concurrency" ], "additionalProperties": false, "description": "*beta* describes how to do a build on the local docker daemon and optionally push to a repository.", diff --git a/pkg/skaffold/build/local/local.go b/pkg/skaffold/build/local/local.go index 35ac2074fa5..80c0d676923 100644 --- a/pkg/skaffold/build/local/local.go +++ b/pkg/skaffold/build/local/local.go @@ -44,7 +44,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, tags tag.ImageTags, defer b.localDocker.Close() // TODO(dgageot): parallel builds - return build.InSequence(ctx, out, tags, artifacts, b.buildArtifact) + return build.InParallel(ctx, out, tags, artifacts, b.buildArtifact, *b.cfg.Concurrency) } func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, artifact *latest.Artifact, tag string) (string, error) { diff --git a/pkg/skaffold/build/local/local_test.go b/pkg/skaffold/build/local/local_test.go index 3fc025657c8..5e0a8be7301 100644 --- a/pkg/skaffold/build/local/local_test.go +++ b/pkg/skaffold/build/local/local_test.go @@ -27,6 +27,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext" @@ -226,7 +227,8 @@ func TestLocalRun(t *testing.T) { }) builder, err := NewBuilder(stubRunContext(latest.LocalBuild{ - Push: util.BoolPtr(test.pushImages), + Push: util.BoolPtr(test.pushImages), + Concurrency: &constants.DefaultLocalConcurrency, })) t.CheckNoError(err) @@ -272,7 +274,7 @@ func TestNewBuilder(t *testing.T) { }, shouldErr: false, expectedBuilder: &Builder{ - cfg: &latest.LocalBuild{}, + cfg: latest.LocalBuild{}, kubeContext: "", localDocker: dummyDaemon, localCluster: false, @@ -298,7 +300,7 @@ func TestNewBuilder(t *testing.T) { shouldErr: false, expectedBuilder: &Builder{ pushImages: false, //this will be false too - cfg: &latest.LocalBuild{ // and the config is inherited + cfg: latest.LocalBuild{ // and the config is inherited Push: util.BoolPtr(false), }, kubeContext: "", diff --git a/pkg/skaffold/build/local/types.go b/pkg/skaffold/build/local/types.go index fff9e02b5ac..dd0a8ac246d 100644 --- a/pkg/skaffold/build/local/types.go +++ b/pkg/skaffold/build/local/types.go @@ -33,7 +33,7 @@ import ( // Builder uses the host docker daemon to build and tag the image. type Builder struct { - cfg *latest.LocalBuild + cfg latest.LocalBuild localDocker docker.LocalDaemon localCluster bool @@ -72,7 +72,7 @@ func NewBuilder(runCtx *runcontext.RunContext) (*Builder, error) { } return &Builder{ - cfg: runCtx.Cfg.Build.LocalBuild, + cfg: *runCtx.Cfg.Build.LocalBuild, kubeContext: runCtx.KubeContext, localDocker: localDocker, localCluster: localCluster, diff --git a/pkg/skaffold/constants/constants.go b/pkg/skaffold/constants/constants.go index c796eb70df7..6446e9814af 100644 --- a/pkg/skaffold/constants/constants.go +++ b/pkg/skaffold/constants/constants.go @@ -78,6 +78,8 @@ const ( var ( Pod latest.ResourceType = "pod" Service latest.ResourceType = "service" + + DefaultLocalConcurrency = 1 ) var ( diff --git a/pkg/skaffold/schema/defaults/defaults.go b/pkg/skaffold/schema/defaults/defaults.go index d6071c61c92..581a0b4e9d1 100644 --- a/pkg/skaffold/schema/defaults/defaults.go +++ b/pkg/skaffold/schema/defaults/defaults.go @@ -60,6 +60,10 @@ func Set(c *latest.SkaffoldConfig) error { } } + withLocalBuild(c, + setDefaultConcurrency, + ) + withCloudBuildConfig(c, setDefaultCloudBuildDockerImage, setDefaultCloudBuildMavenImage, @@ -103,7 +107,21 @@ func defaultToKubectlDeploy(c *latest.SkaffoldConfig) { c.Deploy.DeployType.KubectlDeploy = &latest.KubectlDeploy{} } -func withCloudBuildConfig(c *latest.SkaffoldConfig, operations ...func(kaniko *latest.GoogleCloudBuild)) { +func withLocalBuild(c *latest.SkaffoldConfig, operations ...func(*latest.LocalBuild)) { + if gcb := c.Build.LocalBuild; gcb != nil { + for _, operation := range operations { + operation(gcb) + } + } +} + +func setDefaultConcurrency(local *latest.LocalBuild) { + if local.Concurrency == nil { + local.Concurrency = &constants.DefaultLocalConcurrency + } +} + +func withCloudBuildConfig(c *latest.SkaffoldConfig, operations ...func(*latest.GoogleCloudBuild)) { if gcb := c.Build.GoogleCloudBuild; gcb != nil { for _, operation := range operations { operation(gcb) @@ -182,7 +200,7 @@ func setDefaultWorkspace(a *latest.Artifact) { a.Workspace = valueOrDefault(a.Workspace, ".") } -func withClusterConfig(c *latest.SkaffoldConfig, opts ...func(cluster *latest.ClusterDetails) error) error { +func withClusterConfig(c *latest.SkaffoldConfig, opts ...func(*latest.ClusterDetails) error) error { clusterDetails := c.Build.BuildType.Cluster if clusterDetails == nil { return nil diff --git a/pkg/skaffold/schema/defaults/defaults_test.go b/pkg/skaffold/schema/defaults/defaults_test.go index 26f7a423097..c8458ca9b02 100644 --- a/pkg/skaffold/schema/defaults/defaults_test.go +++ b/pkg/skaffold/schema/defaults/defaults_test.go @@ -249,6 +249,15 @@ func TestSetDefaultsOnCloudBuild(t *testing.T) { testutil.CheckDeepEqual(t, constants.DefaultCloudBuildGradleImage, cfg.Build.GoogleCloudBuild.GradleImage) } +func TestSetDefaultsOnLocalBuild(t *testing.T) { + cfg := &latest.SkaffoldConfig{} + + err := Set(cfg) + + testutil.CheckError(t, false, err) + testutil.CheckDeepEqual(t, 1, *cfg.Build.LocalBuild.Concurrency) +} + func TestSetDefaultPortForwardNamespace(t *testing.T) { tests := []struct { description string diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go index cb262090b36..563da57192e 100644 --- a/pkg/skaffold/schema/latest/config.go +++ b/pkg/skaffold/schema/latest/config.go @@ -196,6 +196,10 @@ type LocalBuild struct { // UseBuildkit use BuildKit to build Docker images. UseBuildkit bool `yaml:"useBuildkit,omitempty"` + + // Concurrency is how many artifacts can be built concurrently. 0 means "no-limit" + // Defaults to 1. + Concurrency *int `yaml:"concurrency,omitempty"` } // GoogleCloudBuild *beta* describes how to do a remote build on diff --git a/pkg/skaffold/schema/versions_test.go b/pkg/skaffold/schema/versions_test.go index bff02b0827b..73732db97aa 100644 --- a/pkg/skaffold/schema/versions_test.go +++ b/pkg/skaffold/schema/versions_test.go @@ -260,7 +260,7 @@ func config(ops ...func(*latest.SkaffoldConfig)) *latest.SkaffoldConfig { func withLocalBuild(ops ...func(*latest.BuildConfig)) func(*latest.SkaffoldConfig) { return func(cfg *latest.SkaffoldConfig) { - b := latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{}}} + b := latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{Concurrency: &constants.DefaultLocalConcurrency}}} for _, op := range ops { op(&b) }