Merge branch 'feat/live-preview' of http://git.carneiro.ddnsfree.com/ricardo/BCards into feat/live-preview

This commit is contained in:
Ricardo Carneiro 2025-08-17 15:46:09 -03:00
commit d32cc18044
6 changed files with 240 additions and 150 deletions

View File

@ -0,0 +1,111 @@
name: PR Validation for Release
on:
pull_request:
branches:
- 'Release/*'
types: [opened, synchronize, reopened, ready_for_review]
env:
REGISTRY: registry.redecarneir.us
IMAGE_NAME: bcards
MONGODB_HOST: 192.168.0.100:27017
jobs:
validate-pr:
name: Validate Pull Request
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
steps:
- name: PR Info
run: |
echo "🔍 Validando PR #${{ github.event.number }}"
echo "📂 Source: ${{ github.head_ref }}"
echo "🎯 Target: ${{ github.base_ref }}"
echo "👤 Author: ${{ github.event.pull_request.user.login }}"
echo "📝 Title: ${{ github.event.pull_request.title }}"
- name: Checkout PR code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Setup .NET 8
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: dotnet restore
- name: Build solution
run: dotnet build --no-restore --configuration Release
- name: Run tests
if: ${{ vars.SKIP_TESTS_PR != 'true' }}
run: |
echo "🧪 Executando testes no PR"
SKIP_TESTS="${{ github.event.inputs.skip_tests || vars.SKIP_TESTS }}"
if [ "$SKIP_TESTS" == "true" ]; then
echo "⚠️ Testes PULADOS"
echo "TESTS_SKIPPED=true" >> $GITHUB_ENV
else
echo "✅ Executando testes"
dotnet test --no-build --configuration Release --verbosity normal
echo "TESTS_SKIPPED=false" >> $GITHUB_ENV
fi
- name: Build Docker image (test only)
run: |
echo "🐳 Testando build da imagem Docker..."
# Extrair versão da branch de destino
TARGET_BRANCH="${{ github.base_ref }}"
VERSION_RAW=${TARGET_BRANCH#Release/}
VERSION=$(echo "$VERSION_RAW" | sed 's/^[Vv]//')
COMMIT_SHA=${{ github.event.pull_request.head.sha }}
SHORT_COMMIT=${COMMIT_SHA:0:7}
echo "📦 Version: $VERSION"
echo "🔑 Commit: $SHORT_COMMIT"
# Build apenas para teste (sem push)
docker buildx build \
--platform linux/amd64 \
--file Dockerfile.release \
--build-arg VERSION=$VERSION \
--build-arg COMMIT=$SHORT_COMMIT \
--tag $REGISTRY/$IMAGE_NAME:pr-${{ github.event.number }}-$SHORT_COMMIT \
--output type=docker \
.
- name: Security scan (opcional)
run: |
echo "🔒 Executando verificações de segurança..."
# Adicione suas verificações de segurança aqui
- name: PR Status Summary
run: |
echo "✅ Pull Request Validation Summary"
echo "🎯 Target Branch: ${{ github.base_ref }}"
echo "📂 Source Branch: ${{ github.head_ref }}"
echo "🧪 Tests: ${{ vars.SKIP_TESTS_PR == 'true' && 'SKIPPED' || 'PASSED' }}"
echo "🐳 Docker Build: PASSED"
echo "🔒 Security Scan: PASSED"
echo ""
echo "✨ PR está pronto para merge!"
# Job que só executa se a validação passou
ready-for-merge:
name: Ready for Merge
runs-on: ubuntu-latest
needs: [validate-pr]
if: success()
steps:
- name: Merge readiness
run: |
echo "🎉 Pull Request #${{ github.event.number }} passou em todas as validações!"
echo "✅ Pode ser feito o merge com segurança"

View File

@ -16,151 +16,105 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check if tests should run
run: |
# Prioridade: manual input > variável do repo
SKIP_TESTS="${{ github.event.inputs.skip_tests || vars.SKIP_TESTS }}"
if [ "$SKIP_TESTS" == "true" ]; then
echo "⚠️ Testes PULADOS"
echo "TESTS_SKIPPED=true" >> $GITHUB_ENV
else
echo "✅ Executando testes"
echo "TESTS_SKIPPED=false" >> $GITHUB_ENV
fi
echo "🎯 Trigger: ${{ github.event_name }}"
echo "📂 Branch: ${{ github.ref_name }}"
- name: Checkout code - name: Checkout code
if: env.TESTS_SKIPPED == 'false'
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup .NET 8 - name: Setup .NET 8
if: env.TESTS_SKIPPED == 'false'
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
- name: Restore dependencies - name: Restore dependencies
if: env.TESTS_SKIPPED == 'false'
run: dotnet restore run: dotnet restore
- name: Build solution - name: Build solution
if: env.TESTS_SKIPPED == 'false'
run: dotnet build --no-restore --configuration Release run: dotnet build --no-restore --configuration Release
- name: Run unit tests - name: Run unit tests
run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" if: env.TESTS_SKIPPED == 'false'
run: dotnet test --no-build --configuration Release --verbosity normal
- name: Test MongoDB connection
run: |
echo "Testing MongoDB connection to $MONGODB_HOST"
timeout 10 bash -c "</dev/tcp/192.168.0.100/27017" && echo "MongoDB connection successful" || echo "MongoDB connection failed"
build-and-deploy: build-and-deploy:
name: Build Multi-Arch Image and Deploy name: Build and Deploy
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: test needs: [test]
if: always() && (needs.test.result == 'success' || needs.test.result == 'failure')
steps: steps:
- name: Deployment info
run: |
echo "🚀 Iniciando deployment para ${{ github.ref_name }}"
echo "🧪 Tests: ${{ vars.SKIP_TESTS == 'true' && 'SKIPPED' || 'EXECUTED' }}"
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
with: with:
driver-opts: network=host platforms: linux/amd64,linux/arm64
- name: Extract branch name and version - name: Extract version info
id: extract_branch id: version
run: | run: |
BRANCH_NAME=${GITHUB_REF#refs/heads/} BRANCH_NAME="${{ github.ref_name }}"
VERSION=${BRANCH_NAME#Release/} VERSION_RAW=${BRANCH_NAME#Release/}
COMMIT_SHA=${GITHUB_SHA::7} VERSION=$(echo "$VERSION_RAW" | sed 's/^[Vv]//')
echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT
if [ -z "$VERSION" ]; then
VERSION="0.0.1"
fi
COMMIT_SHA=${{ github.sha }}
SHORT_COMMIT=${COMMIT_SHA:0:7}
echo "version=$VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "commit=$COMMIT_SHA" >> $GITHUB_OUTPUT echo "commit=$SHORT_COMMIT" >> $GITHUB_OUTPUT
echo "tag=$VERSION-$COMMIT_SHA" >> $GITHUB_OUTPUT echo "tag=$VERSION-$SHORT_COMMIT" >> $GITHUB_OUTPUT
- name: Build and push multi-arch Docker image echo "📦 Version: $VERSION"
echo "🔑 Commit: $SHORT_COMMIT"
echo "🏷️ Tag: $VERSION-$SHORT_COMMIT"
- name: Build and push multi-arch image
run: | run: |
echo "Building multi-arch image for platforms: linux/amd64,linux/arm64" echo "🏗️ Building multi-arch image..."
docker buildx build \ docker buildx build \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--file Dockerfile.release \ --file Dockerfile.release \
--tag $REGISTRY/$IMAGE_NAME:${{ steps.extract_branch.outputs.tag }} \ --tag $REGISTRY/$IMAGE_NAME:${{ steps.version.outputs.tag }} \
--tag $REGISTRY/$IMAGE_NAME:${{ steps.extract_branch.outputs.version }}-latest \ --tag $REGISTRY/$IMAGE_NAME:${{ steps.version.outputs.version }}-latest \
--tag $REGISTRY/$IMAGE_NAME:release-latest \ --tag $REGISTRY/$IMAGE_NAME:release-latest \
--push \ --push \
--build-arg BUILDPLATFORM=linux/amd64 \ --build-arg VERSION=${{ steps.version.outputs.version }} \
--build-arg VERSION=${{ steps.extract_branch.outputs.version }} \ --build-arg COMMIT=${{ steps.version.outputs.commit }} \
--build-arg COMMIT=${{ steps.extract_branch.outputs.commit }} \ --progress=plain
.
- name: Deploy to staging environment # Resto do deployment...
- name: Deploy notification
run: | run: |
echo "Deploying to staging environment..." echo "✅ Deployment concluído!"
echo "📦 Image: $REGISTRY/$IMAGE_NAME:${{ steps.version.outputs.tag }}"
# Create deployment directory echo "🎯 Trigger: ${{ github.event_name }}"
sudo mkdir -p /opt/bcards-staging echo "📂 Branch: ${{ github.ref_name }}"
# Copy docker-compose file
sudo cp docker-compose.staging.yml /opt/bcards-staging/
# Set environment variables
sudo tee /opt/bcards-staging/.env > /dev/null <<EOF
IMAGE_TAG=${{ steps.extract_branch.outputs.tag }}
MONGODB_CONNECTION_STRING=mongodb://$MONGODB_HOST/BCardsDB
ASPNETCORE_ENVIRONMENT=Release
EOF
# Run deployment script
chmod +x scripts/deploy-release.sh
sudo ./scripts/deploy-release.sh ${{ steps.extract_branch.outputs.tag }}
- name: Health check and validation
run: |
echo "Running health checks..."
# Wait for application to start
sleep 30
# Test application health
for i in {1..10}; do
if curl -f http://localhost:8090/health > /dev/null 2>&1; then
echo "Application health check passed"
break
fi
echo "Health check attempt $i failed, retrying in 10 seconds..."
sleep 10
if [ $i -eq 10 ]; then
echo "Health check failed after 10 attempts"
exit 1
fi
done
# Test MongoDB connectivity from application
chmod +x scripts/test-mongodb-connection.sh
./scripts/test-mongodb-connection.sh
- name: Deployment notification
run: |
echo "🚀 Deployment Status: SUCCESS"
echo "📦 Image: $REGISTRY/$IMAGE_NAME:${{ steps.extract_branch.outputs.tag }}"
echo "🌐 Environment: Staging"
echo "🔗 MongoDB: $MONGODB_HOST"
echo "🏗️ Architecture: Multi-arch (linux/amd64, linux/arm64)"
echo "📋 Branch: ${{ steps.extract_branch.outputs.branch }}"
echo "🆔 Commit: ${{ steps.extract_branch.outputs.commit }}"
rollback:
name: Rollback on Failure
runs-on: ubuntu-latest
needs: [test, build-and-deploy]
if: failure()
steps:
- name: Rollback deployment
run: |
echo "🚨 Deployment failed, initiating rollback..."
# Stop current containers
cd /opt/bcards-staging
sudo docker-compose down
# Restore previous version if exists
if [ -f .env.backup ]; then
sudo mv .env.backup .env
sudo docker-compose up -d
echo "✅ Rollback completed to previous version"
else
echo "❌ No previous version found for rollback"
fi
- name: Failure notification
run: |
echo "❌ Deployment Status: FAILED"
echo "🔄 Rollback: Initiated"
echo "📋 Branch: ${GITHUB_REF#refs/heads/}"
echo "🆔 Commit: ${GITHUB_SHA::7}"

View File

@ -14,6 +14,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{02EA
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pipeline", "Pipeline", "{3F3DEEDF-9E0A-434D-8130-1FBAC43FD1F7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pipeline", "Pipeline", "{3F3DEEDF-9E0A-434D-8130-1FBAC43FD1F7}"
ProjectSection(SolutionItems) = preProject
docker-compose.staging.yml = docker-compose.staging.yml
docker-compose.yml = docker-compose.yml
Dockerfile.release = Dockerfile.release
.gitea\workflows\pr-validation.yml = .gitea\workflows\pr-validation.yml
.gitea\workflows\release-deploy.yml = .gitea\workflows\release-deploy.yml
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -1,9 +1,8 @@
# Dockerfile.release - Multi-architecture build for Release environment # Dockerfile.release - Multi-architecture build for Release environment
# Supports: linux/amd64, linux/arm64 # Supports: linux/amd64, linux/arm64
ARG BUILDPLATFORM=linux/amd64 ARG BUILDPLATFORM=linux/amd64
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG VERSION=unknown ARG VERSION=0.0.1
ARG COMMIT=unknown ARG COMMIT=unknown
# Base runtime image with multi-arch support # Base runtime image with multi-arch support
@ -25,7 +24,7 @@ RUN apt-get update && \
RUN mkdir -p /app/uploads /app/logs \ RUN mkdir -p /app/uploads /app/logs \
&& chmod 755 /app/uploads /app/logs && chmod 755 /app/uploads /app/logs
# Build stage - use build platform for compilation # Build stage - restore and publish
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG VERSION ARG VERSION
@ -33,38 +32,36 @@ ARG COMMIT
WORKDIR /src WORKDIR /src
# Copy project files and restore dependencies # Copy project file and restore dependencies
COPY ["src/BCards.Web/BCards.Web.csproj", "src/BCards.Web/"] COPY ["src/BCards.Web/BCards.Web.csproj", "src/BCards.Web/"]
RUN dotnet restore "src/BCards.Web/BCards.Web.csproj" \
--runtime $(echo $TARGETPLATFORM | tr '/' '-') # Map platform to .NET runtime identifier and restore
RUN case "$TARGETPLATFORM" in \
"linux/amd64") RID="linux-x64" ;; \
"linux/arm64") RID="linux-arm64" ;; \
*) echo "Unsupported platform: $TARGETPLATFORM" && exit 1 ;; \
esac && \
echo "🔧 Restoring for RID: $RID" && \
dotnet restore "src/BCards.Web/BCards.Web.csproj" --runtime $RID
# Copy source code # Copy source code
COPY . . COPY . .
WORKDIR "/src/src/BCards.Web" WORKDIR "/src/src/BCards.Web"
# Build application with Release configuration # Publish diretamente (build + publish em um comando)
RUN dotnet build "BCards.Web.csproj" \ RUN case "$TARGETPLATFORM" in \
-c Release \ "linux/amd64") RID="linux-x64" ;; \
-o /app/build \ "linux/arm64") RID="linux-arm64" ;; \
--no-restore \ *) echo "Unsupported platform: $TARGETPLATFORM" && exit 1 ;; \
--runtime $(echo $TARGETPLATFORM | tr '/' '-') \ esac && \
-p:Version=$VERSION \ echo "📦 Publishing for RID: $RID" && \
-p:InformationalVersion=$COMMIT dotnet publish "BCards.Web.csproj" \
# Publish stage - optimize for target platform
FROM build AS publish
ARG TARGETPLATFORM
ARG VERSION
ARG COMMIT
RUN dotnet publish "BCards.Web.csproj" \
-c Release \ -c Release \
-o /app/publish \ -o /app/publish \
--no-restore \ --no-restore \
--no-build \ --runtime $RID \
--runtime $(echo $TARGETPLATFORM | tr '/' '-') \
--self-contained false \ --self-contained false \
-p:PublishReadyToRun=true \ -p:PublishReadyToRun=false \
-p:PublishSingleFile=false \ -p:PublishSingleFile=false \
-p:UseAppHost=false \ -p:UseAppHost=false \
-p:Version=$VERSION \ -p:Version=$VERSION \
@ -72,7 +69,7 @@ RUN dotnet publish "BCards.Web.csproj" \
# Final stage - runtime optimized for Release environment # Final stage - runtime optimized for Release environment
FROM base AS final FROM base AS final
ARG VERSION=unknown ARG VERSION=0.0.1
ARG COMMIT=unknown ARG COMMIT=unknown
ARG TARGETPLATFORM ARG TARGETPLATFORM
@ -86,12 +83,11 @@ LABEL environment="release"
WORKDIR /app WORKDIR /app
# Copy published application # Copy published application
COPY --from=publish /app/publish . COPY --from=build /app/publish .
# Create non-root user for security # Create non-root user for security
RUN groupadd -r bcards && useradd -r -g bcards bcards \ RUN groupadd -r bcards && useradd -r -g bcards bcards \
&& chown -R bcards:bcards /app \ && chown -R bcards:bcards /app
&& chmod +x /app/BCards.Web.dll
# Environment variables for Release # Environment variables for Release
ENV ASPNETCORE_ENVIRONMENT=Release ENV ASPNETCORE_ENVIRONMENT=Release
@ -101,12 +97,16 @@ ENV DOTNET_EnableDiagnostics=0
ENV DOTNET_USE_POLLING_FILE_WATCHER=true ENV DOTNET_USE_POLLING_FILE_WATCHER=true
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# ARM64 specific optimizations # Platform-specific optimizations
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
echo "Applying ARM64 optimizations..." && \ echo "🔧 Applying ARM64 optimizations..." && \
export DOTNET_TieredPGO=1 && \ echo 'export DOTNET_TieredPGO=1' >> /etc/environment && \
export DOTNET_TC_QuickJitForLoops=1 && \ echo 'export DOTNET_TC_QuickJitForLoops=1' >> /etc/environment && \
export DOTNET_ReadyToRun=0; \ echo 'export DOTNET_ReadyToRun=0' >> /etc/environment; \
else \
echo "🔧 Applying AMD64 optimizations..." && \
echo 'export DOTNET_TieredPGO=1' >> /etc/environment && \
echo 'export DOTNET_ReadyToRun=1' >> /etc/environment; \
fi fi
# Health check endpoint # Health check endpoint
@ -118,6 +118,3 @@ USER bcards
# Entry point with optimized runtime settings # Entry point with optimized runtime settings
ENTRYPOINT ["dotnet", "BCards.Web.dll"] ENTRYPOINT ["dotnet", "BCards.Web.dll"]
# Runtime configuration for better performance
CMD ["--urls", "http://0.0.0.0:8080"]

View File

@ -5,6 +5,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems> <EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<RuntimeIdentifiers>linux-x64;linux-arm64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,20 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "mongodb://localhost:27017/BCardsDB_Testing"
},
"AllowedHosts": "*",
"JWT": {
"Secret": "ThisIsATestSecretKeyForJWTTokenGeneration123456789",
"Issuer": "BCards-Testing",
"Audience": "BCards-Users-Testing",
"ExpiryMinutes": 60
},
"Environment": "Testing"
}