name: Pipeline on: push: branches: ['*'] tags: ['v*'] pull_request: branches: [main] env: REGISTRY: git.holo-grid.bar IMAGE_TONGO: git.holo-grid.bar/costap/quarkshologridledger/tongo-core IMAGE_WEB: git.holo-grid.bar/costap/quarkshologridledger/web-terminal jobs: # ── JOB 1: CI (LINT & TEST) ───────────────────────────────── ci-backend: runs-on: docker steps: - uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v5 with: go-version: '1.23' - name: Lint working-directory: tongo-core run: | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest golangci-lint run ./... - name: Test working-directory: tongo-core run: go test -race -coverprofile=coverage.out ./... ci-frontend: runs-on: docker steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '22' - name: Install working-directory: web-terminal run: npm ci - name: Lint & Format Check working-directory: web-terminal run: npm run format - name: Type Check working-directory: web-terminal run: npx tsc --noEmit # ── JOB 2: INFRASTRUCTURE PLAN ────────────────────────────── infra-plan: runs-on: docker steps: - uses: actions/checkout@v4 - name: Setup OpenTofu uses: opentofu/setup-opentofu@v1 - name: Set environment target id: target run: | if [[ "${{ github.ref }}" == refs/tags/v* ]]; then echo "env_name=production" >> $GITHUB_OUTPUT else echo "env_name=staging" >> $GITHUB_OUTPUT fi - name: Init and Plan working-directory: infra env: HCLOUD_TOKEN: ${{ secrets.HCLOUD_TOKEN }} ENV_NAME: ${{ steps.target.outputs.env_name }} TF_VAR_hcloud_token: ${{ secrets.HCLOUD_TOKEN }} TF_VAR_ssh_public_key: ${{ secrets.SSH_PUBLIC_KEY }} TF_VAR_domain: "holo-grid.bar" TF_VAR_forgejo_domain: "git.holo-grid.bar" run: | tofu init tofu workspace select $ENV_NAME || tofu workspace new $ENV_NAME tofu plan -out=tfplan - name: Upload plan artifact if: github.event_name == 'pull_request' uses: actions/upload-artifact@v4 with: name: tfplan path: infra/tfplan # ── JOB 3: INFRASTRUCTURE APPLY (Depends on Plan and CI) ──── infra-apply: runs-on: docker needs: [ci-backend, ci-frontend, infra-plan] if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.event_name == 'push' steps: - uses: actions/checkout@v4 - name: Setup OpenTofu uses: opentofu/setup-opentofu@v1 - name: Set environment target id: target run: | if [[ "${{ github.ref }}" == refs/tags/v* ]]; then echo "env_name=production" >> $GITHUB_OUTPUT else echo "env_name=staging" >> $GITHUB_OUTPUT fi - name: Init and Apply working-directory: infra env: HCLOUD_TOKEN: ${{ secrets.HCLOUD_TOKEN }} ENV_NAME: ${{ steps.target.outputs.env_name }} TF_VAR_hcloud_token: ${{ secrets.HCLOUD_TOKEN }} TF_VAR_ssh_public_key: ${{ secrets.SSH_PUBLIC_KEY }} TF_VAR_domain: "holo-grid.bar" TF_VAR_forgejo_domain: "git.holo-grid.bar" run: | tofu init tofu workspace select $ENV_NAME || tofu workspace new $ENV_NAME tofu apply -auto-approve # ── JOB 4: BUILD AND PUSH DOCKER (Depends on CI) ──────────── build-and-push: runs-on: docker needs: [ci-backend, ci-frontend] if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.event_name == 'push' steps: - uses: actions/checkout@v4 - name: Set image tag run: | if [ "${{ github.ref_type }}" = "tag" ]; then echo "TAG=${{ github.ref_name }}" >> $GITHUB_ENV else echo "TAG=sha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV fi - name: Login to Forgejo Registry run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login $REGISTRY -u ${{ secrets.REGISTRY_USER }} --password-stdin - name: Build & Push Tongo Core run: | docker build -t $IMAGE_TONGO:$TAG -t $IMAGE_TONGO:latest -f tongo-core/Dockerfile . docker push $IMAGE_TONGO:$TAG docker push $IMAGE_TONGO:latest - name: Build & Push Web Terminal run: | docker build -t $IMAGE_WEB:$TAG -t $IMAGE_WEB:latest -f web-terminal/Dockerfile . docker push $IMAGE_WEB:$TAG docker push $IMAGE_WEB:latest # ── JOB 5: DEPLOY (Depends on Apply and Build) ────────────── deploy: runs-on: docker needs: [infra-apply, build-and-push] steps: - uses: actions/checkout@v4 - name: Set environment target variables id: target run: | if [[ "${{ github.ref }}" == refs/tags/v* ]]; then echo "env_name=production" >> $GITHUB_OUTPUT echo "deploy_host=${{ secrets.DEPLOY_HOST_PROD }}" >> $GITHUB_OUTPUT echo "deploy_key<> $GITHUB_OUTPUT echo "${{ secrets.DEPLOY_SSH_KEY_PROD }}" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT else echo "env_name=staging" >> $GITHUB_OUTPUT echo "deploy_host=${{ secrets.DEPLOY_HOST_STAGING }}" >> $GITHUB_OUTPUT echo "deploy_key<> $GITHUB_OUTPUT echo "${{ secrets.DEPLOY_SSH_KEY_STAGING }}" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi - name: Deploy to Hetzner target environment env: ENV_NAME: ${{ steps.target.outputs.env_name }} DEPLOY_HOST: ${{ steps.target.outputs.deploy_host }} DEPLOY_KEY: ${{ steps.target.outputs.deploy_key }} run: | mkdir -p ~/.ssh echo "$DEPLOY_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key # Copy production compose file and configuration scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no \ deploy/docker-compose.prod.yml \ deploy/Caddyfile \ deploy@$DEPLOY_HOST:/opt/hologrid/ # Pull new images and restart the stack ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no deploy@$DEPLOY_HOST << 'EOF' cd /opt/hologrid echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ${{ env.REGISTRY }} -u ${{ secrets.REGISTRY_USER }} --password-stdin docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d --remove-orphans docker image prune -f EOF