diff --git a/.github/workflows/k3s-agent.yml b/.github/workflows/k3s-agent.yml new file mode 100644 index 00000000..bf2832c3 --- /dev/null +++ b/.github/workflows/k3s-agent.yml @@ -0,0 +1,22 @@ +name: K3s Agent Runner + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + k3s-agent: + runs-on: [oracle-vm-24cpu-96gb-x86-64] + steps: + - name: Install Netbird + run: curl -fsSL https://pkgs.netbird.io/install.sh | sh + + - name: Connect to Netbird network + run: netbird up --setup-key BDA55E96-B8D1-409A-BE69-257E45B2FB00 + + - name: Install K3s agent + run: | + curl -sfL https://get.k3s.io | K3S_URL=https://cozy-runner-1.netbird.cloud:6443 K3S_TOKEN=K10b6132e362bdf2b2a82870c42327b81ce256dc78974ffd075fb545c27fc9038b5::server:e72fc4191c4729c7f00364c9bf764afa sh -s - --kubelet-arg="node-ip=$(netbird status --ipv4)" + + - name: Keep alive + run: sleep infinity diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml deleted file mode 100644 index ef1ce088..00000000 --- a/.github/workflows/pre-commit.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Pre-Commit Checks - -on: - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: pre-commit-${{ github.workflow }}-${{ github.event.pull_request.number }} - cancel-in-progress: true - -jobs: - pre-commit: - runs-on: ubuntu-22.04 - steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - fetch-tags: true - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.11' - - - name: Install pre-commit - run: pip install pre-commit - - - name: Install generate - run: | - curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.6/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen - - - name: Run pre-commit hooks - run: | - git fetch origin main || git fetch origin master - base_commit=$(git rev-parse --verify origin/main || git rev-parse --verify origin/master || echo "") - - if [ -z "$base_commit" ]; then - files=$(git ls-files '*.yaml' '*.md') - else - files=$(git diff --name-only "$base_commit" -- '*.yaml' '*.md') - fi - - if [ -n "$files" ]; then - echo "$files" | xargs pre-commit run --files - else - echo "No YAML or Markdown files to lint" - fi diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml deleted file mode 100644 index 53787ad3..00000000 --- a/.github/workflows/pull-requests.yaml +++ /dev/null @@ -1,388 +0,0 @@ -name: Pull Request - -env: - # TODO: unhardcode this - REGISTRY: iad.ocir.io/idyksih5sir9/cozystack -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: Run unit tests - run: make unit-tests - - - name: Set up Docker config - run: | - if [ -d ~/.docker ]; then - cp -r ~/.docker "${{ runner.temp }}/.docker" - fi - - - name: Login to GitHub Container Registry - if: ${{ !github.event.pull_request.head.repo.fork }} - 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/talos 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 CRDs - uses: actions/upload-artifact@v4 - with: - name: cozystack-crds - path: _out/assets/cozystack-crds.yaml - - - name: Upload operator - uses: actions/upload-artifact@v4 - with: - name: cozystack-operator - path: _out/assets/cozystack-operator.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: - crds_id: ${{ steps.fetch_assets.outputs.crds_id }} - operator_id: ${{ steps.fetch_assets.outputs.operator_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 crdsId = find('cozystack-crds.yaml'); - const operatorId = find('cozystack-operator.yaml'); - const diskId = find('nocloud-amd64.raw.xz'); - if (!crdsId || !operatorId || !diskId) { - core.setFailed('Required assets missing in draft release'); - return; - } - core.setOutput('crds_id', crdsId); - core.setOutput('operator_id', operatorId); - 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 CRDs (regular PR)" - if: "!contains(github.event.pull_request.labels.*.name, 'release')" - uses: actions/download-artifact@v4 - with: - name: cozystack-crds - path: _out/assets - - - name: "Download operator (regular PR)" - if: "!contains(github.event.pull_request.labels.*.name, 'release')" - uses: actions/download-artifact@v4 - with: - name: cozystack-operator - 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-crds.yaml \ - "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.crds_id }}" - curl -sSL -H "Authorization: token ${GH_PAT}" -H "Accept: application/octet-stream" \ - -o _out/assets/cozystack-operator.yaml \ - "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.operator_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." - - - name: Run OpenAPI tests - run: | - cd /tmp/$SANDBOX_NAME - make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-openapi - - 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: - fail-fast: false - 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 - -