Skip to content
2 changes: 1 addition & 1 deletion docs/user/reference/cli/azldev_component_build.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/user/reference/cli/azldev_component_diff-sources.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion docs/user/reference/cli/azldev_component_list.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/user/reference/cli/azldev_component_query.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/user/reference/cli/azldev_component_render.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion docs/user/reference/cli/azldev_component_update.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions internal/app/azldev/cmds/component/changed.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ detected via lock file presence in the compared refs when using -a.`,
RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) {
options.ComponentFilter.ComponentNamePatterns = append(args, options.ComponentFilter.ComponentNamePatterns...)

// Skip lock validation -- this command inspects historical locks at
// arbitrary refs, so HEAD-state validation is irrelevant.
options.ComponentFilter.SkipLockValidation = true

return ChangedComponents(env, options)
}),
ValidArgsFunction: components.GenerateComponentNameCompletions,
Expand Down Expand Up @@ -123,6 +119,10 @@ const (
func ChangedComponents(
env *azldev.Env, options *ChangedComponentOptions,
) ([]ChangedResult, error) {
// Changed compares lock files between git refs — skip validation since
// the current working-tree locks may legitimately be stale.
options.ComponentFilter.SkipLockValidation = true

resolver := components.NewResolver(env)

comps, err := resolver.FindComponents(&options.ComponentFilter)
Expand Down
16 changes: 11 additions & 5 deletions internal/app/azldev/cmds/component/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ Component name patterns support glob syntax (*, ?, []).`,
RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) {
options.ComponentFilter.ComponentNamePatterns = append(args, options.ComponentFilter.ComponentNamePatterns...)

// List is read-only — skip lock validation so users can always
// inspect their components even when locks are stale.
options.ComponentFilter.SkipLockValidation = true

return ListComponentConfigs(env, options)
}),
ValidArgsFunction: components.GenerateComponentNameCompletions,
Expand All @@ -61,15 +57,25 @@ Component name patterns support glob syntax (*, ?, []).`,

components.AddComponentFilterOptionsToCommand(cmd, &options.ComponentFilter)

// List always skips lock validation (read-only), so the flag is
// meaningless here. Hide it to avoid confusion.
_ = cmd.Flags().MarkHidden("skip-lock-validation")

return cmd
}

// Lists components in the env, in accordance with options. Returns the found components.
// ListComponentConfigs lists components in the env, in accordance with options.
// Lock validation is always skipped regardless of the caller's SkipLockValidation
// value — list is read-only.
func ListComponentConfigs(
env *azldev.Env, options *ListComponentOptions,
) (results []projectconfig.ComponentConfig, err error) {
var comps *components.ComponentSet

// List is read-only — skip lock validation so it works even when
// locks are missing or stale.
options.ComponentFilter.SkipLockValidation = true

resolver := components.NewResolver(env)

comps, err = resolver.FindComponents(&options.ComponentFilter)
Expand Down
12 changes: 9 additions & 3 deletions internal/app/azldev/cmds/component/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,6 @@ Cannot be combined with --bump.`,
# CI gate: exit 0 if locks are fresh, 1 if anything would change
azldev component update -a --check-only -q`,
RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) {
// Skip lock validation -- update is the lock file writer.
options.ComponentFilter.SkipLockValidation = true

options.ComponentFilter.ComponentNamePatterns = append(
args, options.ComponentFilter.ComponentNamePatterns...,
)
Expand All @@ -116,6 +113,10 @@ Cannot be combined with --bump.`,

cmd.MarkFlagsMutuallyExclusive("bump", "check-only")

// Update always skips lock validation (it's the lock writer), so the
// flag is meaningless here. Hide it to avoid confusion.
_ = cmd.Flags().MarkHidden("skip-lock-validation")

return cmd
}

Expand Down Expand Up @@ -149,6 +150,8 @@ type UpdateResult struct {

// UpdateComponents resolves source identities for all selected components and
// writes the results to per-component lock files under locks/.
// Lock validation is always skipped regardless of the caller's SkipLockValidation
// value — update is the lock writer.
func UpdateComponents(env *azldev.Env, options *UpdateComponentOptions) ([]UpdateResult, error) {
if options.Bump && options.CheckOnly {
return nil, fmt.Errorf("%w: --bump and --check-only are mutually exclusive", azldev.ErrInvalidUsage)
Expand All @@ -158,6 +161,9 @@ func UpdateComponents(env *azldev.Env, options *UpdateComponentOptions) ([]Updat
// Suppress staleness warnings — we're about to refresh the locks ourselves,
// so warning the user to "run component update" would be self-referential noise.
resolver.SuppressLockWarnings = true
// Skip lock validation — update is the lock file writer, so missing or
// stale locks are expected and will be fixed by this command.
options.ComponentFilter.SkipLockValidation = true
// Enable freshness checking so the resolver computes FreshnessStatus for
// each component. This lets resolveSourceIdentitiesParallel skip
// re-resolution for components whose resolution inputs haven't changed.
Expand Down
4 changes: 3 additions & 1 deletion internal/app/azldev/cmds/component/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ func setupMockGit(env *testutils.TestEnv, commitHash string) {
}
}

// addUpstreamComponent registers an upstream component in the test config.
// addUpstreamComponent adds an upstream component to the test config
// without writing a lock file. Used by update tests where the update command
// itself creates the lock.
func addUpstreamComponent(env *testutils.TestEnv, name string) {
env.Config.Components[name] = projectconfig.ComponentConfig{
Name: name,
Expand Down
8 changes: 2 additions & 6 deletions internal/app/azldev/core/components/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package components

import (
"os"
"strings"

"github.com/microsoft/azure-linux-dev-tools/internal/app/azldev"
Expand All @@ -25,10 +24,7 @@ type ComponentFilter struct {
IncludeAllComponents bool
// SkipLockValidation disables lock file consistency checks for this
// filter's resolution. Commands that write lock files (update) or are
// read-only (list) set this to true. The '--skip-lock-validation' flag
// defaults based on AZLDEV_ENABLE_LOCK_VALIDATION during rollout.
//nolint:godox // tracked by TODO(lockfiles) tag.
// TODO(lockfiles): remove env var gate; default to false (validation on).
// read-only (list) set this to true.
SkipLockValidation bool
}

Expand Down Expand Up @@ -58,7 +54,7 @@ func AddComponentFilterOptionsToCommand(cmd *cobra.Command, filter *ComponentFil
_ = cmd.MarkFlagFilename("spec-path", ".spec")

cmd.Flags().BoolVar(&filter.SkipLockValidation, "skip-lock-validation",
os.Getenv("AZLDEV_ENABLE_LOCK_VALIDATION") != "1",
false,
"skip lock file consistency checks")
Comment thread
dmcilvaney marked this conversation as resolved.
}

Expand Down
12 changes: 4 additions & 8 deletions internal/app/azldev/core/components/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"log/slog"
"os"
"path"
"path/filepath"
"strings"
Expand Down Expand Up @@ -54,13 +53,10 @@ func NewResolver(env *azldev.Env) *Resolver {
// Given a component filter, finds all components defined in the environment that match the filter.
func (r *Resolver) FindComponents(filter *ComponentFilter) (components *ComponentSet, err error) {
// The filter's SkipLockValidation field is the primary control. When
// created via AddComponentFilterOptionsToCommand, its default comes from
// the AZLDEV_ENABLE_LOCK_VALIDATION env var. For programmatic callers
// (including tests), also check the env var here so the rollout gate
// applies uniformly.
//nolint:godox // tracked by TODO(lockfiles) tag.
// TODO(lockfiles): remove env var gate; filter.SkipLockValidation becomes sole control.
skipValidation := filter.SkipLockValidation || os.Getenv("AZLDEV_ENABLE_LOCK_VALIDATION") != "1"
// created via AddComponentFilterOptionsToCommand, its default is false
// (validation on). Commands that write locks (update) or are read-only
// (list) explicitly set it to true.
skipValidation := filter.SkipLockValidation
Comment thread
dmcilvaney marked this conversation as resolved.
Comment thread
dmcilvaney marked this conversation as resolved.

Comment thread
dmcilvaney marked this conversation as resolved.
Comment thread
dmcilvaney marked this conversation as resolved.
// For usability's sake, detect if the caller/user forgot to specify *any* criteria.
if filter.HasNoCriteria() {
Expand Down
Loading
Loading