Feature/18 lending option #158
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Publish | |
| on: | |
| push: | |
| branches: | |
| - dev | |
| - master | |
| pull_request: | |
| branches: | |
| - dev | |
| - master | |
| env: | |
| REGISTRY: ${{ vars.DOCKER_REGISTRY || 'docker.io' }} | |
| IMAGE_NAME: ${{ vars.DOCKER_IMAGE_NAME || 'uping/boardgametracker' }} | |
| jobs: | |
| version: | |
| name: Calculate Version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.versioning.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Git Semantic Version | |
| uses: PaulHatch/semantic-version@v5.4.0 | |
| id: versioning | |
| with: | |
| enable_prerelease_mode: ${{ github.ref == 'refs/heads/dev' || github.event_name == 'pull_request' }} | |
| namespace: beta | |
| bump_each_commit: true | |
| version_format: "${{ (github.ref == 'refs/heads/dev' || github.event_name == 'pull_request') && '${major}.${minor}.${patch}-beta' || '${major}.${minor}.${patch}' }}" | |
| debug: true | |
| test-and-analyze: | |
| name: Test and SonarCloud Analysis | |
| runs-on: ubuntu-latest | |
| needs: [version] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: 17 | |
| distribution: 'zulu' | |
| - name: Setup dotnet v8 | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "8.x" | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20.x" | |
| cache: 'npm' | |
| cache-dependency-path: boardgametracker.client/package-lock.json | |
| - name: Cache SonarCloud packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.sonar/cache | |
| key: ${{ runner.os }}-sonar | |
| restore-keys: ${{ runner.os }}-sonar | |
| - name: Cache SonarCloud scanner | |
| id: cache-sonar-scanner | |
| uses: actions/cache@v4 | |
| with: | |
| path: ./.sonar/scanner | |
| key: ${{ runner.os }}-sonar-scanner | |
| restore-keys: ${{ runner.os }}-sonar-scanner | |
| - name: Install SonarCloud scanner | |
| if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' | |
| run: | | |
| mkdir -p ./.sonar/scanner | |
| dotnet tool update dotnet-sonarscanner --tool-path ./.sonar/scanner | |
| - name: Install .NET dependencies | |
| run: dotnet restore ./BoardGameTracker.sln | |
| - name: Begin SonarCloud analysis | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| run: | | |
| ./.sonar/scanner/dotnet-sonarscanner begin \ | |
| /k:"${{ secrets.SONAR_PROJECT_KEY }}" \ | |
| /o:"${{ secrets.SONAR_ORGANIZATION }}" \ | |
| /d:sonar.host.url="https://sonarcloud.io" \ | |
| /d:sonar.token="${{ secrets.SONAR_TOKEN }}" \ | |
| /v:"${{ needs.version.outputs.version }}" \ | |
| /d:sonar.cs.opencover.reportsPaths="TestResults/**/coverage.opencover.xml" \ | |
| /d:sonar.cs.vstest.reportsPaths="TestResults/*.trx" \ | |
| /d:sonar.javascript.lcov.reportPaths="boardgametracker.client/coverage/lcov.info" \ | |
| /d:sonar.exclusions="**/node_modules/**,**/dist/**,**/build/**,**/coverage/**,**/TestResults/**,**/obj/**,**/bin/**" \ | |
| /d:sonar.coverage.exclusions="**/BoardGameTracker.Host/**/*.cs,**/BoardGameTracker.Core/Datastore/**/*.cs,**/ViewModels/**/*.cs,**/Entities/**/*.cs,**/routeTree.gen.ts,**/tailwind.config.js,**/node_modules/**" | |
| if: env.SONAR_TOKEN != '' | |
| - name: Build .NET | |
| run: dotnet build --no-restore | |
| - name: Run .NET tests | |
| run: | | |
| dotnet test ./BoardGameTracker.Tests/BoardGameTracker.Tests.csproj \ | |
| --no-build \ | |
| --no-restore \ | |
| --logger trx \ | |
| --results-directory "TestResults" \ | |
| --collect "XPlat Code Coverage;Format=opencover" \ | |
| -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByFile="**/BoardGameTracker.Host/**/*.cs,**/DataStore/**/*.cs,**/ViewModels/**/*.cs,**/Entities/**/*.cs" | |
| - name: Install frontend dependencies | |
| run: | | |
| cd boardgametracker.client | |
| npm ci | |
| - name: Run Prettier check | |
| run: | | |
| cd boardgametracker.client | |
| npm run prettier | |
| - name: Run frontend tests with coverage | |
| run: | | |
| cd boardgametracker.client | |
| npm run test:coverage | |
| - name: End SonarCloud analysis | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| run: ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" | |
| if: env.SONAR_TOKEN != '' && github.event_name != 'pull_request' | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: | | |
| TestResults | |
| boardgametracker.client/coverage | |
| retention-days: 7 | |
| if: success() || failure() | |
| - name: Code Coverage Report | |
| uses: danielpalme/ReportGenerator-GitHub-Action@5.3.11 | |
| with: | |
| reports: "TestResults/**/coverage.opencover.xml;boardgametracker.client/coverage/lcov.info" | |
| targetdir: "coveragereport" | |
| reporttypes: "MarkdownSummaryGithub;Cobertura" | |
| sourcedirs: "boardgametracker.client" | |
| assemblyfilters: "-BoardGameTracker.Host;-BoardGameTracker.DataStore" | |
| filefilters: "-**/ViewModels/**;-**/Entities/**" | |
| - name: Publish Coverage Summary | |
| run: cat coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY | |
| - name: Add Coverage PR Comment | |
| uses: marocchino/sticky-pull-request-comment@v2 | |
| if: github.event_name == 'pull_request' | |
| with: | |
| recreate: true | |
| path: coveragereport/SummaryGithub.md | |
| build-linux-multiarch: | |
| needs: [version, test-and-analyze] | |
| name: Build Multi-Arch Linux Containers | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| if: github.event_name != 'pull_request' | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Update package.json version | |
| run: | | |
| cd boardgametracker.client | |
| npm version ${{ needs.version.outputs.version }} --no-git-tag-version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| with: | |
| platforms: all | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Extract metadata for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=raw,value=${{ needs.version.outputs.version }} | |
| type=raw,value=${{ github.ref == 'refs/heads/dev' && 'dev' || 'latest' }} | |
| - name: Build and Push Multi-Architecture Images | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: linux/amd64,linux/arm64,linux/arm/v7 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| build-args: | | |
| VERSION=${{ needs.version.outputs.version }} | |
| ASPNETCORE_ENVIRONMENT=production | |
| BUILDKIT_INLINE_CACHE=1 | |
| security-scan: | |
| needs: [version, build-linux-multiarch] | |
| name: Security Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| if: github.event_name != 'pull_request' | |
| permissions: | |
| security-events: write | |
| actions: read | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.IMAGE_NAME }}:${{ needs.version.outputs.version }} | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| severity: 'CRITICAL,HIGH' | |
| timeout: '10m' | |
| - name: Upload Trivy results to GitHub Security tab | |
| uses: github/codeql-action/upload-sarif@v3 | |
| if: always() | |
| with: | |
| sarif_file: 'trivy-results.sarif' | |
| - name: Run Trivy vulnerability scanner (fail on critical) | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.IMAGE_NAME }}:${{ needs.version.outputs.version }} | |
| format: 'table' | |
| severity: 'CRITICAL,HIGH' | |
| exit-code: '1' | |
| timeout: '10m' | |
| - name: Generate SBOM | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.IMAGE_NAME }}:${{ needs.version.outputs.version }} | |
| format: 'cyclonedx' | |
| output: 'sbom.json' | |
| - name: Upload SBOM artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sbom-${{ needs.version.outputs.version }} | |
| path: sbom.json | |
| retention-days: 90 |