# Version Constraints for Multi-Version Images

LLMS index: [llms.txt](https://hummingbird-project.io/llms.txt) | Full content: [llms-full.txt](https://hummingbird-project.io/llms-full.txt)

---

## Overview

Version constraints prevent unwanted major or minor version updates for multi-version
container images (e.g., python-3-11, nodejs-20). Constraints are defined in
`properties.yml` and validated during `make check` by comparing VERSION files against
defined patterns.

## Adding Version Constraints

Edit the image's `properties.yml` to add a version constraint:

```yaml
---
main_package: python3.11
version_constraints: '3.11.*'  # Allow 3.11.X, block 3.12+ and 4.X
```

The constraint applies to all distros for the image:

```yaml
---
main_package: dotnet-sdk-8.0
version_constraints: '8.*'  # Applies to rawhide, hummingbird, and any other distros
```

### Constraint Patterns

Constraints use glob-style patterns:

- `3.11.*` - Match any 3.11.X version (recommended for version families)
- `20.*` - Match any 20.X version
- `8.*` - Match any 8.X version
- `1.25.*` - Match any 1.25.X version (for Go-style 3-part versions)

The pattern matches against the version from the VERSION file. For example, if the
VERSION file contains `3.11.14`, the constraint `3.11.*` will match.

## How Validation Works

1. **Lockfile Generation**: When `make all` runs, lockfiles are generated with resolved package versions
2. **VERSION File Creation**: `generate_jinja2.py` creates VERSION files from resolved package versions
3. **Constraint Checking**: When `make check` runs, `check_version_constraints.py` validates VERSION files against constraints
4. **Failure**: If a violation is detected, the build fails with a detailed error message
5. **Renovate Integration**: Renovate MRs that violate constraints fail CI and are blocked from automerge

## Handling Constraint Violations

When a build fails due to a version constraint violation, you have several options:

### Option 1: Accept the new version (create new image)

If the new major/minor version is acceptable:

1. Create a new image directory (e.g., `images/python-3-14/`)
2. Copy properties and configuration from the old version
3. Update the constraint in the new directory:

   ```yaml
   version_constraints: '3.14.*'
   ```

4. Update `repository` field to group versions together
5. Consider adding `latest` tag to the new version if appropriate

### Option 2: Block the version update (exclude package)

If the new version should be blocked entirely:

1. Add the package to `yum-repos/*.repo` excludepkgs
2. Follow the procedure in [Excluding Packages from Images](https://hummingbird-project.io/docs/operating/excluding-packages-from-images/)
3. Renovate will skip the excluded version in future updates
4. When the issue is resolved, remove the exclusion

### Option 3: Update the constraint (allow version bump)

If the version bump is acceptable for the existing image:

1. Update the constraint in `properties.yml`:

   ```yaml
   version_constraints: '3.12.*'  # Allow 3.12.X now
   ```

2. Consider if this changes the image's purpose (major version change)
3. Update image documentation and tags accordingly
4. Consider renaming the image directory to reflect the new version

## Examples

### Python Multi-Version Images

```yaml
# images/python-3-11/properties.yml
distros:
  - hummingbird
main_package: python3.11
repository: python
version_constraints: '3.11.*'
```

```yaml
# images/python-3-13/properties.yml
distros:
  - hummingbird
main_package: python3.13
repository: python
version_constraints: '3.13.*'
```

### Node.js Multi-Version Images

```yaml
# images/nodejs-20/properties.yml
main_package: nodejs20
repository: nodejs
version_constraints: '20.*'
```

```yaml
# images/nodejs-24/properties.yml
main_package: nodejs24
repository: nodejs
version_constraints: '24.*'
```

### .NET SDK Multi-Version Images

```yaml
# images/dotnet-sdk-8-0/properties.yml
main_package: dotnet-sdk-8.0
repository: dotnet-sdk
version_constraints: '8.*'
```

### .NET Runtime Multi-Version Images

```yaml
# images/dotnet-runtime-8-0/properties.yml
main_package: dotnet-runtime-8.0
repository: dotnet-runtime
version_constraints: '8.*'
```

### ASP.NET Runtime Multi-Version Images

```yaml
# images/aspnet-runtime-8-0/properties.yml
main_package: aspnetcore-runtime-8.0
repository: aspnet-runtime
version_constraints: '8.*'
```

### OpenJDK Multi-Version Images

```yaml
# images/openjdk-21/properties.yml
main_package: java-21-openjdk-headless
repository: openjdk
version_constraints: '21.*'
```

### Go Multi-Version Images (3-part versions)

```yaml
# images/go-1-25/properties.yml
main_package: golang1.25
repository: go
distros:
  - hummingbird
version_constraints: '1.25.*'  # Matches 1.25.0, 1.25.3, etc.
```

## Troubleshooting

### Constraint not working

- Verify package name matches exactly (case-sensitive)
- Ensure pattern syntax is correct (use `*` wildcard)
- Run `make all` to regenerate VERSION files before `make check`

### False positive violations

- Check for typos in the constraint pattern
- Verify the pattern matches the version format (e.g., `3.11.*` not `3.11*`)
- Ensure you're using glob patterns, not regex

### Package renamed in repositories

If a package is renamed (e.g., `python3.11` → `python311`):

1. Update `main_package` field
2. Update constraint with new package name (not needed - constraints check VERSION files)
3. Regenerate lockfiles and VERSION files with `make all`

## Implementation Details

The version constraint system consists of:

1. **properties.yml**: Optional `version_constraints` field with a glob pattern string
2. **ci/check_version_constraints.py**: Python script that validates VERSION files
3. **Makefile integration**: Script runs as part of `make check`
4. **CI integration**: Failures block merge, including Renovate automerge

The validation process:

1. Reads `properties.yml` for each image
2. If `version_constraints` defined, finds all VERSION files across all distros
3. Applies the same constraint pattern to all distros for the image
4. Compares VERSION file content against glob pattern using Python's `fnmatch`
5. Reports violations with file path, version, constraint, and properties file location
6. Exits with error code 1 if any violations found

## See Also

- [Image Configuration Reference](https://hummingbird-project.io/docs/contributing/image-configuration-reference/) - Complete `properties.yml` field reference
- [Excluding Packages from Images](https://hummingbird-project.io/docs/operating/excluding-packages-from-images/) - How to exclude problematic package versions
- [Switching Fedora Streams](https://hummingbird-project.io/docs/operating/switching-fedora-streams/) - How to pin distro versions
