diff --git a/.github/workflows/build-and-package.yml b/.github/workflows/build-and-package.yml new file mode 100644 index 00000000..fb098c88 --- /dev/null +++ b/.github/workflows/build-and-package.yml @@ -0,0 +1,132 @@ +name: Deploy blog + +on: + push: + branches: + - feature* + tags: + - '*' + +env: + # Rama principal del proyecto - modificar aquí para cambiar la rama por defecto + DEFAULT_BRANCH: v1636-2 + +jobs: + build-and-package: + runs-on: ubuntu-latest + + env: + BRANCH_NAME: ${{ github.ref_name }} + PACKAGE_NAME: docs-sp-${{ github.ref_name }}.tar.gz + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.1.1 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: pnpm + + - name: Install Deps + run: pnpm install --no-frozen-lockfile + + - name: Build Blog + env: + NODE_OPTIONS: --max_old_space_size=8192 + BRANCH_NAME: ${{ github.ref_name }} + DEFAULT_BRANCH: ${{ env.DEFAULT_BRANCH }} + run: pnpm run build:webpack + + - name: Compress Build Output (tar.gz) + run: tar -czvf $PACKAGE_NAME -C dist . + + - name: Upload site pack to S3 + uses: BetaHuhn/do-spaces-action@v2 + with: + access_key: ${{ vars.AWS_ACCESS_KEY_ID}} + secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + space_name: 'docs-sp' + space_region: 'nyc3' + source: ${{ env.PACKAGE_NAME }} + out_dir: 'html/' + overwrite: true + + check-digitalocean-secrets: + name: Check if Digitalocean registry information was set on secrets + needs: + - build-and-package + runs-on: ubuntu-latest + outputs: + is_have_secrets: ${{ steps.check_digitalocean_secrets_job.outputs.is_have_secrets }} + steps: + - id: check_digitalocean_secrets_job + run: | + if [[ "${{ vars.DIGITALOCEAN_REGISTRY }}" != "" && \ + "${{ vars.DOCKER_REPO_DOCS_SP }}" != "" && \ + "${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}" != "" ]]; \ + then + echo "Secrets to use DigitalOcean container registry are configured in the repo" + echo "is_have_secrets=true" >> $GITHUB_OUTPUT + else + echo "Secrets to use DigitalOcean container registry were not configured in the repo" + echo "is_have_secrets=false" >> $GITHUB_OUTPUT + fi + + build-nginx-image: + name: Build and Push Nginx Image + runs-on: ubuntu-latest + needs: + - check-digitalocean-secrets + if: needs.check-digitalocean-secrets.outputs.is_have_secrets == 'true' + steps: + + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Create download directory + run: mkdir -p s3-downloads + + - name: Download from DigitalOcean Spaces + env: + AWS_ACCESS_KEY_ID: ${{ vars.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + echo "Descargando archivos de docs-sp/html..." + aws s3 sync \ + s3://docs-sp/html/ \ + s3-downloads/ \ + --endpoint-url https://nyc3.digitaloceanspaces.com \ + --no-progress + + - name: show-directory + run: ls -alh s3-downloads + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to DigitalOcean Container Registry + uses: docker/login-action@v3 + with: + registry: registry.digitalocean.com + username: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + password: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Build and push Nginx image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ vars.DIGITALOCEAN_REGISTRY }}/${{ vars.DOCKER_REPO_DOCS_SP }}:main + file: ./Dockerfile + build-args: | + DEFAULT_BRANCH=${{ env.DEFAULT_BRANCH }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index e5d9de57..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Test blog - -on: - push: - pull_request: - -jobs: - build-test: - name: Test build using ${{ matrix.bundler }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - bundler: - - webpack - - vite - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false - submodules: true - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 9.1.1 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: pnpm - - - name: Install Deps - run: pnpm install --no-frozen-lockfile - - - name: Build Blog with ${{ matrix.bundler }} - env: - NODE_OPTIONS: --max_old_space_size=8192 - run: pnpm run build:${{ matrix.bundler }} - - linter-test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false - submodules: true - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 9.1.1 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: pnpm - - - name: Install Deps - run: pnpm install --no-frozen-lockfile - - - name: Linter test - run: pnpm run lint diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..014af459 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# Usar la última versión estable de nginx +FROM nginx:stable + +# Argumentos para configuración (debe ser pasado desde el build) +ARG DEFAULT_BRANCH + +# Convertir los ARGs en variables de entorno +ENV DEFAULT_BRANCH=${DEFAULT_BRANCH} + +# Crear directorio temporal para los archivos comprimidos +WORKDIR /tmp + +# Copiar todos los archivos tar.gz descargados de S3 +COPY s3-downloads/*.tar.gz /tmp/ + +# Copiar configuración estática de nginx +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Copiar el script de configuración de base paths +COPY configure-base-paths.sh /tmp/configure-base-paths.sh + +# Dar permisos de ejecución y ejecutar el script +RUN chmod +x /tmp/configure-base-paths.sh && \ + /tmp/configure-base-paths.sh && \ + rm /tmp/configure-base-paths.sh + +# Exponer el puerto 80 +EXPOSE 80 + +# El comando por defecto de nginx ya está definido en la imagen base +# nginx -g "daemon off;" diff --git a/configure-base-paths.sh b/configure-base-paths.sh new file mode 100644 index 00000000..2f66d005 --- /dev/null +++ b/configure-base-paths.sh @@ -0,0 +1,87 @@ +#!/bin/bash +set -e + +# La variable DEFAULT_BRANCH debe ser pasada como variable de entorno +if [ -z "$DEFAULT_BRANCH" ]; then + echo "ERROR: DEFAULT_BRANCH no está definida" + exit 1 +fi + +echo "=== Configurando base paths para cada directorio ===" +echo "DEFAULT_BRANCH: ${DEFAULT_BRANCH}" +echo "" + +# Procesar cada archivo tar.gz descargado +# TODAS las ramas van a subdirectorios (incluyendo la principal) +for file in /tmp/*.tar.gz; do + if [ -f "$file" ]; then + filename=$(basename "$file") + dirname=$(basename "$file" .tar.gz) + # Eliminar el prefijo "docs-sp-" si existe + branch=${dirname#docs-sp-} + + echo "Procesando: $branch" + + # TODAS las ramas van a su propio subdirectorio + BASE_PATH="/${branch}/" + TARGET_DIR="/usr/share/nginx/html/${branch}" + + if [ "$branch" = "${DEFAULT_BRANCH}" ]; then + echo " -> Base path: ${BASE_PATH} (rama principal)" + else + echo " -> Base path: ${BASE_PATH}" + fi + + # Crear el directorio de destino + mkdir -p "${TARGET_DIR}" + + # Descomprimir + echo " -> Descomprimiendo en ${TARGET_DIR}" + tar -xzf "$file" -C "${TARGET_DIR}/" + + # Agregar/modificar el base tag en todos los archivos HTML + echo " -> Configurando base path en archivos HTML" + find "${TARGET_DIR}" -type f -name "*.html" | while read html_file; do + # Verificar si ya existe un tag + if grep -q " + sed -i "s||\n |" "$html_file" + fi + done + + echo " -> ✓ Completado" + echo "" + fi +done + +# Crear redirección 301 en la raíz hacia la rama principal +echo "=== Creando redirección en raíz ===" +cat > /usr/share/nginx/html/index.html << EOF + + + + + + + Redireccionando... + + +

Redireccionando a /${DEFAULT_BRANCH}/...

+ + + +EOF +echo " -> Redirección creada: / → /${DEFAULT_BRANCH}/" + +echo "" +echo "=== Estructura de directorios final ===" +ls -la /usr/share/nginx/html/ +echo "" + +# Limpiar los archivos comprimidos +rm -f /tmp/*.tar.gz + +echo "=== Configuración completada ===" diff --git a/docker-compose/.env b/docker-compose/.env new file mode 100644 index 00000000..1ac9bf70 --- /dev/null +++ b/docker-compose/.env @@ -0,0 +1,7 @@ + +GENERAL_VIRTUAL_HOST="docs1.dev.solopcloud.com" +GENERAL_LETSENCRYPT_EMAIL=${GENERAL_STACK_NAME}@solopcloud.com + +# Networks +DEFAULT_NETWORK="proxy.network" +IS_EXTERNAL_NETWORK=true \ No newline at end of file diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml new file mode 100644 index 00000000..692e6a63 --- /dev/null +++ b/docker-compose/docker-compose.yml @@ -0,0 +1,29 @@ +services: + docs-sp-nginx: + image: registry.digitalocean.com/spuy/docs-sp:main + container_name: docs-sp-nginx + ports: + - "8081:80" + restart: unless-stopped + environment: + TZ: America/Montevideo + VIRTUAL_HOST: "${GENERAL_VIRTUAL_HOST}" + VIRTUAL_PORT: 80 + LETSENCRYPT_HOST: "${GENERAL_VIRTUAL_HOST}" + LETSENCRYPT_EMAIL: test@solopcloud.com + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:80"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + networks: + - private_network + - shared_network + +networks: + shared_network: + name: ${DEFAULT_NETWORK} + external: ${IS_EXTERNAL_NETWORK} + private_network: + name: docs1.network \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..540ea057 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,47 @@ +server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html index.htm; + + # Logs + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + # Desactivar logs para favicon + location = /favicon.ico { + log_not_found off; + access_log off; + } + + # Desactivar logs para robots.txt + location = /robots.txt { + log_not_found off; + access_log off; + } + + # Configuración para archivos estáticos comunes (debe ir primero para mayor prioridad) + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot|json|xml|txt|pdf|map)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + try_files $uri =404; + } + + # Configuración para cada subdirectorio (ramas/tags) + # Cada directorio se trata como una SPA independiente + location ~ ^/([^/]+)(/|$) { + set $branch_dir $1; + + # Primero intentar servir el archivo exacto + # Si no existe, intentar como directorio con index.html + # Si tampoco existe, servir el index.html del directorio raíz de esa rama (para SPAs) + try_files $uri $uri/ /$branch_dir/index.html =404; + } + + # Configuración para la raíz - página de redirección + # Esto debe ir al final para que tenga menor prioridad + location = / { + try_files /index.html =404; + } +} diff --git a/src/.vuepress/config.ts b/src/.vuepress/config.ts index 87f0d276..b18a2ed9 100644 --- a/src/.vuepress/config.ts +++ b/src/.vuepress/config.ts @@ -3,7 +3,28 @@ import theme from "./theme"; import { searchPlugin } from '@vuepress/plugin-search' import { path } from "@vuepress/utils"; +// Configuración dinámica del base path según la rama +// TODAS las ramas usan su propio base path (incluyendo la rama principal) +// La variable BRANCH_NAME debe ser pasada desde el build +const branchName = process.env.BRANCH_NAME; + +if (!branchName) { + throw new Error('ERROR: BRANCH_NAME no está definida. Debe ser pasada desde el build.'); +} + +// Siempre usar /nombre-de-la-rama/ (sin excepciones) +const basePath = `/${branchName}/`; + +console.log('========================================'); +console.log('VuePress Base Path Configuration'); +console.log('========================================'); +console.log('BRANCH_NAME:', branchName); +console.log('Base Path:', basePath); +console.log('========================================'); + export default defineUserConfig({ + base: basePath, + alias: { "@Releases": path.resolve(__dirname, "components/Releases.vue"), }, diff --git a/src/docs/test-page/README.md b/src/docs/test-page/README.md new file mode 100644 index 00000000..ff8e72a2 --- /dev/null +++ b/src/docs/test-page/README.md @@ -0,0 +1,5 @@ + +### Página de Prueba - Nuevo Sitio + +Lorem Ipsum is simply dummy text of the printing and typesetting industry. +