fix: auto-detect MIME type for file uploads (fixes image upload error) #48
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
| # 📁 release.yml - NuGet publishing workflow | |
| # 🎯 Core function: Builds, tests, publishes packages, and creates GitHub releases on version tags | |
| # 🔗 Key dependencies: .NET 10/9/8 SDKs, NuGet.org feed, GitHub Releases | |
| # 💡 Usage: Triggered via git tags (v*), pushes packages automatically | |
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| env: | |
| DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true | |
| DOTNET_NOLOGO: true | |
| NUGET_SOURCE: https://api.nuget.org/v3/index.json | |
| COVERAGE_THRESHOLD: 60 | |
| jobs: | |
| publish: | |
| name: Publish NuGet Package | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: | | |
| 10.0.x | |
| 9.0.x | |
| 8.0.x | |
| - name: Restore | |
| run: dotnet restore Max.Bot.sln | |
| - name: Verify formatting | |
| run: dotnet format Max.Bot.sln --verify-no-changes | |
| - name: Run analyzers | |
| run: dotnet format analyzers Max.Bot.sln --verify-no-changes --no-restore | |
| - name: Build | |
| run: dotnet build Max.Bot.sln --configuration Release --no-restore -warnaserror | |
| - name: Test with coverage | |
| run: > | |
| dotnet test Max.Bot.sln | |
| --configuration Release | |
| --no-build | |
| /p:CollectCoverage=true | |
| /p:CoverletOutput=TestResults/Coverage/ | |
| /p:CoverletOutputFormat="cobertura%2copencover" | |
| /p:Threshold=${{ env.COVERAGE_THRESHOLD }} | |
| /p:ThresholdType=line | |
| /p:ThresholdStat=total | |
| /p:ExcludeByAttribute="GeneratedCodeAttribute" | |
| - name: Determine package version | |
| id: version | |
| shell: bash | |
| run: echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" | |
| - name: Validate release metadata | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.version.outputs.value }}" | |
| if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then | |
| echo "::error::Tag version '$VERSION' is not a valid SemVer value." | |
| exit 1 | |
| fi | |
| if ! grep -q "<Version>$VERSION</Version>" src/Max.Bot/Max.Bot.csproj; then | |
| echo "::error::src/Max.Bot/Max.Bot.csproj does not contain <Version>$VERSION</Version>." | |
| exit 1 | |
| fi | |
| if ! grep -q "^## \[$VERSION\]" CHANGELOG.md; then | |
| echo "::error::CHANGELOG.md does not contain a release section for $VERSION." | |
| exit 1 | |
| fi | |
| - name: Extract release notes | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.version.outputs.value }}" | |
| NOTES_FILE="${RUNNER_TEMP}/release-notes.md" | |
| awk -v version="$VERSION" ' | |
| BEGIN { found = 0 } | |
| $0 ~ "^## \\[" version "\\]" { found = 1; next } | |
| found && /^## \[/ { exit } | |
| found { print } | |
| END { if (!found) exit 1 } | |
| ' CHANGELOG.md > "$NOTES_FILE" | |
| if ! grep -q '[^[:space:]]' "$NOTES_FILE"; then | |
| echo "::error::Release notes for $VERSION are empty." | |
| exit 1 | |
| fi | |
| echo "Release notes extracted to $NOTES_FILE" | |
| - name: Pack | |
| run: > | |
| dotnet pack src/Max.Bot/Max.Bot.csproj | |
| --configuration Release | |
| --no-build | |
| --output ./nupkgs | |
| /p:ContinuousIntegrationBuild=true | |
| /p:Version=${{ steps.version.outputs.value }} | |
| /p:PackageVersion=${{ steps.version.outputs.value }} | |
| - name: Upload package artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nuget-release | |
| path: | | |
| ./nupkgs/*.nupkg | |
| ./nupkgs/*.snupkg | |
| - name: Publish to NuGet | |
| env: | |
| NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} | |
| shell: bash | |
| run: | | |
| if [ -z "$NUGET_API_KEY" ]; then | |
| echo "::error::NUGET_API_KEY secret is not configured." | |
| exit 1 | |
| fi | |
| echo "Looking for packages in ./nupkgs/" | |
| ls -la ./nupkgs/ || echo "nupkgs directory not found" | |
| find ./nupkgs -name "*.nupkg" -type f || echo "No .nupkg files found" | |
| find ./nupkgs -name "*.snupkg" -type f || echo "No .snupkg files found" | |
| PACKAGE_COUNT=0 | |
| for package in ./nupkgs/*.nupkg; do | |
| if [ -f "$package" ]; then | |
| echo "Pushing package: $package" | |
| dotnet nuget push "$package" --api-key "$NUGET_API_KEY" --source "$NUGET_SOURCE" --skip-duplicate || { | |
| echo "::error::Failed to push $package" | |
| exit 1 | |
| } | |
| echo "Successfully pushed: $package" | |
| PACKAGE_COUNT=$((PACKAGE_COUNT + 1)) | |
| fi | |
| done | |
| if [ $PACKAGE_COUNT -eq 0 ]; then | |
| echo "::error::No packages found to publish" | |
| exit 1 | |
| fi | |
| for symbols in ./nupkgs/*.snupkg; do | |
| if [ -f "$symbols" ]; then | |
| echo "Pushing symbols: $symbols" | |
| dotnet nuget push "$symbols" --api-key "$NUGET_API_KEY" --source "$NUGET_SOURCE" --skip-duplicate || { | |
| echo "::warning::Failed to push symbols $symbols (non-critical)" | |
| } | |
| fi | |
| done | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: MaxMessenger.Bot ${{ github.ref_name }} | |
| body_path: ${{ runner.temp }}/release-notes.md | |
| prerelease: ${{ contains(github.ref_name, '-') }} | |
| files: | | |
| ./nupkgs/*.nupkg | |
| ./nupkgs/*.snupkg |