name: Test and deploy on: pull_request: branches: - main push: branches: - main workflow_dispatch: jobs: verify: name: Verify production build if: gitea.event_name != 'pull_request' || gitea.event.pull_request.head.repo.full_name == gitea.repository runs-on: portfolio-ci timeout-minutes: 15 env: BUILDER_NAME: portfolio-builder VERIFY_IMAGE: portfolio-verify:${{ gitea.sha }} RUNTIME_IMAGE: amiirkhl-portfolio:${{ gitea.sha }} NPM_REGISTRY: https://package-mirror.liara.ir/repository/npm/ steps: - name: Check out repository uses: actions/checkout@v4 - name: Prepare persistent BuildKit builder shell: bash run: | set -Eeuo pipefail if ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then docker buildx create \ --name "$BUILDER_NAME" \ --driver docker-container \ --buildkitd-config .gitea/buildkitd.toml fi docker buildx use "$BUILDER_NAME" docker buildx inspect --bootstrap - name: Verify application once shell: bash run: | set -Eeuo pipefail docker buildx build \ --builder "$BUILDER_NAME" \ --target verification \ --build-arg "NPM_REGISTRY=$NPM_REGISTRY" \ --tag "$VERIFY_IMAGE" \ --load \ --progress plain \ . - name: Audit dependencies shell: bash run: | set -Eeuo pipefail docker run --rm "$VERIFY_IMAGE" \ npm audit \ --registry="$NPM_REGISTRY" \ --audit-level=high - name: Create immutable runtime image shell: bash run: | set -Eeuo pipefail docker buildx build \ --builder "$BUILDER_NAME" \ --target runtime \ --build-arg "NPM_REGISTRY=$NPM_REGISTRY" \ --tag "$RUNTIME_IMAGE" \ --load \ --progress plain \ . - name: Smoke-test runtime image shell: bash run: bash scripts/smoke-container.sh "$RUNTIME_IMAGE" - name: Configure deployment SSH if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' shell: bash env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }} SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }} run: | set -Eeuo pipefail : "${DEPLOY_HOST:?DEPLOY_HOST secret is required}" : "${DEPLOY_KNOWN_HOSTS:?DEPLOY_KNOWN_HOSTS secret is required}" : "${SSH_PRIVATE_KEY:?DEPLOY_SSH_KEY secret is required}" install -d -m 700 "$HOME/.ssh" printf '%s\n' "$SSH_PRIVATE_KEY" > "$HOME/.ssh/deploy_key" chmod 600 "$HOME/.ssh/deploy_key" printf '%s\n' "$DEPLOY_KNOWN_HOSTS" > "$HOME/.ssh/known_hosts" chmod 600 "$HOME/.ssh/known_hosts" - name: Upload release manifest if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' shell: bash env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} run: | set -Eeuo pipefail : "${DEPLOY_USER:?DEPLOY_USER secret is required}" DEPLOY_PORT="${DEPLOY_PORT:-22}" scp \ -i "$HOME/.ssh/deploy_key" \ -o BatchMode=yes \ -o StrictHostKeyChecking=yes \ -P "$DEPLOY_PORT" \ compose.yaml \ "$DEPLOY_USER@$DEPLOY_HOST:/tmp/portfolio-${{ gitea.sha }}-compose.yaml" - name: Activate verified image if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' shell: bash env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} run: | set -Eeuo pipefail : "${DEPLOY_PATH:?DEPLOY_PATH secret is required}" DEPLOY_PORT="${DEPLOY_PORT:-22}" remote_compose="/tmp/portfolio-${{ gitea.sha }}-compose.yaml" printf -v remote_command \ 'bash -s -- %q %q %q %q %q' \ "$DEPLOY_PATH" \ "${{ gitea.sha }}" \ "$RUNTIME_IMAGE" \ "${{ gitea.run_number }}" \ "$remote_compose" ssh \ -i "$HOME/.ssh/deploy_key" \ -o BatchMode=yes \ -o StrictHostKeyChecking=yes \ -p "$DEPLOY_PORT" \ "$DEPLOY_USER@$DEPLOY_HOST" \ "$remote_command" \ < scripts/deploy-release.sh - name: Remove temporary verification image if: always() shell: bash run: docker image rm "$VERIFY_IMAGE" >/dev/null 2>&1 || true