From 798e131cea6cf7a1eec6958c6512578d899d17a8 Mon Sep 17 00:00:00 2001 From: ksemenenko Date: Sun, 2 Nov 2025 20:16:50 +0100 Subject: [PATCH] chore: align workflows with .NET 9 pipelines --- .github/workflows/ci.yml | 40 +++++ .github/workflows/codeql-analysis.yml | 58 +++---- .github/workflows/dotnet.yml | 51 ------ .github/workflows/mime-sync.yml | 2 +- .github/workflows/nuget.yml | 35 ---- .github/workflows/release.yml | 227 ++++++++++++++++++++++++++ 6 files changed, 288 insertions(+), 125 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/dotnet.yml delete mode 100644 .github/workflows/nuget.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..925d975 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +env: + DOTNET_VERSION: '9.0.x' + +jobs: + build: + name: Build and Test + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration Release --no-restore + + - name: Test + run: dotnet test --configuration Release --no-build --verbosity normal --collect:"XPlat Code Coverage" + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./**/coverage.cobertura.xml + fail_ci_if_error: false diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7ae370e..a6ae2da 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,67 +1,49 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: push: branches: [ main ] pull_request: - # The branches below must be a subset of the branches above branches: [ main ] schedule: - - cron: '35 11 * * 4' + - cron: '0 0 * * 1' + +env: + DOTNET_VERSION: '9.0.x' jobs: analyze: name: Analyze runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write strategy: fail-fast: false matrix: language: [ 'csharp' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + - name: Restore dependencies + run: dotnet restore - #- run: | - # make bootstrap - # make release + - name: Build + run: dotnet build --no-restore - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml deleted file mode 100644 index e0d32d5..0000000 --- a/.github/workflows/dotnet.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: .NET - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - - build-and-test: - runs-on: ubuntu-latest - - steps: - - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 9.0.x - - # run build and test - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build --no-restore - - name: Test - run: dotnet test --no-build --logger 'trx;LogFileName=test-results.trx' - - name: Collect Code Coverage - run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=ManagedCode.MimeTypes.Tests/lcov.info - env: - DEFAULT_REGION: eu-west-1 - AWS_ACCESS_KEY_ID: localkey - AWS_SECRET_ACCESS_KEY: localsecret - - - name : coverlet - uses: b3b00/coverlet-action@1.1.9 - with: - testProject: 'ManagedCode.MimeTypes.Tests/ManagedCode.MimeTypes.Tests.csproj' - output: 'lcov.info' - outputFormat: 'lcov' - excludes: '[program]*,[test]test.*' - - name: coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{secrets.GITHUB_TOKEN }} - path-to-lcov: ManagedCode.MimeTypes.Tests/lcov.info \ No newline at end of file diff --git a/.github/workflows/mime-sync.yml b/.github/workflows/mime-sync.yml index aec0b0d..1bf1465 100644 --- a/.github/workflows/mime-sync.yml +++ b/.github/workflows/mime-sync.yml @@ -20,7 +20,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.x + dotnet-version: 9.0.x - name: Restore dependencies run: dotnet restore diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml deleted file mode 100644 index 863f706..0000000 --- a/.github/workflows/nuget.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: nuget - -on: - push: - branches: [ main ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - nuget-pack: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 9.0.x - - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build --configuration Release - - name: Pack - run: dotnet pack --configuration Release - - - name: publish nuget packages - run: | - shopt -s globstar - for file in **/*.nupkg - do - dotnet nuget push "$file" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json - done \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..690c714 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,227 @@ +name: Release + +on: + push: + branches: [ main ] + workflow_dispatch: + +env: + DOTNET_VERSION: '9.0.x' + +jobs: + build: + name: Build and Test + runs-on: ubuntu-latest + + outputs: + version: ${{ steps.version.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Extract version from Directory.Build.props + id: version + run: | + VERSION=$(grep -oPm1 "(?<=)[^<]+" Directory.Build.props) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Version from Directory.Build.props: $VERSION" + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration Release --no-restore + + - name: Test + run: dotnet test --configuration Release --no-build --verbosity normal + + - name: Pack NuGet packages + run: dotnet pack --configuration Release --no-build --output ./artifacts + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: nuget-packages + path: ./artifacts/*.nupkg + retention-days: 5 + + publish-nuget: + name: Publish to NuGet + needs: build + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + + outputs: + published: ${{ steps.publish.outputs.published }} + version: ${{ needs.build.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Download artifacts + uses: actions/download-artifact@v5 + with: + name: nuget-packages + path: ./artifacts + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Publish to NuGet + id: publish + continue-on-error: true + run: | + set +e + OUTPUT="" + PUBLISHED=false + + for package in ./artifacts/*.nupkg; do + echo "Publishing $package..." + RESULT=$(dotnet nuget push "$package" \ + --api-key ${{ secrets.NUGET_API_KEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate 2>&1) + EXIT_CODE=$? + echo "$RESULT" + OUTPUT="$OUTPUT$RESULT" + + if [ $EXIT_CODE -eq 0 ]; then + echo "Successfully published $package" + PUBLISHED=true + elif echo "$RESULT" | grep -q "already exists"; then + echo "Package already exists, skipping..." + else + echo "Failed to publish $package" + exit 1 + fi + done + + if [ "$PUBLISHED" = true ] || echo "$OUTPUT" | grep -q "Your package was pushed"; then + echo "published=true" >> $GITHUB_OUTPUT + echo "At least one package was successfully published" + else + echo "published=false" >> $GITHUB_OUTPUT + echo "No new packages were published (all already exist)" + fi + + create-release: + name: Create GitHub Release and Tag + needs: publish-nuget + runs-on: ubuntu-latest + if: needs.publish-nuget.outputs.published == 'true' + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Download artifacts + uses: actions/download-artifact@v5 + with: + name: nuget-packages + path: ./artifacts + + - name: Create and push tag + id: create_tag + run: | + VERSION="${{ needs.publish-nuget.outputs.version }}" + TAG="v$VERSION" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG already exists" + echo "tag_exists=true" >> $GITHUB_OUTPUT + else + echo "Creating tag $TAG" + git tag -a "$TAG" -m "Release $VERSION" + git push origin "$TAG" + echo "tag_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Get previous tag + id: prev_tag + run: | + CURRENT_TAG="v${{ needs.publish-nuget.outputs.version }}" + PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -A1 "^$CURRENT_TAG$" | tail -n1 || echo "") + if [ "$PREVIOUS_TAG" = "$CURRENT_TAG" ] || [ -z "$PREVIOUS_TAG" ]; then + PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -v "^$CURRENT_TAG$" | head -n1 || echo "") + fi + echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT + echo "Current tag: $CURRENT_TAG" + echo "Previous tag: $PREVIOUS_TAG" + + - name: Generate release notes + id: release_notes + run: | + VERSION="${{ needs.publish-nuget.outputs.version }}" + CURRENT_TAG="v$VERSION" + PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" + + echo "# Release $VERSION" > release_notes.md + echo "" >> release_notes.md + echo "Released on $(date +'%Y-%m-%d')" >> release_notes.md + echo "" >> release_notes.md + + if [ -n "$PREVIOUS_TAG" ]; then + echo "## 📋 Changes since $PREVIOUS_TAG" >> release_notes.md + echo "" >> release_notes.md + + echo "### ✨ Features" >> release_notes.md + git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..HEAD --grep="^feat" --grep="^feature" >> release_notes.md || true + echo "" >> release_notes.md + + echo "### 🐛 Bug Fixes" >> release_notes.md + git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..HEAD --grep="^fix" --grep="^bugfix" >> release_notes.md || true + echo "" >> release_notes.md + + echo "### 📚 Documentation" >> release_notes.md + git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..HEAD --grep="^docs" --grep="^doc" >> release_notes.md || true + echo "" >> release_notes.md + + echo "### 🔧 Other Changes" >> release_notes.md + git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..HEAD --invert-grep --grep="^feat" --grep="^feature" --grep="^fix" --grep="^bugfix" --grep="^docs" --grep="^doc" >> release_notes.md || true + echo "" >> release_notes.md + else + echo "## 🎉 Initial Release" >> release_notes.md + echo "" >> release_notes.md + echo "### Recent Changes" >> release_notes.md + git log --pretty=format:"- %s (%h)" --max-count=20 >> release_notes.md + echo "" >> release_notes.md + fi + + echo "" >> release_notes.md + echo "## đŸ“Ļ NuGet Packages" >> release_notes.md + echo "" >> release_notes.md + for package in ./artifacts/*.nupkg; do + PACKAGE_NAME=$(basename "$package" .nupkg) + BASE_NAME=$(echo "$PACKAGE_NAME" | sed "s/\.$VERSION//") + echo "- [$BASE_NAME v$VERSION](https://www.nuget.org/packages/$BASE_NAME/$VERSION)" >> release_notes.md + done + + echo "" >> release_notes.md + echo "---" >> release_notes.md + echo "*This release was automatically created by GitHub Actions*" >> release_notes.md + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ needs.publish-nuget.outputs.version }} + name: v${{ needs.publish-nuget.outputs.version }} + body_path: release_notes.md + draft: false + prerelease: false + files: ./artifacts/*.nupkg + token: ${{ secrets.GITHUB_TOKEN }}