Skip to content

Commit 8cb26b4

Browse files
indradhanushclaude
andcommitted
ci: rearchitect CI to drop workflow_run, split build/test/e2e
workflow_run-triggered workflows don't exist as a check until the upstream workflow they chain off of finishes — no pending state before that. Seeing every check queued immediately when a PR opens is a hard requirement, and workflow_run can't deliver that. Split into 4 directly-triggered, standalone workflow files instead: build-agent-bundle, unit-test, build-controller-manager, e2e. Each publish step (quay.io push) now runs as a gated, conditional step inside the job that already built the artifact, rather than a separate workflow_run-chained workflow — gated on github.ref == main or a manual ci-<tag> escape hatch (new `make ci` target). e2e still needs the controller-manager image from a separate workflow file (kept distinct so it shows as its own check); it polls for that job's completion via the new .ci/wait-for-job.sh script instead of workflow_run, so its own check still shows as running/in-progress immediately rather than not existing at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 5c9e694 commit 8cb26b4

12 files changed

Lines changed: 292 additions & 275 deletions

.ci/build-agent-bundle.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env bash
2+
set -Eeuo pipefail
3+
4+
main() {
5+
export BYOH_DEB_VERSION=${BYOH_DEB_VERSION:-$(make tag)}
6+
7+
echo 'alias shasum="sha512sum"' >>~/.bashrc
8+
# shellcheck disable=SC1090 # sourcing the user's own ~/.bashrc, not a repo file shellcheck can resolve
9+
source ~/.bashrc
10+
11+
echo "removing build/ if already present"
12+
rm -rf build/
13+
echo "started building byoh-agent binary"
14+
make build-host-agent-binary
15+
16+
echo "started building deb package for byoh-agent"
17+
make build-host-agent-deb
18+
19+
echo "created deb package under build/pf9-byohost/debsrc/ "
20+
}
21+
22+
main "$@"
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
#!/usr/bin/env bash
22

3-
# build-and-push.sh - CI script for building and publishing the byoh controller manager Docker image.
3+
# build-controller-manager.sh - CI script for building the byoh controller manager Docker image.
44
#
55
# Parameters:
6-
# - IMAGE_REGISTRY Registry to publish the Docker image. By default 'quay.io/platform9/cluster-api-provider-bringyourownhost' is used.
6+
# - IMAGE_REGISTRY Registry to tag the Docker image for. By default 'quay.io/platform9/cluster-api-provider-bringyourownhost' is used.
77
# - IMAGE_NAME Name to use for this image. By default 'controller-manager' is used.
88
# - IMAGE_TAG Tag to use for the image. By default the output of `make tag` (git describe) is used.
9-
# - DRY_RUN If non-empty, no Docker image will be published.
109
# - CONTAINER_TAG Location of the container_tag file (used as an artifact in TeamCity)
11-
# - DOCKER_USERNAME Username to login to quay.io.
12-
# - DOCKER_PASSWORD Password to login to quay.io.
1310
#
1411
# Examples:
15-
# - `USE_SYSTEM_GO=1 IMAGE_REGISTRY=quay.io IMAGE_NAME=platform9/cluster-api-provider-bringyourownhost/controller-manager IMAGE_TAG=latest ./build-and-push.sh`: To test the script locally without gimme and push to Docker
12+
# - `USE_SYSTEM_GO=1 IMAGE_REGISTRY=quay.io IMAGE_NAME=platform9/cluster-api-provider-bringyourownhost/controller-manager IMAGE_TAG=latest ./build-controller-manager.sh`: To test the script locally without gimme
1613

1714
set -o nounset
1815
set -o errexit
1916
set -o pipefail
2017

21-
project_root=$(realpath "$(dirname $0)/..")
18+
project_root=$(realpath "$(dirname "$0")/..")
2219
build_dir=${project_root}/build
2320
CONTAINER_TAG=${CONTAINER_TAG:-${build_dir}/manager-container-tag}
2421
CONTAINER_FULL_TAG=${CONTAINER_FULL_TAG:-${build_dir}/manager-container-full-tag}
@@ -41,28 +38,24 @@ if [[ "${IMAGE_TAG}" =~ [[:space:]] ]]; then
4138
exit 1
4239
fi
4340

44-
4541
main() {
4642
# Move to the project directory
4743
pushd "${project_root}"
4844
trap on_exit EXIT
4945

5046
if [ -n "${BASH_DEBUG:-}" ]; then
51-
set -x
52-
PS4='${BASH_SOURCE}.${LINENO} '
47+
set -x
48+
PS4='${BASH_SOURCE}.${LINENO} '
5349
fi
5450

5551
info "Verifying prerequisites"
5652
#which aws > /dev/null || (echo "error: missing required command 'aws'" && exit 1)
57-
which docker > /dev/null || (echo "error: missing required command 'docker'" && exit 1)
53+
which docker >/dev/null || (echo "error: missing required command 'docker'" && exit 1)
5854
# note: go and/or gimme are checked in configure_go
5955

6056
info "Preparing build environment"
6157
mkdir -p "${build_dir}"
6258

63-
info "Configure Docker registry and create image repository if not present"
64-
configure_docker_registry "${IMAGE_NAME}"
65-
6659
info "Configure go"
6760
configure_go
6861

@@ -73,17 +66,10 @@ main() {
7366
# Do not build the image with the registry prefix, because docker will think it is part of the name.
7467
make docker-build IMG="${IMAGE_REGISTRY_NAME_TAG}"
7568

76-
info "Pushing Docker image to ${IMAGE_REGISTRY_NAME_TAG}"
77-
if [ -z "${DRY_RUN:-}" ] ; then
78-
make docker-push IMG="${IMAGE_REGISTRY_NAME_TAG}"
79-
else
80-
info "DRY_RUN is set; not publishing the image"
81-
fi
82-
8369
info "Publish artifacts"
8470
mkdir -p "$(dirname "${CONTAINER_TAG}")" "$(dirname "${CONTAINER_FULL_TAG}")"
85-
echo -n "${IMAGE_TAG}" > "${CONTAINER_TAG}"
86-
echo -n "${IMAGE_REGISTRY_NAME_TAG}" > "${CONTAINER_FULL_TAG}"
71+
echo -n "${IMAGE_TAG}" >"${CONTAINER_TAG}"
72+
echo -n "${IMAGE_REGISTRY_NAME_TAG}" >"${CONTAINER_FULL_TAG}"
8773
echo "Stored image tag in ${CONTAINER_TAG}:"
8874
cat "${CONTAINER_TAG}" && echo ""
8975
echo "Stored image full tag in ${CONTAINER_FULL_TAG}:"
@@ -93,31 +79,19 @@ main() {
9379
on_exit() {
9480
ret=$?
9581
info "-------cleanup--------"
96-
if [ -z "${SKIP_CLEANUP:-}" ] ; then
82+
if [ -z "${SKIP_CLEANUP:-}" ]; then
9783
make docker-clean IMG="${IMAGE_REGISTRY_NAME_TAG}" || true
9884
fi
9985
popd
10086
exit ${ret}
10187
}
10288

103-
configure_docker_registry() {
104-
repository=$1
105-
if [ "${IMAGE_REGISTRY}" = "quay.io/platform9/cluster-api-provider-bringyourownhost" ]; then
106-
if [ -n "${DOCKER_PASSWORD:-}" ] ; then
107-
echo -n "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin "${IMAGE_REGISTRY}"
108-
else
109-
echo "Using default docker registry"
110-
fi
111-
fi
112-
echo "Configured registry '${IMAGE_REGISTRY}' for '${repository}'"
113-
}
114-
11589
configure_go() {
116-
if [ -n "${USE_SYSTEM_GO:-}" ] ; then
90+
if [ -n "${USE_SYSTEM_GO:-}" ]; then
11791
echo "\$USE_SYSTEM_GO set, using system go instead of gimme"
11892
return 0
11993
else
120-
which gimme > /dev/null || (echo "error: missing required command 'gimme'" && exit 1)
94+
which gimme >/dev/null || (echo "error: missing required command 'gimme'" && exit 1)
12195
eval "$(GIMME_GO_VERSION=${GO_VERSION} gimme)"
12296
fi
12397
which go
@@ -127,8 +101,11 @@ configure_go() {
127101
RED='\033[1;31m'
128102
YELLOW='\033[1;33m'
129103
NC='\033[0m'
130-
info() { echo -e >&2 "${YELLOW}[INFO] $@${NC}" ; }
131-
fatal() { echo >&2 "${RED}[FATAL] $@${NC}" ; exit 1 ; }
104+
info() { echo -e "${YELLOW}[INFO] $*${NC}" >&2; }
105+
fatal() {
106+
echo >&2 "${RED}[FATAL] $*${NC}"
107+
exit 1
108+
}
132109

133110
# shellcheck disable=SC2068
134-
main $@
111+
main $@

.ci/build-push-agent-deb.sh

Lines changed: 0 additions & 24 deletions
This file was deleted.

.ci/report-commit-status.sh

Lines changed: 0 additions & 28 deletions
This file was deleted.

.ci/wait-for-job.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env bash
2+
set -Eeuo pipefail
3+
4+
# wait-for-job.sh - polls a GitHub Actions workflow for a specific job's completion
5+
# on a given commit. GitHub Actions has no native way to block on a job in a
6+
# different, independently-triggered workflow file, so this fills that gap.
7+
#
8+
# Usage: wait-for-job.sh <workflow-file> <job-name> <sha>
9+
# Required env: GH_TOKEN, GITHUB_REPOSITORY
10+
# Optional env: MAX_ATTEMPTS (default 60), POLL_INTERVAL_SECONDS (default 30)
11+
# On success, appends "run_id=<id>" to $GITHUB_OUTPUT (if set) and exits 0.
12+
13+
main() {
14+
local workflow=$1
15+
local job_name=$2
16+
local sha=$3
17+
local max_attempts=${MAX_ATTEMPTS:-60}
18+
local poll_interval=${POLL_INTERVAL_SECONDS:-30}
19+
local attempt=1
20+
21+
while ((attempt <= max_attempts)); do
22+
local run_id
23+
run_id=$(gh run list --repo "${GITHUB_REPOSITORY}" --workflow "${workflow}" --commit "${sha}" \
24+
--json databaseId --jq '.[0].databaseId // empty')
25+
26+
if [[ -n "${run_id}" ]]; then
27+
local job_conclusion
28+
# shellcheck disable=SC2016 # single-quoted on purpose: $name is a jq var bound via --arg, not a shell expansion
29+
job_conclusion=$(gh run view "${run_id}" --repo "${GITHUB_REPOSITORY}" --json jobs \
30+
--jq --arg name "${job_name}" '.jobs[] | select(.name == $name) | .conclusion // empty')
31+
32+
case "${job_conclusion}" in
33+
success)
34+
echo "${job_name} succeeded (run ${run_id})"
35+
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
36+
echo "run_id=${run_id}" >>"${GITHUB_OUTPUT}"
37+
fi
38+
return 0
39+
;;
40+
failure | cancelled)
41+
echo "${job_name} did not succeed: ${job_conclusion}" >&2
42+
return 1
43+
;;
44+
esac
45+
fi
46+
47+
echo "waiting for ${job_name} on ${workflow} (attempt ${attempt}/${max_attempts})..."
48+
sleep "${poll_interval}"
49+
((attempt++))
50+
done
51+
52+
echo "timed out waiting for ${job_name} on ${workflow}" >&2
53+
return 1
54+
}
55+
56+
main "$@"
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Build Agent Bundle
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
tags: [ 'ci-*' ]
7+
paths-ignore:
8+
- '*.md'
9+
- 'docs/**'
10+
- 'LICENSE'
11+
- 'NOTICE'
12+
- 'PROJECT'
13+
- 'SECURITY_CONTACTS'
14+
pull_request:
15+
types: [opened, synchronize, reopened, ready_for_review]
16+
paths-ignore:
17+
- '*.md'
18+
- 'docs/**'
19+
- 'LICENSE'
20+
- 'NOTICE'
21+
- 'PROJECT'
22+
- 'SECURITY_CONTACTS'
23+
24+
jobs:
25+
build-host-agent-binary:
26+
if: ${{ !github.event.pull_request.draft }}
27+
runs-on: ubuntu-22.04
28+
steps:
29+
- name: Checkout code
30+
uses: actions/checkout@v3
31+
- name: build host agent binary
32+
run: make host-agent-binaries
33+
- name: Upload agent binary artifact
34+
uses: actions/upload-artifact@v4
35+
with:
36+
name: byoh-hostagent-linux-amd64
37+
path: bin/byoh-hostagent-linux-amd64
38+
retention-days: 1
39+
40+
build-agent-bundle:
41+
needs: build-host-agent-binary
42+
if: ${{ !github.event.pull_request.draft }}
43+
runs-on: ubuntu-22.04
44+
steps:
45+
- name: Checkout code
46+
uses: actions/checkout@v3
47+
with:
48+
fetch-depth: 0
49+
- name: Download agent binary artifact
50+
uses: actions/download-artifact@v4
51+
with:
52+
name: byoh-hostagent-linux-amd64
53+
path: bin
54+
- name: Install fpm build dependencies
55+
run: |
56+
sudo apt-get update
57+
sudo apt-get install -y --no-install-recommends ruby ruby-dev rubygems build-essential
58+
sudo gem install --no-document fpm
59+
- name: Build agent deb bundle
60+
env:
61+
SKIP_BUILD: "1"
62+
run: bash .ci/build-agent-bundle.sh
63+
- name: Upload agent bundle artifact
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: agent-bundle-deb
67+
path: build/pf9-byohost/debsrc/
68+
retention-days: 1
69+
70+
- name: Log in to Quay
71+
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/ci-') }}
72+
uses: docker/login-action@v3
73+
with:
74+
registry: quay.io
75+
username: ${{ secrets.QUAY_USERNAME }}
76+
password: ${{ secrets.QUAY_TOKEN }}
77+
78+
- name: Push agent bundle
79+
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/ci-') }}
80+
run: make push-agent-bundle TAG=$(make --no-print-directory tag)

0 commit comments

Comments
 (0)