Repository navigation
Fix state publish meta data issues found testing 0.48.2-RC1 - #3867
icanhasmath wants to merge 5 commits into
Conversation
- state export ingredient-meta writes plain yaml, unwrapped and without field help comments, so the file can be passed back with --meta. - Dependencies and conditions without a version range (a bare name in pyproject.toml, --depend without a version, or a condition inherited without requirements) get >=0. The platform rejected them with "Expecting an OBJECT with a field named 'versionRequirements'". - When --build can't determine the name or version, say which is missing, why pyproject.toml didn't provide it (no file, not in [project], or listed in [project].dynamic), and how to set it. - Answering 'n' at the publish confirmation offers to edit the meta data in the editor or save it to <name>-<version>.meta.yaml with the command to publish it, instead of only cancelling. With --build or --edit, a name, namespace or version change in the editor is saved to a file instead, as the package was already built and looked up with them. - Fields removed in the editor are removed from the request, and the publish API error is shown instead of <no value>. The platform requires the source with every publish, so --edit still needs --build or an archive; the readme now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
echo v4.15.4 has GHSA-cxf3-9h37-7rr8 (critical), GHSA-9969-6676-49h5, GHSA-f48p-c9v4-h7xv and GHSA-h7wr-284f-5qvc, which failed the Scan job. err_uploadingredient_publish is defined in en-us.yaml without a {{.V0}}, so the joined message passed to it was never shown. The wrapped error is already printed beneath it, so drop the argument and the changelog claim.
err_uploadingredient_publish in en-us.yaml ends in "Error received: {{.V0}}"
and overrides the fallback text, so without the argument the message
reads "<no value>". The wrapped API error isn't user-facing, so it isn't
printed beneath it either; it only reaches the log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Restored the |
|
Agreed on the fix in d1d6fa3, and I got this wrong in 2663339. [importance 3 / effort 1] The new code comment's reasoning doesn't match the code for the main failure path. Keeping the argument is still right, because the template needs it. Suggested wording: // en-us.yaml's err_uploadingredient_publish ends in "Error received: {{.V0}}" and overrides the fallback text, so the
// message must be passed in, or the user sees "<no value>".Or, to stop the duplicate on the API path, pass [importance 1 / effort 1] The PR body no longer mentions the |
| // en-us.yaml's err_uploadingredient_publish ends in "Error received: {{.V0}}" and overrides the fallback text, so | ||
| // the message must be passed in: without it the user sees "<no value>", and the wrapped API error is not | ||
| // user-facing, so it would otherwise only appear in the log. |
There was a problem hiding this comment.
[importance 3 / effort 1] The second half of this comment doesn't hold for an API failure. bp.Publish returns client.Run errors through processBuildPlannerError (pkg/platform/model/buildplanner/build.go:158). That gives back either the input error unchanged or a *response.BuildPlannerError, and both are user-facing: BuildPlannerError implements LocaleError() (pkg/platform/api/buildplanner/response/shared.go:29). OutputError.MarshalOutput (internal/runbits/errors/errors.go:67-80) prints every ErrorLocalizer that locale.UnpackError finds in the chain, so the API error is printed beneath this message as well as inside {{.V0}}. Only a request.Publish failure (an errs.Wrap) is shown solely through {{.V0}}.
The argument is still needed. Suggested wording:
| // en-us.yaml's err_uploadingredient_publish ends in "Error received: {{.V0}}" and overrides the fallback text, so | |
| // the message must be passed in: without it the user sees "<no value>", and the wrapped API error is not | |
| // user-facing, so it would otherwise only appear in the log. | |
| // en-us.yaml's err_uploadingredient_publish ends in "Error received: {{.V0}}" and overrides the fallback text, so | |
| // the message must be passed in, or the user sees "<no value>". |
There was a problem hiding this comment.
Agreed for client.Run failures: processBuildPlannerError returns either the input error or a *response.BuildPlannerError, both user-facing, so those print beneath the message as well.
The RC1 failure took the other path, though. "File to upload was not provided" came back in the publish result, and bp.Publish turns that into errs.New("API responded with error: %s", res.Error) (pkg/platform/model/buildplanner/publish.go:21; the RC1 trace's "Created at" points there). That error isn't user-facing, so {{.V0}} is the only place it reaches the user.
I left out the suggested wording because it drops that case. bdd6c7d rewrites the comment to say the argument prevents <no value>, and that it's the only place an error from the publish result gets shown, unlike a BuildPlannerError.
TestOpen removed its temp file while the hail watcher could still be
reading it for a later write event: the remove was deferred after the
cancel, so it ran first. On Windows an open file can't be removed. Stop
the watcher and drain its channel before removing the file.
The publish error comment said the wrapped API error is never printed;
a transport failure becomes a user-facing BuildPlannerError and is. Only
an error reported in the publish result (an errs.New) relies on {{.V0}}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MDrakos
left a comment
There was a problem hiding this comment.
Requesting changes because edits made in the new confirm loop skip the checks that run before it.
The fixes this PR is about aren't guarded by tests. With the fillVersionRequirements calls in Run and FetchMeta removed, OpenInEditor back to the in-place unmarshal, and the errs.JoinMessage(err) argument dropped, go test ./internal/runners/publish/ still passes. TestFillVersionRequirements only covers the helper, and nothing runs export ingredient-meta, so the plain-yaml export could be reverted with CI staying green. I think one test per fix through the real call path (a fake prompt.Prompter works for the loop, and $EDITOR pointed at a script for the editor path) would keep these from regressing before the next RC.
1 inline comment below.
| // Until the user confirms, they can edit the prepared meta data or save it to a file and start over with it. | ||
| for { | ||
| if params.Build != "" { | ||
| addPrivateBuilderDependency(&reqVars) // again, in case it was removed in the editor | ||
| } | ||
| fillVersionRequirements(&reqVars) |
There was a problem hiding this comment.
An edit made in the new confirm loop skips the checks that ran before it. If you clear namespace in the editor you get the vague "either Path of Name and Namespace are required" from MarshalJSON, and checkEditKeepsIdentity never sees authors or description added on a revision. imo the simplest fix is to run both checks at the top of each pass:
| // Until the user confirms, they can edit the prepared meta data or save it to a file and start over with it. | |
| for { | |
| if params.Build != "" { | |
| addPrivateBuilderDependency(&reqVars) // again, in case it was removed in the editor | |
| } | |
| fillVersionRequirements(&reqVars) | |
| // Until the user confirms, they can edit the prepared meta data or save it to a file and start over with it. | |
| for { | |
| if params.Build != "" { | |
| addPrivateBuilderDependency(&reqVars) // again, in case it was removed in the editor | |
| } | |
| fillVersionRequirements(&reqVars) | |
| if reqVars.Namespace == "" { | |
| return locale.NewInputError("err_uploadingredient_namespace_required", "You have to supply the namespace when working outside of a project context") | |
| } | |
| if err := checkEditKeepsIdentity(&reqVars, params.Edit, isRevision); err != nil { | |
| return err | |
| } |
There was a problem hiding this comment.
Agreed, done in 8ecef8d. The loop is now confirmRequest, and each pass re-adds the private-builder (for --build), fills empty version requirements, then checks the namespace and checkEditKeepsIdentity before showing the request. I removed the pre-loop copies of both checks, since the first pass now does them. One small change in behaviour: with --editor, a description given on a revision is now rejected after the editor closes instead of before it opens.
New tests cover both cases through the editor: a cleared namespace gives the namespace error, and a description added on a revision gives the identity error.
…all paths Address review on #3867: - Run the namespace and checkEditKeepsIdentity checks at the top of each pass of the confirm loop, now confirmRequest, so a namespace cleared or a description added in the editor is rejected with a clear message instead of failing in MarshalJSON or the API. - Add tests that fail if a fix is reverted: confirmRequest with a fake prompter (>=0 filling, editor removing fields, cleared namespace, description on a revision, private-builder restored, save, cancel), using the test binary as $EDITOR so it also runs on Windows; publishFailedError keeping the API error; metaFromIngredient filling conditions; and writeIngredientMeta writing plain yaml that round-trips. FetchMeta's pure part moves into metaFromIngredient and the export's writing into writeIngredientMeta so they can be tested without the API. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@MDrakos thanks. I've added tests through the real call paths in 8ecef8d. Each one fails when its fix is reverted (I checked each by hand):
The loop tests run On the earlier note about duplicates: an error from a failed request now shows twice (inside |
Fixes for
state publish/state export ingredient-metafound while testing 0.48.2-RC1 (PROD-240). Targetsversion/0-48-2-RC2, which isbeta(0.48.2-RC1) plus theversion.txtbump.Export output was not a valid meta file.
state export ingredient-metaprinted the publish prompt's yaml, with a# ...help comment above every field, through the plain outputer, which word-wraps to the terminal width in an interactive shell. The wrapped comments turned into non-comment lines. It now writes plain yaml straight to stdout.Expecting an OBJECT with a field named 'versionRequirements'. A dependency without a version range (a barerequestsinpyproject.toml,--dependwithout a version, or a condition such askernel/Windowsinherited without requirements, which also made the exported file incomplete) had an emptyversionRequirements, which is omitted from the request. Empty requirements are now>=0, both when publishing and when exporting.Unclear error when pyproject.toml lacks the name or version. The error now lists each missing field, why it wasn't found (no
pyproject.toml, not in[project], or listed in[project].dynamic), and where to set it (pyproject.toml,--name/--version, or a--metafile).Fixing the meta data before publishing. The
Y/nconfirmation is unchanged (defaults,-nand--forcebehave as before), but answeringnnow offers:$EDITOR, then asks again. With--buildor--edit, changing the name, namespace or version there would no longer match the built package or the looked-up ingredient, so those edits are saved to a file with instructions to re-run instead.<name>-<version>.meta.yaml(asks before replacing) and prints the command to publish it, e.g.state publish --build ./src --meta mypkg-1.0.0.meta.yaml.Every pass of the confirmation re-adds the private-builder for
--build, fills empty requirements, and checks the namespace and that a revision's authors and description are unchanged. An edit can't skip those checks.Also: fields deleted in the editor are now removed from the publish instead of keeping their old values, and a failed publish shows the API error instead of
Error received: <no value>(en-us.yaml'serr_uploadingredient_publishneeds it as{{.V0}}).Security:
github.com/labstack/echo/v44.15.4 → 4.16.1 (GHSA-cxf3-9h37-7rr8 critical, GHSA-9969-6676-49h5, GHSA-f48p-c9v4-h7xv, GHSA-h7wr-284f-5qvc), which failed the Scan job.Not changed:
--editstill needs the source. Thepublishmutation requiresfileon every publish and has no way to reference the existing upload, so a metadata-only edit would need a platform change. The readme now says to pass--buildwith--edit.Testing
confirmRequestwith a fake prompter and the test binary as$EDITOR(filling requirements, removing fields, cleared namespace, description on a revision, private-builder, save, cancel),publishFailedError,metaFromIngredientandwriteIngredientMeta.Cancel Publishintegration test selects the defaultCancelafter answeringn.internal/hailTestOpenfailing intermittently on Windows (it removed the file while the watcher could still be reading it).🤖 Generated with Claude Code