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
20 changes: 15 additions & 5 deletions .github/workflows/integration_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,17 @@ on:
upload-image:
type: string
description: >-
Can be either 'artifact' or 'registry', which determines the method by which images used
in integration tests are uploaded. If set to 'artifact', the images will be uploaded as GitHub
action artifacts. If set to 'registry', the images will be uploaded to ghcr.
If this parameter is not specified, the default behavior is to use 'artifact' for pull requests
originating from forked repositories, and 'registry' for all other cases.
Can be either 'artifact' or 'registry'. 'artifact' uploads built images as
GitHub Actions artifacts and uses a local registry during tests. 'registry'
pushes images to GHCR. If unspecified, artifact mode is used for test
pull-request events with the default MicroK8s provider; other events and providers
retain registry mode unless overridden.
Use 'registry' when a remote image is explicitly required.
default: ""
artifact-retention-days:
type: number
description: Number of days to retain build artifacts.
default: 30
use-canonical-k8s:
type: boolean
description: (Experimental) Whether to use canonical k8s instead of microk8s
Expand All @@ -170,6 +175,7 @@ jobs:
runs-on: ${{ inputs.builder-runner-label }}
outputs:
plan: ${{ steps.plan.outputs.plan }}
image-output-type: ${{ steps.plan.outputs.image-output-type }}
has-code-changes: ${{ steps.changes.outputs.has_code_changes }}
steps:
- name: Validate input
Expand All @@ -187,6 +193,8 @@ jobs:
with:
identifier: ${{ inputs.identifier }}
upload-image: ${{ inputs.upload-image }}
provider: ${{ inputs.provider }}
artifact-retention-days: ${{ inputs.artifact-retention-days }}
working-directory: ${{ inputs.working-directory }}

- name: Find changes
Expand Down Expand Up @@ -277,6 +285,7 @@ jobs:
with:
build-plan: ${{ toJSON(matrix.build) }}
build-context: ${{ inputs.build-context }}
artifact-retention-days: ${{ inputs.artifact-retention-days }}
github-token: ${{ secrets.GITHUB_TOKEN }}

plan-scan:
Expand Down Expand Up @@ -413,6 +422,7 @@ jobs:
tmate-timeout: ${{ inputs.tmate-timeout }}
with-uv: ${{ inputs.with-uv }}
working-directory: ${{ inputs.working-directory }}
image-output-type: ${{ needs.plan.outputs.image-output-type || (inputs.upload-image == 'registry' && 'registry' || inputs.upload-image == 'artifact' && 'file' || (github.event_name == 'pull_request' && (inputs.provider == 'microk8s' || github.event.pull_request.head.repo.full_name != github.repository)) && 'file' || 'registry') }}
required_status_checks:
name: Required Integration Test Status Checks
runs-on: ${{ inputs.builder-runner-label }}
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/integration_test_run.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ on:
type: string
description: Registry owner to push the built images
default: ""
image-output-type:
type: string
description: Image output mode selected by the planner (file or registry).
default: registry
plan:
type: string
description: Plan generated by integration test planner.
Expand Down Expand Up @@ -298,8 +302,8 @@ jobs:
credentials-yaml: ${{ steps.canonical-k8s.outputs.kubeconfig }}
microk8s-addons: >-
${{
(
github.event.pull_request.head.repo.full_name != github.repository &&
(
inputs.image-output-type == 'file' &&
!contains(inputs.microk8s-addons, 'registry')
) &&
(
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ GitHub organisations can set the default `GITHUB_TOKEN` permissions to read-only
| `docs_spread.yaml` | `contents: read` | Checks out the repository for Spread-based documentation testing |
| `docs.yaml` | `contents: read` | Checks out the repository for Vale and Lychee linting |
| `generate_terraform_docs.yaml` | `contents: write`<br>`pull-requests: write` | Commits generated Terraform docs and opens a PR with the changes |
| `integration_test.yaml` | `contents: read`<br>`packages: write`<br>`pull-requests: write` *(optional)* | Checks out the repository; pushes built OCI images to `ghcr.io` when `upload-image: registry` is used or when running on non-forked PRs; `pull-requests: write` is only needed to post `.trivyignore` warning comments (non-fatal if absent) |
| `integration_test.yaml` | `contents: read`<br>`packages: write`<br>`pull-requests: write` *(optional)* | Checks out the repository; uploads built OCI images as GitHub artifacts for test events by default, or pushes to `ghcr.io` when `upload-image: registry` is explicitly selected; `pull-requests: write` is only needed to post `.trivyignore` warning comments (non-fatal if absent) |
| `promote_charm.yaml` | `contents: write` | Creates a git tag via `charming-actions/release-charm` |
| `publish_charm.yaml` | `contents: write`<br>`packages: write`<br>`actions: read` | Creates git tags and releases libraries; pushes OCI images to `ghcr.io`; downloads build artifacts from a prior integration test run |
| `publish_charm.yaml` | `contents: write`<br>`packages: write`<br>`actions: read` | Creates git tags and releases libraries; publishes OCI image resources from artifacts or explicitly selected registry images; downloads build artifacts from a prior integration test run |
| `terraform_modules_release.yaml` | `contents: write` *(push to main only)* | Creates and pushes a semver tag; on PRs runs compliance checks with `contents: read` |
| `terraform_modules_test.yaml` | `contents: read` | Checks out the repository to run `terraform test` |
| `test.yaml` | `contents: read`<br>`pull-requests: write` | Checks out the repository; `charming-actions/check-libraries` posts a comment on PRs when charm libraries are out of date |
Expand All @@ -175,4 +175,6 @@ jobs:
secrets: inherit
```

> **Note:** `packages: write` is only needed by `integration_test.yaml` and `publish_charm.yaml` when OCI images are pushed to `ghcr.io`. If your charm has no OCI images, `contents: read` is sufficient for `integration_test.yaml`.
`integration_test.yaml` uses artifact mode by default for pull-request test events with the default MicroK8s provider and retains build artifacts for 30 days. Other events and providers retain registry mode unless `upload-image` is explicitly set. Set `artifact-retention-days` to override the retention period, or set `upload-image: registry` when the test explicitly requires a remote GHCR image.

> **Note:** `packages: write` is needed when `upload-image: registry` is selected or when `publish_charm.yaml` pushes OCI images to `ghcr.io`. Artifact-mode test runs do not push to GHCR, but the reusable workflow currently retains this permission for explicit registry opt-in. If your charm has no OCI images, `contents: read` is sufficient for `integration_test.yaml`.
20 changes: 13 additions & 7 deletions dist/build/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/build/index.js.map

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions dist/plan/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/plan/index.js.map

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to this project will be documented in this file.

## Unreleased

- Default integration-test image builds to artifact mode for pull-request test runs with the default MicroK8s provider; other events and providers retain registry mode unless overridden, with a configurable 30-day artifact retention period. Use `upload-image: registry` when a remote GHCR image is required.

Comment on lines +5 to +8

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Let's set the release date to 2026-08-08

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

Each revision is versioned by the date of the revision.
Expand Down
10 changes: 6 additions & 4 deletions docs/explanation/integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,18 @@ Tox argument: `--charm-file=./<charm-build-output-file>.charm`

The rocks are pushed to the local MicroK8s image registry (localhost:32000)
using `rockcraft.skopeo copy --insecure-policy --dest-tls-verify=false ...` command if the
rock is downloaded as a tarball artifact. By default, the GitHub registry is
used.
rock is downloaded as a tarball artifact. Artifact mode is used by default for pull-request test runs with the default
MicroK8s provider. Other events and providers use registry mode unless
`upload-image: artifact` is explicitly selected. Artifact archives are retained for
30 days by default; override this with `artifact-retention-days`.

Tox argument: `--<rock-name>-image=<local-registry-image-name>`

### Docker

The Docker images are referred to from the image registry that is output from
the build step. The integration test workflow usually uses the GitHub Container
Registry (ghcr), unless specified otherwise in the workflow.
the build step. Artifact-mode builds are loaded into the local test registry;
`upload-image: registry` uses the GitHub Container Registry (ghcr).

Tox argument: `--<image-name>-image=<image-resource-uri>`

Expand Down
3 changes: 3 additions & 0 deletions internal/build/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ inputs:
build-context:
description: The directory to use as the build context for charmbuild.
default: "."
artifact-retention-days:
description: Number of days to retain build artifacts.
default: '30'
github-token:
description: github token.
required: true
Expand Down
8 changes: 8 additions & 0 deletions internal/plan/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ inputs:
upload-image:
description: upload-image
default: ''
provider:
description: Integration provider used to select the safe default image mode.
default: microk8s
artifact-retention-days:
description: Number of days to retain build artifacts.
default: '30'
outputs:
plan:
description: The generated plan for the entire workflow.
image-output-type:
description: The selected image output mode (file or registry).
runs:
using: node20
main: ../../dist/plan/index.js
28 changes: 21 additions & 7 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ import { DefaultArtifactClient } from '@actions/artifact'
import fs from 'fs'
import path from 'path'

function artifactUploadOptions(): { retentionDays?: number } {
const retentionDays = Number(core.getInput('artifact-retention-days'))
return Number.isInteger(retentionDays) && retentionDays > 0
? { retentionDays }
: {}
}

interface BuildCharmParams {
plan: BuildPlan
buildContext: string
Expand Down Expand Up @@ -55,7 +62,8 @@ async function buildCharm(params: BuildCharmParams): Promise<void> {
await artifact.uploadArtifact(
params.plan.output,
[...charmFiles, manifestFile],
params.plan.source_directory
params.plan.source_directory,
artifactUploadOptions()
)
}

Expand Down Expand Up @@ -90,7 +98,8 @@ async function buildFileResource(plan: BuildPlan): Promise<void> {
await artifact.uploadArtifact(
plan.output,
[...resourceFiles, manifestFile],
plan.source_directory
plan.source_directory,
artifactUploadOptions()
)
}

Expand Down Expand Up @@ -127,7 +136,8 @@ async function buildDockerImage({
await artifact.uploadArtifact(
plan.output,
[manifest, path.join(plan.source_directory, file)],
plan.source_directory
plan.source_directory,
artifactUploadOptions()
)
}
if (plan.output_type == 'registry') {
Expand All @@ -146,7 +156,8 @@ async function buildDockerImage({
await artifact.uploadArtifact(
plan.output,
[manifest],
plan.source_directory
plan.source_directory,
artifactUploadOptions()
)
}
}
Expand Down Expand Up @@ -220,7 +231,8 @@ async function restoreRock(
await artifact.uploadArtifact(
plan.output,
[manifestFile],
plan.source_directory
plan.source_directory,
artifactUploadOptions()
)
return true
}
Expand Down Expand Up @@ -279,7 +291,8 @@ async function buildRock({
await artifact.uploadArtifact(
plan.output,
[...rocks, manifestFile],
plan.source_directory
plan.source_directory,
artifactUploadOptions()
)
} else {
const tree = await gitTreeId(plan.source_directory)
Expand Down Expand Up @@ -320,7 +333,8 @@ async function buildRock({
await artifact.uploadArtifact(
plan.output,
[manifestFile],
plan.source_directory
plan.source_directory,
artifactUploadOptions()
)
}
}
Expand Down
Loading
Loading