From d0945bdf7068dcaee968be654664d819a077d7f1 Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Tue, 14 Apr 2026 13:14:55 +0200 Subject: [PATCH 1/7] chore: add workflow files for pull-requests, code-scan, release and publishing refs: #5 #6 --- .github/workflows/code-scan.yaml | 39 +++++++++++++++++ .github/workflows/publish.yaml | 56 +++++++++++++++++++++++++ .github/workflows/pull-request.yaml | 49 ++++++++++++++++++++++ .github/workflows/release.yaml | 50 ++++++++++++++++++++++ src/ShinyPDF/Resources/Description.md | 35 ---------------- src/ShinyPDF/Resources/PackageReadme.md | 2 +- src/ShinyPDF/ShinyPDF.csproj | 6 ++- 7 files changed, 199 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/code-scan.yaml create mode 100644 .github/workflows/publish.yaml create mode 100644 .github/workflows/pull-request.yaml create mode 100644 .github/workflows/release.yaml delete mode 100644 src/ShinyPDF/Resources/Description.md diff --git a/.github/workflows/code-scan.yaml b/.github/workflows/code-scan.yaml new file mode 100644 index 000000000..cf75ef3b8 --- /dev/null +++ b/.github/workflows/code-scan.yaml @@ -0,0 +1,39 @@ +name: Code Scan + +on: + pull_request: + branches: + - main + push: + branches: + - main + schedule: + - cron: '0 0 * * 1' # Every Monday at 00:00 UTC + workflow_dispatch: + +permissions: + contents: read + security-events: write + +jobs: + scan: + name: Trivy Code Scan + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@v0.35.0 + with: + scan-type: 'fs' + scan-ref: '.' + format: 'sarif' + output: 'trivy-results.sarif' + + - name: Upload Trivy results to GitHub Security + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: 'trivy-results.sarif' + category: 'Trivy' diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 000000000..f6fee2d0b --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,56 @@ +name: Publish + +on: + workflow_call: + inputs: + version: + required: true + type: string + description: 'Version to publish (e.g., 1.0.0)' + notes: + required: true + type: string + description: 'Release notes for the NuGet package' + +permissions: + contents: read + +jobs: + publish: + name: Publish to NuGet + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + + - name: Build + run: | + dotnet build \ + --configuration Release \ + src/ShinyPDF/ShinyPDF.csproj \ + /p:Version=${{ inputs.version }} \ + /p:AssemblyVersion=${{ inputs.version }} \ + /p:FileVersion=${{ inputs.version }} \ + /p:InformationalVersion=${{ inputs.version }} + + - name: Pack NuGet package + run: | + dotnet pack \ + --configuration Release \ + --output . \ + src/ShinyPDF/ShinyPDF.csproj \ + /p:Version=${{ inputs.version }} \ + /p:PackageVersion=${{ inputs.version }} \ + /p:AssemblyVersion=${{ inputs.version }} \ + /p:FileVersion=${{ inputs.version }} \ + /p:InformationalVersion=${{ inputs.version }} \ + /p:PackageReleaseNotes="${{ inputs.notes }}" + + - name: Publish to NuGet + run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml new file mode 100644 index 000000000..d3c46d3b2 --- /dev/null +++ b/.github/workflows/pull-request.yaml @@ -0,0 +1,49 @@ +name: Pull Request + +on: + pull_request: + branches: + - main + +permissions: + contents: read + checks: write + pull-requests: write + +jobs: + build: + name: Build and Test + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration Release --no-restore + + - name: Run unit tests + run: | + dotnet test \ + src/ShinyPDF.UnitTests/ShinyPDF.UnitTests.csproj \ + --configuration Release \ + --no-build \ + --verbosity normal \ + --logger "trx;LogFileName=test-results.trx" + + - name: Parse and comment test results + if: always() + uses: dorny/test-reporter@v3 + with: + name: Unit Test Results + path: 'src/ShinyPDF.UnitTests/TestResults/test-results.trx' + reporter: 'dotnet-trx' + fail-on-error: false diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..7c7e5171c --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,50 @@ +name: Release + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + name: Create GitHub release + runs-on: ubuntu-latest + outputs: + version: ${{ steps.changelog.outputs.version }} + clean_changelog: ${{ steps.changelog.outputs.clean_changelog }} + skipped: ${{ steps.changelog.outputs.skipped }} + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Generate version from Conventional Commits + id: changelog + uses: TriPSs/conventional-changelog-action@v6 + with: + fallback-version: 1.0.0 + + + - name: Create GitHub release + if: ${{ steps.changelog.outputs.skipped == 'false' }} + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.changelog.outputs.tag }} + name: ${{ steps.changelog.outputs.version }} + body: ${{ steps.changelog.outputs.clean_changelog }} + + publish: + name: Publish to NuGet + needs: release + if: ${{ needs.release.result == 'success' && needs.release.outputs.skipped == 'false' }} + uses: ./.github/workflows/publish.yaml + secrets: inherit + with: + version: ${{ needs.release.outputs.version }} + notes: ${{ needs.release.outputs.clean_changelog }} diff --git a/src/ShinyPDF/Resources/Description.md b/src/ShinyPDF/Resources/Description.md deleted file mode 100644 index 5a39b9782..000000000 --- a/src/ShinyPDF/Resources/Description.md +++ /dev/null @@ -1,35 +0,0 @@ -![License](https://img.shields.io/github/license/LM-Development/ShinyPDF) - -# ShinyPDF - -ShinyPDF is a modern open-source .NET library for PDF document generation. Offering comprehensive layout engine powered by concise and discoverable C# Fluent API. Shiny PDF is based on the latest fully open source version of [QuestPDF](https://github.com/QuestPDF/QuestPDF). - - - - - - - - - - - - - - - - - - - - - - - -
👨‍💻Build production-ready PDFs in pure C# with a code-first workflow that fits naturally into your existing development process.
🧱Compose rich layouts with predictable building blocks: text, images, borders, tables, layers, headers, footers, and more.
⚙️Rely on a layout engine purpose-built for document generation, with robust paging, measurement, and rendering behavior.
📖Stay productive with a concise Fluent API and full IntelliSense discoverability across the entire document DSL.
🔗No proprietary template language. Use modern .NET features, reusable abstractions, and the tools you already trust.
- -
- -## Let's get started - -Begin exploring the ShinyPDF library today. diff --git a/src/ShinyPDF/Resources/PackageReadme.md b/src/ShinyPDF/Resources/PackageReadme.md index f68ef00b0..173c68923 100644 --- a/src/ShinyPDF/Resources/PackageReadme.md +++ b/src/ShinyPDF/Resources/PackageReadme.md @@ -1,4 +1,4 @@ -# ShinyPDF +# ShinyPDF ShinyPDF is a modern open-source .NET library for PDF document generation. Offering comprehensive layout engine powered by concise and discoverable C# Fluent API. Shiny PDF is based on the latest fully open source version of [QuestPDF](https://github.com/QuestPDF/QuestPDF). diff --git a/src/ShinyPDF/ShinyPDF.csproj b/src/ShinyPDF/ShinyPDF.csproj index 5574f6d22..ccedad777 100644 --- a/src/ShinyPDF/ShinyPDF.csproj +++ b/src/ShinyPDF/ShinyPDF.csproj @@ -3,11 +3,13 @@ LM Development LM IT Services AG ShinyPDF - ShinyPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API. Easily generate PDF reports, invoices, exports, etc. + ./Resources/PackageReadme.md + ShinyPDF is an open-source, modern library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API. Easily generate PDF reports, invoices, exports, etc. + ./Resources/Logo.png https://github.com/LM-Development/ShinyPDF.git git LM IT Services AG, ShinyPDF contributors - pdf report file export generate generation tool create creation render portable document format quest html library converter open source free standard core + pdf report file export generate generation tool create creation render portable document format shiny library converter open source free standard core MIT enable net10.0 From 6843e061021a8082952a32a22eddfd02cf07c2c6 Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Tue, 14 Apr 2026 13:17:55 +0200 Subject: [PATCH 2/7] chore: add slnx files to restore and build path --- .github/workflows/pull-request.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index d3c46d3b2..cea4fe9d9 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -25,10 +25,10 @@ jobs: dotnet-version: '10.0.x' - name: Restore dependencies - run: dotnet restore + run: dotnet restore src/ShinyPDF.slnx - name: Build - run: dotnet build --configuration Release --no-restore + run: dotnet build src/ShinyPDF.slnx --configuration Release --no-restore - name: Run unit tests run: | From dc83cbef5fe6bc09c34a65552ab240ef1d8696ca Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Wed, 15 Apr 2026 10:50:01 +0200 Subject: [PATCH 3/7] chore: address review comments --- .github/workflows/publish.yaml | 22 ++++++++++++++++++---- .github/workflows/pull-request.yaml | 2 +- src/ShinyPDF/Resources/PackageReadme.md | 2 +- src/ShinyPDF/ShinyPDF.csproj | 5 +++-- src/global.json | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index f6fee2d0b..7e0ed5457 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -27,7 +27,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v5 with: - dotnet-version: '10.0.x' + global-json-file: src/global.json - name: Build run: | @@ -39,6 +39,12 @@ jobs: /p:FileVersion=${{ inputs.version }} \ /p:InformationalVersion=${{ inputs.version }} + - name: Write package release notes file + env: + PACKAGE_RELEASE_NOTES_RAW: ${{ inputs.notes }} + run: | + printf '%s' "$PACKAGE_RELEASE_NOTES_RAW" > "src/ShinyPDF/release-notes.txt" + - name: Pack NuGet package run: | dotnet pack \ @@ -49,8 +55,16 @@ jobs: /p:PackageVersion=${{ inputs.version }} \ /p:AssemblyVersion=${{ inputs.version }} \ /p:FileVersion=${{ inputs.version }} \ - /p:InformationalVersion=${{ inputs.version }} \ - /p:PackageReleaseNotes="${{ inputs.notes }}" + /p:InformationalVersion=${{ inputs.version }} - name: Publish to NuGet - run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json + run: | + dotnet nuget push "*.nupkg" \ + --api-key ${{ secrets.NUGET_API_KEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate + + dotnet nuget push "*.snupkg" \ + --api-key ${{ secrets.NUGET_API_KEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index cea4fe9d9..7fc66d09c 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -22,7 +22,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v5 with: - dotnet-version: '10.0.x' + global-json-file: src/global.json - name: Restore dependencies run: dotnet restore src/ShinyPDF.slnx diff --git a/src/ShinyPDF/Resources/PackageReadme.md b/src/ShinyPDF/Resources/PackageReadme.md index 173c68923..5b2cc3c81 100644 --- a/src/ShinyPDF/Resources/PackageReadme.md +++ b/src/ShinyPDF/Resources/PackageReadme.md @@ -1,4 +1,4 @@ -# ShinyPDF +# ShinyPDF ShinyPDF is a modern open-source .NET library for PDF document generation. Offering comprehensive layout engine powered by concise and discoverable C# Fluent API. Shiny PDF is based on the latest fully open source version of [QuestPDF](https://github.com/QuestPDF/QuestPDF). diff --git a/src/ShinyPDF/ShinyPDF.csproj b/src/ShinyPDF/ShinyPDF.csproj index ccedad777..f07762bb1 100644 --- a/src/ShinyPDF/ShinyPDF.csproj +++ b/src/ShinyPDF/ShinyPDF.csproj @@ -3,14 +3,15 @@ LM Development LM IT Services AG ShinyPDF - ./Resources/PackageReadme.md + PackageReadme.md ShinyPDF is an open-source, modern library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API. Easily generate PDF reports, invoices, exports, etc. - ./Resources/Logo.png + Logo.png https://github.com/LM-Development/ShinyPDF.git git LM IT Services AG, ShinyPDF contributors pdf report file export generate generation tool create creation render portable document format shiny library converter open source free standard core MIT + $([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)/release-notes.txt')) enable net10.0 true diff --git a/src/global.json b/src/global.json index 445f0e64a..0dd55c3c3 100644 --- a/src/global.json +++ b/src/global.json @@ -2,6 +2,6 @@ "sdk": { "version": "10.0.201", "rollForward": "latestMinor", - "allowPrerelease": true + "allowPrerelease": false } } From 12d91d6cd7e0745fe20cfeb620a1854af87d053c Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Wed, 15 Apr 2026 11:22:38 +0200 Subject: [PATCH 4/7] chore: use nuget login action --- .github/workflows/publish.yaml | 15 +++++++++++++-- .github/workflows/pull-request.yaml | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 7e0ed5457..9a1e5cba2 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -14,6 +14,7 @@ on: permissions: contents: read + id-token: write jobs: publish: @@ -49,6 +50,8 @@ jobs: run: | dotnet pack \ --configuration Release \ + --no-build \ + --no-restore \ --output . \ src/ShinyPDF/ShinyPDF.csproj \ /p:Version=${{ inputs.version }} \ @@ -57,14 +60,22 @@ jobs: /p:FileVersion=${{ inputs.version }} \ /p:InformationalVersion=${{ inputs.version }} + - name: NuGet login + uses: NuGet/login@v1 + id: login + with: + user: ${{ secrets.NUGET_USER }} + - name: Publish to NuGet + env: + NUGET_API_KEY: ${{ steps.login.outputs.NUGET_API_KEY }} run: | dotnet nuget push "*.nupkg" \ - --api-key ${{ secrets.NUGET_API_KEY }} \ + --api-key "$NUGET_API_KEY" \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate dotnet nuget push "*.snupkg" \ - --api-key ${{ secrets.NUGET_API_KEY }} \ + --api-key "$NUGET_API_KEY" \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 7fc66d09c..d1ef40e5f 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -36,6 +36,7 @@ jobs: src/ShinyPDF.UnitTests/ShinyPDF.UnitTests.csproj \ --configuration Release \ --no-build \ + --results-directory src/ShinyPDF.UnitTests/TestResults \ --verbosity normal \ --logger "trx;LogFileName=test-results.trx" From 690efde738d3b2464c1d9e2aa8263c3b94aa768f Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Wed, 15 Apr 2026 11:45:31 +0200 Subject: [PATCH 5/7] chore: harden workflows --- .github/workflows/code-scan.yaml | 1 + .github/workflows/publish.yaml | 5 +++-- .github/workflows/pull-request.yaml | 4 ++-- src/ShinyPDF/ShinyPDF.csproj | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/code-scan.yaml b/.github/workflows/code-scan.yaml index cf75ef3b8..03d2fe0dd 100644 --- a/.github/workflows/code-scan.yaml +++ b/.github/workflows/code-scan.yaml @@ -33,6 +33,7 @@ jobs: output: 'trivy-results.sarif' - name: Upload Trivy results to GitHub Security + if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }} uses: github/codeql-action/upload-sarif@v4 with: sarif_file: 'trivy-results.sarif' diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 9a1e5cba2..230950b56 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -44,7 +44,7 @@ jobs: env: PACKAGE_RELEASE_NOTES_RAW: ${{ inputs.notes }} run: | - printf '%s' "$PACKAGE_RELEASE_NOTES_RAW" > "src/ShinyPDF/release-notes.txt" + printf '%s' "$PACKAGE_RELEASE_NOTES_RAW" > "$RUNNER_TEMP/release-notes.txt" - name: Pack NuGet package run: | @@ -58,7 +58,8 @@ jobs: /p:PackageVersion=${{ inputs.version }} \ /p:AssemblyVersion=${{ inputs.version }} \ /p:FileVersion=${{ inputs.version }} \ - /p:InformationalVersion=${{ inputs.version }} + /p:InformationalVersion=${{ inputs.version }} \ + /p:PackageReleaseNotesFile="$RUNNER_TEMP/release-notes.txt" - name: NuGet login uses: NuGet/login@v1 diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index d1ef40e5f..6ea81d231 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -40,8 +40,8 @@ jobs: --verbosity normal \ --logger "trx;LogFileName=test-results.trx" - - name: Parse and comment test results - if: always() + - name: Parse and report test results + if: ${{ always() && !github.event.pull_request.head.repo.fork }} uses: dorny/test-reporter@v3 with: name: Unit Test Results diff --git a/src/ShinyPDF/ShinyPDF.csproj b/src/ShinyPDF/ShinyPDF.csproj index f07762bb1..6aa96fe37 100644 --- a/src/ShinyPDF/ShinyPDF.csproj +++ b/src/ShinyPDF/ShinyPDF.csproj @@ -11,7 +11,7 @@ LM IT Services AG, ShinyPDF contributors pdf report file export generate generation tool create creation render portable document format shiny library converter open source free standard core MIT - $([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)/release-notes.txt')) + $([System.IO.File]::ReadAllText('$(PackageReleaseNotesFile)')) enable net10.0 true From 5012a7b352f5e929422dbf423928518e5ac3ed38 Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Wed, 15 Apr 2026 11:51:32 +0200 Subject: [PATCH 6/7] chore: fix check for forked prs --- .github/workflows/code-scan.yaml | 2 +- .github/workflows/pull-request.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-scan.yaml b/.github/workflows/code-scan.yaml index 03d2fe0dd..2c8ddd612 100644 --- a/.github/workflows/code-scan.yaml +++ b/.github/workflows/code-scan.yaml @@ -33,7 +33,7 @@ jobs: output: 'trivy-results.sarif' - name: Upload Trivy results to GitHub Security - if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }} + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} uses: github/codeql-action/upload-sarif@v4 with: sarif_file: 'trivy-results.sarif' diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 6ea81d231..e56ce3a11 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -41,7 +41,7 @@ jobs: --logger "trx;LogFileName=test-results.trx" - name: Parse and report test results - if: ${{ always() && !github.event.pull_request.head.repo.fork }} + if: ${{ always() && github.event.pull_request.head.repo.full_name == github.repository }} uses: dorny/test-reporter@v3 with: name: Unit Test Results From a82405b794535362007039a43ef7fafb04e9663c Mon Sep 17 00:00:00 2001 From: "Kamp, Fabian" Date: Wed, 15 Apr 2026 12:06:24 +0200 Subject: [PATCH 7/7] chore: give release higher permissions --- .github/workflows/release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7c7e5171c..c7932f688 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -8,6 +8,7 @@ on: permissions: contents: write + id-token: write jobs: release: