Skip to content
Draft
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
15 changes: 15 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,23 @@ azldev.toml # Root config — includes distro/ and base
│ ├── distro.toml # Includes all *.distro.toml
│ ├── fedora.distro.toml # Fedora: dist-git URIs, lookaside, version branches
│ └── mock/ # Mock build environment configs
├── specs/ # Rendered specs (generated by `azldev comp render`)
│ └── <first-char>/<name>/ # Per-component: spec, patches, scripts (no source tarballs)
└── external/schemas/
└── azldev.schema.json # Authoritative schema for all TOML config files
```

## Rendered Specs (`specs/`)

The `specs/` directory contains rendered spec files generated by `azldev comp render`. These are the final specs with all overlays applied — ready for check-in. After adding or modifying components/overlays, re-render:

```bash
azldev comp render -p <name> # Single component
azldev comp render -a # All components (slow)
```

To inspect what a component's spec looks like after overlays, read `specs/<first-char>/<name>/<name>.spec` directly — no need to run `prep-sources` just to view the result. Use `prep-sources` when you need the full source tree (tarballs) or want to diff pre/post overlay output for debugging.

## Key Concepts

**Components** = unit of packaging (→ one or more RPMs). Spec sources: upstream (default, from Fedora dist-git), local, or pinned upstream. See [`comp-toml.instructions.md`](instructions/comp-toml.instructions.md#spec-source-types) for syntax.
Expand All @@ -52,6 +65,8 @@ Run all commands from the repo root (where `azldev.toml` lives). If the terminal
| Add a component | `azldev comp add` |
| Build a component | `azldev comp build -p <name> -q` |
| Build chain (auto-publish to local repo) | `azldev comp build --local-repo-with-publish ./base/out -p <a> -p <b> -q` |
| Render many specs for check-in | `azldev comp render -a` |
| Render a single component | `azldev comp render -p <name>` |
| Prepare sources (apply overlays) | `azldev comp prep-sources -p <name> --force -o <dir> -q` |
| Prepare sources (skip overlays) | `azldev comp prep-sources -p <name> --skip-overlays --force -o <dir> -q` |
| Build, keep env on failure | `azldev comp build -p <name> --preserve-buildenv on-failure -q` |
Expand Down
32 changes: 32 additions & 0 deletions .github/instructions/rendered-specs.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
applyTo: "specs/**/*"
description: ALWAYS refer to this when working with rendered spec files (`*.spec`) in the `specs/` directory.
---

# Rendered Spec Files (`specs/*.spec`)

## What are rendered specs?

Rendered specs are generated by the `azldev component render` command based on the component definitions and overlays. They are output to the `specs/` directory and should not be edited directly.

They are meant to be consumed by downstream processes (e.g., build pipelines) and are the source of truth for all subsequent steps. Any changes to the spec should be made via the component definition and overlays, not by editing the rendered spec.

## Changing a rendered spec

To change a rendered spec, modify the component's `.comp.toml` and/or its overlays. Then re-run the render command to regenerate the spec:

```bash
# VERY SLOW - Re-render all specs, removes any stale specs that are no longer defined in the components
azldev component render -a --clean-stale -O json
```

```bash
# Small set, will NOT remove stale specs, faster for iterative development
azldev component render <component-1> <component-2> -O json
```

```bash
# Custom output directory, useful for debugging. When not using the automatically configured spec directory, --force is
# required to delete and re-create the output folders if they already exist.
azldev component render <component> -O json -o ./base/build/work/scratch/rendered-specs --force
```
3 changes: 2 additions & 1 deletion .github/instructions/spec.instructions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
applyTo: "**/*.spec"
applyTo: "base/**/*.spec"
description: Read this when working with spec files (`*.spec`) that are hand-maintained in the Azure Linux repo (not rendered).
---

# RPM Spec Files (`*.spec`)
Expand Down
2 changes: 1 addition & 1 deletion .github/prompts/azl-add-component.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ Follow the workflow in the [skill-add-component skill](../skills/skill-add-compo
- Needs overlays or customizations → create `${input:component_name}/${input:component_name}.comp.toml`
- Needs extensive changes overlays can't handle → forked local spec (**last resort**, requires explicit user sign-off)
6. Add overlays with meaningful `description` fields explaining *why* each change is needed
7. Validate: `azldev comp prep-sources -p ${input:component_name} --force -o base/build/work/scratch/${input:component_name}-post -q` (with overlays) and diff against the skip-overlays output
7. Render and verify: `azldev comp render -p ${input:component_name}` and inspect `specs/` output. For deeper debugging, diff pre/post overlay output with `prep-sources`.
8. Build: `azldev comp build -p ${input:component_name} -q`
9. Smoke-test the built RPMs in a mock chroot
10 changes: 8 additions & 2 deletions .github/prompts/azl-debug-component.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,21 @@ First, determine the error category:
- Follow the `skill-mock` workflow: install RPMs in a mock chroot, verify contents, check dependencies
- Common causes: missing Requires, wrong file paths, permission issues

**When in doubt**, start with a `prep-sources` pre/post diff to determine if the issue is overlay-related:
**When in doubt**, start with a render to determine if the issue is overlay-related:

```bash
azldev comp render -p ${input:component_name}
```

If `render` fails, the issue is overlay-related (category 1). For deeper debugging, diff pre/post overlay output:

```bash
azldev comp prep-sources -p ${input:component_name} --skip-overlays -o base/build/work/scratch/${input:component_name}-pre --force
azldev comp prep-sources -p ${input:component_name} -o base/build/work/scratch/${input:component_name}-post --force
diff -r base/build/work/scratch/${input:component_name}-pre base/build/work/scratch/${input:component_name}-post
```

If `prep-sources` itself fails, the issue is overlay-related (category 1). If it succeeds but `comp build` fails, it's a build issue (category 2).
If both render and `prep-sources` succeed but `comp build` fails, it's a build issue (category 2).

## Fix

Expand Down
4 changes: 4 additions & 0 deletions .github/prompts/azl-update-component.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Use structural patterns from [comp-toml.instructions.md](../instructions/comp-to
- `config` — build config changes (`build.defines`, `build.without`)
3. **Apply changes** to the `.comp.toml` file
4. **Verify overlays still apply:**
```bash
azldev comp render -p ${input:component_name}
```
Inspect `specs/` output. For deeper debugging, diff pre/post overlay output:
```bash
azldev comp prep-sources -p ${input:component_name} --skip-overlays -o base/build/work/scratch/${input:component_name}-pre --force
azldev comp prep-sources -p ${input:component_name} -o base/build/work/scratch/${input:component_name}-post --force
Expand Down
14 changes: 13 additions & 1 deletion .github/skills/skill-add-component/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ Overlays are vastly preferable to maintaining a forked spec, they get automatic

## Validate

After adding overlays or customizations, render the spec to verify:

```bash
azldev comp render -p <name>
# Inspect the result
cat specs/<first-char>/<name>/<name>.spec
```

For deeper debugging (diffing pre/post overlay output with full sources):

> Use a temp dir for `prep-sources` output. Use `--force` to overwrite an existing output dir.

`prep-sources -o <dir>` writes to a user-specified directory (NOT `base/out/` — that's for `comp build` output).
Expand All @@ -77,9 +87,11 @@ Overlays are vastly preferable to maintaining a forked spec, they get automatic
azldev comp prep-sources -p <name> --skip-overlays --force -o base/build/work/scratch/<name>-pre -q
azldev comp prep-sources -p <name> --force -o base/build/work/scratch/<name>-post -q
diff -r base/build/work/scratch/<name>-pre base/build/work/scratch/<name>-post
```

```bash
# Test build (RPMs land in base/out/ per project.toml output-dir)
azldev comp build -p <name> -q
```

For testing the built RPMs, see the [`skill-mock`](../skill-mock/SKILL.md) skill. New components always need a smoke-test. For the full inner loop cycle (investigate → modify → verify → build → test → inspect), see [`skill-build-component`](../skill-build-component/SKILL.md).
For testing the built RPMs, see the [`skill-mock`](../skill-mock/SKILL.md) skill. New components always need a smoke-test. For the full inner loop cycle (investigate → modify → render → build → test → inspect), see [`skill-build-component`](../skill-build-component/SKILL.md).
28 changes: 21 additions & 7 deletions .github/skills/skill-build-component/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,40 @@ Build foundational packages first (e.g., `azurelinux-rpm-config`), then dependen
The standard cycle for investigating, modifying, and verifying components:

```
investigate → modify → verify → build → test → inspect
investigate → modify → render → build → test → inspect
```

| Step | Command | What to check |
|------|---------|---------------|
| **Investigate** | `prep-sources --skip-overlays --force -o base/build/work/scratch/<name>-pre` | Upstream spec/sources as-is |
| **Compare** | `prep-sources --force -o base/build/work/scratch/<name>-post` + `diff -r ...-pre ...-post` | Current overlay effect |
| **Investigate** | Read `specs/<first-char>/<name>/<name>.spec` or `prep-sources --skip-overlays --force -o base/build/work/scratch/<name>-pre` | Upstream spec/sources as-is |
| **Compare** | `prep-sources --force -o base/build/work/scratch/<name>-post` + `diff -r ...-pre ...-post` | Current overlay effect (deep debug) |
| **Modify** | Edit `*.comp.toml` (overlays, defines, without) | — |
| **Verify** | `prep-sources --force -o base/build/work/scratch/<name>-post` | Overlay applies cleanly |
| **Verify** | `comp render -p <name>` + inspect `specs/<first-char>/<name>/` | Overlay applies cleanly (fast path) |
| **Build** | `comp build -p <name>` | RPMs appear in `base/out/` |
| **Test** | `adv mock shell --add-package base/out/<name>*.rpm` | Package installs, binary runs, basic functionality works |
| **Inspect** | `comp build --preserve-buildenv always` + `adv mock shell` | BUILDROOT contents, file lists |

> **Prefer `comp render` for quick verification.** It's faster than `prep-sources` since it skips downloading source tarballs. Use `prep-sources` when you need the full source tree or want to diff pre/post overlay output for debugging.

> Use a temp dir for `prep-sources` output. Use `--force` to overwrite an existing output dir.

> Package builds are often very long, so adjust command timeouts accordingly when using shell tools to run builds, or use background mode if available.

## Debugging Build Failures

### 1. Diff sources pre/post overlay
### 1. Render and inspect the spec

The fastest way to verify overlays applied correctly:

```bash
azldev comp render -p <name>
# Inspect the result
cat specs/<first-char>/<name>/<name>.spec
```

### 2. Diff sources pre/post overlay (deep debug)

When you need to understand exactly what upstream provides vs. what overlays change:

```bash
azldev comp prep-sources -p <name> --skip-overlays --force -o base/build/work/scratch/<name>-pre -q
Expand All @@ -78,14 +92,14 @@ diff -r base/build/work/scratch/<name>-pre base/build/work/scratch/<name>-post

This reveals whether overlays apply as intended or whether upstream changed.

### 2. Preserve build environment on failure
### 3. Preserve build environment on failure

```bash
azldev comp build -p <name> --preserve-buildenv on-failure -q
# Use `always` to inspect even successful builds
```

### 3. Enter mock shell (deep debug)
### 4. Enter mock shell (deep debug)

For testing built RPMs or inspecting the chroot, see the [`skill-mock`](../skill-mock/SKILL.md) skill. Quick reference:

Expand Down
22 changes: 17 additions & 5 deletions .github/skills/skill-fix-overlay/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,21 @@ description: "[Skill] Diagnose and fix overlay issues in Azure Linux components.

## Diagnosis Workflow

### 1. Reproduce and inspect
### 1. Render and inspect

The fastest way to check if overlays apply cleanly:

```bash
azldev comp render -p <name>
# Inspect the result
cat specs/<first-char>/<name>/<name>.spec
```

If `render` fails, the error message will identify which overlay failed and why.

### 2. Diff pre/post overlay (deep debug)

When you need to understand exactly what upstream provides vs. what overlays change:

> Use a temp dir for `prep-sources` output. Use `--force` to overwrite an existing output dir.

Expand All @@ -19,9 +33,7 @@ azldev comp prep-sources -p <name> --force -o base/build/work/scratch/<name>-pos
diff -r base/build/work/scratch/<name>-pre base/build/work/scratch/<name>-post
```

If `prep-sources` fails, the error message will identify which overlay failed and why.

### 2. Inspect the upstream spec/sources
### 3. Inspect the upstream spec/sources

Look at the pre-overlay output dir — this is what the overlay is trying to modify. Common root cause: upstream changed and the overlay's assumptions no longer hold.

Expand Down Expand Up @@ -61,5 +73,5 @@ For overlay type reference (all 12 types with key fields), see [`comp-toml.instr
- **Test incrementally.** Apply one overlay at a time and verify with `prep-sources`. Debugging 10 overlays at once is painful.
- **Minimize overlays.** Each is a potential failure point. Prefer the smallest delta from upstream.
- **Verify in chroot.** If overlays apply but the build still fails, use [`skill-mock`](../skill-mock/SKILL.md) to inspect the build environment.
- **Follow the inner loop.** The full cycle is: investigate → modify → verify → build → test → inspect. See [`skill-build-component`](../skill-build-component/SKILL.md) for details.
- **Follow the inner loop.** The full cycle is: investigate → modify → render → build → test → inspect. See [`skill-build-component`](../skill-build-component/SKILL.md) for details.
- **Smoke-test after fixing overlays.** A clean apply and successful build don't guarantee working RPMs. See [`skill-mock`](../skill-mock/SKILL.md).
124 changes: 124 additions & 0 deletions .github/workflows/check-rendered-specs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Check Rendered Specs

on:
pull_request:
branches:
- tomls/base/main

permissions: {}

concurrency:
group: render-check-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
check:
name: Rendered specs freshness
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # Post/update/delete drift comments on PRs
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: "stable"

- name: Install azldev
run: go install github.com/microsoft/azure-linux-dev-tools/cmd/azldev@main

- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"

- name: Build render container
run: |
docker build \
--build-arg UID=$(id -u) \
-t azldev-render \
-f .github/workflows/containers/render.Dockerfile \
.github/workflows/containers/

- name: Render specs
env:
WORKSPACE: ${{ github.workspace }}
run: |
set -o pipefail
docker run --privileged --rm \
-v "$WORKSPACE:/workdir" \
-v "$(go env GOPATH)/bin:/gobin:ro" \
-e PATH="/gobin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
azldev-render \
azldev component render -q -a --clean-stale -O json \
| tee render-output.json

- name: Resolve specs directory
id: specs-dir
run: |
SPECS_DIR=$(azldev config dump -q | grep 'rendered-specs-dir' | cut -d"'" -f2)
echo "path=$SPECS_DIR" >> "$GITHUB_OUTPUT"

- name: Check for drift
id: check
continue-on-error: true # Non-blocking while the feature stabilizes
env:
SPECS_DIR: ${{ steps.specs-dir.outputs.path }}
run: |
python .github/workflows/scripts/check_rendered_specs.py \
--specs-dir "$SPECS_DIR" \
--report render-check-report.json \
--patch rendered-specs.patch

- name: Upload fix patch
id: upload-patch
if: hashFiles('rendered-specs.patch') != ''
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
path: rendered-specs.patch
archive: false

# Also upload as a zipped artifact so `gh run download` works.
# The non-zipped upload above is for browser preview/download, but
# `gh run download` doesn't support non-zipped artifacts yet.
# See: https://github.com/cli/cli/issues/13012
- name: Upload fix patch (for gh cli)
if: hashFiles('rendered-specs.patch') != ''
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: rendered-specs-patch
path: rendered-specs.patch

- name: Post PR comment
if: always()
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
SPECS_DIR: ${{ steps.specs-dir.outputs.path }}
PATCH_URL: ${{ steps.upload-patch.outputs.artifact-url }}
RUN_ID: ${{ github.run_id }}
run: |
python .github/workflows/scripts/check_rendered_specs.py \
--specs-dir "$SPECS_DIR" \
--repo "$PR_REPO" \
--pr "$PR_NUMBER" \
--report render-check-report.json \
--artifacts-url "$PATCH_URL" \
--run-id "$RUN_ID"

- name: Upload render output
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: render-output
path: |
render-output.json
render-check-report.json
20 changes: 20 additions & 0 deletions .github/workflows/containers/render.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM mcr.microsoft.com/azurelinux/base/core:3.0

# Install mock and dependencies needed for azldev component render.
# Go and azldev are bind-mounted from the host via GOPATH.
RUN tdnf -y install \
ca-certificates \
git \
mock \
mock-rpmautospec \
python3 \
shadow-utils \
sudo \
&& tdnf clean all

ARG UID=1000

RUN useradd -u "${UID}" -G mock -m builduser

USER builduser
WORKDIR /workdir
Loading
Loading