Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support installing multiple versions of .NET Core SxS #25

Closed
natemcmaster opened this issue Aug 22, 2019 · 40 comments · Fixed by #124
Closed

Support installing multiple versions of .NET Core SxS #25

natemcmaster opened this issue Aug 22, 2019 · 40 comments · Fixed by #124

Comments

@natemcmaster
Copy link

I would like to use this action to setup .NET Core for some class libraries I support. I like to run tests on multiple versions of .NET Core, but it appears I cannot use this task to install multiple versions of .NET Core.

Repro

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/setup-dotnet@v1
      with:
        version: '2.1.801'        
    - run: dotnet --info
    - uses: actions/setup-dotnet@v1
      with:
        version: '3.0.100-preview8-013656'
    - run: dotnet --info

Expected

Both .NET Core 2.1 and 3.0 are installed and available when running dotnet commands.

Actual

Usages of actions/setup-dotnet are not additive; the last one wins, so only 3.0.100-preview8-013656 is available.

logs.zip

@damccorm
Copy link
Contributor

This seems like reasonable behavior to me, but I may be missing something - in general, I think I would want the most recent version to win. Also note that after you've installed a version once, setting it back to that version is essentially free since its cached, you just need to run setup-dotnet again with that version.

Am I missing a use case here?

@natemcmaster
Copy link
Author

Here is one use case (there are more, but this is the most common). Consider, for instance, a test project file like this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
     <TargetFrameworks>netcoreapp3.0;netcoreapp2.2;netcoreapp2.1</TargetFrameworks>
  </PropertyGroup>
  <ItemGroup>
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.0" />
  </ItemGroup>
</Project>

When you run dotnet test for this project, the test runner will launch tests for the three versions of .NET Core listed, 2.1, 2.2, and 3.0. If only 3.0 is installed, the 2.1 and 2.2 test runs would fail.

The way to make this work is to install all versions of .NET Core into the same root folder.

@natemcmaster
Copy link
Author

Elaborating more on on this:

The way to make this work is to install all versions of .NET Core into the same root folder.

.NET Core can have multiple versions installed side by side. Invoking the dotnet executable dispatches to the right version based on the app's configuration. So, with the repro above, I was expecting to see the installation of .NET Core look something like this on disk:

- /opt/tools/dotnet/x64/
    + dotnet                             <--- the main dotnet executable on PATH
    - shared/
        - Microsoft.NETCore.App/
            + 2.1.12/
            + 3.0.0-preview8-28405-07/
        - Microsoft.AspNetCore.App/
            + 2.1.12/
            + 3.0.0-preview8.19405.7/
    - sdk/
        + 2.1.801/
        + 3.0.100-preview8-013656/

The actual layout created by the setup-dotnet action was to install .NET Core into two different locations:

- /opt/hostedtoolcache/dncs/2.1.801/x64/
    + dotnet
    - shared/
        - Microsoft.NETCore.App/
            + 2.1.12/
        - Microsoft.AspNetCore.App/
            + 2.1.12/
    - sdk/
        + 2.1.801/
- /opt/hostedtoolcache/dncs/3.0.100-preview8-013656/x64/
    + dotnet
    - shared/
        - Microsoft.NETCore.App/
            + 3.0.0-preview8-28405-07/
        - Microsoft.AspNetCore.App/
            + 3.0.0-preview8.19405.7/
    - sdk/
        + 3.0.100-preview8-013656/

Both /opt/hostedtoolcache/dncs/3.0.100-preview8-013656/x64/dotnet and /opt/hostedtoolcache/dncs/2.1.801/x64/dotnet are in PATH, but the 3.0 version is listed first so it wins.

@NickCraver
Copy link

I just hit this as well. Context: we need to test libs against 2.x and 3.x (same as @natemcmaster) but the install for both doesn't work. Still getting the CI/CD working, but I'm currently jammed up on this issue. If it helps, my log is at: https://github.com/MiniProfiler/dotnet/pull/416/checks?check_run_id=210166603

@daveaglick
Copy link

Multiple SDK version support is also important for things like build tooling. For example, Cake requires one version of the SDK but the app being built may require a different version.

@blane-nelson
Copy link

I hit this as well. I was able to get around by using the --framework parameter for dotnet, but it makes the yml file more complex, because of having the extra steps to switch the framework back and forth. If this can be changed so that it adds each sdk side by side I think it would be helpful.

@bryanmacfarlane bryanmacfarlane changed the title Support installing multiple versions of .NET Core Support installing multiple versions of .NET Core SxS Sep 15, 2019
@alaatm
Copy link

alaatm commented Nov 21, 2019

This is also required when a referenced library is explicitly using a different runtime. Having the latest 3.0 and attempting to build the project will cause an error, for example: The specified framework 'Microsoft.NETCore.App', version '2.0.0' was not found. Just got stuck with this issue!

@msmolka
Copy link

msmolka commented Nov 22, 2019

I have other issue. I have app multitarget: net461, netstandard2, netcoreap3. To build it I need SDK 3. To test netstandard I need SDK 2 for netcoreapp. So for now I'm not able to test it properly for multitarget.

@alaatm
Copy link

alaatm commented Nov 22, 2019

The following can be used as a workaround until this gets implemented:

  - name: Setup .net core 2.2
    uses: actions/setup-dotnet@v1
    with:
      dotnet-version: 2.2.402

  - name: Setup .net core 3.0
    uses: actions/setup-dotnet@v1
    with:
      dotnet-version: 3.0.100

  - name: .net SxS
    run: |
      rsync -a ${DOTNET_ROOT/3.0.100/2.2.402}/* $DOTNET_ROOT/

@actions actions deleted a comment Nov 27, 2019
@jetersen
Copy link

@alaatm thanks for the workaround 🙏

@airbreather
Copy link

airbreather commented Jan 14, 2020

Our use case: our automated tests run on netcoreapp2.2 so that the solution should continue to build and run on Visual Studio 2017, but our published NuGet packages use package license expressions. Support for package license expressions was only added in SDK version 3.0.

So we need SDK version 3.0+, and I would prefer to have version 2.2 of the runtime available in order to run the actual tests (as opposed to artificially changing the tests to target whatever version of the runtime happens to come with whatever version of the SDK happens to be used to build the project).

@coderpatros
Copy link
Contributor

Thanks @alaatm for the workaround. Here's a xplat one that works with ubuntu-latest, windows-latest and macos-latest too (assuming a matrix strategy with os set)...

    - name: Setup .NET Core 2.1
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 2.1.803
  
    - name: Setup .NET Core 3.1
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.101

    - name: Setup side by side .NET SDKs on Windows
      if: matrix.os == 'windows-latest'
      run: |
        SET DOTNET_21_ROOT=%DOTNET_ROOT:3.1.101=2.1.803%
        xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
      shell: cmd

    - name: Setup side by side .NET SDKs on *nix
      if: matrix.os != 'windows-latest'
      run: |
        rsync -a ${DOTNET_ROOT/3.1.101/2.1.803}/* $DOTNET_ROOT/

@fluffynuts
Copy link

Unfortunately the workaround proposed by @alaatm has either stopped working, or I'm (quite possibly) doing something stupid.

NExpect has a netcoreapp2.2 project to prove that it works with older SDKs, however those tests fail to build:

 Test run for /home/runner/work/NExpect/NExpect/src/NExpect.Tests.Core/bin/Debug/netcoreapp2.2/NExpect.Tests.Core.dll(.NETCoreApp,Version=v2.2)
Microsoft (R) Test Execution Command Line Tool Version 16.3.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

A total of 1 test files matched the specified pattern.
Testhost process exited with error: It was not possible to find any compatible framework version
The framework 'Microsoft.NETCore.App', version '2.2.0' was not found.
  - The following frameworks were found:
      3.1.1 at [/opt/hostedtoolcache/dncs/3.1.101/x64/shared/Microsoft.NETCore.App]

As far as I can tell, I've replicated @alaatm's workaround, with a subtle version change for the 2.2 sdk:

name: .NET Core

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Setup .NET Core 2
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 2.2.402
    - name: Setup .NET Core 3
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.101
    - name: .net SxS
      run: |
        rsync -a ${DOTNET_ROOT/3.0.101/2.2.402}/* $DOTNET_ROOT/
    - uses: actions/setup-node@v2-beta
      with:
        node-version: '12'
    - name: Build and test
      env:
        DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
        DOTNET_CLI_TELEMETRY_OPTOUT: 1
      run: |
        git submodule update --init
        npm ci
        npm test

If I'm doing something wrong, I'd really appreciate a heads-up: I'm new to GH actions, so I could be doing this completely wrong. Otherwise, super-+1 for enabling multiple sdk versions (:

@coderpatros
Copy link
Contributor

@fluffynuts the rsync command isn't quite right, you've specified .net 3.1.101 but have 3.0.101 in the rsync line.

@fluffynuts
Copy link

fluffynuts commented May 23, 2020

🤦 thanks for debugging for me!

@david-driscoll
Copy link

For anyone running into this still, I have a slightly updated work around, that allows the version to vary, or support any number of additional sdks or runtimes (looking at you .net 5... 😄). Works on ubuntu, mac and windows from my testing.

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: 🔨 Use .NET Core 2.1 SDK
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: '2.1.x'
      - name: 🔨 Use .NET Core 3.1 SDK
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: '3.1.x'
      - name: 🪓 **DOTNET HACK** 🪓
        shell: pwsh
        run: |
          $version = Split-Path (Split-Path $ENV:DOTNET_ROOT -Parent) -Leaf;
          $root = Split-Path (Split-Path $ENV:DOTNET_ROOT -Parent) -Parent;
          $directories = Get-ChildItem $root | Where-Object { $_.Name -ne $version };
          foreach ($dir in $directories) {
            $from = $dir.FullName;
            $to = "$root/$version";
            Write-Host Copying from $from to $to;
            Copy-Item "$from\*" $to -Recurse -Force;
          }

RobertIndie added a commit to RobertIndie/pulsar-dotpulsar that referenced this issue Jun 24, 2020
@david-driscoll
Copy link

The question is still valid, will this be fixed by this action eventually? Yes or No?

All the workarounds don't avoid the glaring issue that installing specific versions onto github actions causes immediate friction, when on something like Azure Pipelines where the sdk install task installs them all SxS by default (to be fair this wasn't the case with the first version of that task a year or two ago, but that was fixed before this task was created)

@adamralph
Copy link
Contributor

@0xced I'm not sure how well that will work for scenarios where tests need to be run against multiple SDK versions.

Still, it's really a hack for this action not supporting multiple SDK's, which, as @david-driscoll mentions, already works on other CI systems.

@coderpatros
Copy link
Contributor

@adamralph I took your deterministic build comment to be about being able to re-run it and have the same outcome (success/failure). But if you meant byte for byte deterministic I've also raised this issue dotnet/dotnet-docker#2048

I have a use case that I want consumers of a package to be able to easily verify that a published package matches the publicly available source code. And I don't think github workflows really solves that. Even with this issue resolved.

@clairernovotny
Copy link

@coderpatros I have a use case that I want consumers of a package to be able to easily verify that a published package matches the publicly available source code.

This is something we're working on separately. I'd love to hear more about your use case. Happy to connect over email. first dot last at microsoft dot com.

@adamralph
Copy link
Contributor

But if you meant byte for byte deterministic I've also raised this issue dotnet/dotnet-docker#2048

@coderpatros no, I wasn't referring to that.

@coderpatros
Copy link
Contributor

coderpatros commented Jul 1, 2020

This is something we're working on separately. I'd love to hear more about your use case. Happy to connect over email. first dot last at microsoft dot com.

@clairernovotny done

@coderpatros
Copy link
Contributor

This query popped up on another thread. You can build 2.1 projects using the 3.1 SDK but you can't run them. Test projects are built and then run. So you can build multiple target versions. But you can't test them. Nate was specific about testing. But just wanted to call it out again in case that was missed by the maintainers of this action.

@buvinghausen
Copy link

buvinghausen commented Jul 30, 2020

@coderpatros you are absolutely correct the issue is not building only testing. To that end you only need to install the lower level runtimes and not the full SDK.

With this installation setup I can test every single .NET Core app release from 1.0 to 3.1
image

So one possible solution would be to simply include those two runtimes in the base image software install. Since they have both reached EOL they wouldn't have to be patched at anytime going forward.

heaths added a commit to heaths/KeyVaultProxy that referenced this issue Aug 10, 2020
heaths added a commit to heaths/KeyVaultProxy that referenced this issue Aug 10, 2020
* Rename package AzureSamples.Security.KeyVault.Proxy

Basically, replaced "AzureSample" with "AzureSamples", which sounds better.

* Resolve feedback

* Use same test frameworks as azure-sdk-for-net

* Fix TargetFrameworks for non-Windows

* Use dotnet-version 2.1.20

* Use SDK version (not runtime)

* Install 2.1 runtime to fix build

Also separates build and test to more obviously show which one failed.

* Work around actions/setup-dotnet#25

* Use SDK version instead of runtime version

* More build fixes

CIs really need some way of testing locally. 😔

* Fix xcopy command on Windows
niklaslundberg added a commit to niklaslundberg/Arbor.AppModel that referenced this issue Sep 4, 2020
@egil
Copy link

egil commented Sep 15, 2020

@ZEisinger I see you closed this in #124. Can you share how to install multiple SDK versions when #124 is released (if it is not already)?

@ZEisinger
Copy link
Contributor

@egil I added an example to the README just now: https://github.com/actions/setup-dotnet#usage

@slozier
Copy link

slozier commented Sep 17, 2020

@ZEisinger Thanks for the example, I tried it and unfortunately it didn't work as presented. I also tried using main instead of v1. The only way I managed to get it working was using main and an explicit patch version (e.g. 2.1.810 instead of 2.1.x).

@ZEisinger
Copy link
Contributor

Thanks @slozier, I reverted the change for a couple of days due to other issues #128 and #130. v1 should be good now

0xced added a commit to 0xced/codecov-exe that referenced this issue Jan 21, 2021
It is causing this error:

```
Run SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
  shell: C:\windows\system32\cmd.EXE /D /E:ON /V:OFF /S /C "CALL "{0}""
  env:
    DOTNET_ROOT: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet
Cannot perform a cyclic copy
0 File(s) copied
Error: Process completed with exit code 4.
```

Moreover, this workaround should no longer be required, see actions/setup-dotnet#25
0xced added a commit to 0xced/codecov-exe that referenced this issue Jan 21, 2021
It is causing this error:

```
Run SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
  shell: C:\windows\system32\cmd.EXE /D /E:ON /V:OFF /S /C "CALL "{0}""
  env:
    DOTNET_ROOT: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet
Cannot perform a cyclic copy
0 File(s) copied
Error: Process completed with exit code 4.
```

Moreover, this workaround should no longer be required, see actions/setup-dotnet#25
0xced added a commit to 0xced/codecov-exe that referenced this issue Jan 21, 2021
It is causing this error:

```
Run SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
  shell: C:\windows\system32\cmd.EXE /D /E:ON /V:OFF /S /C "CALL "{0}""
  env:
    DOTNET_ROOT: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet
Cannot perform a cyclic copy
0 File(s) copied
Error: Process completed with exit code 4.
```

Moreover, this workaround should no longer be required, see actions/setup-dotnet#25
0xced added a commit to 0xced/codecov-exe that referenced this issue Jan 23, 2021
It is causing this error:

```
Run SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
  shell: C:\windows\system32\cmd.EXE /D /E:ON /V:OFF /S /C "CALL "{0}""
  env:
    DOTNET_ROOT: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet
Cannot perform a cyclic copy
0 File(s) copied
Error: Process completed with exit code 4.
```

Moreover, this workaround should no longer be required, see actions/setup-dotnet#25
0xced added a commit to 0xced/codecov-exe that referenced this issue Jan 25, 2021
It is causing this error:

```
Run SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
  shell: C:\windows\system32\cmd.EXE /D /E:ON /V:OFF /S /C "CALL "{0}""
  env:
    DOTNET_ROOT: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet
Cannot perform a cyclic copy
0 File(s) copied
Error: Process completed with exit code 4.
```

Moreover, this workaround should no longer be required, see actions/setup-dotnet#25
0xced added a commit to 0xced/codecov-exe that referenced this issue Jan 25, 2021
It is causing this error:

```
Run SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  SET DOTNET_31_ROOT=%DOTNET_ROOT:3.1.300=2.1.806%
  xcopy /s /y /d %DOTNET_31_ROOT% %DOTNET_ROOT%
  shell: C:\windows\system32\cmd.EXE /D /E:ON /V:OFF /S /C "CALL "{0}""
  env:
    DOTNET_ROOT: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet
Cannot perform a cyclic copy
0 File(s) copied
Error: Process completed with exit code 4.
```

Moreover, this workaround should no longer be required, see actions/setup-dotnet#25
mikelor added a commit to mikelor/FunkySix that referenced this issue Sep 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.