-
Notifications
You must be signed in to change notification settings - Fork 140
feat: add elastic-package requires update command to bump requires pins from the registry
#3593
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
teresaromero
merged 31 commits into
elastic:main
from
teresaromero:requires-update-command
Jun 2, 2026
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
b6aada7
feat: add `elastic-package requires` command to manage package depend…
teresaromero e682a05
refactor: simplify error handling in dependency resolution
teresaromero 0f0fb75
refactor: rename SetRequiresDependencyVersion to setRequiresDependenc…
teresaromero 64bc533
refactor: reorganize requires updates functionality
teresaromero 18cbcff
refactor: streamline requires command output and dependency sorting
teresaromero 0d190d5
feat: add tests for content dependency updates in requires updates
teresaromero aa5c49b
refactor: simplify version replacement logic in manifest handling
teresaromero 1e761d1
test: add unit tests for latestRevision function in updates
teresaromero 8c2f0e6
test: enhance Kibana constraints tests for strict-greater lower bounds
teresaromero 74861af
refactor: use cobraext.GetProfileFlag in requires update command
teresaromero 226e2db
refactor: remove requiresBold duplicate, reuse bold from status.go
teresaromero 99cc538
refactor: remove redundant early return for SkipReason in requires up…
teresaromero e192ceb
refactor: reduce complexity in requiresupdates package
teresaromero 2f1c153
refactor: address remaining requiresupdates review items
teresaromero 4d81ccd
fix: update no-op message for requires update command
teresaromero 1e5f9ad
fix: suppress plain-text output after JSON and on skip in requires up…
teresaromero 9121c05
refactor: replace hardcoded Kibana probe versions with constraint-der…
teresaromero 4e30654
Merge branch 'main' of github.com:elastic/elastic-package into requir…
teresaromero 1c4b472
refactor: replace kibana overlap check with subset check
teresaromero 0f96716
test: complete subset-check test coverage and rename filter function
teresaromero 59f83d8
refactor: fetch all registry versions in a single request and add --p…
teresaromero fa48919
refactor: extract Apply function from Update write loop
teresaromero 8d5ec20
refactor: split Update into Resolve (resolution-only) and delegate Ap…
teresaromero 9e68b52
refactor: replace manifest.go YAML helpers with internal/yamledit
teresaromero a49e987
feat: add debug logging to requires update command
teresaromero d2122f4
docs: fix wording in dependency_management.md requires section
teresaromero f9b3ee3
refactor: expose NewJSONFormatter for non-spec callers and reuse in r…
teresaromero ee2eebe
test: add table-driven unit tests for fetchAllRevisions registry client
teresaromero d3cf953
refactor: convert updates_test.go to table-driven tests
teresaromero 7ad0939
refactor: clean up flag definitions in cobraext package
teresaromero 871d7d9
Merge branch 'main' into requires-update-command
teresaromero File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,221 @@ | ||
| // Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| // or more contributor license agreements. Licensed under the Elastic License; | ||
| // you may not use this file except in compliance with the Elastic License. | ||
|
|
||
| package cmd | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "io" | ||
| "os" | ||
| "path/filepath" | ||
| "slices" | ||
| "strings" | ||
|
|
||
| "github.com/olekukonko/tablewriter" | ||
| "github.com/olekukonko/tablewriter/renderer" | ||
| "github.com/spf13/cobra" | ||
|
|
||
| "github.com/elastic/elastic-package/internal/cobraext" | ||
| "github.com/elastic/elastic-package/internal/formatter" | ||
| "github.com/elastic/elastic-package/internal/install" | ||
| "github.com/elastic/elastic-package/internal/logger" | ||
| "github.com/elastic/elastic-package/internal/packages" | ||
| "github.com/elastic/elastic-package/internal/registry" | ||
| "github.com/elastic/elastic-package/internal/requiresupdates" | ||
| "github.com/elastic/elastic-package/internal/stack" | ||
| ) | ||
|
|
||
| const ( | ||
| requiresLongDescription = `Manage requires dependencies for integration packages (requires.input and requires.content in manifest.yml). | ||
|
|
||
| Use "requires update" to bump requires.input and requires.content versions from the package registry, | ||
| respecting the integration package Kibana version constraint.` | ||
|
|
||
| requiresUpdateLongDescription = `Update requires.input and requires.content pins to the latest registry versions compatible with this package's Kibana constraint. | ||
|
|
||
| By default manifest.yml is updated. Use --dry-run to report available bumps without writing the manifest. | ||
| Version pins must be exact semver versions (constraints such as ^0.3.0 are not accepted). | ||
|
|
||
| When a newer dependency exists but requires a higher Kibana version than this package allows, a warning is printed suggesting to bump conditions.kibana.version on the integration package.` | ||
| ) | ||
|
|
||
| func setupRequiresCommand() *cobraext.Command { | ||
| updateCmd := &cobra.Command{ | ||
| Use: "update", | ||
| Short: "Update requires.input and requires.content versions from the registry", | ||
| Long: requiresUpdateLongDescription, | ||
| Args: cobra.NoArgs, | ||
| RunE: requiresUpdateCommandAction, | ||
| } | ||
| updateCmd.Flags().Bool(cobraext.RequiresDryRunFlagName, false, cobraext.RequiresDryRunFlagDescription) | ||
| updateCmd.Flags().String(cobraext.RequiresFormatFlagName, requiresFormatTable, fmt.Sprintf(cobraext.RequiresFormatFlagDescription, strings.Join(requiresFormatChoices, "|"))) | ||
| updateCmd.Flags().Bool(cobraext.RequiresPrereleaseFlagName, false, cobraext.RequiresPrereleaseFlagDescription) | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have you considered adding a flag to optionally add the changelog automatically?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, still pending to implement it |
||
| cmd := &cobra.Command{ | ||
| Use: "requires", | ||
| Short: "Manage requires dependencies for integration packages", | ||
| Long: requiresLongDescription, | ||
| } | ||
| cmd.AddCommand(updateCmd) | ||
| cmd.PersistentFlags().StringP(cobraext.ProfileFlagName, "p", "", fmt.Sprintf(cobraext.ProfileFlagDescription, install.ProfileNameEnvVar)) | ||
|
|
||
| return cobraext.NewCommand(cmd, cobraext.ContextPackage) | ||
| } | ||
|
|
||
| const ( | ||
| requiresFormatTable = "table" | ||
| requiresFormatJSON = "json" | ||
| ) | ||
|
|
||
| var requiresFormatChoices = []string{requiresFormatTable, requiresFormatJSON} | ||
|
|
||
| func requiresUpdateCommandAction(cmd *cobra.Command, _ []string) error { | ||
| dryRun, err := cmd.Flags().GetBool(cobraext.RequiresDryRunFlagName) | ||
| if err != nil { | ||
| return cobraext.FlagParsingError(err, cobraext.RequiresDryRunFlagName) | ||
| } | ||
| format, err := cmd.Flags().GetString(cobraext.RequiresFormatFlagName) | ||
| if err != nil { | ||
| return cobraext.FlagParsingError(err, cobraext.RequiresFormatFlagName) | ||
| } | ||
| if !slices.Contains(requiresFormatChoices, format) { | ||
| return fmt.Errorf("unsupported format %q, supported formats: %s", format, strings.Join(requiresFormatChoices, ", ")) | ||
| } | ||
| prerelease, err := cmd.Flags().GetBool(cobraext.RequiresPrereleaseFlagName) | ||
| if err != nil { | ||
| return cobraext.FlagParsingError(err, cobraext.RequiresPrereleaseFlagName) | ||
| } | ||
|
|
||
| packageRoot, err := packages.MustFindPackageRoot() | ||
| if err != nil { | ||
| return fmt.Errorf("locating package root failed: %w", err) | ||
| } | ||
|
|
||
| prof, err := cobraext.GetProfileFlag(cmd) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| appConfig, err := install.Configuration() | ||
| if err != nil { | ||
| return fmt.Errorf("loading configuration failed: %w", err) | ||
| } | ||
|
|
||
| baseURL := stack.PackageRegistryBaseURL(prof, appConfig) | ||
| eprClient, err := registry.NewClient(baseURL, stack.RegistryClientOptions(baseURL, prof)...) | ||
| if err != nil { | ||
| return fmt.Errorf("creating package registry client failed: %w", err) | ||
| } | ||
| logger.Debugf("using package registry: %s", baseURL) | ||
|
|
||
| result, err := requiresupdates.Resolve(requiresupdates.Options{ | ||
| PackageRoot: packageRoot, | ||
| RegistryClient: eprClient, | ||
| Prerelease: prerelease, | ||
| }) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| applied := false | ||
| hasBumps := slices.ContainsFunc(result.Proposals, func(p requiresupdates.UpdateProposal) bool { | ||
| return p.Proposed != "" | ||
| }) | ||
| if !dryRun && hasBumps { | ||
| manifestPath := filepath.Join(packageRoot, packages.PackageManifestFile) | ||
| manifestBytes, err := os.ReadFile(manifestPath) | ||
| if err != nil { | ||
| return fmt.Errorf("reading manifest file failed: %w", err) | ||
| } | ||
| manifestBytes, err = requiresupdates.Apply(manifestBytes, result.Proposals) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| logger.Debugf("writing updated manifest: %s", manifestPath) | ||
| if err := os.WriteFile(manifestPath, manifestBytes, 0o644); err != nil { | ||
| return fmt.Errorf("writing manifest file failed: %w", err) | ||
| } | ||
| applied = true | ||
| } | ||
|
|
||
| for _, p := range result.Proposals { | ||
| if p.Warning != "" { | ||
| logger.Warn(p.Warning) | ||
| } | ||
| } | ||
|
|
||
| if err := printRequiresUpdateResult(result, os.Stdout, format); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if format == requiresFormatJSON { | ||
| return nil | ||
| } | ||
|
|
||
| if dryRun && hasBumps { | ||
| cmd.Println("Dry run: manifest.yml was not modified") | ||
| } else if applied { | ||
| cmd.Println("Updated manifest.yml") | ||
| } else if len(result.Proposals) == 0 && result.SkipReason == "" { | ||
| cmd.Println("No dependencies to update") | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func printRequiresUpdateResult(result *requiresupdates.Result, w io.Writer, format string) error { | ||
| if result == nil { | ||
| return nil | ||
| } | ||
| switch format { | ||
| case requiresFormatJSON: | ||
| data, err := formatter.NewJSONFormatter().Encode(result) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| _, err = fmt.Fprintln(w, string(data)) | ||
| return err | ||
| case requiresFormatTable: | ||
| if result.Package != "" { | ||
| bold.Fprint(w, "Package: ") //nolint:errcheck | ||
| fmt.Fprintln(w, result.Package) //nolint:errcheck | ||
| } | ||
| if result.CodeOwner != "" { | ||
| bold.Fprint(w, "Code owner: ") //nolint:errcheck | ||
| fmt.Fprintln(w, result.CodeOwner) //nolint:errcheck | ||
| } | ||
| if result.SkipReason != "" { | ||
| fmt.Fprintln(w, result.SkipReason) //nolint:errcheck | ||
| return nil | ||
| } | ||
| if len(result.Proposals) == 0 { | ||
| return nil | ||
| } | ||
| bold.Fprintln(w, "Requires updates:") //nolint:errcheck | ||
| table := tablewriter.NewTable(w, | ||
| tablewriter.WithRenderer(renderer.NewColorized(defaultColorizedConfig())), | ||
| tablewriter.WithConfig(defaultTableConfig), | ||
| ) | ||
| table.Header([]string{"Kind", "Dependency", "Current", "Proposed", "Kibana", "Warning"}) | ||
| for _, p := range result.Proposals { | ||
| proposed := p.Proposed | ||
| if proposed == "" { | ||
| proposed = "-" | ||
| } | ||
| if err := table.Append([]string{ | ||
| string(p.Kind), | ||
| p.Package, | ||
| p.Current, | ||
| proposed, | ||
| p.KibanaConstraint, | ||
| p.Warning, | ||
| }); err != nil { | ||
| return fmt.Errorf("populating requires update table: %w", err) | ||
| } | ||
| } | ||
| return table.Render() | ||
| default: | ||
| return fmt.Errorf("unsupported format %q", format) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure this will be used on the automated script but i believe is worth enabling it for local use