Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ images:
- directory: "python/3.10-22.04"
- directory: "python/3.12-24.04"
- directory: "python/3.13-25.10"
- directory: "python/3.14-26.04"

## Example of specifying different registries for a specific rock
# - directory: "my-rock-name/0.1-24.04"
Expand Down
137 changes: 137 additions & 0 deletions .github/workflows/image-internal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# This workflow is intended for internal Canonical repositories only.
# It includes steps that rely on internal actions or secrets,
# and it performs additional checks to prevent accidental usage in public repositories.
# If you are working in a public repository, please use the .github/workflows/image.yaml workflow instead.
#
name: Build and Publish Rocks (Internal)

on:
# Uncomment these lines to enable the workflow on push and pull_request events
# push:
# branches: [main]
# pull_request:
# branches: [main]
workflow_dispatch:

jobs:

prepare:
runs-on: ubuntu-latest
outputs:
ghcr-upload: ${{ steps.read-ci-config.outputs.ghcr-upload }}
build-matrix: ${{ steps.read-ci-config.outputs.build-matrix }}
upload-matrix: ${{ steps.read-ci-config.outputs.upload-matrix }}
steps:
- name: Pre-Check
if: |
github.repository_owner != 'canonical' ||
github.event.repository.visibility == 'public'
run: |
echo "::error::This workflow is intended for internal repositories only. Please use the .github/workflows/image.yaml workflow instead."
exit 1

- name: Checkout Repository
uses: actions/checkout@v5

- name: Read .github/ci.yaml
id: read-ci-config
uses: canonical/rocks-template-actions/actions/read-ci-config@v1


build-internal:
needs: [prepare]
strategy:
fail-fast: true
matrix: ${{ fromJSON(needs.prepare.outputs.build-matrix) }}
uses: canonical/oci-factory-internal/.github/workflows/Build-Rock.yaml@main
with:
rock-repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
rock-repo-commit: ${{ github.ref }}
rockfile-directory: ${{ matrix.directory }}
oci-archive-name: ${{ matrix.artifact-name }}
secrets:
host-github-token: ${{ secrets.GITHUB_TOKEN }}
source-github-token: ${{ secrets.REPO_CLONER_TOKEN }}


test:
needs: [prepare, build-internal]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.prepare.outputs.build-matrix) }}
uses: canonical/oci-factory/.github/workflows/Test-Rock.yaml@main
with:
oci-archive-name: ${{ matrix.artifact-name }}


upload-ghcr:
needs: [prepare, test]
runs-on: ubuntu-latest
if: |
needs.prepare.outputs.ghcr-upload == 'true' &&
github.event_name != 'pull_request' &&
github.ref == 'refs/heads/main'
strategy:
matrix: ${{ fromJSON(needs.prepare.outputs.build-matrix) }}
fail-fast: false
permissions:
packages: write
steps:
- name: Upload Rock to GHCR
uses: canonical/oci-factory/.github/actions/upload-rock@main
with:
artifact_name: ${{ matrix.artifact-name }}
tags: ${{ matrix.tag }}
name: ${{ matrix.name }}
registry: ghcr.io/${{ github.repository }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}


upload-registries:
needs: [prepare, test]
runs-on: ubuntu-latest
if: |
needs.prepare.outputs.upload-matrix != '{"include": []}' &&
github.event_name != 'pull_request' &&
github.ref == 'refs/heads/main'
strategy:
matrix: ${{ fromJSON(needs.prepare.outputs.upload-matrix) }}
fail-fast: false
steps:
- name: Prepare ECR Session Token
if: ${{ contains(matrix.registry-auth-method, 'ecr') }}
id: get-ecr-token
env:
AWS_ACCESS_KEY_ID: ${{ secrets[matrix.registry-auth-username] }}
AWS_SECRET_ACCESS_KEY: ${{ secrets[matrix.registry-auth-password] }}
run: |
session_token=$(aws ${{ matrix.registry-auth-method }} \
get-login-password \
--region ${{ matrix.registry-auth-region }} \
)
echo "::add-mask::$session_token"
echo "aws-session-token=$session_token" >> $GITHUB_OUTPUT

- name: Upload Rock to ECR
uses: canonical/oci-factory/.github/actions/upload-rock@main
if: ${{ contains(matrix.registry-auth-method, 'ecr') }}
with:
artifact_name: ${{ matrix.artifact-name }}
tags: ${{ matrix.tag }}
name: ${{ matrix.name }}
registry: ${{ matrix.registry-uri }}
username: AWS
password: ${{ steps.get-ecr-token.outputs.aws-session-token }}

- name: Upload Rock to Registry
uses: canonical/oci-factory/.github/actions/upload-rock@main
if: matrix.registry-auth-method == 'basic'
with:
artifact_name: ${{ matrix.artifact-name }}
tags: ${{ matrix.tag }}
name: ${{ matrix.name }}
registry: ${{ matrix.registry-uri }}
username: ${{ secrets[matrix.registry-auth-username] }}
password: ${{ secrets[matrix.registry-auth-password] }}

125 changes: 60 additions & 65 deletions .github/workflows/publish.yaml → .github/workflows/image.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build and Publish Rocks to GHCR
name: Build and Publish Rocks

on:
push:
Expand All @@ -8,102 +8,97 @@ on:
workflow_dispatch:

jobs:

read-config:
prepare:
runs-on: ubuntu-latest
outputs:
ghcr-upload: ${{ steps.read-ci-config.outputs.ghcr-upload }}
ghcr-cve-scan: ${{ steps.read-ci-config.outputs.ghcr-cve-scan }}
build-matrix: ${{ steps.read-ci-config.outputs.build-matrix }}
upload-matrix: ${{ steps.read-ci-config.outputs.upload-matrix }}
arch-map: ${{ steps.set-map.outputs.arch-map }}
steps:
- name: Checkout repository
- name: Checkout Repository
uses: actions/checkout@v5

- name: Read .github/ci.yaml
id: read-ci-config
uses: canonical/rocks-template-actions/actions/read-ci-config@v1

get-runners:
runs-on: ubuntu-latest
outputs:
arch-map: ${{ steps.set-map.outputs.arch-map }}
steps:
- id: set-map
- name: Set Architecture Map
id: set-map
run: |
if [[ "${{ github.repository_owner }}" == "canonical" ]]; then
echo 'arch-map={"amd64":["noble","X64","large"],"arm64":["noble","ARM64","large"]}' >> $GITHUB_OUTPUT
else
if [[ "${{ github.repository_owner }}" != "canonical" ]]; then
echo 'arch-map={"amd64":["ubuntu-24.04"],"arm64":["ubuntu-24.04-arm"]}' >> $GITHUB_OUTPUT
fi

# Why do we need this duplicate job and reusable Build-Rock workflow?
# - the Build-Rock wf may need an an environment setup that relies on an internal action
# - to call an internal action, the repo must also be internal/private
# - but the OCI Factory is not internal/private, so that internal action cannot be called from there
# build-internal:
# needs: [get-runners, read-config]
# if: github.event.repository.visibility != 'public'
# strategy:
# fail-fast: true
# matrix: ${{ fromJSON(needs.read-config.outputs.build-matrix) }}
# uses: canonical/oci-factory-internal/.github/workflows/Build-Rock.yaml@main
# with:
# rock-repo: ${{ github.repository }}
# rock-repo-commit: ${{ github.ref }}
# rockfile-directory: ${{ matrix.directory }}
# oci-archive-name: ${{ matrix.artifact-name }}
# arch-map: ${{ needs.get-runners.outputs.arch-map }}
# secrets:
# host-github-token: ${{ secrets.GITHUB_TOKEN }}
# source-github-token: ${{ secrets.REPO_CLONER_TOKEN }}
# TODO: remove once the pro-feature is stable in rockcraft
# Warn the user if using tests in a pro enabled build
- name: Check Pro and Test Incompatibility
run: |
build_matrix='${{ steps.read-ci-config.outputs.build-matrix }}'

# Use jq to iterate over the 'include' array
echo "$build_matrix" | jq -c '.include[]' | while read -r row; do
directory=$(echo "$row" | jq -r '.["directory"] // "unknown"')
pro_services=$(echo "$row" | jq -r '.["pro-services"] // ""')
run_tests=$(echo "$row" | jq -r '.["run-tests"] // "false"')

if [[ -n "$pro_services" && "$run_tests" == "true" ]]; then
echo "::warning::Tests for Pro Services are currently not supported. Rockcraft tests will be skipped for ${directory}."
fi
done


build:
needs: [get-runners, read-config]
if: github.event.repository.visibility == 'public'
needs: [prepare]
strategy:
matrix: ${{ fromJSON(needs.read-config.outputs.build-matrix) }}
matrix: ${{ fromJSON(needs.prepare.outputs.build-matrix) }}
uses: canonical/oci-factory/.github/workflows/Build-Rock.yaml@main
with:
rock-repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
rock-repo-commit: ${{ github.head_ref || github.ref_name }}
rockfile-directory: ${{ matrix.directory }}
oci-archive-name: ${{ matrix.artifact-name }}
arch-map: ${{ needs.get-runners.outputs.arch-map }}
arch-map: ${{ needs.prepare.outputs.arch-map }}
rockcraft-test: ${{ matrix.run-tests }}
pro-services: ${{ matrix.pro-services }}
secrets:
source-github-token: ${{ secrets.REPO_CLONER_TOKEN }}
pro-token: ${{ secrets[matrix.pro-token] }}
pro-artifact-passphrase: ${{ secrets[matrix.pro-artifact-passphrase] }}


test:
needs: [read-config, build]
# Uncomment these lines if using build-internal job and remove the line above
# needs: [read-config, build, build-internal]
# if: |
# always() && needs.read-config.result == 'success' &&
# (needs.build-internal.result == 'success' && needs.build.result == 'skipped') ||
# (needs.build-internal.result == 'skipped' && needs.build.result == 'success')
needs: [prepare, build]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.read-config.outputs.build-matrix) }}
matrix: ${{ fromJSON(needs.prepare.outputs.build-matrix) }}
uses: canonical/oci-factory/.github/workflows/Test-Rock.yaml@main
with:
oci-archive-name: ${{ matrix.artifact-name }}
secrets:
pro-artifact-passphrase: ${{ secrets[matrix.pro-artifact-passphrase] }}


upload-ghcr:
needs: [read-config, test]
# Note: the !cancelled() is required to workaround the job being skipped
# due to a skipped job in the indirect dependency chain:
# https://github.com/orgs/community/discussions/25224
needs: [prepare, test]
runs-on: ubuntu-latest
if: |
github.event_name != 'pull_request' && !cancelled() && !failure() &&
github.ref == 'refs/heads/main' &&
needs.read-config.outputs.ghcr-upload == 'true'
needs.prepare.outputs.ghcr-upload == 'true' &&
github.event_name != 'pull_request' &&
github.ref == 'refs/heads/main'
strategy:
matrix: ${{ fromJSON(needs.read-config.outputs.build-matrix) }}
matrix: ${{ fromJSON(needs.prepare.outputs.build-matrix) }}
fail-fast: false
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Pre-Check Pro Enabled Rocks
if: ${{ github.event.repository.visibility == 'public' && matrix.pro-services != '' }}
run: |
echo "::warning::Uploading Pro enabled rocks to GHCR is not allowed for public repositories."

- name: Upload Rock to GHCR
if: ${{ github.event.repository.visibility != 'public' || matrix.pro-services == '' }}
uses: canonical/oci-factory/.github/actions/upload-rock@main
with:
artifact_name: ${{ matrix.artifact-name }}
Expand All @@ -112,20 +107,19 @@ jobs:
registry: ghcr.io/${{ github.repository }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
decrypt-passphrase: ${{ secrets[matrix.pro-artifact-passphrase] }}


upload-registries:
needs: [read-config, test]
# Note: the !cancelled() is required to workaround the job being skipped
# due to a skipped job in the indirect dependency chain:
# https://github.com/orgs/community/discussions/25224
needs: [prepare, test]
runs-on: ubuntu-latest
if: |
github.event_name != 'pull_request' && !cancelled() && !failure() &&
github.ref == 'refs/heads/main' &&
needs.read-config.outputs.upload-matrix != '{"include": []}'
needs.prepare.outputs.upload-matrix != '{"include": []}' &&
github.event_name != 'pull_request' &&
github.ref == 'refs/heads/main'
strategy:
matrix: ${{ fromJSON(needs.read-config.outputs.upload-matrix) }}
matrix: ${{ fromJSON(needs.prepare.outputs.upload-matrix) }}
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Prepare ECR Session Token
if: ${{ contains(matrix.registry-auth-method, 'ecr') }}
Expand All @@ -151,6 +145,7 @@ jobs:
registry: ${{ matrix.registry-uri }}
username: AWS
password: ${{ steps.get-ecr-token.outputs.aws-session-token }}
decrypt-passphrase: ${{ secrets[matrix.pro-artifact-passphrase] }}

- name: Upload Rock to Registry
uses: canonical/oci-factory/.github/actions/upload-rock@main
Expand All @@ -162,4 +157,4 @@ jobs:
registry: ${{ matrix.registry-uri }}
username: ${{ secrets[matrix.registry-auth-username] }}
password: ${{ secrets[matrix.registry-auth-password] }}

decrypt-passphrase: ${{ secrets[matrix.pro-artifact-passphrase] }}
Loading
Loading