ci(admin-web): Docker build & push vers registry Gitea + reusable tests
Some checks failed
CI / Detect Changes (pull_request) Successful in 3s
CI / YouTube Worker (pull_request) Failing after 6s
CI / Admin Web CI (pull_request) Failing after 7s
CI / Deploy (pull_request) Has been skipped
PR → Build → WiFi/USB Deploy → LGTM / Build & Deploy to iPhone (WiFi/USB) (pull_request) Failing after 2m54s
PR → Build → WiFi/USB Deploy → LGTM / Wait for LGTM comment (pull_request) Has been skipped
Some checks failed
CI / Detect Changes (pull_request) Successful in 3s
CI / YouTube Worker (pull_request) Failing after 6s
CI / Admin Web CI (pull_request) Failing after 7s
CI / Deploy (pull_request) Has been skipped
PR → Build → WiFi/USB Deploy → LGTM / Build & Deploy to iPhone (WiFi/USB) (pull_request) Failing after 2m54s
PR → Build → WiFi/USB Deploy → LGTM / Wait for LGTM comment (pull_request) Has been skipped
- Nouveau Dockerfile multi-stage Next.js standalone (node:22-bookworm-slim) - Configuration semantic-release (.releaserc.json, version.json, devDeps) - docker-compose.portainer.yml pour déploiement Portainer - Workflow docker-admin-web.yml : test → semantic-release → build push → deploy - Extraction admin-web-tests.yml (reusable workflow) appelé par ci.yml et docker-admin-web.yml → 0 duplication - next.config.ts : ajout output: 'standalone' - .dockerignore : exclusions node_modules, .next, etc.
This commit is contained in:
41
.github/workflows/admin-web-tests.yml
vendored
Normal file
41
.github/workflows/admin-web-tests.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Admin Web Tests
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
node-version:
|
||||
type: string
|
||||
default: '22'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
defaults:
|
||||
run:
|
||||
working-directory: admin-web
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: admin-web/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Type check
|
||||
run: npx tsc --noEmit
|
||||
|
||||
- name: Run unit tests
|
||||
run: npx vitest run
|
||||
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install --with-deps chromium
|
||||
|
||||
- name: Run E2E tests
|
||||
run: npx playwright test
|
||||
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -38,34 +38,9 @@ jobs:
|
||||
name: Admin Web CI
|
||||
needs: changes
|
||||
if: needs.changes.outputs.admin-web == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: admin-web
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: admin-web/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Type check
|
||||
run: npx tsc --noEmit
|
||||
|
||||
- name: Run unit tests
|
||||
run: npx vitest run
|
||||
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install --with-deps chromium
|
||||
|
||||
- name: Run E2E tests
|
||||
run: npx playwright test
|
||||
uses: ./.github/workflows/admin-web-tests.yml
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
# ── YouTube Worker: Node.js microservice ──
|
||||
youtube-worker-check:
|
||||
|
||||
154
.github/workflows/docker-admin-web.yml
vendored
Normal file
154
.github/workflows/docker-admin-web.yml
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
name: Docker Admin Web
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'admin-web/**'
|
||||
- '.github/workflows/docker-admin-web.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: docker-admin-web-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
admin-web-test:
|
||||
uses: ./.github/workflows/admin-web-tests.yml
|
||||
|
||||
semantic-release:
|
||||
name: Semantic Release
|
||||
needs: admin-web-test
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
defaults:
|
||||
run:
|
||||
working-directory: admin-web
|
||||
outputs:
|
||||
released: ${{ steps.check-release.outputs.released }}
|
||||
version: ${{ steps.check-release.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: admin-web/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Record version before release
|
||||
id: before
|
||||
run: echo "version=$(node -p "require('./version.json').version")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run semantic-release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.CI_GITEA_TOKEN }}
|
||||
GITEA_URL: https://gitea.1000co.fr
|
||||
run: npx semantic-release
|
||||
|
||||
- name: Check if released
|
||||
id: check-release
|
||||
run: |
|
||||
VERSION=$(node -p "require('./version.json').version")
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
if [ "${{ steps.before.outputs.version }}" != "$VERSION" ]; then
|
||||
echo "released=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "released=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
build-and-push:
|
||||
name: Build & Push Docker Image
|
||||
needs: semantic-release
|
||||
if: needs.semantic-release.outputs.released == 'true' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Install Docker CLI
|
||||
run: apt-get update -qq && apt-get install -y -qq docker.io
|
||||
|
||||
- name: Login to Gitea registry
|
||||
run: |
|
||||
echo "${{ secrets.DOCKER_PASSWORD }}" | \
|
||||
docker login gitea.1000co.fr \
|
||||
-u "${{ secrets.DOCKER_USERNAME }}" \
|
||||
--password-stdin
|
||||
|
||||
- name: Build and push
|
||||
run: |
|
||||
U="${{ secrets.DOCKER_USERNAME }}"
|
||||
V="${{ needs.semantic-release.outputs.version }}"
|
||||
docker build \
|
||||
--file ./admin-web/Dockerfile \
|
||||
--tag "gitea.1000co.fr/$U/tabatago-admin-web:$V" \
|
||||
--tag "gitea.1000co.fr/$U/tabatago-admin-web:latest" \
|
||||
./admin-web
|
||||
docker push "gitea.1000co.fr/$U/tabatago-admin-web:$V"
|
||||
docker push "gitea.1000co.fr/$U/tabatago-admin-web:latest"
|
||||
|
||||
deploy:
|
||||
name: Deploy to Portainer
|
||||
needs: [semantic-release, build-and-push]
|
||||
if: needs.semantic-release.outputs.released == 'true' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install deps
|
||||
run: apt-get update -qq && apt-get install -y -qq gettext-base jq curl
|
||||
|
||||
- name: Deploy stack to Portainer
|
||||
env:
|
||||
PORTAINER_TOKEN: ${{ secrets.PORTAINER_ACCESS_TOKEN }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
VERSION: ${{ needs.semantic-release.outputs.version }}
|
||||
run: |
|
||||
set -e
|
||||
|
||||
# Substitute env vars in compose file
|
||||
export DOCKER_USERNAME VERSION
|
||||
COMPOSE=$(envsubst '$DOCKER_USERNAME $VERSION' < admin-web/docker-compose.portainer.yml)
|
||||
|
||||
# Authenticate and discover Docker endpoint (first endpoint = local Docker)
|
||||
ENDPOINT_ID=$(curl -sSf -H "X-API-Key: $PORTAINER_TOKEN" \
|
||||
"https://portainer.1000co.fr/api/endpoints" | jq -r '.[0].Id')
|
||||
echo "Endpoint ID: $ENDPOINT_ID"
|
||||
|
||||
# Check if "tabatago-admin-web" stack already exists
|
||||
STACK_ID=$(curl -sSf -H "X-API-Key: $PORTAINER_TOKEN" \
|
||||
"https://portainer.1000co.fr/api/stacks" | jq -r '.[] | select(.Name == "tabatago-admin-web") | .Id')
|
||||
|
||||
if [ -n "$STACK_ID" ] && [ "$STACK_ID" != "null" ]; then
|
||||
echo "Stack tabatago-admin-web exists (ID: $STACK_ID), updating compose content..."
|
||||
HTTP_RESPONSE=$(curl -s -w '\n%{http_code}' \
|
||||
-X PUT \
|
||||
-H "X-API-Key: $PORTAINER_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(jq -n --arg content "$COMPOSE" '{stackFileContent: $content, prune: false, pullImage: true}')" \
|
||||
"https://portainer.1000co.fr/api/stacks/$STACK_ID?endpointId=$ENDPOINT_ID" || true)
|
||||
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')
|
||||
HTTP_CODE=$(echo "$HTTP_RESPONSE" | tail -1)
|
||||
|
||||
if [ -z "$HTTP_CODE" ] || [ "$HTTP_CODE" -ge 400 ]; then
|
||||
echo "Portainer API error (HTTP ${HTTP_CODE:-connection failed}):"
|
||||
echo "$HTTP_BODY"
|
||||
exit 1
|
||||
fi
|
||||
echo "Stack updated. Portainer will redeploy with new images."
|
||||
else
|
||||
echo "⚠️ Stack tabatago-admin-web not found in Portainer."
|
||||
echo "Create it manually in Portainer first: Stacks → Add stack → paste compose content from admin-web/docker-compose.portainer.yml"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user