diff --git a/internal/runbits/runtime/requirements/requirements.go b/internal/runbits/runtime/requirements/requirements.go index 2485d893ad..59b3b3ae17 100644 --- a/internal/runbits/runtime/requirements/requirements.go +++ b/internal/runbits/runtime/requirements/requirements.go @@ -21,11 +21,11 @@ import ( "github.com/ActiveState/cli/internal/primer" "github.com/ActiveState/cli/internal/prompt" "github.com/ActiveState/cli/internal/rtutils/ptr" - "github.com/ActiveState/cli/internal/runbits/buildscript" + buildscript_runbit "github.com/ActiveState/cli/internal/runbits/buildscript" "github.com/ActiveState/cli/internal/runbits/cves" "github.com/ActiveState/cli/internal/runbits/dependencies" "github.com/ActiveState/cli/internal/runbits/rationalize" - "github.com/ActiveState/cli/internal/runbits/runtime" + runtime_runbit "github.com/ActiveState/cli/internal/runbits/runtime" "github.com/ActiveState/cli/internal/runbits/runtime/trigger" "github.com/ActiveState/cli/pkg/buildplan" "github.com/ActiveState/cli/pkg/buildscript" @@ -214,10 +214,14 @@ func (r *RequirementOperation) ExecuteRequirementOperation(ts *time.Time, requir Script: script, } - commitID, err := bp.StageCommit(params) + // Solve runtime + solveSpinner := output.StartSpinner(r.Output, locale.T("progress_solve_preruntime"), constants.TerminalAnimationInterval) + commit, err := bp.StageCommit(params) if err != nil { + solveSpinner.Stop(locale.T("progress_fail")) return locale.WrapError(err, "err_package_save_and_build", "Error occurred while trying to create a commit") } + solveSpinner.Stop(locale.T("progress_success")) pg.Stop(locale.T("progress_success")) pg = nil @@ -233,32 +237,22 @@ func (r *RequirementOperation) ExecuteRequirementOperation(ts *time.Time, requir trig = trigger.TriggerPackage } - // Solve runtime - solveSpinner := output.StartSpinner(r.Output, locale.T("progress_solve_preruntime"), constants.TerminalAnimationInterval) - bpm := bpModel.NewBuildPlannerModel(r.Auth) - rtCommit, err := bpm.FetchCommit(commitID, r.Project.Owner(), r.Project.Name(), nil) - if err != nil { - solveSpinner.Stop(locale.T("progress_fail")) - return errs.Wrap(err, "Failed to fetch build result") - } - solveSpinner.Stop(locale.T("progress_success")) - var oldBuildPlan *buildplan.BuildPlan - if rtCommit.ParentID != "" { + if commit.ParentID != "" { bpm := bpModel.NewBuildPlannerModel(r.Auth) - commit, err := bpm.FetchCommit(rtCommit.ParentID, r.Project.Owner(), r.Project.Name(), nil) + oldCommit, err := bpm.FetchCommit(commit.ParentID, r.Project.Owner(), r.Project.Name(), nil) if err != nil { return errs.Wrap(err, "Failed to fetch build result") } - oldBuildPlan = commit.BuildPlan() + oldBuildPlan = oldCommit.BuildPlan() } r.Output.Notice("") // blank line - dependencies.OutputChangeSummary(r.Output, rtCommit.BuildPlan(), oldBuildPlan) + dependencies.OutputChangeSummary(r.Output, commit.BuildPlan(), oldBuildPlan) // Report CVEs names := requirementNames(requirements...) - if err := cves.NewCveReport(r.prime).Report(rtCommit.BuildPlan(), oldBuildPlan, names...); err != nil { + if err := cves.NewCveReport(r.prime).Report(commit.BuildPlan(), oldBuildPlan, names...); err != nil { return errs.Wrap(err, "Could not report CVEs") } @@ -268,13 +262,13 @@ func (r *RequirementOperation) ExecuteRequirementOperation(ts *time.Time, requir // refresh or install runtime _, err = runtime_runbit.Update(r.prime, trig, - runtime_runbit.WithCommit(rtCommit), + runtime_runbit.WithCommit(commit), runtime_runbit.WithoutBuildscriptValidation(), ) if err != nil { if !IsBuildError(err) { // If the error is not a build error we want to retain the changes - if err2 := r.updateCommitID(commitID); err2 != nil { + if err2 := r.updateCommitID(commit.CommitID); err2 != nil { return errs.Pack(err, locale.WrapError(err2, "err_package_update_commit_id")) } } @@ -282,7 +276,7 @@ func (r *RequirementOperation) ExecuteRequirementOperation(ts *time.Time, requir } } - if err := r.updateCommitID(commitID); err != nil { + if err := r.updateCommitID(commit.CommitID); err != nil { return locale.WrapError(err, "err_package_update_commit_id") } diff --git a/internal/runners/commit/commit.go b/internal/runners/commit/commit.go index 8deb3fc19f..17b18484ef 100644 --- a/internal/runners/commit/commit.go +++ b/internal/runners/commit/commit.go @@ -8,7 +8,7 @@ import ( "github.com/ActiveState/cli/internal/locale" "github.com/ActiveState/cli/internal/output" "github.com/ActiveState/cli/internal/primer" - "github.com/ActiveState/cli/internal/runbits/buildscript" + buildscript_runbit "github.com/ActiveState/cli/internal/runbits/buildscript" "github.com/ActiveState/cli/internal/runbits/cves" "github.com/ActiveState/cli/internal/runbits/dependencies" "github.com/ActiveState/cli/internal/runbits/rationalize" @@ -106,7 +106,7 @@ func (c *Commit) Run() (rerr error) { } }() - stagedCommitID, err := bp.StageCommit(buildplanner.StageCommitParams{ + stagedCommit, err := bp.StageCommit(buildplanner.StageCommitParams{ Owner: proj.Owner(), Project: proj.Name(), ParentCommit: localCommitID.String(), @@ -117,12 +117,12 @@ func (c *Commit) Run() (rerr error) { } // Update local commit ID - if err := localcommit.Set(proj.Dir(), stagedCommitID.String()); err != nil { + if err := localcommit.Set(proj.Dir(), stagedCommit.CommitID.String()); err != nil { return errs.Wrap(err, "Could not set local commit ID") } // Update our local build expression to match the committed one. This allows our API a way to ensure forward compatibility. - newScript, err := bp.GetBuildScript(stagedCommitID.String()) + newScript, err := bp.GetBuildScript(stagedCommit.CommitID.String()) if err != nil { return errs.Wrap(err, "Unable to get the remote build script") } @@ -141,7 +141,7 @@ func (c *Commit) Run() (rerr error) { }() // Solve runtime - rtCommit, err := bp.FetchCommit(stagedCommitID, proj.Owner(), proj.Name(), nil) + rtCommit, err := bp.FetchCommit(stagedCommit.CommitID, proj.Owner(), proj.Name(), nil) if err != nil { return errs.Wrap(err, "Could not fetch staged commit") } @@ -167,7 +167,7 @@ func (c *Commit) Run() (rerr error) { out.Print(output.Prepare( locale.Tl( "commit_success", - "", stagedCommitID.String(), proj.NamespaceString(), + "", stagedCommit.CommitID.String(), proj.NamespaceString(), ), &struct { Namespace string `json:"namespace"` @@ -176,7 +176,7 @@ func (c *Commit) Run() (rerr error) { }{ proj.NamespaceString(), proj.Dir(), - stagedCommitID.String(), + stagedCommit.CommitID.String(), }, )) diff --git a/internal/runners/packages/import.go b/internal/runners/packages/import.go index 4977d7846f..035776ddda 100644 --- a/internal/runners/packages/import.go +++ b/internal/runners/packages/import.go @@ -14,7 +14,7 @@ import ( "github.com/ActiveState/cli/internal/runbits/dependencies" "github.com/ActiveState/cli/internal/runbits/org" "github.com/ActiveState/cli/internal/runbits/rationalize" - "github.com/ActiveState/cli/internal/runbits/runtime" + runtime_runbit "github.com/ActiveState/cli/internal/runbits/runtime" "github.com/ActiveState/cli/internal/runbits/runtime/trigger" "github.com/ActiveState/cli/pkg/buildscript" "github.com/ActiveState/cli/pkg/localcommit" @@ -126,7 +126,7 @@ func (i *Import) Run(params *ImportRunParams) (rerr error) { } msg := locale.T("commit_reqstext_message") - stagedCommitId, err := bp.StageCommit(buildplanner.StageCommitParams{ + stagedCommit, err := bp.StageCommit(buildplanner.StageCommitParams{ Owner: proj.Owner(), Project: proj.Name(), ParentCommit: localCommitId.String(), @@ -140,12 +140,12 @@ func (i *Import) Run(params *ImportRunParams) (rerr error) { pg.Stop(locale.T("progress_success")) pg = nil - if err := localcommit.Set(proj.Dir(), stagedCommitId.String()); err != nil { + if err := localcommit.Set(proj.Dir(), stagedCommit.CommitID.String()); err != nil { return locale.WrapError(err, "err_package_update_commit_id") } // Solve the runtime. - rtCommit, err := bp.FetchCommit(stagedCommitId, proj.Owner(), proj.Name(), nil) + rtCommit, err := bp.FetchCommit(stagedCommit.CommitID, proj.Owner(), proj.Name(), nil) if err != nil { return errs.Wrap(err, "Failed to fetch build result for staged commit") } @@ -164,7 +164,7 @@ func (i *Import) Run(params *ImportRunParams) (rerr error) { return errs.Wrap(err, "Could not report CVEs") } - _, err = runtime_runbit.Update(i.prime, trigger.TriggerImport, runtime_runbit.WithCommitID(stagedCommitId)) + _, err = runtime_runbit.Update(i.prime, trigger.TriggerImport, runtime_runbit.WithCommitID(stagedCommit.CommitID)) if err != nil { return errs.Wrap(err, "Runtime update failed") } diff --git a/internal/runners/revert/revert.go b/internal/runners/revert/revert.go index 46b7646e0d..6ac4641c91 100644 --- a/internal/runners/revert/revert.go +++ b/internal/runners/revert/revert.go @@ -12,7 +12,7 @@ import ( "github.com/ActiveState/cli/internal/prompt" "github.com/ActiveState/cli/internal/runbits/commit" "github.com/ActiveState/cli/internal/runbits/rationalize" - "github.com/ActiveState/cli/internal/runbits/runtime" + runtime_runbit "github.com/ActiveState/cli/internal/runbits/runtime" "github.com/ActiveState/cli/internal/runbits/runtime/trigger" "github.com/ActiveState/cli/pkg/localcommit" gqlmodel "github.com/ActiveState/cli/pkg/platform/api/graphql/model" @@ -208,10 +208,10 @@ func (r *Revert) revertToCommit(params revertParams, bp *buildplanner.BuildPlann Script: bs, } - newCommitID, err := bp.StageCommit(stageCommitParams) + newCommit, err := bp.StageCommit(stageCommitParams) if err != nil { return "", errs.Wrap(err, "Could not stage commit") } - return newCommitID, nil + return newCommit.CommitID, nil } diff --git a/pkg/platform/api/buildplanner/request/stagecommit.go b/pkg/platform/api/buildplanner/request/stagecommit.go index 286b63fbd2..16b5f9d30c 100644 --- a/pkg/platform/api/buildplanner/request/stagecommit.go +++ b/pkg/platform/api/buildplanner/request/stagecommit.go @@ -35,6 +35,168 @@ mutation ($organization: String!, $project: String!, $parentCommit: ID!, $descri __typename expr commitId + build { + __typename + ... on BuildCompleted { + buildLogIds { + ... on AltBuildId { + id + } + } + } + ... on BuildStarted { + buildLogIds { + ... on AltBuildId { + id + } + } + } + ... on Build { + status + terminals { + tag + nodeIds + } + sources: nodes { + ... on Source { + nodeId + ingredientID + ingredientVersionID + revision + name + namespace + version + licenses + } + } + steps: steps { + ... on Step { + stepId + inputs { + tag + nodeIds + } + outputs + } + } + artifacts: nodes { + ... on ArtifactSucceeded { + __typename + nodeId + displayName + mimeType + generatedBy + runtimeDependencies + status + logURL + url + checksum + } + ... on ArtifactUnbuilt { + __typename + nodeId + displayName + mimeType + generatedBy + runtimeDependencies + status + } + ... on ArtifactStarted { + __typename + nodeId + displayName + mimeType + generatedBy + runtimeDependencies + status + } + ... on ArtifactTransientlyFailed { + __typename + nodeId + displayName + mimeType + generatedBy + runtimeDependencies + status + logURL + errors + attempts + nextAttemptAt + } + ... on ArtifactPermanentlyFailed { + __typename + nodeId + displayName + mimeType + generatedBy + runtimeDependencies + status + logURL + errors + } + ... on ArtifactFailed { + __typename + nodeId + displayName + mimeType + generatedBy + runtimeDependencies + status + logURL + errors + } + } + resolvedRequirements { + requirement { + name + namespace + version_requirements: versionRequirements { + comparator + version + } + } + resolvedSource + } + } + ... on Error { + message + } + ... on PlanningError { + message + subErrors { + __typename + ... on GenericSolveError { + path + message + isTransient + validationErrors { + error + jsonPath + } + } + ... on RemediableSolveError { + path + message + isTransient + errorType + validationErrors { + error + jsonPath + } + suggestedRemediations { + remediationType + command + parameters + } + } + ... on TargetNotFound { + message + requestedTarget + possibleTargets + } + } + } + } } ... on Error { __typename @@ -69,7 +231,7 @@ mutation ($organization: String!, $project: String!, $parentCommit: ID!, $descri commitId message } - ...on ValidationError { + ... on ValidationError { __typename subErrors { __typename diff --git a/pkg/platform/model/buildplanner/commit.go b/pkg/platform/model/buildplanner/commit.go index 66710d43a0..e558b29273 100644 --- a/pkg/platform/model/buildplanner/commit.go +++ b/pkg/platform/model/buildplanner/commit.go @@ -1,8 +1,13 @@ package buildplanner import ( + "time" + "github.com/ActiveState/cli/internal/errs" "github.com/ActiveState/cli/internal/logging" + "github.com/ActiveState/cli/internal/rtutils/ptr" + "github.com/ActiveState/cli/pkg/buildplan" + "github.com/ActiveState/cli/pkg/buildplan/raw" "github.com/ActiveState/cli/pkg/buildscript" "github.com/ActiveState/cli/pkg/platform/api/buildplanner/request" "github.com/ActiveState/cli/pkg/platform/api/buildplanner/response" @@ -26,39 +31,61 @@ type StageCommitParams struct { Script *buildscript.BuildScript } -func (b *BuildPlanner) StageCommit(params StageCommitParams) (strfmt.UUID, error) { +func (b *BuildPlanner) StageCommit(params StageCommitParams) (*Commit, error) { logging.Debug("StageCommit, params: %+v", params) script := params.Script if script == nil { - return "", errs.New("Script is nil") + return nil, errs.New("Script is nil") } expression, err := script.MarshalBuildExpression() if err != nil { - return "", errs.Wrap(err, "Failed to marshal build expression") + return nil, errs.Wrap(err, "Failed to marshal build expression") } // With the updated build expression call the stage commit mutation request := request.StageCommit(params.Owner, params.Project, params.ParentCommit, params.Description, script.AtTime(), expression) resp := &response.StageCommitResult{} if err := b.client.Run(request, resp); err != nil { - return "", processBuildPlannerError(err, "failed to stage commit") + return nil, processBuildPlannerError(err, "failed to stage commit") } if resp.Commit == nil { - return "", errs.New("Staged commit is nil") + return nil, errs.New("Staged commit is nil") } if response.IsErrorResponse(resp.Commit.Type) { - return "", response.ProcessCommitError(resp.Commit, "Could not process error response from stage commit") + return nil, response.ProcessCommitError(resp.Commit, "Could not process error response from stage commit") } if resp.Commit.CommitID == "" { - return "", errs.New("Staged commit does not contain commitID") + return nil, errs.New("Staged commit does not contain commitID") + } + + // The BuildPlanner will return a build plan with a status of + // "planning" if the build plan is not ready yet. We need to + // poll the BuildPlanner until the build is ready. + if resp.Commit.Build.Status == raw.Planning { + resp.Commit.Build, err = b.pollBuildPlanned(resp.Commit.CommitID.String(), params.Owner, params.Project, nil) + if err != nil { + return nil, errs.Wrap(err, "failed to poll build plan") + } + } + + commit := resp.Commit + + bp, err := buildplan.Unmarshal(commit.Build.RawMessage) + if err != nil { + return nil, errs.Wrap(err, "failed to unmarshal build plan") + } + + stagedScript, err := buildscript.UnmarshalBuildExpression(commit.Expression, ptr.To(time.Time(commit.AtTime))) + if err != nil { + return nil, errs.Wrap(err, "failed to parse build expression") } - return resp.Commit.CommitID, nil + return &Commit{commit, bp, stagedScript}, nil } func (b *BuildPlanner) RevertCommit(organization, project, parentCommitID, commitID string) (strfmt.UUID, error) {