Repository navigation
feat: add optional unique mock roots - #400
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
Root initialization, reuse, and cleanup across workflows need human validation with real mock beyond the command-capture tests.
No open issues 🎉
What changed in this PR
Adds opt-in mock-root isolation to azldev while preserving default root naming. Each runner receives a bounded, labeled extension that remains stable across commands, clones, and cleanup.
Changes:
- Adds global
--unique-mockrootsupport with action/component labels and a six-character random suffix. - Propagates labels through build, render, query, source-preparation, and advanced mock workflows.
- Adds lifecycle and boundary tests, updates user and agent guidance, and refreshes CLI documentation and help snapshots.
| File | Description |
|---|---|
scenario/__snapshots__/TestSnapshotsContainer_help_stdout_1.snap |
Adds flag to container help snapshot. |
scenario/__snapshots__/TestSnapshotsContainer_--help_stdout_1.snap |
Adds flag to container --help snapshot. |
scenario/__snapshots__/TestSnapshotsContainer_--bogus-flag_stderr_1.snap |
Updates container error-help snapshot. |
scenario/__snapshots__/TestSnapshots_help_stdout_1.snap |
Adds flag to help snapshot. |
scenario/__snapshots__/TestSnapshots_--help_with_color_stdout_1.snap |
Updates colored help snapshot. |
scenario/__snapshots__/TestSnapshots_--help_stdout_1.snap |
Adds flag to --help snapshot. |
scenario/__snapshots__/TestSnapshots_--bogus-flag_stderr_1.snap |
Updates error-help snapshot. |
internal/rpm/mock/uniqueroot.go |
Generates bounded, sanitized root extensions. |
internal/rpm/mock/uniqueroot_test.go |
Tests labels, lifecycle stability, and defaults. |
internal/rpm/mock/mock.go |
Stores, clones, and passes --uniqueext. |
internal/app/azldev/env.go |
Adds root-label context helpers. |
internal/app/azldev/env_test.go |
Tests context propagation and isolation. |
internal/app/azldev/core/workdir/workdir.go |
Labels component build environments. |
internal/app/azldev/core/workdir/workdir_test.go |
Tests component-specific root extensions. |
internal/app/azldev/cmds/component/update.go |
Passes component labels and worker context. |
internal/app/azldev/cmds/component/render.go |
Labels batch rendering and source preparation. |
internal/app/azldev/cmds/component/refreshupstreamcommit.go |
Passes component labels and worker context. |
internal/app/azldev/cmds/component/query.go |
Labels query processor roots. |
internal/app/azldev/cmds/component/preparesources.go |
Labels source-preparation roots. |
internal/app/azldev/cmds/component/diffsources.go |
Labels source-diff roots. |
internal/app/azldev/cmds/component/build.go |
Labels batch and individual builds. |
internal/app/azldev/cmds/advanced/mock.go |
Labels advanced builds and shell sessions. |
internal/app/azldev/cmds/advanced/mock_test.go |
Tests advanced command extension propagation. |
internal/app/azldev/app.go |
Registers and applies the global flag. |
internal/app/azldev/app_test.go |
Tests flag wiring and default behavior. |
internal/app/azldev/agentskill/content/mock.md.tmpl |
Explains unique shell roots and re-entry. |
internal/app/azldev/agentskill/content/build-component.md.tmpl |
Documents isolated builds and inspection. |
internal/app/azldev/agentskill/agentskill_test.go |
Checks emitted unique-root guidance. |
docs/user/reference/cli/azldev.md |
Documents the global flag. |
docs/user/reference/cli/azldev_version.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_repo.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_repo_query.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_repo_compare.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_project.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_project_new.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_project_init.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_package.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_package_list.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image_test.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image_list.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image_inject-files.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image_customize.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image_build.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_image_boot.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_docs.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_docs_markdown.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_docs_agent.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_docs_agent_show.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_docs_agent_install.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_config.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_config_generate-schema.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_config_dump.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_update.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_test.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_render.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_query.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_prepare-sources.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_metadata.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_list.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_history.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_diff-sources.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_changed.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_build.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_component_add.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_completion.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_completion_zsh.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_completion_powershell.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_completion_fish.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_completion_bash.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced_wget.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced_mock.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced_mock_shell.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced_mock_build-rpms.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced_mcp.md |
Lists inherited flag. |
docs/user/reference/cli/azldev_advanced_download-sources.md |
Lists inherited flag. |
docs/user/how-to/build-component.md |
Explains isolation, labels, and preserved-root inspection. |
Review effort: Balanced
| app.cmd.PersistentFlags().BoolVar(&app.uniqueMockRoot, "unique-mockroot", false, | ||
| "use unique mock roots labeled with the action, components, and a random suffix (at most 24 characters)") |
There was a problem hiding this comment.
Copilot can you check the latest commit to see if this is addressed?
|
|
||
| args = append(args, "--configdir", filepath.Dir(r.mockConfigPath)) | ||
| if r.uniqueExtension != "" { | ||
| args = append(args, "--uniqueext", r.uniqueExtension) |
There was a problem hiding this comment.
Is leaving the unique bootstrap roots behind intentional? With bootstrap enabled, --uniqueext gives the bootstrap root a unique name too, but the normal cleanup path still uses --scrub chroot, which only removes the main build root. Previously the retained bootstrap could be reused; with a fresh extension for each runner, wouldn’t these accumulate across components and subsequent commands? Should we also clean up the unique bootstrap root while preserving shared caches, or is there another cleanup mechanism I’m missing?
There was a problem hiding this comment.
wouldn’t these accumulate across components
yes, and mock --scrub-all-chroots doesn't work for any of our mockroots because we aren't doing things correctly and placing our mock config into /etc/mock, so mock doesn't recognize any of our mockroots.
i'll get copilot to address this while using azldev, but directly calling mock will still be basically broken for anything involving azl4 (without specifying multiple parameters to point to our in-repo mock files)
There was a problem hiding this comment.
PTAL to see if copilot correctly fixed your feedback about removing both of the mockroots
Previously the retained bootstrap could be reused
i think the correct way to do this is for us to publish an image and use that, instead of (re)generating a bootstrap mockroot from rpms. that should be part of our work to update our mock configuration upstream.
Add the global --unique-mockroot flag and pass mock a stable --uniqueext for each runner. Limit extensions to 24 characters with component labels of up to 12 characters and a six-character random suffix. Use bld, rndr, qry, and shl for build, render, query, and shell actions. Preserve the extension across runner clones and cleanup without changing default root naming. Propagate component labels through builds, rendering, queries, custom source preparation, and advanced mock commands. Add lifecycle and label boundary tests, update user and agent guidance, and refresh generated CLI docs and help snapshots. Quality checks and affected unit packages pass. Help snapshots were refreshed from verified CLI output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 086236b0-c4cd-4289-ace7-c82d78940883
22447c3 to
c16a09e
Compare
Address review feedback on unique mock roots: - Scrub the bootstrap root along with the main chroot when a unique extension is in use, since mock gives the bootstrap root a unique name too and nothing would reuse or remove it later. - Initialize the fresh unique root before entering `mock --shell` when no packages are being installed, as mock requires an initialized chroot for shell mode. - Add the unique-mockroot flag to the MCP tools/list snapshot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6a5e36c4-2d25-42f4-8047-ba75293d4a6c
Regenerate TestMCPServerMode_1.snap.json so the unique-mockroot property is in the order emitted by the MCP tool schema. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 077c559f-4c80-4bff-86f8-1841925e81b3
When --unique-mockroot is set, 'component build' now builds multiple components in parallel, each with its own mock processor and mock root, bounded by the CPU-bound concurrency limit. Builds stay sequential for a single component or when --local-repo-with-publish is used, since publishing requires ordered builds and mutates shared repo metadata. Add env.UniqueMockRootEnabled() and mock.UniqueRootsEnabled(), update the flag help text, and regenerate CLI docs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 36bd7f34-6b81-42da-b6a1-af2040d23322
|
added commit to parallellize actions if |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved issues include races in the shared event listener, cancellation paths that can skip cleanup or report incomplete builds as successful, and help/MCP snapshots that mismatch the final flag description.
5 open issues
Regenerate help and MCP snapshots for the updated usage text · New Protect the shared event nesting counter from races · New Return an error when cancellation skips queued builds · New Refresh MCP snapshot to include the unique-mockroot flag Detach cleanup from cancellation to remove build roots · New
Review effort: Balanced
| "use unique mock roots labeled with the action, components, and a random suffix (at most 24 characters); "+ | ||
| "allows 'component build' to build multiple components concurrently") |
| func(_ context.Context, component components.Component) buildOutcome { | ||
| // workerEnv (captured) carries the cancellation context. | ||
| //nolint:contextcheck // env carries the ctx | ||
| componentResults, buildErr := BuildComponent(workerEnv, component, workDirFactory, options) |
| if !options.ContinueOnError { | ||
| cancel() |
Protect shared event nesting from concurrent workers, return cancellation when queued builds are skipped, and run chroot cleanup with bounded, cancellation-detached contexts. Refresh CLI and MCP snapshots for the updated --unique-mockroot description. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4b65bb80-fb20-4e66-aaac-2bf4ae60835c
There was a problem hiding this comment.
🔵 Needs a closer look
Human assessment is needed to evaluate shared-SRPM corruption risks, potentially excessive nested parallelism, and missing workflow tests for the new concurrent build path.
4 open issues
1 resolved since last review
Review effort: Balanced
Probe mock help for bootstrap-cache support before scrubbing unique roots. On older versions, scrub only the main root and remove the validated unique bootstrap directory with sudo after mock exits, preserving shared caches. Cover capability detection, custom root paths, cleanup failures, and cache preservation with regression tests, and update user and agent guidance. Validation: mage all passed with refreshed Docker group membership; mage mutationDiff HEAD killed all 24 mutants with none surviving or uncovered. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1dd8217a-74b0-49ad-9004-917ec834302f
There was a problem hiding this comment.
🟡 Changes recommended
With --unique-mockroot --dry-run, empty command output causes ScrubRoot path validation to fail instead of previewing cleanup; capability and path discovery must be skipped during dry runs.
5 open issues
Review effort: Balanced
Skip mock capability and root-path discovery when previewing unique-root cleanup. Keep the wrapped scrub command so dry runs log cleanup without requiring output from commands that are not executed. Preserve dry-run behavior across runner clones, add regression coverage for default and private base directories, and document the cleanup preview. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fc0e0213-1257-4970-b4a6-e865ac20b402
There was a problem hiding this comment.
🔵 Needs a closer look
Human assessment is needed because concurrent builders can share and scrub the same overridden root directory, risking build interference, while parallel scheduling and failure handling lack behavioral tests.
4 open issues
1 resolved since last review
Review effort: Balanced
Pass --disable-plugin yum_cache whenever mock uses --uniqueext, leaving non-unique commands unchanged. Cover the unique-root lifecycle and update user and agent documentation in both lockfile modes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e25b5788-5449-4db1-ae9d-5c235e69dbc5
|
Nan Liu (@liunan-ms) I don't think I have the ACL for Copilot to actually respond to me, and i'm pretty sure most of its earlier complaints have been resolved...can you ask it to please recheck all its open issues to see if any still need attention? |
Nan Liu (liunan-ms)
left a comment
There was a problem hiding this comment.
The changes look good, confirmed that all Copilot comments are addressed in the code.


Add the global --unique-mockroot flag and pass mock a stable --uniqueext for each runner. Limit extensions to 24 characters with component labels of up to 12 characters and a six-character random suffix. Use bld, rndr, qry, and shl for build, render, query, and shell actions. Preserve the extension across runner clones and cleanup without changing default root naming.
Propagate component labels through builds, rendering, queries, custom source preparation, and advanced mock commands. Add lifecycle and label boundary tests, update user and agent guidance, and refresh generated CLI docs and help snapshots.
Quality checks and affected unit packages pass. Help snapshots were refreshed from verified CLI output.