Skip to content

feat(projectconfig): add package publish channel annotations to TOML schema#38

Draft
liunan-ms wants to merge 4 commits intomicrosoft:mainfrom
liunan-ms:toml_schema
Draft

feat(projectconfig): add package publish channel annotations to TOML schema#38
liunan-ms wants to merge 4 commits intomicrosoft:mainfrom
liunan-ms:toml_schema

Conversation

@liunan-ms
Copy link
Contributor

This PR introduces a layered package-config configuration for managing binary package publishing in the project. It adds support for per-package and per-group publish settings, allowing fine-grained control over how and where RPMs are published. Publish channel annotation is added into build results.

Schema additions

  • PackagePublishConfig { channel, description }
  • PackageConfig { description, publish: PackagePublishConfig }
  • PackageGroupConfig { description, package-patterns: []glob, default-package-config: PackageConfig }
  • ProjectConfig.DefaultPackageConfig — project-wide baseline (lowest priority)
  • ProjectConfig.PackageGroups — named groups matched by binary package name globs
  • ComponentConfig.DefaultPackageConfig, ComponentConfig.Packages

Publish Channel
channel is a free-form string — it can be any target name, tag, or pipeline-defined label (e.g., "rpm-base", "rpm-build-only", "none"). The build team defines its own channel vocabulary.

Resolution order

For a given binary package name, the resolver applies config in priority order — later layers override earlier ones:

  1. Project default-package-config — the project-wide baseline; lowest priority of all
  2. All matching package-groups — applied in alphabetical group name order for determinism; later-named groups override earlier-named ones for the same field
  3. Component default-package-config — overrides any group default for all packages of that component
  4. Component packages.<exact-name> — highest priority; overrides everything for one specific package

Build output

  • RPMResult struct with Path, PackageName, Channel
  • ComponentBuildResults.RPMs and RPMChannels populated post-build

Examples

  • Create a packages.toml with the content below and imported in project.toml:
# Project-level package publish configuration

[default-package-config]
description = "Project-wide baseline publish channel"
publish = { channel = "rpms-base" }

[package-groups.debug-packages]
description = "Debug info and source — not published"
package-patterns = ["*-debuginfo", "*-debugsource"]

[package-groups.debug-packages.default-package-config.publish]
channel = "rpm-debug"

[package-groups.build-time-deps]
description = "Headers, static libs, and compilers — build deps only, not user-facing"
package-patterns = ["*-devel", "*-headers", "*-static"]

[package-groups.build-time-deps.default-package-config.publish]
channel = "rpm-build-only"
  • Component level configuration:
[components.curl.packages.curl-devel.publish]
channel = "rpm-base"
  • Build output:
image

…schema

Introduces a layered package-config resolution system that annotates each
built binary RPM with a publish channel derived from project config.

Schema additions:
- PackagePublishConfig { channel, description }
- PackageConfig { description, publish }
- PackageGroupConfig { description, package-patterns, default-package-config }
- ProjectConfig.DefaultPackageConfig — project-wide baseline (lowest priority)
- ProjectConfig.PackageGroups — named groups matched by binary package name globs
- ComponentConfig.DefaultPackageConfig, ComponentConfig.Packages

Build output enrichment:
- RPMResult struct with Path, PackageName, Channel
- ComponentBuildResults.RPMs and RPMChannels populated post-build
Copilot AI review requested due to automatic review settings March 20, 2026 20:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds layered per-binary-package publish configuration to projectconfig, and surfaces resolved publish channels in component build output.

Changes:

  • Introduces package-level config types (PackageConfig, PackageGroupConfig, publish channel) plus deterministic resolution/merge logic.
  • Extends project/component config loading and validation to support project defaults and package-groups.
  • Enriches azldev component build results with per-RPM package name + resolved publish channel.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
internal/projectconfig/project.go Adds project-level default-package-config and package-groups to ProjectConfig.
internal/projectconfig/package.go Implements package config structs, validation, and config resolution order.
internal/projectconfig/package_test.go Adds unit tests for group validation, merge behavior, and resolution precedence.
internal/projectconfig/loader.go Merges project default package config and package groups while loading; adds duplicate-group error.
internal/projectconfig/configfile.go Adds TOML fields for defaults/groups and validates group patterns during config-file validation.
internal/projectconfig/component.go Adds component-level default package config and per-package overrides; ensures deep copy in path normalization.
internal/app/azldev/cmds/component/build.go Adds RPM result enrichment (package name + resolved channel) to build results.

Regenerate schemas/azldev.schema.json and scenario snapshots to include
the new default-package-config and package-groups config keys introduced
by the new package.go types.
- Use env.FS() in packageNameFromRPM instead of os.Open to stay
  consistent with the repo's filesystem abstraction and improve
  unit testability
- Add docs/user/reference/config/package-groups.md with full reference
  for package-groups, PackageConfig, and the 4-layer resolution order
- Update docs/user/reference/config/project.md to document
  default-package-config and package-groups top-level fields
- Update docs/user/reference/config/components.md to document
  per-component default-package-config and packages overrides
Copilot AI review requested due to automatic review settings March 20, 2026 21:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

// Path is the absolute path to the RPM file.
Path string `json:"path" table:"Path"`

// PackageName is the binary package name extracted from the RPM filename (e.g., "curl-devel").
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment for RPMResult.PackageName says the name is extracted from the RPM filename, but the implementation populates it by reading the RPM header (Name tag). Please update the comment to match the behavior to avoid misleading consumers.

Suggested change
// PackageName is the binary package name extracted from the RPM filename (e.g., "curl-devel").
// PackageName is the binary package name read from the RPM header Name tag (e.g., "curl-devel").

Copilot uses AI. Check for mistakes.
// packageNameFromRPM extracts the binary package name from an RPM file by reading
// its headers. Reading the Name tag directly from the RPM metadata is authoritative and
// handles all valid package names regardless of naming conventions.
func packageNameFromRPM(fs opctx.FS, rpmPath string) (pkgName string, err error) {
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

packageNameFromRPM uses named return values (pkgName, err) but doesn't rely on deferred modification of returns or need named returns for readability. Consider switching to unnamed returns to match the repo’s usual style and keep return flow clearer.

Suggested change
func packageNameFromRPM(fs opctx.FS, rpmPath string) (pkgName string, err error) {
func packageNameFromRPM(fs opctx.FS, rpmPath string) (string, error) {

Copilot uses AI. Check for mistakes.
Comment on lines +315 to +319
// Enrich each RPM with its binary package name and resolved publish channel.
results.RPMs, err = resolveRPMResults(env.FS(), results.RPMPaths, env.Config(), component.GetConfig())
if err != nil {
return results, fmt.Errorf("failed to resolve publish channels for %q:\n%w", component.GetName(), err)
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New behavior enriches build results with RPM package names/channels (RPMs/RPMChannels), but there are no unit tests exercising this path (e.g., that channels are resolved and populated, and that failures to read RPM metadata surface correctly). Adding focused tests here would prevent regressions; use the in-memory test environment FS and avoid spawning external processes.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +122 to +128
if err := mergeDefaultPackageConfig(resolvedCfg, loadedCfg); err != nil {
return err
}

if err := mergePackageGroups(resolvedCfg, loadedCfg); err != nil {
return err
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loader now merges default-package-config and package-groups, but loader tests don’t appear to cover parsing/merging/duplicate detection for these new fields. Please add loader-level tests (similar to existing component-group/distro tests) to lock down TOML behavior and validation.

Copilot generated this review using guidance from repository custom instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants