Skip to content

Feature/18 lending option #158

Feature/18 lending option

Feature/18 lending option #158

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