Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/shp_build_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ shp build run <name> [flags]
--runtime-class string specify the runtime class to be used for the Pod
--sa-name string Kubernetes service-account name
--scheduler-name string specify the scheduler to be used to dispatch the Pod
--step-resources stringArray override compute resources for a build step, as <step>=<limits|requests>.<resource>=<quantity> (repeatable) (default [])
--timeout duration build process timeout
```

Expand Down
2 changes: 2 additions & 0 deletions docs/shp_build_upload.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ shp build upload <build-name> [path/to/source|.] [flags]

```
--buildref-name string name of build resource to reference
--buildrun-name string stream the local source into an existing BuildRun instead of creating one
-e, --env stringArray specify a key-value pair for an environment variable to set for the build container (default [])
-F, --follow Start a build and watch its log until it completes or fails.
-h, --help help for upload
Expand All @@ -44,6 +45,7 @@ shp build upload <build-name> [path/to/source|.] [flags]
--runtime-class string specify the runtime class to be used for the Pod
--sa-name string Kubernetes service-account name
--scheduler-name string specify the scheduler to be used to dispatch the Pod
--step-resources stringArray override compute resources for a build step, as <step>=<limits|requests>.<resource>=<quantity> (repeatable) (default [])
--timeout duration build process timeout
```

Expand Down
1 change: 1 addition & 0 deletions docs/shp_buildrun_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ shp buildrun create <name> [flags]
--runtime-class string specify the runtime class to be used for the Pod
--sa-name string Kubernetes service-account name
--scheduler-name string specify the scheduler to be used to dispatch the Pod
--step-resources stringArray override compute resources for a build step, as <step>=<limits|requests>.<resource>=<quantity> (repeatable) (default [])
--timeout duration build process timeout
```

Expand Down
90 changes: 87 additions & 3 deletions pkg/shp/cmd/build/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path"
"strings"
"time"

buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/shipwright-io/cli/pkg/shp/reactor"
"github.com/shipwright-io/cli/pkg/shp/streamer"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -30,6 +32,7 @@ type UploadCommand struct {
follow bool // flag to tail pod logs

buildRefName string // build name
buildRunName string // name of an existing BuildRun to stream into, instead of creating one
sourceDir string // local directory to be streamed

dataStreamer *streamer.Streamer // tar streamer instance
Expand Down Expand Up @@ -152,6 +155,43 @@ func (u *UploadCommand) Validate() error {
if !stat.IsDir() {
return fmt.Errorf("informed path is not a directory: '%s'", u.sourceDir)
}
if err := u.checkBuildRunNameConflicts(); err != nil {
return err
}
// streaming into an existing BuildRun only supports the local-copy path; a source bundle image
Comment thread
psrvere marked this conversation as resolved.
// requires this command to create the BuildRun and push the bundle itself.
if u.buildRunName != "" && u.sourceBundleImage != "" {
return fmt.Errorf("--%s is not supported for Builds using a source bundle image", flags.BuildrunNameFlag)
}
return nil
}

// checkBuildRunNameConflicts makes sure that, when an existing BuildRun is referenced with the
// --buildrun-name flag, none of the flags that only apply to a BuildRun this command creates are
// also set. Those flags would have no effect on an existing BuildRun, so they are rejected with an
// error. Global flags inherited from the root command, such as --namespace, are not checked.
func (u *UploadCommand) checkBuildRunNameConflicts() error {
if u.buildRunName == "" {
return nil
}
// flags that remain valid together with --buildrun-name
allowed := map[string]bool{
flags.BuildrunNameFlag: true,
flags.BuildrefNameFlag: true, // set programmatically from the positional argument
"follow": true,
}
var conflicting []string
u.cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
if f.Changed && !allowed[f.Name] {
conflicting = append(conflicting, "--"+f.Name)
}
})
if len(conflicting) > 0 {
return fmt.Errorf(
Comment thread
psrvere marked this conversation as resolved.
"--%s cannot be combined with %s; set those fields on the BuildRun you create instead",
flags.BuildrunNameFlag, strings.Join(conflicting, ", "),
)
}
return nil
}

Expand Down Expand Up @@ -203,6 +243,36 @@ func (u *UploadCommand) createBuildRun(p *params.Params) (*buildv1beta1.BuildRun
return br, nil
}

// resolveBuildRun returns the BuildRun to stream into: when --buildrun-name is set it fetches the
// existing BuildRun, otherwise it creates a new one.
func (u *UploadCommand) resolveBuildRun(p *params.Params) (*buildv1beta1.BuildRun, error) {
if u.buildRunName == "" {
return u.createBuildRun(p)
}

ns := p.Namespace()
clientset, err := p.ShipwrightClientSet()
if err != nil {
return nil, err
}
br, err := clientset.ShipwrightV1beta1().
BuildRuns(ns).
Get(u.cmd.Context(), u.buildRunName, metav1.GetOptions{})
if err != nil {
return nil, err
}
// the build pod is found by the Build name, so a BuildRun of another Build would never be matched
if br.Spec.Build.Name == nil || *br.Spec.Build.Name != u.buildRefName {
return nil, fmt.Errorf("BuildRun '%s' does not reference Build '%s'", br.GetName(), u.buildRefName)
}
// without a Local source the build pod has no container waiting for the upload
if br.Spec.Source == nil || br.Spec.Source.Type != buildv1beta1.LocalType {
return nil, fmt.Errorf("BuildRun '%s' must have a source of type %q to receive an upload", br.GetName(), buildv1beta1.LocalType)
}
fmt.Fprintf(u.ioStreams.Out, "Streaming into existing BuildRun '%s/%s'...\n", ns, br.GetName())
return br, nil
}

// performDataStreaming execute the data transfer process end-to-end.
func (u *UploadCommand) performDataStreaming(target *streamer.Target) error {
if u.streamingIsDone {
Expand Down Expand Up @@ -282,8 +352,8 @@ func (u *UploadCommand) onPodModifiedEventBundling(pod *corev1.Pod) error {
// Run executes the primary business logic of this subcommand, by starting to watch over the build
// pod status and react accordingly.
func (u *UploadCommand) Run(p *params.Params, ioStreams *genericclioptions.IOStreams) error {
// creating a BuildRun with settings for the local source upload
br, err := u.createBuildRun(p)
// creating a BuildRun with settings for the local source upload, or resolving an existing one
br, err := u.resolveBuildRun(p)
if err != nil {
return err
}
Expand All @@ -307,7 +377,10 @@ func (u *UploadCommand) Run(p *params.Params, ioStreams *genericclioptions.IOStr

// Using streaming to upload local source code
default:
// registering the routine that will react upon build pod state changes
// registering the routine that will react upon build pod state changes; it also handles the
// first event, since the pod of an existing BuildRun may already be running when the watch
// starts and would then only change again when the upload times out
u.pw.WithOnPodAddedFn(u.onPodModifiedEventStreaming)
u.pw.WithOnPodModifiedFn(u.onPodModifiedEventStreaming)
}

Expand Down Expand Up @@ -340,5 +413,16 @@ func uploadCmd() runner.SubCommand {
follow: false,
}
flags.FollowFlag(cmd.Flags(), &u.follow)
buildRunNameFlag(cmd.Flags(), &u.buildRunName)
return u
}

// buildRunNameFlag registers the --buildrun-name flag, storing the value on the informed pointer.
func buildRunNameFlag(flagSet *pflag.FlagSet, buildRunName *string) {
flagSet.StringVar(
buildRunName,
flags.BuildrunNameFlag,
"",
"stream the local source into an existing BuildRun instead of creating one",
)
}
Loading
Loading