Give each package a readme that stands on its own #7
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: Release (NuGet) | |
| # Publishes the YandexMusic, YandexMusic.Ynison, YandexMusic.Quasar and YandexMusic.DependencyInjection | |
| # packages to NuGet.org. | |
| # Trigger by pushing a version tag, e.g.: git tag v0.1.0 && git push origin v0.1.0 | |
| # The tag (without the "v" prefix) IS the package version, and the GitHub Release is created here. | |
| # | |
| # Authentication is Trusted Publishing (OIDC): no long-lived API key is stored anywhere. It requires | |
| # a policy on nuget.org for each package id, naming this repository, this workflow file and the | |
| # "nuget" environment, plus the repository variable NUGET_USER. | |
| on: | |
| push: | |
| tags: [ 'v*' ] | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write # create the GitHub Release | |
| id-token: write # OIDC token for NuGet Trusted Publishing | |
| jobs: | |
| publish: | |
| name: Pack & push to NuGet | |
| runs-on: ubuntu-latest | |
| environment: nuget # named by the Trusted Publishing policy; can be protected with reviewers | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET (8 / 9 / 10) | |
| uses: actions/setup-dotnet@v6 | |
| with: | |
| dotnet-version: | | |
| 8.0.x | |
| 9.0.x | |
| 10.0.x | |
| - name: Resolve version from tag | |
| id: version | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| echo "value=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "Publishing version $VERSION" | |
| - name: Restore | |
| run: dotnet restore YandexMusic.slnx | |
| - name: Build (Release) | |
| run: dotnet build YandexMusic.slnx -c Release --no-restore -p:Version=${{ steps.version.outputs.value }} | |
| - name: Test | |
| run: dotnet test YandexMusic.slnx -c Release --no-build | |
| # Only IsPackable=true projects produce packages: YandexMusic, YandexMusic.Ynison, | |
| # YandexMusic.Quasar and YandexMusic.DependencyInjection. Every satellite declares a NuGet | |
| # dependency on the core, so they ship together on one version line. Symbol packages (.snupkg) | |
| # are produced alongside via IncludeSymbols; tests and the sample are IsPackable=false. | |
| - name: Pack | |
| run: dotnet pack YandexMusic.slnx -c Release --no-build -p:Version=${{ steps.version.outputs.value }} -o artifacts | |
| # Trusted Publishing: exchange the GitHub OIDC token for a short-lived NuGet API key. | |
| - name: NuGet login (Trusted Publishing) | |
| id: nuget-login | |
| uses: NuGet/login@v1 | |
| with: | |
| user: ${{ vars.NUGET_USER }} | |
| - name: Push to NuGet.org | |
| run: > | |
| dotnet nuget push "artifacts/*.nupkg" | |
| --api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} | |
| --source https://api.nuget.org/v3/index.json | |
| --skip-duplicate | |
| # Created as a DRAFT on purpose. The install scripts resolve "latest release" and pick the | |
| # ymt-* archive out of it, so a visible release without those archives is a broken install | |
| # command for everyone. The release is undrafted by the finalize job, once the player | |
| # archives are actually attached. | |
| # | |
| # Re-running a failed release must work, so an existing draft is topped up instead of failing. | |
| - name: Create the GitHub Release (draft) | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ github.ref_name }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| if gh release view "$TAG" -R "$REPO" >/dev/null 2>&1; then | |
| echo "Release $TAG already exists (re-run) — refreshing its package assets." | |
| gh release upload "$TAG" artifacts/*.nupkg artifacts/*.snupkg -R "$REPO" --clobber | |
| else | |
| gh release create "$TAG" artifacts/*.nupkg artifacts/*.snupkg -R "$REPO" \ | |
| --generate-notes --title "$TAG" --draft | |
| fi | |
| # Publishes the sample terminal player as versioned, self-contained single-file CLIs and attaches | |
| # them to the GitHub Release. Two flavours ship: Windows (net*-windows TFM, real NAudio playback) | |
| # built on Windows, and Linux (plain net10.0 TFM, simulated audio) built on Ubuntu. The build is | |
| # not trimmed because the sample uses reflection-based JSON. | |
| player: | |
| name: Publish player (${{ matrix.rid }}) | |
| needs: publish | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| rid: win-x64 | |
| tfm: net10.0-windows10.0.19041.0 | |
| - os: ubuntu-latest | |
| rid: linux-x64 | |
| tfm: net10.0 | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET 10 | |
| uses: actions/setup-dotnet@v6 | |
| with: | |
| dotnet-version: 10.0.x | |
| - name: Resolve version from tag | |
| id: version | |
| shell: bash | |
| run: echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" | |
| - name: Publish (${{ matrix.rid }}, self-contained, single file) | |
| run: > | |
| dotnet publish samples/YandexMusicTerminal/YandexMusicTerminal.csproj | |
| -c Release -r ${{ matrix.rid }} --self-contained true | |
| -p:PublishSingleFile=true -p:Version=${{ steps.version.outputs.value }} | |
| -p:PlayerTargetFramework=${{ matrix.tfm }} -o publish/player | |
| # Windows ships a zip; Linux a tar.gz, so the executable bit survives packaging. | |
| - name: Package | |
| id: package | |
| shell: pwsh | |
| run: | | |
| $version = '${{ steps.version.outputs.value }}'.Split('+')[0] | |
| if ('${{ matrix.rid }}' -eq 'win-x64') { | |
| $archive = "ymt-$version-win-x64.zip" | |
| Compress-Archive -Path publish/player/* -DestinationPath $archive | |
| } | |
| else { | |
| $archive = "ymt-$version-linux-x64.tar.gz" | |
| tar -czf $archive -C publish/player . | |
| } | |
| "archive=$archive" >> $env:GITHUB_OUTPUT | |
| - name: Upload workflow artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ymt-${{ steps.version.outputs.value }}-${{ matrix.rid }} | |
| path: ${{ steps.package.outputs.archive }} | |
| - name: Attach to the GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: gh release upload "${{ github.ref_name }}" "${{ steps.package.outputs.archive }}" --clobber | |
| # The release becomes visible only once both player archives are on it, so "latest release" is | |
| # never a state the install scripts cannot work with. | |
| finalize: | |
| name: Publish the release | |
| needs: [ publish, player ] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Undraft the release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ github.ref_name }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| assets=$(gh release view "$TAG" -R "$REPO" --json assets --jq '[.assets[].name] | join(" ")') | |
| echo "Assets on $TAG: $assets" | |
| for expected in win-x64.zip linux-x64.tar.gz; do | |
| case "$assets" in | |
| *"$expected"*) ;; | |
| *) echo "::error::the release is missing a ymt-*-$expected archive; leaving it as a draft" && exit 1 ;; | |
| esac | |
| done | |
| gh release edit "$TAG" -R "$REPO" --draft=false --latest |