Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ROCKS 1452 - Refactor Build Rock workflow to be externally reusable #233

Open
wants to merge 65 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
134291d
ROCKS 1452 - Refactor Build Rock workflow to be externally reusable
clay-lake Sep 6, 2024
962aa3c
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Sep 6, 2024
3007b0b
feat: added runner triplets to Image workflow
clay-lake Sep 6, 2024
a70a819
feat: added GithubOutput class
clay-lake Sep 8, 2024
11e9887
Merge branch 'ROCKS-1452/oci-factory-refactor-build-rock-to-be-extern…
clay-lake Sep 9, 2024
f3514ef
feat: applied suggested changes from zhijie-yang
clay-lake Sep 9, 2024
3902e82
feat: added suggested changes from linostar
clay-lake Sep 9, 2024
7f362cb
fix(src/build_rock/configure/requirements.txt): added pydantic
clay-lake Sep 9, 2024
94a5722
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Sep 9, 2024
f5b8d15
Merge branch 'main' of https://github.com/canonical/oci-factory into …
clay-lake Sep 16, 2024
41f7d75
Merge branch 'ROCKS-1452/oci-factory-refactor-build-rock-to-be-extern…
clay-lake Sep 16, 2024
a175429
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Sep 16, 2024
448b8a2
refactor: remove arch-map value from call to build-rock in Image work…
clay-lake Sep 23, 2024
3c5d295
feat: make default arch-map value use labels instead of runner name
clay-lake Sep 23, 2024
c3e30c9
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Sep 23, 2024
dacd870
fix: "Rock" now uses sentance case
clay-lake Oct 7, 2024
55ed796
fix(tests/data/rockcraft.yaml): added missing newline
clay-lake Oct 7, 2024
403d559
refactor(tests/etc/requirements.txt): test requirements.txt now refre…
clay-lake Oct 7, 2024
1bb9f6d
refactor: ran autoformatter on edited yaml files
clay-lake Oct 7, 2024
4cbf7c2
refactor(tests/fixtures/buffers.py): switch to tmp_path fixture
clay-lake Oct 8, 2024
151ddcd
Merge branch 'main' of https://github.com/canonical/oci-factory into …
clay-lake Oct 8, 2024
001ddde
fix: repair configure workflow after merge
clay-lake Oct 8, 2024
922dd23
Update .github/workflows/Build-Rock.yaml
clay-lake Oct 8, 2024
22a6236
refactor: remove dead step from repair
clay-lake Oct 8, 2024
b2e471d
Merge branch 'ROCKS-1452/oci-factory-refactor-build-rock-to-be-extern…
clay-lake Oct 8, 2024
73ef99a
fix: stray checkout
clay-lake Oct 8, 2024
b2ecdcf
refactor(src/build_rock/configure/generate_build_matrix.py): used def…
clay-lake Oct 8, 2024
34d14cd
refactor(.github/workflows/Build-Rock.yaml): extra line
clay-lake Oct 8, 2024
a22eb9d
test build: prototype dynamic branch selection
clay-lake Oct 8, 2024
ac8dee4
fix: set select branch name
clay-lake Oct 9, 2024
c0a869c
fix: switch to ref name
clay-lake Oct 9, 2024
34a2bbe
fix: corrected validation paths
clay-lake Oct 9, 2024
bdabf43
test buidl with debug statment
clay-lake Oct 9, 2024
cc48df3
test build
clay-lake Oct 9, 2024
842aa07
fix: correct glob behavior
clay-lake Oct 9, 2024
d73c323
fix: correct folder name validation
clay-lake Oct 9, 2024
296eb23
test build: check folder_name
clay-lake Oct 9, 2024
3670096
fix: disable image folder validation
clay-lake Oct 9, 2024
616f4db
test build
clay-lake Oct 9, 2024
3d342f3
feat: add access validation job
clay-lake Oct 9, 2024
d44fa58
trigger test build
clay-lake Oct 9, 2024
f4319ef
fix(.github/workflows/Build-Rock.yaml): invalid yaml syntax
clay-lake Oct 9, 2024
168bc23
fix: path validation and step namea
clay-lake Oct 9, 2024
445c324
refactor: move path validation outside of build rock repo
clay-lake Oct 9, 2024
3b0933b
feat: added job to image workflow for matrix validation
clay-lake Oct 9, 2024
426cdff
fix(Image.yaml): bad job name
clay-lake Oct 9, 2024
f988941
refactor(Image.yaml): adjust whitespace and comments
clay-lake Oct 9, 2024
3511bce
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Oct 9, 2024
51968d1
test: github property exposing wf call params
clay-lake Oct 9, 2024
899df8c
Merge branch 'ROCKS-1452/oci-factory-refactor-build-rock-to-be-extern…
clay-lake Oct 9, 2024
9e21470
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Oct 9, 2024
9430e88
feat: forward workflow ref to self checkout
clay-lake Oct 9, 2024
d62e023
Merge branch 'ROCKS-1452/oci-factory-refactor-build-rock-to-be-extern…
clay-lake Oct 9, 2024
786af95
test build
clay-lake Oct 9, 2024
4201240
test: canonical/get-workflow-version-action@v1
clay-lake Oct 9, 2024
5bd360c
fix: missing toJSON call
clay-lake Oct 9, 2024
d1e0edb
test: checkout self according to sha
clay-lake Oct 9, 2024
df5df0d
fix: bash syntax error
clay-lake Oct 9, 2024
271c535
fix: bash syntax error
clay-lake Oct 9, 2024
dc7b533
fix: syntax errors in workflow
clay-lake Oct 9, 2024
b6d8a23
fix: correct step name
clay-lake Oct 9, 2024
d7e543b
test: adaptor git checkout action
clay-lake Oct 9, 2024
fb7ee58
fix: missing file extension
clay-lake Oct 9, 2024
0e848d3
fix: bad action path
clay-lake Oct 9, 2024
67947b0
ci: automatically update oci/mock-rock/_releases.json, from https://g…
Oct 9, 2024
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
314 changes: 167 additions & 147 deletions .github/workflows/Build-Rock.yaml
Original file line number Diff line number Diff line change
@@ -1,54 +1,62 @@
name: Build rock
name: Build Rock

clay-lake marked this conversation as resolved.
Show resolved Hide resolved
on:
workflow_call:
inputs:
# build configuration
oci-archive-name:
description: "Final filename of the rock's OCI archive"
description: "Final filename of the Rock OCI archive."
type: string
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
required: true
oci-factory-path:
description: "Path, in the OCI Factory, to this rock"
arch-map:
description: "JSON string mapping target architecture to runner."
type: string
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
required: true
rock-name:
description: "Name of the rock"
type: string
required: true
default: '{"amd64": "ubuntu-22.04"}'
lpci-fallback:
description: 'Enable fallback to Launchpad build when runners for target arch are not available.'
type: boolean
default: false

# source configuration
rock-repo:
description: "Public Git repo where to build the rock from"
description: "Public Git repo where to build the rock from."
type: string
required: true
rock-repo-commit:
description: "Git ref from where to build the rock from"
description: "Git ref from where to build the rock from."
type: string
required: true
rockfile-directory:
description: "Directory, in 'rock-repo', where to find the rockcraft.yaml file"
description: "Directory in repository where to find the rockcraft.yaml file."
type: string
required: true


env:
ROCKS_CI_FOLDER: ci-rocks
ROCK_REPO_DIR: rock-repo # path where the image repo is cloned to
ROCK_CI_FOLDER: ci-rocks # path of uploaded/downloaded artifacts

clay-lake marked this conversation as resolved.
Show resolved Hide resolved
OCI_FACTORY_REPO: canonical/oci-factory
# TODO: update before final merge
OCI_FACTORY_BRANCH: ROCKS-1452/oci-factory-refactor-build-rock-to-be-externally-reusable # required for external workflow calls.

clay-lake marked this conversation as resolved.
Show resolved Hide resolved
jobs:
prepare-multi-arch-matrix:

configure-build:
# configure-build reads the rockcraft.yaml, creating one or more *-build job runs
# depending on the target architecture.
runs-on: ubuntu-22.04
outputs:
build-for: ${{ steps.rock-platforms.outputs.build-for }}
build-with-lpci: ${{ steps.rock-platforms.outputs.build-with-lpci }}
runner-build-matrix: ${{ steps.configure.outputs.runner-build-matrix }}
lpci-build-matrix: ${{ steps.configure.outputs.lpci-build-matrix }}
steps:
- name: Clone GitHub image repository
uses: actions/checkout@v4
id: clone-image-repo
continue-on-error: true

# Job Setup
- uses: actions/checkout@v4
with:
repository: ${{ inputs.rock-repo }}
fetch-depth: 0
- name: Clone generic image repository
if: ${{ steps.clone-image-repo.outcome == 'failure' }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

why are you removing this? Without it, non-github repos won't work.

run: |
git clone ${{ inputs.rock-repo }} .
repository: ${{ env.OCI_FACTORY_REPO }}
ref: ${{ env.OCI_FACTORY_BRANCH }}
fetch-depth: 1

- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
Expand All @@ -58,159 +66,171 @@ jobs:
image-path: ${{ inputs.oci-factory-path }}
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- run: git checkout ${{ inputs.rock-repo-commit }}

Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

- run: sudo snap install yq --channel=v4/stable
- name: Validate image naming and base
working-directory: ${{ inputs.rockfile-directory }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

(mentioned above in https://github.com/canonical/oci-factory/pull/233/files#diff-dd4702d1da9984f398938d6d41f0c95aef455bcedbbe87ed3f336b9e0259ab9eL14)

this shouldn't be removed. is a needed assertion for in-repo builds.

run: |
rock_name=`cat rockcraft.y*ml | yq -r .name`
if [[ "${{ inputs.oci-factory-path }}" != *"${rock_name}"* ]]
then
echo "ERROR: the rock's name '${rock_name}' must match the OCI folder name!"
exit 1
fi
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- run: pip install pyyaml
- name: Get rock archs
uses: jannekem/run-python-script-action@v1
id: rock-platforms
python-version: "3.x"

- run: pip install -r src/build_rock/configure/requirements.txt


- uses: actions/checkout@v4
with:
script: |
import yaml
import os

BUILD_WITH_LPCI = 0

with open("${{ inputs.rockfile-directory }}/rockcraft.yaml") as rf:
rockcraft_yaml = yaml.safe_load(rf)

platforms = rockcraft_yaml["platforms"]

target_archs = []
for platf, values in platforms.items():
if isinstance(values, dict) and "build-for" in values:
target_archs += list(values["build-for"])
continue
target_archs.append(platf)

print(f"Target architectures: {set(target_archs)}")

matrix = {"include": []}
gh_supported_archs = {"amd64": "ubuntu-22.04", "arm64": "Ubuntu_ARM64_4C_16G_01"}
if set(target_archs) - set(gh_supported_archs.keys()):
# Then there are other target archs, so we need to build in LP
matrix["include"].append(
{"architecture": "-".join(set(target_archs)), "runner": gh_supported_archs["amd64"]}
)
BUILD_WITH_LPCI = 1
else:
for runner_arch, runner_name in gh_supported_archs.items():
if runner_arch in target_archs:
matrix["include"].append(
{"architecture": runner_arch, "runner": runner_name}
)

with open(os.environ["GITHUB_OUTPUT"], "a") as gh_out:
print(f"build-for={matrix}", file=gh_out)
print(f"build-with-lpci={BUILD_WITH_LPCI}", file=gh_out)

build:
needs: [prepare-multi-arch-matrix]
repository: ${{ inputs.rock-repo }}
path: ${{ env.ROCK_REPO_DIR }}
ref: ${{ inputs.rock-repo-commit }}
submodules: 'recursive'


# Configure matrices for each *-build job
- name: Configure
id: configure
run: |
python3 -m src.build_rock.configure.generate_build_matrix \
--rockfile-directory "${{ env.ROCK_REPO_DIR }}/${{ inputs.rockfile-directory }}" \
--lpci-fallback "${{ toJSON(inputs.lpci-fallback) }}" \
--config ${{ toJSON(inputs.arch-map) }} # important: do not use quotes here


runner-build:
# runner-build builds rocks per target architecture using pre configured runner images.
needs: [configure-build]
if: fromJSON(needs.configure-build.outputs.runner-build-matrix).include[0] != ''
strategy:
fail-fast: true
matrix: ${{ fromJSON(needs.prepare-multi-arch-matrix.outputs.build-for) }}
runs-on: ${{ matrix.runner }}
name: 'Build ${{ inputs.rock-name }} | ${{ matrix.architecture }}'
matrix: ${{ fromJSON(needs.configure-build.outputs.runner-build-matrix) }}
runs-on: ${{ matrix.runner }}
name: 'runner-build | ${{ matrix.architecture }} '
Copy link
Collaborator

Choose a reason for hiding this comment

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

if using LPCI, I think you're not setting the runner at https://github.com/canonical/oci-factory/pull/233/files#diff-d14de60b7f1da617d4f2bec5847471874842e992154e38edcf760909e46d8dcdR58. Even if GH somehow defaults to something, it would be better to set the default value explicitly, to be predictable.

steps:
Copy link
Collaborator

Choose a reason for hiding this comment

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

we're losing useful logging information here. the name of the rock helps a lot with the GUI navigation when the matrix is big

- name: Clone GitHub image repository

- name: Clone Repo
uses: actions/checkout@v4
id: clone-image-repo
continue-on-error: true
with:
repository: ${{ inputs.rock-repo }}
fetch-depth: 0
- name: Clone generic image repository
if: ${{ steps.clone-image-repo.outcome == 'failure' }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

same comment as above - this is needed for non-GH repos.

run: |
git clone ${{ inputs.rock-repo }} .
- run: git checkout ${{ inputs.rock-repo-commit }}
- name: Build rock ${{ inputs.rock-name }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

path: ${{ env.ROCK_REPO_DIR }}
ref: ${{ inputs.rock-repo-commit }}
submodules: 'recursive'


- name: Build Target
id: rockcraft
if: needs.prepare-multi-arch-matrix.outputs.build-with-lpci == 0
uses: canonical/craft-actions/rockcraft-pack@main
with:
path: "${{ inputs.rockfile-directory }}"
path: "${{ env.ROCK_REPO_DIR }}/${{ inputs.rockfile-directory }}"
verbosity: debug
- uses: actions/setup-python@v5
if: needs.prepare-multi-arch-matrix.outputs.build-with-lpci == 1


- name: Collect Artifacts
id: collect-artifacts
run: |
mkdir -p ${{ env.ROCK_CI_FOLDER }} && cp ${{ steps.rockcraft.outputs.rock }} "$_"
echo "filename=$(basename ${{ steps.rockcraft.outputs.rock }})" >> $GITHUB_OUTPUT

clay-lake marked this conversation as resolved.
Show resolved Hide resolved

- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
python-version: '3.x'
- uses: nick-fields/[email protected]
name: Build multi-arch ${{ inputs.rock-name }} in Launchpad
if: needs.prepare-multi-arch-matrix.outputs.build-with-lpci == 1
name: ${{ inputs.oci-archive-name }}-${{ steps.collect-artifacts.outputs.filename }}
path: ${{ env.ROCK_CI_FOLDER }}
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
if-no-files-found: error


lpci-build:
# lpci-build is a fallback for building rocks if no suitable runners are
# configured for the required architecture. Builds in this job will be
# outsourced to Launchpad for completion.
# Note the Secret
needs: [configure-build]
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
if: fromJSON(needs.configure-build.outputs.lpci-build-matrix).include[0] != ''
strategy:
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
fail-fast: true
matrix: ${{ fromJSON(needs.configure-build.outputs.lpci-build-matrix) }}
runs-on: ubuntu-22.04
name: 'lpci-build | ${{ matrix.architecture }} '
steps:
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above, we could use the rock's name


clay-lake marked this conversation as resolved.
Show resolved Hide resolved
# Job Setup
- uses: actions/checkout@v4
with:
repository: ${{ env.OCI_FACTORY_REPO }}
ref: ${{ env.OCI_FACTORY_BRANCH }}
fetch-depth: 1


- name: Clone Repo
uses: actions/checkout@v4
with:
repository: ${{ inputs.rock-repo }}
path: ${{ env.ROCK_REPO_DIR }}
ref: ${{ inputs.rock-repo-commit }}
submodules: 'recursive'


Copy link
Collaborator

Choose a reason for hiding this comment

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

same comments as above wrt non-GH repos

- name: Build Target
# TODO: Replace this retry action with bash equivalent for better testing
uses: nick-fields/[email protected]
with:
timeout_minutes: 180
max_attempts: 4
polling_interval_seconds: 5
retry_wait_seconds: 30
command: |
set -ex
cd ${{ inputs.rockfile-directory }}
rocks_toolbox="$(mktemp -d)"
git clone --depth 1 --branch v1.1.2 https://github.com/canonical/rocks-toolbox $rocks_toolbox
${rocks_toolbox}/rockcraft_lpci_build/requirements.sh
pip3 install -r ${rocks_toolbox}/rockcraft_lpci_build/requirements.txt

python3 ${rocks_toolbox}/rockcraft_lpci_build/rockcraft_lpci_build.py \
--lp-credentials-b64 "${{ secrets.LP_CREDENTIALS_B64 }}" \
--launchpad-accept-public-upload
- name: Rename rock OCI archive
id: rock
src/build_rock/lpci_build/lpci_build.sh \
-c "${{ secrets.LP_CREDENTIALS_B64 }}" \
-d "${{ env.ROCK_REPO_DIR }}/${{ inputs.rockfile-directory }}"


- name: Collect Artifacts
id: collect-artifacts
run: |
mkdir ${{ env.ROCKS_CI_FOLDER }}
if [ ${{ needs.prepare-multi-arch-matrix.outputs.build-with-lpci }} -eq 0 ]
then
cp ${{ steps.rockcraft.outputs.rock }} ${{ env.ROCKS_CI_FOLDER }}/$(basename ${{ steps.rockcraft.outputs.rock }})
echo "filename=$(basename ${{ steps.rockcraft.outputs.rock }})" >> $GITHUB_OUTPUT
else
cp ${{ inputs.rockfile-directory }}/*.rock ${{ env.ROCKS_CI_FOLDER }}
echo "filename=${{ inputs.rock-name }}_${{ matrix.architecture }}" >> $GITHUB_OUTPUT
fi
- name: Upload ${{ inputs.rock-name }} for ${{ matrix.architecture }}
mkdir -p ${{ env.ROCK_CI_FOLDER }} && cp ${{ env.ROCK_REPO_DIR }}/${{ inputs.rockfile-directory }}/*.rock "$_"
echo "filename=${{ matrix.rock-name }}_${{ matrix.architecture }}" >> $GITHUB_OUTPUT


- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.oci-archive-name }}-${{ steps.rock.outputs.filename }}
path: ${{ env.ROCKS_CI_FOLDER }}
name: ${{ inputs.oci-archive-name }}-${{ steps.collect-artifacts.outputs.filename }}
path: ${{ env.ROCK_CI_FOLDER }}
if-no-files-found: error


assemble-rock:
needs: [prepare-multi-arch-matrix, build]
# Assemble individual single-arch rocks into multi-arch rocks
needs: [runner-build, lpci-build]
runs-on: ubuntu-22.04
# Always run even if one of the *-build jobs are skipped
# Nice example from benjamin-bergia/github-workflow-patterns...
if: ${{ always() && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }}
steps:
clay-lake marked this conversation as resolved.
Show resolved Hide resolved
- uses: actions/download-artifact@v4

# Job Setup
- uses: actions/checkout@v4
with:
repository: ${{ env.OCI_FACTORY_REPO }}
ref: ${{ env.OCI_FACTORY_BRANCH }}
fetch-depth: 1

- run: src/build_rock/assemble_rock/requirements.sh


clay-lake marked this conversation as resolved.
Show resolved Hide resolved
- name: Download Single Arch Rocks
uses: actions/download-artifact@v4
id: download
- run: sudo apt update && sudo apt install buildah -y
- name: Merge single-arch rocks into multi-arch OCI archive
with:
path: ${{ env.ROCK_CI_FOLDER }}
pattern: ${{ inputs.oci-archive-name }}-*


Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change

nit: not sure if there are others like this, but better run a yaml formatter on all these files

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem. Do we have a preferred autoformatter? I can add it to the docs.

- name: Assemble Multi Arch Rock
run: |
set -xe
ls ./${{ inputs.oci-archive-name }}*
buildah manifest create multi-arch-rock
for rock in `find ${{ inputs.oci-archive-name }}*/*.rock`
do
test -f $rock
buildah manifest add multi-arch-rock oci-archive:$rock
done
buildah manifest push --all multi-arch-rock oci-archive:${{ inputs.oci-archive-name }}
- name: Upload multi-arch ${{ inputs.oci-archive-name }} OCI archive
src/build_rock/assemble_rock/assemble.sh \
-n "${{ inputs.oci-archive-name }}" \
-d "${{ env.ROCK_CI_FOLDER }}"


- name: Upload Multi Arch Rock
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.oci-archive-name }}
path: ${{ inputs.oci-archive-name }}
if-no-files-found: error
- uses: actions/cache/save@v4
with:
path: ${{ inputs.oci-archive-name }}
key: ${{ github.run_id }}-${{ inputs.oci-archive-name }}
Loading
Loading