Search code examples
c#testinggithub-actionsnuget-package-restoremultitargeting

How to dotnet restore a multi-target framework in CI for testing using old version of dotnet?


I have a C# package which currently supports dotnet 8 and I'm trying to modify it to add dotnet 6 and 7 support as well. I've gotten it to build for all versions using dotnet 8 locally on my laptop, using <TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks> in the .csproj file and removing all C# features added after net6.0. However when I push it to GitHub and my workflow runs in Github Actions, I test it against dotnet 6 and 7 as well as 8, and it breaks on the dotnet restore step.

My workflow:

name: .NET

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

env:
  DOTNET_CLI_TELEMETRY_OPTOUT: true
  DOTNET_GENERATE_ASPNET_CERTIFICATE: false

jobs:
  build:

    runs-on: macos-latest
    name: .NET ${{ matrix.dotnet }}
    strategy:
      matrix:
        dotnet:
          - 8.0 # EOL: 2026-11-10
          - 7.0 # EOL: 2024-05-14
          - 6.0 # EOL: 2024-11-12
          # version support doc: https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core
    steps:
    - uses: actions/checkout@v3
      with:
        repository: getargv/getargv
        path: getargv
        token: ${{ secrets.GH_PAT }}
    - name: Build libgetargv
      run: make install_dylib
      working-directory: getargv
    - uses: actions/checkout@v3
      with:
        path: getargv.cs
    - name: Setup .NET
      uses: actions/setup-dotnet@v4
      id: setup
      with:
        dotnet-version: ${{ matrix.dotnet }}.x
    - name: Create temporary global.json
      run: "echo '{\"sdk\":{\"version\": \"${{ steps.setup.outputs.dotnet-version }}\"}}' > ./global.json"
      working-directory: getargv.cs
    - name: Restore dependencies
      run: dotnet restore
      working-directory: getargv.cs
    - name: Build
      run: dotnet build --no-restore --framework net${{ matrix.dotnet }}
      working-directory: getargv.cs
    - name: Test
      run: dotnet test --no-build --verbosity normal
      working-directory: getargv.cs

I can set the framework when building with a flag, but the restore step has no such flag.

The error I get is fairly predictable:

Error: /Users/runner/.dotnet/sdk/7.0.404/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(160,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 8.0.  Either target .NET 7.0 or lower, or use a version of the .NET SDK that supports .NET 8.0. Download the .NET SDK from https://aka.ms/dotnet/download [/Users/runner/work/getargv.cs/getargv.cs/getargv.cs/Getargv/Getargv.csproj::TargetFramework=net8.0]
Error: /Users/runner/.dotnet/sdk/7.0.404/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(160,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 8.0.  Either target .NET 7.0 or lower, or use a version of the .NET SDK that supports .NET 8.0. Download the .NET SDK from https://aka.ms/dotnet/download [/Users/runner/work/getargv.cs/getargv.cs/getargv.cs/Getargv.Tool/Getargv.Tool.csproj::TargetFramework=net8.0]
Error: /Users/runner/.dotnet/sdk/7.0.404/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(160,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 8.0.  Either target .NET 7.0 or lower, or use a version of the .NET SDK that supports .NET 8.0. Download the .NET SDK from https://aka.ms/dotnet/download [/Users/runner/work/getargv.cs/getargv.cs/getargv.cs/Getargv.Tests/Getargv.Tests.csproj::TargetFramework=net8.0]
Error: /Users/runner/.dotnet/sdk/6.0.417/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(144,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0.  Either target .NET 6.0 or lower, or use a version of the .NET SDK that supports .NET 7.0. [/Users/runner/work/getargv.cs/getargv.cs/getargv.cs/Getargv/Getargv.csproj]
Error: /Users/runner/.dotnet/sdk/6.0.417/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(144,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0.  Either target .NET 6.0 or lower, or use a version of the .NET SDK that supports .NET 7.0. [/Users/runner/work/getargv.cs/getargv.cs/getargv.cs/Getargv.Tool/Getargv.Tool.csproj]
Error: /Users/runner/.dotnet/sdk/6.0.417/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(144,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0.  Either target .NET 6.0 or lower, or use a version of the .NET SDK that supports .NET 7.0. [/Users/runner/work/getargv.cs/getargv.cs/getargv.cs/Getargv.Tests/Getargv.Tests.csproj]

How do people test against older dotnet versions while also supporting newer versions?

Edit:

Changing the build command to: dotnet build --framework net${{ matrix.dotnet }} doesn't use the specified framework for restore.


Solution

  • You can specify the target framework for dotnet restore with dotnet restore -p:TargetFramework=net7.0.

    dotnet restore and dotnet build are wrappers around dotnet msbuild, and dotnet restore is actually the same as calling dotnet msbuild -t:restore. Some additional information can be found in this question.

    I would try changing your code like this:

        - name: Restore dependencies
          run: dotnet restore -p:TargetFramework=net${{ matrix.dotnet }}