mirror of
https://github.com/outbackdingo/cozystack.git
synced 2026-01-27 18:18:41 +00:00
* Simplify test discovery logic in workflow. * Delete Clickhouse after successful test. * Separate two k8s tests into separate jobs. Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
353 lines
12 KiB
YAML
353 lines
12 KiB
YAML
name: Pull Request
|
||
|
||
env:
|
||
REGISTRY: ${{ secrets.OCIR_REPO }}
|
||
on:
|
||
pull_request:
|
||
types: [opened, synchronize, reopened]
|
||
paths-ignore:
|
||
- 'docs/**/*'
|
||
|
||
# Cancel in‑flight runs for the same PR when a new push arrives.
|
||
concurrency:
|
||
group: pr-${{ github.workflow }}-${{ github.event.pull_request.number }}
|
||
cancel-in-progress: true
|
||
|
||
jobs:
|
||
build:
|
||
name: Build
|
||
runs-on: [self-hosted]
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
|
||
# Never run when the PR carries the "release" label.
|
||
if: |
|
||
!contains(github.event.pull_request.labels.*.name, 'release')
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
fetch-tags: true
|
||
|
||
- name: Login to GitHub Container Registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
username: ${{ secrets.OCIR_USER}}
|
||
password: ${{ secrets.OCIR_TOKEN }}
|
||
registry: iad.ocir.io
|
||
env:
|
||
DOCKER_CONFIG: ${{ runner.temp }}/.docker
|
||
|
||
- name: Build
|
||
run: make build
|
||
env:
|
||
DOCKER_CONFIG: ${{ runner.temp }}/.docker
|
||
|
||
- name: Build Talos image
|
||
run: make -C packages/core/installer talos-nocloud
|
||
|
||
- name: Save git diff as patch
|
||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||
run: git diff HEAD > _out/assets/pr.patch
|
||
|
||
- name: Upload git diff patch
|
||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: pr-patch
|
||
path: _out/assets/pr.patch
|
||
|
||
- name: Upload installer
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: cozystack-installer
|
||
path: _out/assets/cozystack-installer.yaml
|
||
|
||
- name: Upload Talos image
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: talos-image
|
||
path: _out/assets/nocloud-amd64.raw.xz
|
||
|
||
resolve_assets:
|
||
name: "Resolve assets"
|
||
runs-on: ubuntu-latest
|
||
if: contains(github.event.pull_request.labels.*.name, 'release')
|
||
outputs:
|
||
installer_id: ${{ steps.fetch_assets.outputs.installer_id }}
|
||
disk_id: ${{ steps.fetch_assets.outputs.disk_id }}
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
if: contains(github.event.pull_request.labels.*.name, 'release')
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
fetch-tags: true
|
||
|
||
- name: Extract tag from PR branch (release PR)
|
||
if: contains(github.event.pull_request.labels.*.name, 'release')
|
||
id: get_tag
|
||
uses: actions/github-script@v7
|
||
with:
|
||
script: |
|
||
const branch = context.payload.pull_request.head.ref;
|
||
const m = branch.match(/^release-(\d+\.\d+\.\d+(?:[-\w\.]+)?)$/);
|
||
if (!m) {
|
||
core.setFailed(`❌ Branch '${branch}' does not match 'release-X.Y.Z[-suffix]'`);
|
||
return;
|
||
}
|
||
core.setOutput('tag', `v${m[1]}`);
|
||
|
||
- name: Find draft release & asset IDs (release PR)
|
||
if: contains(github.event.pull_request.labels.*.name, 'release')
|
||
id: fetch_assets
|
||
uses: actions/github-script@v7
|
||
with:
|
||
github-token: ${{ secrets.GH_PAT }}
|
||
script: |
|
||
const tag = '${{ steps.get_tag.outputs.tag }}';
|
||
const releases = await github.rest.repos.listReleases({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
per_page: 100
|
||
});
|
||
const draft = releases.data.find(r => r.tag_name === tag && r.draft);
|
||
if (!draft) {
|
||
core.setFailed(`Draft release '${tag}' not found`);
|
||
return;
|
||
}
|
||
const find = (n) => draft.assets.find(a => a.name === n)?.id;
|
||
const installerId = find('cozystack-installer.yaml');
|
||
const diskId = find('nocloud-amd64.raw.xz');
|
||
if (!installerId || !diskId) {
|
||
core.setFailed('Required assets missing in draft release');
|
||
return;
|
||
}
|
||
core.setOutput('installer_id', installerId);
|
||
core.setOutput('disk_id', diskId);
|
||
|
||
|
||
prepare_env:
|
||
name: "Prepare environment"
|
||
runs-on: [self-hosted]
|
||
permissions:
|
||
contents: read
|
||
packages: read
|
||
needs: ["build", "resolve_assets"]
|
||
if: ${{ always() && (needs.build.result == 'success' || needs.resolve_assets.result == 'success') }}
|
||
|
||
steps:
|
||
# ▸ Checkout and prepare the codebase
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
# ▸ Regular PR path – download artefacts produced by the *build* job
|
||
- name: "Download Talos image (regular PR)"
|
||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: talos-image
|
||
path: _out/assets
|
||
|
||
- name: Download PR patch
|
||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: pr-patch
|
||
path: _out/assets
|
||
|
||
- name: Apply patch
|
||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||
run: |
|
||
git apply _out/assets/pr.patch
|
||
|
||
# ▸ Release PR path – fetch artefacts from the corresponding draft release
|
||
- name: Download assets from draft release (release PR)
|
||
if: contains(github.event.pull_request.labels.*.name, 'release')
|
||
run: |
|
||
mkdir -p _out/assets
|
||
curl -sSL -H "Authorization: token ${GH_PAT}" -H "Accept: application/octet-stream" \
|
||
-o _out/assets/nocloud-amd64.raw.xz \
|
||
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.disk_id }}"
|
||
env:
|
||
GH_PAT: ${{ secrets.GH_PAT }}
|
||
|
||
- name: Set sandbox ID
|
||
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
|
||
|
||
# ▸ Start actual job steps
|
||
- name: Prepare workspace
|
||
run: |
|
||
rm -rf /tmp/$SANDBOX_NAME
|
||
cp -r ${{ github.workspace }} /tmp/$SANDBOX_NAME
|
||
|
||
- name: Prepare environment
|
||
run: |
|
||
cd /tmp/$SANDBOX_NAME
|
||
attempt=0
|
||
until make SANDBOX_NAME=$SANDBOX_NAME prepare-env; do
|
||
attempt=$((attempt + 1))
|
||
if [ $attempt -ge 3 ]; then
|
||
echo "❌ Attempt $attempt failed, exiting..."
|
||
exit 1
|
||
fi
|
||
echo "❌ Attempt $attempt failed, retrying..."
|
||
done
|
||
echo "✅ The task completed successfully after $attempt attempts"
|
||
|
||
install_cozystack:
|
||
name: "Install Cozystack"
|
||
runs-on: [self-hosted]
|
||
permissions:
|
||
contents: read
|
||
packages: read
|
||
needs: ["prepare_env", "resolve_assets"]
|
||
if: ${{ always() && needs.prepare_env.result == 'success' }}
|
||
|
||
steps:
|
||
- name: Prepare _out/assets directory
|
||
run: mkdir -p _out/assets
|
||
|
||
# ▸ Regular PR path – download artefacts produced by the *build* job
|
||
- name: "Download installer (regular PR)"
|
||
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: cozystack-installer
|
||
path: _out/assets
|
||
|
||
# ▸ Release PR path – fetch artefacts from the corresponding draft release
|
||
- name: Download assets from draft release (release PR)
|
||
if: contains(github.event.pull_request.labels.*.name, 'release')
|
||
run: |
|
||
mkdir -p _out/assets
|
||
curl -sSL -H "Authorization: token ${GH_PAT}" -H "Accept: application/octet-stream" \
|
||
-o _out/assets/cozystack-installer.yaml \
|
||
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.installer_id }}"
|
||
env:
|
||
GH_PAT: ${{ secrets.GH_PAT }}
|
||
|
||
# ▸ Start actual job steps
|
||
- name: Set sandbox ID
|
||
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
|
||
|
||
- name: Sync _out/assets directory
|
||
run: |
|
||
mkdir -p /tmp/$SANDBOX_NAME/_out/assets
|
||
mv _out/assets/* /tmp/$SANDBOX_NAME/_out/assets/
|
||
|
||
- name: Install Cozystack into sandbox
|
||
run: |
|
||
cd /tmp/$SANDBOX_NAME
|
||
attempt=0
|
||
until make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME install-cozystack; do
|
||
attempt=$((attempt + 1))
|
||
if [ $attempt -ge 3 ]; then
|
||
echo "❌ Attempt $attempt failed, exiting..."
|
||
exit 1
|
||
fi
|
||
echo "❌ Attempt $attempt failed, retrying..."
|
||
done
|
||
echo "✅ The task completed successfully after $attempt attempts."
|
||
|
||
detect_test_matrix:
|
||
name: "Detect e2e test matrix"
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
matrix: ${{ steps.set.outputs.matrix }}
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
- id: set
|
||
run: |
|
||
apps=$(ls hack/e2e-apps/*.bats | cut -f3 -d/ | cut -f1 -d. | jq -R | jq -cs)
|
||
echo "matrix={\"app\":$apps}" >> "$GITHUB_OUTPUT"
|
||
|
||
test_apps:
|
||
strategy:
|
||
matrix: ${{ fromJson(needs.detect_test_matrix.outputs.matrix) }}
|
||
name: Test ${{ matrix.app }}
|
||
runs-on: [self-hosted]
|
||
needs: [install_cozystack,detect_test_matrix]
|
||
if: ${{ always() && (needs.install_cozystack.result == 'success' && needs.detect_test_matrix.result == 'success') }}
|
||
|
||
steps:
|
||
- name: Set sandbox ID
|
||
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
|
||
|
||
- name: E2E Apps
|
||
run: |
|
||
cd /tmp/$SANDBOX_NAME
|
||
attempt=0
|
||
until make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-apps-${{ matrix.app }}; do
|
||
attempt=$((attempt + 1))
|
||
if [ $attempt -ge 3 ]; then
|
||
echo "❌ Attempt $attempt failed, exiting..."
|
||
exit 1
|
||
fi
|
||
echo "❌ Attempt $attempt failed, retrying..."
|
||
done
|
||
echo "✅ The task completed successfully after $attempt attempts"
|
||
|
||
collect_debug_information:
|
||
name: Collect debug information
|
||
runs-on: [self-hosted]
|
||
needs: [test_apps]
|
||
if: ${{ always() }}
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Set sandbox ID
|
||
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
|
||
|
||
- name: Collect report
|
||
run: |
|
||
cd /tmp/$SANDBOX_NAME
|
||
make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-report
|
||
|
||
- name: Upload cozyreport.tgz
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: cozyreport
|
||
path: /tmp/${{ env.SANDBOX_NAME }}/_out/cozyreport.tgz
|
||
|
||
- name: Collect images list
|
||
run: |
|
||
cd /tmp/$SANDBOX_NAME
|
||
make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-images
|
||
|
||
- name: Upload image list
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: image-list
|
||
path: /tmp/${{ env.SANDBOX_NAME }}/_out/images.txt
|
||
|
||
cleanup:
|
||
name: Tear down environment
|
||
runs-on: [self-hosted]
|
||
needs: [collect_debug_information]
|
||
if: ${{ always() && needs.test_apps.result == 'success' }}
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
fetch-tags: true
|
||
|
||
- name: Set sandbox ID
|
||
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
|
||
|
||
- name: Tear down sandbox
|
||
run: make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME delete
|
||
|
||
- name: Remove workspace
|
||
run: rm -rf /tmp/$SANDBOX_NAME
|
||
|
||
|