Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions docs/user/reference/config/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ The `[components.<name>.release]` section controls how azldev manages the Releas

| Mode | Behavior |
|------|----------|
| `auto` | Auto-detects from the spec's Release tag value. If `%autorelease` is found, rpmautospec handles it. If a static integer is found, optionally followed by `%{?dist}` or `%{dist}`, it is bumped by the synthetic commit count. |
| `auto` | Auto-detects `%autorelease` and leaves it to rpmautospec. All other Release forms are bumped by `rpmdev-bumpspec`, once for each fingerprint-derived synthetic change. |
| `autorelease` | Explicitly declares the spec uses `%autorelease`. Skips all Release manipulation. Use this for specs with conditional `%autorelease`/`%else` fallbacks that confuse auto-detection. |
| `static` | Explicitly declares the spec uses a static integer release. Bumps it by the synthetic commit count only when the Release tag is an integer, optionally followed by `%{?dist}` or `%{dist}`. Non-integer or other non-standard Release values (for example, `%{pkg_release}`) require `manual` or an overlay. |
| `static` | Requires a non-`%autorelease` Release and invokes `rpmdev-bumpspec` once for each fingerprint-derived synthetic change. rpmdev-bumpspec natively attempts integer, dotted, macro, conditional, and fallback forms; azldev accepts the operation only when host RPM evaluation proves the source Release is strictly newer. Inactive conditional definitions or otherwise ineffective mutations fail and restore the original spec. |
| `manual` | Skips all automatic Release manipulation. Use for components that manage their own release numbering (e.g. kernel). |

Most components use `auto` (the default) and need no release configuration. Examples:
Expand All @@ -129,6 +129,33 @@ calculation = "autorelease"
calculation = "manual"
```

### Host requirement and troubleshooting

Automatic non-`%autorelease` release handling requires `rpmdev-bumpspec`,
`rpmdev-packager`, `rpm`, `rpmspec`, and `python3` with the RPM Python module. The
tested implementation is `rpmdevtools` 9.6 (`rpmdev-bumpspec` 1.0.13), but azldev
accepts a behaviorally compatible newer implementation: it evaluates exactly the
source package EVR with `rpmspec --srpm` before and after every bump and verifies that
RPM orders the new Release strictly higher. azldev converts `build.with` and
`build.without` to their effective `_with_<name>` and `_without_<name>` macro
definitions, then applies explicit defines and undefines with the same precedence as
the build. A component build also passes `target_arch` from `--mock-config-opt` to
both evaluations and the wrapped RPM command; render and `prepare-sources` use the
host RPM target when no target is otherwise available. azldev uses normal host vendor
macros, an isolated HOME, and fixed locale/timezone. If render, build, or
`prepare-sources` (which creates dist-git by default; `--without-git` opts out)
reports a missing or incompatible tool, provision the host runtime rather than adding
a Release overlay.

This is a transitional mutation engine: locks and synthetic history still determine
the ordered fingerprint changes, and azldev invokes `rpmdev-bumpspec` once per
change. Each invocation uses the fixed Azure Linux Packaging Team identity, `- rebuilt`
comment, and `Mon Jan 06 2025` datestamp, so fingerprint author/message/time data do
not affect generated release or changelog bytes. The tool may update both `Release:`
(or its preferred release macro) and `%changelog`; `%autorelease` remains unchanged.
This does not introduce lock-free release calculation or redesign final changelog
ordering.

## Render Configuration

The `[components.<name>.render]` section controls rendering behavior for a component.
Expand Down
9 changes: 9 additions & 0 deletions internal/app/azldev/agentskill/agentskill_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ func TestUpdateComponentSkillStagesRenderedOutputBeforeAmend(t *testing.T) {
"both amend workflows must stage the post-commit render")
}

func TestComponentSkillDocumentsRPMDevBumpspecReleaseHandling(t *testing.T) {
doc, err := agentskill.SkillDocument("azldev-comp-toml", testParams())
require.NoError(t, err)

assert.Contains(t, doc, "rpmdevtools` 9.6")
assert.Contains(t, doc, "fingerprint-derived synthetic change")
assert.Contains(t, doc, "only when host RPM evaluation proves the")
}

func TestImageSkillDocumentsRuntimeConfigOverride(t *testing.T) {
doc, err := agentskill.SkillDocument("azldev-image", testParams())
require.NoError(t, err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ Finalize with `azldev comp update -p <name>` before opening a PR (see the

## Debugging build failures

1. **Render error mentioning a non-standard `Release` tag** — a release-calculation
issue; see the `azldev-comp-toml` skill.
1. **Render error mentioning `rpmdev-bumpspec` or RPM macros** — provision
`rpmdev-bumpspec`, `rpmdev-packager`, `rpm`, `rpmspec`, and `python3-rpm`.
rpmdevtools 9.6 (`rpmdev-bumpspec` 1.0.13) is tested; behaviorally compatible
newer tools are accepted. azldev evaluates one source EVR with `rpmspec --srpm`
and verifies RPM ordering, using effective bcond macro definitions and the build
target when one is configured; see the `azldev-comp-toml` skill.
2. **Overlay did not apply as expected** — `azldev comp diff-sources -p <name>` shows
what the overlays actually change.
3. **Inspect the build environment** — `azldev comp build -p <name> --preserve-buildenv
Expand Down
26 changes: 21 additions & 5 deletions internal/app/azldev/agentskill/content/comp-toml.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,17 @@ without = ["plugin_rhsm"] # disable %bcond_with conditionals

`release.calculation` controls the `Release:` tag. There are four modes:

- `auto` (default) — auto-detect whether the spec uses `%autorelease` or a static
release and handle it accordingly. Correct for most packages.
- `auto` (default) — leave `%autorelease` unchanged; otherwise invoke
`rpmdev-bumpspec` once for each fingerprint-derived synthetic change.
- `autorelease` — force `%autorelease` handling (use when auto-detection misreads a
spec that wraps `%autorelease` in a conditional).
- `static` — force static-integer handling and bump the integer on render (the
inverse of `autorelease`).
- `static` — require a non-`%autorelease` release and invoke `rpmdev-bumpspec`.
It natively attempts integer, dotted, macro, conditional, and fallback Release
forms, but azldev accepts an operation only when host RPM evaluation proves the
source Release is strictly newer. Inactive conditional definitions or otherwise
ineffective mutations fail and restore the original spec.
- `manual` — you own the `Release:` value. Use this only when render fails with a
"non-standard Release tag" error. **A `manual` component is not bumped by the
automatic Release tool. **A `manual` component is not bumped by the
render/commit/amend cycle, so increment its release yourself in the same change**
(see the `azldev-update-component` skill).

Expand All @@ -84,6 +87,19 @@ without = ["plugin_rhsm"] # disable %bcond_with conditionals
calculation = "manual"
```

Non-`%autorelease` rendering requires `rpmdev-bumpspec`, `rpmdev-packager`, `rpm`,
`rpmspec`, and `python3` with its RPM module. `rpmdevtools` 9.6 /
`rpmdev-bumpspec` 1.0.13 is the tested implementation; newer behaviorally compatible
tools are accepted only when `rpmspec --srpm` evaluates source
Name/Epoch/Version/Release before and after the operation and RPM orders the Release
strictly higher. Build bconds are evaluated as effective `_with_<name>` and
`_without_<name>` macro definitions, with explicit defines and undefines retaining
their usual precedence. A build's `--mock-config-opt target_arch=...` is also passed
to both evaluations and the wrapped RPM command. azldev uses normal host vendor macros
and fixed team identity/comment/datestamp inputs, so fingerprint metadata does not
alter the generated release or changelog bytes. Locks and synthetic history still
determine the number and order of bumps.

## Render configuration

`render.skip-file-filter = true` keeps all source and patch files during render.
Expand Down
1 change: 1 addition & 0 deletions internal/app/azldev/cmds/component/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ func buildComponent(
if !options.WithoutGitRepo {
preparerOpts = append(preparerOpts,
sources.WithGitRepo(env, env.LockReader(), distro.Version.ReleaseVer),
sources.WithRPMDevBumpspec(env, env.WorkDir(), options.MockConfigOpts["target_arch"]),
sources.WithDirtyDetection(),
)
}
Expand Down
7 changes: 7 additions & 0 deletions internal/app/azldev/cmds/component/preparesources.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ func PrepareComponentSources(env *azldev.Env, options *PrepareSourcesOptions) er
"synthetic history requires overlays to be applied")
}

if !options.WithoutGitRepo && !options.SkipOverlays {
if err := fileutils.MkdirAll(env.FS(), env.WorkDir()); err != nil {
return fmt.Errorf("failed to create work directory %#q:\n%w", env.WorkDir(), err)
}
}

preparerOpts := buildPreparerOptions(env, distro, options)

preparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, preparerOpts...)
Expand Down Expand Up @@ -157,6 +163,7 @@ func buildPreparerOptions(
if !options.WithoutGitRepo && !options.SkipOverlays {
opts = append(opts,
sources.WithGitRepo(env, env.LockReader(), distro.Version.ReleaseVer),
sources.WithRPMDevBumpspec(env, env.WorkDir(), ""),
sources.WithDirtyDetection(),
)
}
Expand Down
1 change: 1 addition & 0 deletions internal/app/azldev/cmds/component/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ func prepareComponentSources(
// sidecar files are needed for rendering.
preparerOpts := []sources.PreparerOption{
sources.WithGitRepo(env, env.LockReader(), distro.Version.ReleaseVer),
sources.WithRPMDevBumpspec(env, env.WorkDir(), ""),
sources.WithDirtyDetection(),
sources.WithSkipLookaside(),
sources.WithUpstreamProvenance(sources.FedoraDistTag(distro.Ref.Name, distro.Version.ReleaseVer)),
Expand Down
Loading
Loading