Compare commits

..

8 Commits
v3.0.1 ... v2

Author SHA1 Message Date
8e6bd2905e Merge pull request #576 from actions/remove-cdn-fallback-v2
`v2` - Remove `dotnetcli.blob.core.windows.net` storage account fallback logic and update install scripts
2025-02-10 10:11:28 -05:00
603ff3ab1c Update workflow.yml to remove outdated URLs 2025-01-30 16:15:18 -05:00
d284574c05 Update workflow.yml 2025-01-29 16:49:25 -05:00
bac33b41f7 add updated install scripts 2025-01-29 21:37:00 +00:00
f56a6a6861 fix ci by adding unstaged index.js changes 2025-01-02 02:23:32 +00:00
fb81433816 Remove extra spacing 2025-01-02 01:03:07 +00:00
9798ae12d7 Remove CDN fallback logic (v2) 2025-01-02 00:39:19 +00:00
aab9aab748 V2 - Use new .NET CDN URLs and update to latest install scripts (#568)
* new cdn url changes

* Fix Workflow

* Fix CI failures for ubuntu-latest

* Fix upload-artifact@v4

* Fix proxy test issue

* Fix Proxy env issue

* Fix globalization invariant issue

* Fix libssl issue

* Install libssl1.1 to fix CI failures

* Add fallback logic

* Fix CI failures dist

* Update installer.ts

* Update installer.ts

* Fix proxy test failure

* Update signed version

---------

Co-authored-by: Priya Gupta <147705955+priyagupta108@users.noreply.github.com>
2024-12-26 15:00:58 -06:00
27 changed files with 4574 additions and 4617 deletions

View File

@ -45,7 +45,7 @@ jobs:
id: diff id: diff
# If index.js was different than expected, upload the expected version as an artifact # If index.js was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
if: ${{ failure() && steps.diff.conclusion == 'failure' }} if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with: with:
name: dist name: dist

View File

@ -22,7 +22,7 @@ jobs:
steps: steps:
- name: Update the ${{ env.TAG_NAME }} tag - name: Update the ${{ env.TAG_NAME }} tag
id: update-major-tag id: update-major-tag
uses: actions/publish-action@v0.2.0 uses: actions/publish-action@v0.1.0
with: with:
source-tag: ${{ env.TAG_NAME }} source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }} slack-webhook: ${{ secrets.SLACK_WEBHOOK }}

View File

@ -17,7 +17,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
dotnet-version: ['2.1', '2.2', '3.0', '3.1', '5.0'] dotnet-version: ['2.1', '2.2', '3.0', '3.1', '5.0']
steps: steps:
- name: Checkout - name: Checkout

View File

@ -39,7 +39,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -62,7 +62,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macos-13]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -78,7 +78,7 @@ jobs:
uses: ./ uses: ./
with: with:
dotnet-version: 3.1.201 dotnet-version: 3.1.201
# We are including this variable to force the generation of the nuget config file to verify that it is created in the correct place # We are including this veriable to force the generation of the nuget config file to verify that it is created in the correct place
source-url: https://api.nuget.org/v3/index.json source-url: https://api.nuget.org/v3/index.json
env: env:
NUGET_AUTH_TOKEN: NOTATOKEN NUGET_AUTH_TOKEN: NOTATOKEN
@ -95,7 +95,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -115,36 +115,12 @@ jobs:
shell: pwsh shell: pwsh
run: __tests__/verify-dotnet.ps1 3.1 2.2 run: __tests__/verify-dotnet.ps1 3.1 2.2
test-setup-prerelease-version:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Setup dotnet '2.2'
uses: ./
with:
dotnet-version: '2.2'
- name: Setup dotnet '3.1.100-preview1-014459'
uses: ./
with:
dotnet-version: '3.1.100-preview1-014459'
- name: Verify dotnet
shell: pwsh
run: __tests__/verify-dotnet.ps1 3.1.100-preview1-014459
test-setup-latest-patch-version: test-setup-latest-patch-version:
runs-on: ${{ matrix.operating-system }} runs-on: ${{ matrix.operating-system }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -155,20 +131,20 @@ jobs:
uses: ./ uses: ./
with: with:
dotnet-version: 3.1.x dotnet-version: 3.1.x
- name: Setup dotnet 2.2.X - name: Setup dotnet 2.2.x
uses: ./ uses: ./
with: with:
dotnet-version: 2.2.X dotnet-version: 2.2.x
- name: Verify dotnet - name: Verify dotnet
shell: pwsh shell: pwsh
run: __tests__/verify-dotnet.ps1 '2.2' '3.1' run: __tests__/verify-dotnet.ps1 3.1 2.2
test-setup-with-wildcard: test-setup-with-wildcard:
runs-on: ${{ matrix.operating-system }} runs-on: ${{ matrix.operating-system }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -192,7 +168,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest] operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -213,98 +189,21 @@ jobs:
shell: pwsh shell: pwsh
run: __tests__/verify-dotnet.ps1 2.2 3.1 run: __tests__/verify-dotnet.ps1 2.2 3.1
test-setup-with-dotnet-quality:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Setup dotnet 7.0 with preview quality
uses: ./
with:
dotnet-version: "7.0"
dotnet-quality: "preview"
- name: Verify preview version
shell: pwsh
run: |
$version = & dotnet --version
Write-Host "Installed version: $version"
if (-not ($version.Contains("preview") -or $version.Contains("rc"))) { throw "Unexpected version" }
test-dotnet-version-output-during-single-version-installation:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Setup dotnet 6.0.401
uses: ./
id: step1
with:
dotnet-version: "6.0.401"
- name: Verify value of the dotnet-version output
shell: pwsh
run: |
$version = & dotnet --version
Write-Host "Installed version: $version"
if (-not ($version -eq '${{steps.step1.outputs.dotnet-version}}')) { throw "Unexpected output value" }
test-dotnet-version-output-during-multiple-version-installation:
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Clear toolcache
shell: pwsh
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
- name: Setup dotnet 6.0.401, 5.0.408, 7.0.100-rc.1.22431.12
uses: ./
id: step2
with:
dotnet-version: |
7.0.100-rc.1.22431.12
6.0.401
5.0.408
- name: Verify value of the dotnet-version output
shell: pwsh
run: |
$version = "7.0.100-rc.1.22431.12"
if (-not ($version -eq '${{steps.step2.outputs.dotnet-version}}')) { throw "Unexpected output value" }
test-proxy: test-proxy:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
container: container:
image: mcr.microsoft.com/dotnet/core/runtime-deps:3.0-bionic image: ubuntu:20.04
options: --dns 127.0.0.1 options: --dns 127.0.0.1
services: services:
squid-proxy: squid-proxy:
image: datadog/squid:latest image: ubuntu/squid:latest
ports: ports:
- 3128:3128 - 3128:3128
env: env:
https_proxy: http://squid-proxy:3128 https_proxy: http://squid-proxy:3128
http_proxy: http://squid-proxy:3128 http_proxy: http://squid-proxy:3128
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: true
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -313,7 +212,7 @@ jobs:
- name: Install curl - name: Install curl
run: | run: |
apt update apt update
apt -y install curl apt -y install curl libssl1.1 libssl-dev
- name: Setup dotnet 3.1.201 - name: Setup dotnet 3.1.201
uses: ./ uses: ./
with: with:
@ -325,10 +224,10 @@ jobs:
run: __tests__/verify-dotnet.sh 3.1.201 run: __tests__/verify-dotnet.sh 3.1.201
test-bypass-proxy: test-bypass-proxy:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
env: env:
https_proxy: http://no-such-proxy:3128 https_proxy: http://no-such-proxy:3128
no_proxy: github.com,dotnetcli.blob.core.windows.net,download.visualstudio.microsoft.com,api.nuget.org,dotnetcli.azureedge.net no_proxy: github.com,download.visualstudio.microsoft.com,api.nuget.org,builds.dotnet.microsoft.com,ci.dot.net
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3

View File

@ -1,6 +1,6 @@
--- ---
name: "@actions/core" name: "@actions/core"
version: 1.9.1 version: 1.6.0
type: npm type: npm
summary: Actions core lib summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core homepage: https://github.com/actions/toolkit/tree/main/packages/core

View File

@ -1,20 +1,30 @@
--- ---
name: "@actions/exec" name: "@actions/exec"
version: 1.1.1 version: 1.0.4
type: npm type: npm
summary: Actions exec lib summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec homepage: https://github.com/actions/toolkit/tree/master/packages/exec
license: mit license: mit
licenses: licenses:
- sources: LICENSE.md - sources: Auto-generated MIT license text
text: |- text: |
The MIT License (MIT) MIT License
Copyright 2019 GitHub Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices: [] notices: []

View File

@ -1,9 +1,9 @@
--- ---
name: "@actions/http-client" name: "@actions/http-client"
version: 2.0.1 version: 1.0.11
type: npm type: npm
summary: Actions Http Client summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client homepage: https://github.com/actions/http-client#readme
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE

View File

@ -0,0 +1,32 @@
---
name: "@actions/http-client"
version: 1.0.8
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/http-client#readme
license: mit
licenses:
- sources: LICENSE
text: |
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@ -1,20 +1,30 @@
--- ---
name: "@actions/io" name: "@actions/io"
version: 1.1.2 version: 1.0.2
type: npm type: npm
summary: Actions io lib summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io homepage: https://github.com/actions/toolkit/tree/master/packages/io
license: mit license: mit
licenses: licenses:
- sources: LICENSE.md - sources: Auto-generated MIT license text
text: |- text: |
The MIT License (MIT) MIT License
Copyright 2019 GitHub Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices: [] notices: []

View File

@ -1,20 +0,0 @@
---
name: uuid
version: 8.3.2
type: npm
summary: RFC4122 (v1, v4, and v5) UUIDs
homepage:
license: mit
licenses:
- sources: LICENSE.md
text: |
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

169
README.md
View File

@ -8,82 +8,62 @@ This action sets up a [.NET CLI](https://github.com/dotnet/sdk) environment for
- registering problem matchers for error output - registering problem matchers for error output
- setting up authentication to private package sources like GitHub Packages - setting up authentication to private package sources like GitHub Packages
> **Note**: GitHub hosted runners have some versions of the .NET SDK Please Note: GitHub hosted runners have some versions of the .NET SDK
preinstalled. Installed versions are subject to change. Please refer to the preinstalled. Installed versions are subject to change. Please refer to the
documentation documentation
[software installed on github hosted runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software) [software installed on github hosted runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software)
for .NET SDK versions that are currently available. for .NET SDK versions that are currently available.
## Usage # Usage
See [action.yml](action.yml) See [action.yml](action.yml)
**Basic**: Basic:
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v2
with: with:
dotnet-version: '3.1.x' dotnet-version: '3.1.x' # SDK Version to use; x will use the latest version of the 3.1 channel
- run: dotnet build <my project> - run: dotnet build <my project>
``` ```
Multiple versions:
> Note: In case multiple versions are installed, the latest .NET version will be used by default unless another version is specified in the `global.json` file.
**Multiple version installation**:
```yml ```yml
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup dotnet - name: Setup dotnet
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v2
with: with:
dotnet-version: | dotnet-version: |
3.1.x 3.1.x
5.0.x 5.0.x
- run: dotnet build <my project> - run: dotnet build <my project>
``` ```
> **Note**: In case multiple versions are installed, the latest .NET version will be used by default unless another version is specified in the `global.json` file. Preview version:
## Supported version syntax
The `dotnet-version` input supports following syntax:
- **A.B.C** (e.g 6.0.400, 7.0.100-preview.7.22377.5) - installs exact version of .NET SDK
- **A.B** or **A.B.x** (e.g. 3.1, 3.1.x) - installs the latest patch version of .NET SDK on the channel `3.1`, including prerelease versions (preview, rc)
- **A** or **A.x** (e.g. 3, 3.x) - installs the latest minor version of the specified major tag, including prerelease versions (preview, rc)
## Using the `dotnet-quality` input
This input sets up the action to install the latest build of the specified quality in the channel. The possible values of `dotnet-quality` are: **daily**, **signed**, **validated**, **preview**, **ga**.
> **Note**: `dotnet-quality` input can be used only with .NET SDK version in 'A.B', 'A.B.x', 'A' and 'A.x' formats where the major version is higher than 5. In other cases, `dotnet-quality` input will be ignored.
```yml ```yml
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v2
with: with:
dotnet-version: '6.0.x' dotnet-version: '6.0.x'
dotnet-quality: 'preview' include-prerelease: true
- run: dotnet build <my project> - run: dotnet build <my project>
``` ```
global.json in a subdirectory:
## Using the `global-json-file` input
`setup-dotnet` action can read .NET SDK version from a `global.json` file. Input `global-json-file` is used for specifying the path to the `global.json`. If the file that was supplied to `global-json-file` input doesn't exist, the action will fail with error.
>**Note**: In case both `dotnet-version` and `global-json-file` inputs are used, versions from both inputs will be installed.
```yml ```yml
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v2
with: with:
global-json-file: csharp/global.json global-json-file: csharp/global.json
- run: dotnet build <my project> - run: dotnet build <my project>
working-directory: csharp working-directory: csharp
``` ```
## Matrix Testing Matrix Testing:
Using `setup-dotnet` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of .NET SDK: ```yaml
```yml
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -94,20 +74,38 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup dotnet - name: Setup dotnet
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v2
with: with:
dotnet-version: ${{ matrix.dotnet }} dotnet-version: ${{ matrix.dotnet }}
- run: dotnet build <my project> - run: dotnet build <my project>
``` ```
## Setting up authentication for nuget feeds
### Github Package Registry (GPR) Side by Side Testing:
```yml ```yaml
jobs:
build:
runs-on: ubuntu-latest
name: Dotnet Side by Side testing sample
steps:
- uses: actions/checkout@v3
- name: Setup dotnet
uses: actions/setup-dotnet@v2
with:
dotnet-version: |
2.1.x
3.1.x
- run: dotnet build <my project>
- run: dotnet test <my project>
```
Authentication for nuget feeds:
```yaml
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3 # Authenticates packages to push to GPR
- uses: actions/setup-dotnet@v2
with: with:
dotnet-version: '3.1.x' dotnet-version: '3.1.x' # SDK Version to use.
source-url: https://nuget.pkg.github.com/<owner>/index.json source-url: https://nuget.pkg.github.com/<owner>/index.json
env: env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
@ -116,22 +114,19 @@ steps:
run: dotnet pack --configuration Release <my project> run: dotnet pack --configuration Release <my project>
- name: Publish the package to GPR - name: Publish the package to GPR
run: dotnet nuget push <my project>/bin/Release/*.nupkg run: dotnet nuget push <my project>/bin/Release/*.nupkg
```
### Azure Artifacts # Authenticates packages to push to Azure Artifacts
```yml - uses: actions/setup-dotnet@v2
- uses: actions/setup-dotnet@v3
with: with:
source-url: https://pkgs.dev.azure.com/<your-organization>/_packaging/<your-feed-name>/nuget/v3/index.json source-url: https://pkgs.dev.azure.com/<your-organization>/_packaging/<your-feed-name>/nuget/v3/index.json
env: env:
NUGET_AUTH_TOKEN: ${{secrets.AZURE_DEVOPS_PAT}} # Note, create a secret with this name in Settings NUGET_AUTH_TOKEN: ${{secrets.AZURE_DEVOPS_PAT}} # Note, create a secret with this name in Settings
- name: Publish the package to Azure Artifacts - name: Publish the package to Azure Artifacts
run: dotnet nuget push <my project>/bin/Release/*.nupkg run: dotnet nuget push <my project>/bin/Release/*.nupkg
```
### nuget.org # Authenticates packages to push to nuget.org.
```yml # It's only the way to push a package to nuget.org feed for macOS/Linux machines due to API key config store limitations.
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v2
with: with:
dotnet-version: 3.1.x dotnet-version: 3.1.x
- name: Publish the package to nuget.org - name: Publish the package to nuget.org
@ -139,84 +134,32 @@ steps:
env: env:
NUGET_AUTH_TOKEN: ${{ secrets.NUGET_TOKEN }} NUGET_AUTH_TOKEN: ${{ secrets.NUGET_TOKEN }}
``` ```
> **Note**: It's the only way to push a package to nuget.org feed for macOS/Linux machines due to API key config store limitations.
# Outputs and environment variables ## Environment Variables to use with dotnet
## Outputs
### `dotnet-version`
Using the **dotnet-version** output it's possible to get the installed by the action .NET SDK version.
**Single version installation**
In case of a single version installation, the `dotnet-version` output contains the version that is installed by the action.
```yaml
- uses: actions/setup-dotnet@v3
id: cp310
with:
dotnet-version: 3.1.422
- run: echo '${{ steps.cp310.outputs.dotnet-version }}' # outputs 3.1.422
```
**Multiple version installation**
In case of a multiple version installation, the `dotnet-version` output contains the latest version that is installed by the action.
```yaml
- uses: actions/setup-dotnet@v3
id: cp310
with:
dotnet-version: |
3.1.422
5.0.408
- run: echo '${{ steps.cp310.outputs.dotnet-version }}' # outputs 5.0.408
```
**Installation from global.json**
When the `dotnet-version` input is used along with the `global-json-file` input, the `dotnet-version` output contains the version resolved from the `global.json`.
```yaml
- uses: actions/setup-dotnet@v3
id: cp310
with:
dotnet-version: |
3.1.422
5.0.408
global-json-file: "./global.json" # contains version 2.2.207
- run: echo '${{ steps.cp310.outputs.dotnet-version }}' # outputs 2.2.207
```
## Environment variables
Some environment variables may be necessary for your particular case or to improve logging. Some examples are listed below, but the full list with complete details can be found here: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables Some environment variables may be necessary for your particular case or to improve logging. Some examples are listed below, but the full list with complete details can be found here: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables
| **Env.variable** | **Description** | **Default value** | - DOTNET_NOLOGO - removes logo and telemetry message from first run of dotnet cli (default: false)
| ----------- | ----------- | ----------- | - DOTNET_CLI_TELEMETRY_OPTOUT - opt-out of telemetry being sent to Microsoft (default: false)
| DOTNET_INSTALL_DIR |Specifies a directory where .NET SDKs should be installed by the action|*isn't set*| - DOTNET_MULTILEVEL_LOOKUP - configures whether the global install location is used as a fall-back (default: true)
| DOTNET_NOLOGO |Removes logo and telemetry message from first run of dotnet cli|*false*|
| DOTNET_CLI_TELEMETRY_OPTOUT |Opt-out of telemetry being sent to Microsoft|*false*|
| DOTNET_MULTILEVEL_LOOKUP |Configures whether the global install location is used as a fall-back|*true*|
**Example usage**: Example usage:
```yml ```yaml
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
DOTNET_INSTALL_DIR: "path/to/directory" DOTNET_NOLOGO: true
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- uses: actions/setup-dotnet@v3 - uses: actions/setup-dotnet@v2
with: with:
dotnet-version: '3.1.x' dotnet-version: '3.1.x' # SDK Version to use.
``` ```
## License # License
The scripts and documentation in this project are released under the [MIT License](LICENSE) The scripts and documentation in this project are released under the [MIT License](LICENSE)
## Contributions # Contributions
Contributions are welcome! See [Contributor's Guide](docs/contributors.md) Contributions are welcome! See [Contributor's Guide](docs/contributors.md)

View File

@ -1,6 +1,6 @@
import * as io from '@actions/io'; import io = require('@actions/io');
import fs from 'fs'; import fs = require('fs');
import path from 'path'; import path = require('path');
const fakeSourcesDirForTesting = path.join( const fakeSourcesDirForTesting = path.join(
__dirname, __dirname,

View File

@ -1,3 +1,5 @@
import fs = require('fs');
describe('csc tests', () => { describe('csc tests', () => {
it('Valid regular expression', async () => { it('Valid regular expression', async () => {
var cscFile = require('../.github/csc.json'); var cscFile = require('../.github/csc.json');

View File

@ -1,55 +1,34 @@
import * as io from '@actions/io'; import io = require('@actions/io');
import * as os from 'os'; import fs = require('fs');
import fs from 'fs'; import os = require('os');
import path from 'path'; import path = require('path');
import each from 'jest-each'; import hc = require('@actions/http-client');
import * as hc from '@actions/http-client';
import * as installer from '../src/installer';
import {QualityOptions} from '../src/setup-dotnet';
import {IS_WINDOWS} from '../src/utils'; const toolDir = path.join(__dirname, 'runner', 'tools');
import {IS_LINUX} from '../src/utils';
let toolDir: string;
if (IS_WINDOWS) {
toolDir = path.join(process.env['PROGRAMFILES'] + '', 'dotnet');
} else if (IS_LINUX) {
toolDir = '/usr/share/dotnet';
} else {
toolDir = path.join(process.env['HOME'] + '', '.dotnet');
}
const tempDir = path.join(__dirname, 'runner', 'temp'); const tempDir = path.join(__dirname, 'runner', 'temp');
process.env['RUNNER_TOOL_CACHE'] = toolDir; process.env['RUNNER_TOOL_CACHE'] = toolDir;
process.env['RUNNER_TEMP'] = tempDir; process.env['RUNNER_TEMP'] = tempDir;
import * as installer from '../src/installer';
describe('DotnetCoreInstaller tests', () => { const IS_WINDOWS = process.platform === 'win32';
describe('installer tests', () => {
beforeAll(async () => { beforeAll(async () => {
process.env.RUNNER_TOOL_CACHE = toolDir; process.env.RUNNER_TOOL_CACHE = toolDir;
process.env.DOTNET_INSTALL_DIR = toolDir; process.env.DOTNET_INSTALL_DIR = toolDir;
process.env.RUNNER_TEMP = tempDir; process.env.RUNNER_TEMP = tempDir;
process.env.DOTNET_ROOT = ''; process.env.DOTNET_ROOT = '';
try { await io.rmRF(toolDir);
await io.rmRF(`${toolDir}/*`); await io.rmRF(tempDir);
await io.rmRF(`${tempDir}/*`); });
} catch (err) {
console.log(
`Failed to remove test directories, check the error message:${os.EOL}`,
err.message
);
}
}, 30000);
afterEach(async () => { afterAll(async () => {
try { try {
await io.rmRF(`${toolDir}/*`); await io.rmRF(toolDir);
await io.rmRF(`${tempDir}/*`); await io.rmRF(tempDir);
} catch (err) { } catch {
console.log( console.log('Failed to remove test directories');
`Failed to remove test directories, check the error message:${os.EOL}`,
err.message
);
} }
}, 30000); }, 30000);
@ -107,19 +86,14 @@ describe('DotnetCoreInstaller tests', () => {
expect(process.env.PATH?.startsWith(toolDir)).toBe(true); expect(process.env.PATH?.startsWith(toolDir)).toBe(true);
}, 600000); //This needs some time to download on "slower" internet connections }, 600000); //This needs some time to download on "slower" internet connections
it('Returns string with installed SDK version', async () => {
const version = '3.1.120';
let installedVersion: string;
installedVersion = await getDotnet(version);
expect(installedVersion).toBe('3.1.120');
}, 600000);
it('Throws if no location contains correct dotnet version', async () => { it('Throws if no location contains correct dotnet version', async () => {
await expect(async () => { let thrown = false;
try {
await getDotnet('1000.0.0'); await getDotnet('1000.0.0');
}).rejects.toThrow(); } catch {
thrown = true;
}
expect(thrown).toBe(true);
}, 30000); }, 30000);
it('Uses an up to date bash download script', async () => { it('Uses an up to date bash download script', async () => {
@ -163,112 +137,6 @@ describe('DotnetCoreInstaller tests', () => {
}, 30000); }, 30000);
}); });
describe('DotnetVersionResolver tests', () => {
each([
'3.1',
'3.x',
'3.1.x',
'3.1.*',
'3.1.X',
'3.1.2',
'3.1.0-preview1'
]).test(
"if valid version: '%s' is supplied, it should return version object with some value",
async version => {
const dotnetVersionResolver = new installer.DotnetVersionResolver(
version
);
const versionObject = await dotnetVersionResolver.createDotNetVersion();
expect(!!versionObject.value).toBeTruthy;
}
);
each([
'.',
'..',
' . ',
'. ',
' .',
' . . ',
' .. ',
' . ',
'-1.-1',
'-1',
'-1.-1.-1',
'..3',
'1..3',
'1..',
'.2.3',
'.2.x',
'*.',
'1.2.',
'1.2.-abc',
'a.b',
'a.b.c',
'a.b.c-preview',
' 0 . 1 . 2 ',
'invalid'
]).test(
"if invalid version: '%s' is supplied, it should throw",
async version => {
const dotnetVersionResolver = new installer.DotnetVersionResolver(
version
);
await expect(
async () => await dotnetVersionResolver.createDotNetVersion()
).rejects.toThrow();
}
);
each(['3.1', '3.1.x', '3.1.*', '3.1.X']).test(
"if version: '%s' that can be resolved to 'channel' option is supplied, it should set quality flag to 'true' and type to 'channel' in version object",
async version => {
const dotnetVersionResolver = new installer.DotnetVersionResolver(
version
);
const versionObject = await dotnetVersionResolver.createDotNetVersion();
expect(versionObject.type.toLowerCase().includes('channel')).toBeTruthy;
expect(versionObject.qualityFlag).toBeTruthy;
}
);
each(['3.1.2', '3.1.0-preview1']).test(
"if version: '%s' that can be resolved to 'version' option is supplied, it should set quality flag to 'false' and type to 'version' in version object",
async version => {
const dotnetVersionResolver = new installer.DotnetVersionResolver(
version
);
const versionObject = await dotnetVersionResolver.createDotNetVersion();
expect(versionObject.type.toLowerCase().includes('version')).toBeTruthy;
expect(versionObject.qualityFlag).toBeFalsy;
}
);
each(['3.1.2', '3.1']).test(
'it should create proper line arguments for powershell/bash installation scripts',
async version => {
const dotnetVersionResolver = new installer.DotnetVersionResolver(
version
);
const versionObject = await dotnetVersionResolver.createDotNetVersion();
const windowsRegEx = new RegExp(/^-[VC]/);
const nonWindowsRegEx = new RegExp(/^--[vc]/);
if (IS_WINDOWS) {
expect(windowsRegEx.test(versionObject.type)).toBeTruthy;
expect(nonWindowsRegEx.test(versionObject.type)).toBeFalsy;
} else {
expect(nonWindowsRegEx.test(versionObject.type)).toBeTruthy;
expect(windowsRegEx.test(versionObject.type)).toBeFalsy;
}
}
);
});
function normalizeFileContents(contents: string): string { function normalizeFileContents(contents: string): string {
return contents return contents
.trim() .trim()
@ -276,15 +144,8 @@ function normalizeFileContents(contents: string): string {
.replace(new RegExp('\r', 'g'), '\n'); .replace(new RegExp('\r', 'g'), '\n');
} }
async function getDotnet( async function getDotnet(version: string): Promise<void> {
version: string, const dotnetInstaller = new installer.DotnetCoreInstaller(version);
quality: string = '' await dotnetInstaller.installDotnet();
): Promise<string> {
const dotnetInstaller = new installer.DotnetCoreInstaller(
version,
quality as QualityOptions
);
const installedVersion = await dotnetInstaller.installDotnet();
installer.DotnetCoreInstaller.addToPath(); installer.DotnetCoreInstaller.addToPath();
return installedVersion;
} }

View File

@ -1,52 +1,32 @@
import * as io from '@actions/io'; import io = require('@actions/io');
import * as core from '@actions/core'; import fs = require('fs');
import fs from 'fs'; import os = require('os');
import os from 'os'; import path = require('path');
import path from 'path';
import * as setup from '../src/setup-dotnet';
import {IS_WINDOWS} from '../src/utils';
import {IS_LINUX} from '../src/utils';
let toolDir: string;
if (IS_WINDOWS) {
toolDir = path.join(process.env['PROGRAMFILES'] + '', 'dotnet');
} else if (IS_LINUX) {
toolDir = '/usr/share/dotnet';
} else {
toolDir = path.join(process.env['HOME'] + '', '.dotnet');
}
const toolDir = path.join(__dirname, 'runner', 'tools2');
const tempDir = path.join(__dirname, 'runner', 'temp2'); const tempDir = path.join(__dirname, 'runner', 'temp2');
import * as setup from '../src/setup-dotnet';
import * as dotnetInstaller from '../src/installer';
const IS_WINDOWS = process.platform === 'win32';
describe('setup-dotnet tests', () => { describe('setup-dotnet tests', () => {
let getInputSpy = jest.spyOn(core, 'getInput');
let getMultilineInputSpy = jest.spyOn(core, 'getMultilineInput');
let setOutputSpy = jest.spyOn(core, 'setOutput');
let inputs = {} as any;
beforeAll(async () => { beforeAll(async () => {
process.env.RUNNER_TOOL_CACHE = toolDir; process.env.RUNNER_TOOL_CACHE = toolDir;
process.env.DOTNET_INSTALL_DIR = toolDir; process.env.DOTNET_INSTALL_DIR = toolDir;
process.env.RUNNER_TEMP = tempDir; process.env.RUNNER_TEMP = tempDir;
try { process.env['INPUT_INCLUDE-PRERELEASE'] = 'false';
await io.rmRF(`${toolDir}/*`); await io.rmRF(toolDir);
await io.rmRF(`${tempDir}/*`); await io.rmRF(tempDir);
} catch (err) { });
console.log(err.message);
console.log('Failed to remove test directories');
}
}, 30000);
afterEach(async () => { afterEach(async () => {
try { try {
await io.rmRF(path.join(process.cwd(), 'global.json')); await io.rmRF(path.join(process.cwd(), 'global.json'));
await io.rmRF(`${toolDir}/*`); await io.rmRF(toolDir);
await io.rmRF(`${tempDir}/*`); await io.rmRF(tempDir);
} catch (err) { } catch {
console.log(err.message);
console.log('Failed to remove test directories'); console.log('Failed to remove test directories');
} }
}, 30000); }, 30000);
@ -67,32 +47,25 @@ describe('setup-dotnet tests', () => {
} }
}, 400000); }, 400000);
it("Sets output with the latest installed by action version if global.json file isn't specified", async () => { it('Acquires version of dotnet from global.json with rollForward option, install the latest patch', async () => {
inputs['dotnet-version'] = ['3.1.201', '6.0.401'];
getMultilineInputSpy.mockImplementation(input => inputs[input]);
await setup.run();
expect(setOutputSpy).toBeCalledWith('dotnet-version', '6.0.401');
}, 400000);
it("Sets output with the version specified in global.json, if it's present", async () => {
const globalJsonPath = path.join(process.cwd(), 'global.json'); const globalJsonPath = path.join(process.cwd(), 'global.json');
const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version": "3.0.103"${os.EOL}}${os.EOL}}`; const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version":"3.1.201",${os.EOL}"rollForward":"latestFeature"${os.EOL}}${os.EOL}}`;
if (!fs.existsSync(globalJsonPath)) { if (!fs.existsSync(globalJsonPath)) {
fs.writeFileSync(globalJsonPath, jsonContents); fs.writeFileSync(globalJsonPath, jsonContents);
} }
inputs['dotnet-version'] = ['3.1.201', '6.0.401']; const version = '3.1';
inputs['global-json-file'] = './global.json'; const installer = new dotnetInstaller.DotnetCoreInstaller(version);
const patchVersion = await installer.resolveVersion(
getMultilineInputSpy.mockImplementation(input => inputs[input]); new dotnetInstaller.DotNetVersionInfo(version)
);
getInputSpy.mockImplementation(input => inputs[input]);
await setup.run(); await setup.run();
expect(setOutputSpy).toBeCalledWith('dotnet-version', '3.0.103'); expect(fs.existsSync(path.join(toolDir, 'sdk', patchVersion))).toBe(true);
if (IS_WINDOWS) {
expect(fs.existsSync(path.join(toolDir, 'dotnet.exe'))).toBe(true);
} else {
expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true);
}
}, 400000); }, 400000);
}); });

View File

@ -1,7 +1,17 @@
#!/bin/bash #!/bin/bash
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then if [[ "$(git status --porcelain)" != "" ]]; then
echo "Detected uncommitted changes after build. See status below:" echo ----------------------------------------
echo git status
echo ----------------------------------------
git status
echo ----------------------------------------
echo git diff
echo ----------------------------------------
git diff git diff
echo ----------------------------------------
echo Troubleshooting
echo ----------------------------------------
echo "::error::Unstaged changes detected. Locally try running: git clean -ffdx && npm ci && npm run pre-checkin"
exit 1 exit 1
fi fi

View File

@ -0,0 +1,91 @@
import each from 'jest-each';
import * as installer from '../src/installer';
describe('version tests', () => {
each(['3.1.999', '3.1.101-preview.3']).test(
"Exact version '%s' should be the same",
vers => {
let versInfo = new installer.DotNetVersionInfo(vers);
expect(versInfo.isExactVersion()).toBe(true);
expect(versInfo.version()).toBe(vers);
}
);
each([
['3.x', '3.x'],
['3.*', '3.*'],
['3.1.x', '3.1'],
['1.1.*', '1.1'],
['2.0', '2.0']
]).test("Generic version '%s' should be '%s'", (vers, resVers) => {
let versInfo = new installer.DotNetVersionInfo(vers);
expect(versInfo.isExactVersion()).toBe(false);
expect(versInfo.version()).toBe(resVers);
});
each([
'',
'.',
'..',
' . ',
'. ',
' .',
' . . ',
' .. ',
' . ',
'-1.-1',
'-1',
'-1.-1.-1',
'..3',
'1..3',
'1..',
'.2.3',
'.2.x',
'1',
'*.*.1',
'*.1',
'*.',
'1.2.',
'1.2.-abc',
'a.b',
'a.b.c',
'a.b.c-preview',
' 0 . 1 . 2 '
]).test("Malformed version '%s' should throw", vers => {
expect(() => new installer.DotNetVersionInfo(vers)).toThrow();
});
each([
['3.1.x', '3.1.'],
['3.1.*', '3.1.'],
['3.1', '3.1.'],
['5.0.0-preview.6', '5.0.0-preview.6'],
['3.1.201', '3.1.201']
]).test(
"Resolving version '%s' as '%s'",
async (input, expectedVersion) => {
const dotnetInstaller = new installer.DotnetCoreInstaller(input);
let versInfo = await dotnetInstaller.resolveVersion(
new installer.DotNetVersionInfo(input)
);
console.log(versInfo);
expect(versInfo.startsWith(expectedVersion));
},
100000
);
it('Resolving a nonexistent generic version fails', async () => {
const dotnetInstaller = new installer.DotnetCoreInstaller('999.1.x');
try {
await dotnetInstaller.resolveVersion(
new installer.DotNetVersionInfo('999.1.x')
);
fail();
} catch {
expect(true);
}
}, 100000);
});

View File

@ -6,9 +6,7 @@ branding:
color: green color: green
inputs: inputs:
dotnet-version: dotnet-version:
description: 'Optional SDK version(s) to use. If not provided, will install global.json version when available. Examples: 2.2.104, 3.1, 3.1.x, 3.x' description: 'Optional SDK version(s) to use. If not provided, will install global.json version when available. Examples: 2.2.104, 3.1, 3.1.x'
dotnet-quality:
description: 'Optional quality of the build. The possible values are: daily, signed, validated, preview, ga.'
global-json-file: global-json-file:
description: 'Optional global.json location, if your global.json isn''t located in the root of the repo.' description: 'Optional global.json location, if your global.json isn''t located in the root of the repo.'
source-url: source-url:
@ -17,9 +15,10 @@ inputs:
description: 'Optional OWNER for using packages from GitHub Package Registry organizations/users other than the current repository''s owner. Only used if a GPR URL is also provided in source-url' description: 'Optional OWNER for using packages from GitHub Package Registry organizations/users other than the current repository''s owner. Only used if a GPR URL is also provided in source-url'
config-file: config-file:
description: 'Optional NuGet.config location, if your NuGet.config isn''t located in the root of the repo.' description: 'Optional NuGet.config location, if your NuGet.config isn''t located in the root of the repo.'
outputs: include-prerelease:
dotnet-version: description: 'Whether prerelease versions should be matched with non-exact versions (for example 5.0.0-preview.6 being matched by 5, 5.0, 5.x or 5.0.x). Defaults to false if not provided.'
description: 'Contains the installed by action .NET SDK version for reuse.' required: False
default: 'false'
runs: runs:
using: 'node16' using: 'node16'
main: 'dist/index.js' main: 'dist/index.js'

4023
dist/index.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -298,11 +298,20 @@ get_machine_architecture() {
if command -v uname > /dev/null; then if command -v uname > /dev/null; then
CPUName=$(uname -m) CPUName=$(uname -m)
case $CPUName in case $CPUName in
armv1*|armv2*|armv3*|armv4*|armv5*|armv6*)
echo "armv6-or-below"
return 0
;;
armv*l) armv*l)
echo "arm" echo "arm"
return 0 return 0
;; ;;
aarch64|arm64) aarch64|arm64)
if [ "$(getconf LONG_BIT)" -lt 64 ]; then
# This is 32-bit OS running on 64-bit CPU (for example Raspberry Pi OS)
echo "arm"
return 0
fi
echo "arm64" echo "arm64"
return 0 return 0
;; ;;
@ -310,6 +319,22 @@ get_machine_architecture() {
echo "s390x" echo "s390x"
return 0 return 0
;; ;;
ppc64le)
echo "ppc64le"
return 0
;;
loongarch64)
echo "loongarch64"
return 0
;;
riscv64)
echo "riscv64"
return 0
;;
powerpc|ppc)
echo "ppc"
return 0
;;
esac esac
fi fi
@ -326,7 +351,13 @@ get_normalized_architecture_from_architecture() {
local architecture="$(to_lowercase "$1")" local architecture="$(to_lowercase "$1")"
if [[ $architecture == \<auto\> ]]; then if [[ $architecture == \<auto\> ]]; then
echo "$(get_machine_architecture)" machine_architecture="$(get_machine_architecture)"
if [[ "$machine_architecture" == "armv6-or-below" ]]; then
say_err "Architecture \`$machine_architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
return 1
fi
echo $machine_architecture
return 0 return 0
fi fi
@ -347,6 +378,14 @@ get_normalized_architecture_from_architecture() {
echo "s390x" echo "s390x"
return 0 return 0
;; ;;
ppc64le)
echo "ppc64le"
return 0
;;
loongarch64)
echo "loongarch64"
return 0
;;
esac esac
say_err "Architecture \`$architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues" say_err "Architecture \`$architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
@ -384,11 +423,17 @@ get_normalized_architecture_for_specific_sdk_version() {
# args: # args:
# version or channel - $1 # version or channel - $1
is_arm64_supported() { is_arm64_supported() {
#any channel or version that starts with the specified versions # Extract the major version by splitting on the dot
case "$1" in major_version="${1%%.*}"
( "1"* | "2"* | "3"* | "4"* | "5"*)
echo false # Check if the major version is a valid number and less than 6
return 0 case "$major_version" in
[0-9]*)
if [ "$major_version" -lt 6 ]; then
echo false
return 0
fi
;;
esac esac
echo true echo true
@ -407,8 +452,13 @@ get_normalized_os() {
echo "$osname" echo "$osname"
return 0 return 0
;; ;;
macos)
osname='osx'
echo "$osname"
return 0
;;
*) *)
say_err "'$user_defined_os' is not a supported value for --os option, supported values are: osx, linux, linux-musl, freebsd, rhel.6. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues." say_err "'$user_defined_os' is not a supported value for --os option, supported values are: osx, macos, linux, linux-musl, freebsd, rhel.6. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues."
return 1 return 1
;; ;;
esac esac
@ -451,6 +501,10 @@ get_normalized_channel() {
local channel="$(to_lowercase "$1")" local channel="$(to_lowercase "$1")"
if [[ $channel == current ]]; then
say_warning 'Value "Current" is deprecated for -Channel option. Use "STS" instead.'
fi
if [[ $channel == release/* ]]; then if [[ $channel == release/* ]]; then
say_warning 'Using branch name with -Channel option is no longer supported with newer releases. Use -Quality option with a channel in X.Y format instead.'; say_warning 'Using branch name with -Channel option is no longer supported with newer releases. Use -Quality option with a channel in X.Y format instead.';
fi fi
@ -461,6 +515,14 @@ get_normalized_channel() {
echo "LTS" echo "LTS"
return 0 return 0
;; ;;
sts)
echo "STS"
return 0
;;
current)
echo "STS"
return 0
;;
*) *)
echo "$channel" echo "$channel"
return 0 return 0
@ -526,6 +588,40 @@ is_dotnet_package_installed() {
fi fi
} }
# args:
# downloaded file - $1
# remote_file_size - $2
validate_remote_local_file_sizes()
{
eval $invocation
local downloaded_file="$1"
local remote_file_size="$2"
local file_size=''
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
file_size="$(stat -c '%s' "$downloaded_file")"
elif [[ "$OSTYPE" == "darwin"* ]]; then
# hardcode in order to avoid conflicts with GNU stat
file_size="$(/usr/bin/stat -f '%z' "$downloaded_file")"
fi
if [ -n "$file_size" ]; then
say "Downloaded file size is $file_size bytes."
if [ -n "$remote_file_size" ] && [ -n "$file_size" ]; then
if [ "$remote_file_size" -ne "$file_size" ]; then
say "The remote and local file sizes are not equal. The remote file size is $remote_file_size bytes and the local size is $file_size bytes. The local package may be corrupted."
else
say "The remote and local file sizes are equal."
fi
fi
else
say "Either downloaded or local package size can not be measured. One of them may be corrupted."
fi
}
# args: # args:
# azure_feed - $1 # azure_feed - $1
# channel - $2 # channel - $2
@ -860,6 +956,37 @@ get_absolute_path() {
return 0 return 0
} }
# args:
# override - $1 (boolean, true or false)
get_cp_options() {
eval $invocation
local override="$1"
local override_switch=""
if [ "$override" = false ]; then
override_switch="-n"
# create temporary files to check if 'cp -u' is supported
tmp_dir="$(mktemp -d)"
tmp_file="$tmp_dir/testfile"
tmp_file2="$tmp_dir/testfile2"
touch "$tmp_file"
# use -u instead of -n if it's available
if cp -u "$tmp_file" "$tmp_file2" 2>/dev/null; then
override_switch="-u"
fi
# clean up
rm -f "$tmp_file" "$tmp_file2"
rm -rf "$tmp_dir"
fi
echo "$override_switch"
}
# args: # args:
# input_files - stdin # input_files - stdin
# root_path - $1 # root_path - $1
@ -871,15 +998,7 @@ copy_files_or_dirs_from_list() {
local root_path="$(remove_trailing_slash "$1")" local root_path="$(remove_trailing_slash "$1")"
local out_path="$(remove_trailing_slash "$2")" local out_path="$(remove_trailing_slash "$2")"
local override="$3" local override="$3"
local osname="$(get_current_os_name)" local override_switch="$(get_cp_options "$override")"
local override_switch=$(
if [ "$override" = false ]; then
if [ "$osname" = "linux-musl" ]; then
printf -- "-u";
else
printf -- "-n";
fi
fi)
cat | uniq | while read -r file_path; do cat | uniq | while read -r file_path; do
local path="$(remove_beginning_slash "${file_path#$root_path}")" local path="$(remove_beginning_slash "${file_path#$root_path}")"
@ -894,14 +1013,39 @@ copy_files_or_dirs_from_list() {
done done
} }
# args:
# zip_uri - $1
get_remote_file_size() {
local zip_uri="$1"
if machine_has "curl"; then
file_size=$(curl -sI "$zip_uri" | grep -i content-length | awk '{ num = $2 + 0; print num }')
elif machine_has "wget"; then
file_size=$(wget --spider --server-response -O /dev/null "$zip_uri" 2>&1 | grep -i 'Content-Length:' | awk '{ num = $2 + 0; print num }')
else
say "Neither curl nor wget is available on this system."
return
fi
if [ -n "$file_size" ]; then
say "Remote file $zip_uri size is $file_size bytes."
echo "$file_size"
else
say_verbose "Content-Length header was not extracted for $zip_uri."
echo ""
fi
}
# args: # args:
# zip_path - $1 # zip_path - $1
# out_path - $2 # out_path - $2
# remote_file_size - $3
extract_dotnet_package() { extract_dotnet_package() {
eval $invocation eval $invocation
local zip_path="$1" local zip_path="$1"
local out_path="$2" local out_path="$2"
local remote_file_size="$3"
local temp_out_path="$(mktemp -d "$temporary_file_template")" local temp_out_path="$(mktemp -d "$temporary_file_template")"
@ -911,9 +1055,13 @@ extract_dotnet_package() {
local folders_with_version_regex='^.*/[0-9]+\.[0-9]+[^/]+/' local folders_with_version_regex='^.*/[0-9]+\.[0-9]+[^/]+/'
find "$temp_out_path" -type f | grep -Eo "$folders_with_version_regex" | sort | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" false find "$temp_out_path" -type f | grep -Eo "$folders_with_version_regex" | sort | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" false
find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files" find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files"
validate_remote_local_file_sizes "$zip_path" "$remote_file_size"
rm -rf "$temp_out_path" rm -rf "$temp_out_path"
rm -f "$zip_path" && say_verbose "Temporary zip file $zip_path was removed" if [ -z ${keep_zip+x} ]; then
rm -f "$zip_path" && say_verbose "Temporary archive file $zip_path was removed"
fi
if [ "$failed" = true ]; then if [ "$failed" = true ]; then
say_err "Extraction failed" say_err "Extraction failed"
@ -1124,13 +1272,69 @@ downloadwget() {
return 0 return 0
} }
extract_stem() {
local url="$1"
# extract the protocol
proto="$(echo $1 | grep :// | sed -e's,^\(.*://\).*,\1,g')"
# remove the protocol
url="${1/$proto/}"
# extract the path (if any) - since we know all of our feeds have a first path segment, we can skip the first one. otherwise we'd use -f2- to get the full path
full_path="$(echo $url | grep / | cut -d/ -f2-)"
path="$(echo $full_path | cut -d/ -f2-)"
echo $path
}
check_url_exists() {
eval $invocation
local url="$1"
local code=""
if machine_has "curl"
then
code=$(curl --head -o /dev/null -w "%{http_code}" -s --fail "$url");
elif machine_has "wget"
then
# get the http response, grab the status code
server_response=$(wget -qO- --method=HEAD --server-response "$url" 2>&1)
code=$(echo "$server_response" | grep "HTTP/" | awk '{print $2}')
fi
if [ $code = "200" ]; then
return 0
else
return 1
fi
}
sanitize_redirect_url() {
eval $invocation
local url_stem
url_stem=$(extract_stem "$1")
say_verbose "Checking configured feeds for the asset at ${yellow:-}$url_stem${normal:-}"
for feed in "${feeds[@]}"
do
local trial_url="$feed/$url_stem"
say_verbose "Checking ${yellow:-}$trial_url${normal:-}"
if check_url_exists "$trial_url"; then
say_verbose "Found a match at ${yellow:-}$trial_url${normal:-}"
echo "$trial_url"
return 0
else
say_verbose "No match at ${yellow:-}$trial_url${normal:-}"
fi
done
return 1
}
get_download_link_from_aka_ms() { get_download_link_from_aka_ms() {
eval $invocation eval $invocation
#quality is not supported for LTS or current channel #quality is not supported for LTS or STS channel
if [[ ! -z "$normalized_quality" && ("$normalized_channel" == "LTS" || "$normalized_channel" == "current") ]]; then #STS maps to current
if [[ ! -z "$normalized_quality" && ("$normalized_channel" == "LTS" || "$normalized_channel" == "STS") ]]; then
normalized_quality="" normalized_quality=""
say_warning "Specifying quality for current or LTS channel is not supported, the quality will be ignored." say_warning "Specifying quality for STS or LTS channel is not supported, the quality will be ignored."
fi fi
say_verbose "Retrieving primary payload URL from aka.ms for channel: '$normalized_channel', quality: '$normalized_quality', product: '$normalized_product', os: '$normalized_os', architecture: '$normalized_architecture'." say_verbose "Retrieving primary payload URL from aka.ms for channel: '$normalized_channel', quality: '$normalized_quality', product: '$normalized_product', os: '$normalized_os', architecture: '$normalized_architecture'."
@ -1159,6 +1363,12 @@ get_download_link_from_aka_ms() {
http_codes=$( echo "$response" | awk '$1 ~ /^HTTP/ {print $2}' ) http_codes=$( echo "$response" | awk '$1 ~ /^HTTP/ {print $2}' )
# They all need to be 301, otherwise some links are broken (except for the last, which is not a redirect but 200 or 404). # They all need to be 301, otherwise some links are broken (except for the last, which is not a redirect but 200 or 404).
broken_redirects=$( echo "$http_codes" | sed '$d' | grep -v '301' ) broken_redirects=$( echo "$http_codes" | sed '$d' | grep -v '301' )
# The response may end without final code 2xx/4xx/5xx somehow, e.g. network restrictions on www.bing.com causes redirecting to bing.com fails with connection refused.
# In this case it should not exclude the last.
last_http_code=$( echo "$http_codes" | tail -n 1 )
if ! [[ $last_http_code =~ ^(2|4|5)[0-9][0-9]$ ]]; then
broken_redirects=$( echo "$http_codes" | grep -v '301' )
fi
# All HTTP codes are 301 (Moved Permanently), the redirect link exists. # All HTTP codes are 301 (Moved Permanently), the redirect link exists.
if [[ -z "$broken_redirects" ]]; then if [[ -z "$broken_redirects" ]]; then
@ -1169,6 +1379,11 @@ get_download_link_from_aka_ms() {
return 1 return 1
fi fi
sanitized_redirect_url=$(sanitize_redirect_url "$aka_ms_download_link")
if [[ -n "$sanitized_redirect_url" ]]; then
aka_ms_download_link="$sanitized_redirect_url"
fi
say_verbose "The redirect location retrieved: '$aka_ms_download_link'." say_verbose "The redirect location retrieved: '$aka_ms_download_link'."
return 0 return 0
else else
@ -1180,23 +1395,16 @@ get_download_link_from_aka_ms() {
get_feeds_to_use() get_feeds_to_use()
{ {
feeds=( feeds=(
"https://dotnetcli.azureedge.net/dotnet" "https://builds.dotnet.microsoft.com/dotnet"
"https://dotnetbuilds.azureedge.net/public" "https://ci.dot.net/public"
) )
if [[ -n "$azure_feed" ]]; then if [[ -n "$azure_feed" ]]; then
feeds=("$azure_feed") feeds=("$azure_feed")
fi fi
if [[ "$no_cdn" == "true" ]]; then if [[ -n "$uncached_feed" ]]; then
feeds=( feeds=("$uncached_feed")
"https://dotnetcli.blob.core.windows.net/dotnet"
"https://dotnetbuilds.blob.core.windows.net/public"
)
if [[ -n "$uncached_feed" ]]; then
feeds=("$uncached_feed")
fi
fi fi
} }
@ -1239,7 +1447,7 @@ generate_akams_links() {
normalized_version="$(to_lowercase "$version")" normalized_version="$(to_lowercase "$version")"
if [[ "$normalized_version" != "latest" ]] && [ -n "$normalized_quality" ]; then if [[ "$normalized_version" != "latest" ]] && [ -n "$normalized_quality" ]; then
say_err "Quality and Version options are not allowed to be specified simultaneously. See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script#options for details." say_err "Quality and Version options are not allowed to be specified simultaneously. See https://learn.microsoft.com/dotnet/core/tools/dotnet-install-script#options for details."
return 1 return 1
fi fi
@ -1328,7 +1536,7 @@ generate_regular_links() {
link_types+=("legacy") link_types+=("legacy")
else else
legacy_download_link="" legacy_download_link=""
say_verbose "Cound not construct a legacy_download_link; omitting..." say_verbose "Could not construct a legacy_download_link; omitting..."
fi fi
# Check if the SDK version is already installed. # Check if the SDK version is already installed.
@ -1406,10 +1614,11 @@ install_dotnet() {
eval $invocation eval $invocation
local download_failed=false local download_failed=false
local download_completed=false local download_completed=false
local remote_file_size=0
mkdir -p "$install_root" mkdir -p "$install_root"
zip_path="$(mktemp "$temporary_file_template")" zip_path="${zip_path:-$(mktemp "$temporary_file_template")}"
say_verbose "Zip path: $zip_path" say_verbose "Archive path: $zip_path"
for link_index in "${!download_links[@]}" for link_index in "${!download_links[@]}"
do do
@ -1430,10 +1639,10 @@ install_dotnet() {
say "The resource at $link_type link '$download_link' is not available." say "The resource at $link_type link '$download_link' is not available."
;; ;;
*) *)
say "Failed to download $link_type link '$download_link': $download_error_msg" say "Failed to download $link_type link '$download_link': $http_code $download_error_msg"
;; ;;
esac esac
rm -f "$zip_path" 2>&1 && say_verbose "Temporary zip file $zip_path was removed" rm -f "$zip_path" 2>&1 && say_verbose "Temporary archive file $zip_path was removed"
else else
download_completed=true download_completed=true
break break
@ -1446,8 +1655,10 @@ install_dotnet() {
return 1 return 1
fi fi
say "Extracting zip from $download_link" remote_file_size="$(get_remote_file_size "$download_link")"
extract_dotnet_package "$zip_path" "$install_root" || return 1
say "Extracting archive from $download_link"
extract_dotnet_package "$zip_path" "$install_root" "$remote_file_size" || return 1
# Check if the SDK version is installed; if not, fail the installation. # Check if the SDK version is installed; if not, fail the installation.
# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed. # if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed.
@ -1489,7 +1700,6 @@ install_dir="<auto>"
architecture="<auto>" architecture="<auto>"
dry_run=false dry_run=false
no_path=false no_path=false
no_cdn=false
azure_feed="" azure_feed=""
uncached_feed="" uncached_feed=""
feed_credential="" feed_credential=""
@ -1562,10 +1772,6 @@ do
verbose=true verbose=true
non_dynamic_parameters+=" $name" non_dynamic_parameters+=" $name"
;; ;;
--no-cdn|-[Nn]o[Cc]dn)
no_cdn=true
non_dynamic_parameters+=" $name"
;;
--azure-feed|-[Aa]zure[Ff]eed) --azure-feed|-[Aa]zure[Ff]eed)
shift shift
azure_feed="$1" azure_feed="$1"
@ -1597,25 +1803,42 @@ do
override_non_versioned_files=false override_non_versioned_files=false
non_dynamic_parameters+=" $name" non_dynamic_parameters+=" $name"
;; ;;
--keep-zip|-[Kk]eep[Zz]ip)
keep_zip=true
non_dynamic_parameters+=" $name"
;;
--zip-path|-[Zz]ip[Pp]ath)
shift
zip_path="$1"
;;
-?|--?|-h|--help|-[Hh]elp) -?|--?|-h|--help|-[Hh]elp)
script_name="$(basename "$0")" script_name="dotnet-install.sh"
echo ".NET Tools Installer" echo ".NET Tools Installer"
echo "Usage: $script_name [-c|--channel <CHANNEL>] [-v|--version <VERSION>] [-p|--prefix <DESTINATION>]" echo "Usage:"
echo " # Install a .NET SDK of a given Quality from a given Channel"
echo " $script_name [-c|--channel <CHANNEL>] [-q|--quality <QUALITY>]"
echo " # Install a .NET SDK of a specific public version"
echo " $script_name [-v|--version <VERSION>]"
echo " $script_name -h|-?|--help" echo " $script_name -h|-?|--help"
echo "" echo ""
echo "$script_name is a simple command line interface for obtaining dotnet cli." echo "$script_name is a simple command line interface for obtaining dotnet cli."
echo " Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
echo " - The SDK needs to be installed without user interaction and without admin rights."
echo " - The SDK installation doesn't need to persist across multiple CI runs."
echo " To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer."
echo "" echo ""
echo "Options:" echo "Options:"
echo " -c,--channel <CHANNEL> Download from the channel specified, Defaults to \`$channel\`." echo " -c,--channel <CHANNEL> Download from the channel specified, Defaults to \`$channel\`."
echo " -Channel" echo " -Channel"
echo " Possible values:" echo " Possible values:"
echo " - Current - most current release" echo " - STS - the most recent Standard Term Support release"
echo " - LTS - most current supported release" echo " - LTS - the most recent Long Term Support release"
echo " - 2-part version in a format A.B - represents a specific release" echo " - 2-part version in a format A.B - represents a specific release"
echo " examples: 2.0; 1.0" echo " examples: 2.0; 1.0"
echo " - 3-part version in a format A.B.Cxx - represents a specific SDK release" echo " - 3-part version in a format A.B.Cxx - represents a specific SDK release"
echo " examples: 5.0.1xx, 5.0.2xx." echo " examples: 5.0.1xx, 5.0.2xx."
echo " Supported since 5.0 release" echo " Supported since 5.0 release"
echo " Warning: Value 'Current' is deprecated for the Channel parameter. Use 'STS' instead."
echo " Note: The version parameter overrides the channel parameter when any version other than 'latest' is used." echo " Note: The version parameter overrides the channel parameter when any version other than 'latest' is used."
echo " -v,--version <VERSION> Use specific VERSION, Defaults to \`$version\`." echo " -v,--version <VERSION> Use specific VERSION, Defaults to \`$version\`."
echo " -Version" echo " -Version"
@ -1626,7 +1849,7 @@ do
echo " -q,--quality <quality> Download the latest build of specified quality in the channel." echo " -q,--quality <quality> Download the latest build of specified quality in the channel."
echo " -Quality" echo " -Quality"
echo " The possible values are: daily, signed, validated, preview, GA." echo " The possible values are: daily, signed, validated, preview, GA."
echo " Works only in combination with channel. Not applicable for current and LTS channels and will be ignored if those channels are used." echo " Works only in combination with channel. Not applicable for STS and LTS channels and will be ignored if those channels are used."
echo " For SDK use channel in A.B.Cxx format. Using quality for SDK together with channel in A.B format is not supported." echo " For SDK use channel in A.B.Cxx format. Using quality for SDK together with channel in A.B format is not supported."
echo " Supported since 5.0 release." echo " Supported since 5.0 release."
echo " Note: The version parameter overrides the channel parameter when any version other than 'latest' is used, and therefore overrides the quality." echo " Note: The version parameter overrides the channel parameter when any version other than 'latest' is used, and therefore overrides the quality."
@ -1637,7 +1860,7 @@ do
echo " -InstallDir" echo " -InstallDir"
echo " --architecture <ARCHITECTURE> Architecture of dotnet binaries to be installed, Defaults to \`$architecture\`." echo " --architecture <ARCHITECTURE> Architecture of dotnet binaries to be installed, Defaults to \`$architecture\`."
echo " --arch,-Architecture,-Arch" echo " --arch,-Architecture,-Arch"
echo " Possible values: x64, arm, arm64 and s390x" echo " Possible values: x64, arm, arm64, s390x, ppc64le and loongarch64"
echo " --os <system> Specifies operating system to be used when selecting the installer." echo " --os <system> Specifies operating system to be used when selecting the installer."
echo " Overrides the OS determination approach used by the script. Supported values: osx, linux, linux-musl, freebsd, rhel.6." echo " Overrides the OS determination approach used by the script. Supported values: osx, linux, linux-musl, freebsd, rhel.6."
echo " In case any other value is provided, the platform will be determined by the script based on machine configuration." echo " In case any other value is provided, the platform will be determined by the script based on machine configuration."
@ -1653,15 +1876,14 @@ do
echo " --verbose,-Verbose Display diagnostics information." echo " --verbose,-Verbose Display diagnostics information."
echo " --azure-feed,-AzureFeed For internal use only." echo " --azure-feed,-AzureFeed For internal use only."
echo " Allows using a different storage to download SDK archives from." echo " Allows using a different storage to download SDK archives from."
echo " This parameter is only used if --no-cdn is false."
echo " --uncached-feed,-UncachedFeed For internal use only." echo " --uncached-feed,-UncachedFeed For internal use only."
echo " Allows using a different storage to download SDK archives from." echo " Allows using a different storage to download SDK archives from."
echo " This parameter is only used if --no-cdn is true."
echo " --skip-non-versioned-files Skips non-versioned files if they already exist, such as the dotnet executable." echo " --skip-non-versioned-files Skips non-versioned files if they already exist, such as the dotnet executable."
echo " -SkipNonVersionedFiles" echo " -SkipNonVersionedFiles"
echo " --no-cdn,-NoCdn Disable downloading from the Azure CDN, and use the uncached feed directly."
echo " --jsonfile <JSONFILE> Determines the SDK version from a user specified global.json file." echo " --jsonfile <JSONFILE> Determines the SDK version from a user specified global.json file."
echo " Note: global.json must have a value for 'SDK:Version'" echo " Note: global.json must have a value for 'SDK:Version'"
echo " --keep-zip,-KeepZip If set, downloaded file is kept."
echo " --zip-path, -ZipPath If set, downloaded file is stored at the specified path."
echo " -?,--?,-h,--help,-Help Shows this help message" echo " -?,--?,-h,--help,-Help Shows this help message"
echo "" echo ""
echo "Install Location:" echo "Install Location:"
@ -1680,10 +1902,10 @@ do
shift shift
done done
say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:" say_verbose "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
say "- The SDK needs to be installed without user interaction and without admin rights." say_verbose "- The SDK needs to be installed without user interaction and without admin rights."
say "- The SDK installation doesn't need to persist across multiple CI runs." say_verbose "- The SDK installation doesn't need to persist across multiple CI runs."
say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n" say_verbose "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n"
if [ "$internal" = true ] && [ -z "$(echo $feed_credential)" ]; then if [ "$internal" = true ] && [ -z "$(echo $feed_credential)" ]; then
message="Provide credentials via --feed-credential parameter." message="Provide credentials via --feed-credential parameter."
@ -1716,5 +1938,5 @@ else
fi fi
say "Note that the script does not resolve dependencies during installation." say "Note that the script does not resolve dependencies during installation."
say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section." say "To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section."
say "Installation finished successfully." say "Installation finished successfully."

330
package-lock.json generated
View File

@ -1,18 +1,18 @@
{ {
"name": "setup-dotnet", "name": "setup-dotnet",
"version": "3.0.1", "version": "2.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "setup-dotnet", "name": "setup-dotnet",
"version": "3.0.1", "version": "2.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.9.1", "@actions/core": "^1.6.0",
"@actions/exec": "^1.0.4", "@actions/exec": "^1.0.4",
"@actions/github": "^1.1.0", "@actions/github": "^1.1.0",
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.8",
"@actions/io": "^1.0.2", "@actions/io": "^1.0.2",
"fast-xml-parser": "^3.15.1", "fast-xml-parser": "^3.15.1",
"semver": "^6.3.0", "semver": "^6.3.0",
@ -33,18 +33,25 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.9.1", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2" }
},
"node_modules/@actions/core/node_modules/@actions/http-client": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"dependencies": {
"tunnel": "0.0.6"
} }
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
"version": "1.1.1", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==",
"dependencies": { "dependencies": {
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
@ -59,17 +66,25 @@
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "2.0.1", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", "integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
"dependencies": { "dependencies": {
"tunnel": "^0.0.6" "tunnel": "0.0.6"
}
},
"node_modules/@actions/http-client/node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
} }
}, },
"node_modules/@actions/io": { "node_modules/@actions/io": {
"version": "1.1.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" "integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.15.8", "version": "7.15.8",
@ -913,6 +928,15 @@
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
} }
}, },
"node_modules/@jest/types/node_modules/@types/yargs": {
"version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
"integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
"dev": true,
"dependencies": {
"@types/yargs-parser": "*"
}
},
"node_modules/@octokit/endpoint": { "node_modules/@octokit/endpoint": {
"version": "5.3.5", "version": "5.3.5",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.3.5.tgz", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.3.5.tgz",
@ -1152,6 +1176,66 @@
"pretty-format": "^27.0.0" "pretty-format": "^27.0.0"
} }
}, },
"node_modules/@types/jest/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@types/jest/node_modules/diff-sequences": {
"version": "27.0.6",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz",
"integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==",
"dev": true,
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-diff": {
"version": "27.2.5",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.5.tgz",
"integrity": "sha512-7gfwwyYkeslOOVQY4tVq5TaQa92mWfC9COsVYMNVYyJTOYAqbIkoD3twi5A+h+tAPtAelRxkqY6/xu+jwTr0dA==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
"diff-sequences": "^27.0.6",
"jest-get-type": "^27.0.6",
"pretty-format": "^27.2.5"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-get-type": {
"version": "27.0.6",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz",
"integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==",
"dev": true,
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@types/jest/node_modules/pretty-format": {
"version": "27.2.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.5.tgz",
"integrity": "sha512-+nYn2z9GgicO9JiqmY25Xtq8SYfZ/5VCpEU3pppHHNAhd1y+ZXxmNPd1evmNcAd6Hz4iBV2kf0UpGth5A/VJ7g==",
"dev": true,
"dependencies": {
"@jest/types": "^27.2.5",
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "16.11.25", "version": "16.11.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.25.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.25.tgz",
@ -1539,20 +1623,14 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001382", "version": "1.0.30001265",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001382.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz",
"integrity": "sha512-2rtJwDmSZ716Pxm1wCtbPvHtbDWAreTPxXbkc5RkKglow3Ig/4GNGazDI9/BVnXbG/wnv6r3B5FEbkfg9OcTGg==", "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==",
"dev": true, "dev": true,
"funding": [ "funding": {
{ "type": "opencollective",
"type": "opencollective", "url": "https://opencollective.com/browserslist"
"url": "https://opencollective.com/browserslist" }
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
}
]
}, },
"node_modules/chalk": { "node_modules/chalk": {
"version": "4.1.0", "version": "4.1.0",
@ -3207,6 +3285,36 @@
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
} }
}, },
"node_modules/jest-util/node_modules/ci-info": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz",
"integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==",
"dev": true
},
"node_modules/jest-util/node_modules/is-ci": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz",
"integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==",
"dev": true,
"dependencies": {
"ci-info": "^3.1.1"
},
"bin": {
"is-ci": "bin.js"
}
},
"node_modules/jest-util/node_modules/picomatch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/jest-validate": { "node_modules/jest-validate": {
"version": "27.2.5", "version": "27.2.5",
"resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.5.tgz", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.5.tgz",
@ -4379,6 +4487,15 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/ts-jest/node_modules/yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/tunnel": { "node_modules/tunnel": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
@ -4459,14 +4576,6 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-to-istanbul": { "node_modules/v8-to-istanbul": {
"version": "8.1.0", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz",
@ -4725,18 +4834,27 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.9.1", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
"requires": { "requires": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2" },
"dependencies": {
"@actions/http-client": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"requires": {
"tunnel": "0.0.6"
}
}
} }
}, },
"@actions/exec": { "@actions/exec": {
"version": "1.1.1", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==",
"requires": { "requires": {
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
@ -4751,17 +4869,24 @@
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "2.0.1", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", "integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
"requires": { "requires": {
"tunnel": "^0.0.6" "tunnel": "0.0.6"
},
"dependencies": {
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
}
} }
}, },
"@actions/io": { "@actions/io": {
"version": "1.1.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" "integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
}, },
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.15.8", "version": "7.15.8",
@ -5409,6 +5534,17 @@
"@types/node": "*", "@types/node": "*",
"@types/yargs": "^16.0.0", "@types/yargs": "^16.0.0",
"chalk": "^4.0.0" "chalk": "^4.0.0"
},
"dependencies": {
"@types/yargs": {
"version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
"integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
"dev": true,
"requires": {
"@types/yargs-parser": "*"
}
}
} }
}, },
"@octokit/endpoint": { "@octokit/endpoint": {
@ -5639,6 +5775,50 @@
"requires": { "requires": {
"jest-diff": "^27.0.0", "jest-diff": "^27.0.0",
"pretty-format": "^27.0.0" "pretty-format": "^27.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true
},
"diff-sequences": {
"version": "27.0.6",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz",
"integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==",
"dev": true
},
"jest-diff": {
"version": "27.2.5",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.5.tgz",
"integrity": "sha512-7gfwwyYkeslOOVQY4tVq5TaQa92mWfC9COsVYMNVYyJTOYAqbIkoD3twi5A+h+tAPtAelRxkqY6/xu+jwTr0dA==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"diff-sequences": "^27.0.6",
"jest-get-type": "^27.0.6",
"pretty-format": "^27.2.5"
}
},
"jest-get-type": {
"version": "27.0.6",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz",
"integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==",
"dev": true
},
"pretty-format": {
"version": "27.2.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.5.tgz",
"integrity": "sha512-+nYn2z9GgicO9JiqmY25Xtq8SYfZ/5VCpEU3pppHHNAhd1y+ZXxmNPd1evmNcAd6Hz4iBV2kf0UpGth5A/VJ7g==",
"dev": true,
"requires": {
"@jest/types": "^27.2.5",
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
}
}
} }
}, },
"@types/node": { "@types/node": {
@ -5948,9 +6128,9 @@
"dev": true "dev": true
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001382", "version": "1.0.30001265",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001382.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz",
"integrity": "sha512-2rtJwDmSZ716Pxm1wCtbPvHtbDWAreTPxXbkc5RkKglow3Ig/4GNGazDI9/BVnXbG/wnv6r3B5FEbkfg9OcTGg==", "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==",
"dev": true "dev": true
}, },
"chalk": { "chalk": {
@ -7230,6 +7410,29 @@
"graceful-fs": "^4.2.4", "graceful-fs": "^4.2.4",
"is-ci": "^3.0.0", "is-ci": "^3.0.0",
"picomatch": "^2.2.3" "picomatch": "^2.2.3"
},
"dependencies": {
"ci-info": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz",
"integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==",
"dev": true
},
"is-ci": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz",
"integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==",
"dev": true,
"requires": {
"ci-info": "^3.1.1"
}
},
"picomatch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
"dev": true
}
} }
}, },
"jest-validate": { "jest-validate": {
@ -8084,6 +8287,12 @@
"requires": { "requires": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
} }
},
"yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true
} }
} }
}, },
@ -8142,11 +8351,6 @@
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true "dev": true
}, },
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"v8-to-istanbul": { "v8-to-istanbul": {
"version": "8.1.0", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "setup-dotnet", "name": "setup-dotnet",
"version": "3.0.1", "version": "2.1.0",
"private": true, "private": true,
"description": "setup dotnet action", "description": "setup dotnet action",
"main": "lib/setup-dotnet.js", "main": "lib/setup-dotnet.js",
@ -9,7 +9,7 @@
"format": "prettier --write **/*.ts", "format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts", "format-check": "prettier --check **/*.ts",
"prepare": "husky install", "prepare": "husky install",
"test": "jest --coverage --config ./jest.config.js", "test": "jest",
"update-installers": "nwget https://dot.net/v1/dotnet-install.ps1 -O externals/install-dotnet.ps1 && nwget https://dot.net/v1/dotnet-install.sh -O externals/install-dotnet.sh" "update-installers": "nwget https://dot.net/v1/dotnet-install.ps1 -O externals/install-dotnet.ps1 && nwget https://dot.net/v1/dotnet-install.sh -O externals/install-dotnet.sh"
}, },
"repository": { "repository": {
@ -24,10 +24,10 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.9.1", "@actions/core": "^1.6.0",
"@actions/exec": "^1.0.4", "@actions/exec": "^1.0.4",
"@actions/github": "^1.1.0", "@actions/github": "^1.1.0",
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.8",
"@actions/io": "^1.0.2", "@actions/io": "^1.0.2",
"fast-xml-parser": "^3.15.1", "fast-xml-parser": "^3.15.1",
"semver": "^6.3.0", "semver": "^6.3.0",

View File

@ -4,6 +4,7 @@ import * as core from '@actions/core';
import * as github from '@actions/github'; import * as github from '@actions/github';
import * as xmlbuilder from 'xmlbuilder'; import * as xmlbuilder from 'xmlbuilder';
import * as xmlParser from 'fast-xml-parser'; import * as xmlParser from 'fast-xml-parser';
import {ProcessEnvOptions} from 'child_process';
export function configAuthentication( export function configAuthentication(
feedUrl: string, feedUrl: string,
@ -46,7 +47,7 @@ function writeFeedToFile(
existingFileLocation: string, existingFileLocation: string,
tempFileLocation: string tempFileLocation: string
) { ) {
core.info( console.log(
`dotnet-auth: Finding any source references in ${existingFileLocation}, writing a new temporary configuration file with credentials to ${tempFileLocation}` `dotnet-auth: Finding any source references in ${existingFileLocation}, writing a new temporary configuration file with credentials to ${tempFileLocation}`
); );
let xml: xmlbuilder.XMLElement; let xml: xmlbuilder.XMLElement;
@ -57,7 +58,7 @@ function writeFeedToFile(
owner = github.context.repo.owner; owner = github.context.repo.owner;
} }
if (!process.env.NUGET_AUTH_TOKEN) { if (!process.env.NUGET_AUTH_TOKEN || process.env.NUGET_AUTH_TOKEN == '') {
throw new Error( throw new Error(
'The NUGET_AUTH_TOKEN environment variable was not provided. In this step, add the following: \r\nenv:\r\n NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}' 'The NUGET_AUTH_TOKEN environment variable was not provided. In this step, add the following: \r\nenv:\r\n NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}'
); );
@ -66,22 +67,22 @@ function writeFeedToFile(
if (fs.existsSync(existingFileLocation)) { if (fs.existsSync(existingFileLocation)) {
// get key from existing NuGet.config so NuGet/dotnet can match credentials // get key from existing NuGet.config so NuGet/dotnet can match credentials
const curContents: string = fs.readFileSync(existingFileLocation, 'utf8'); const curContents: string = fs.readFileSync(existingFileLocation, 'utf8');
const json = xmlParser.parse(curContents, {ignoreAttributes: false}); var json = xmlParser.parse(curContents, {ignoreAttributes: false});
if (typeof json.configuration === 'undefined') { if (typeof json.configuration == 'undefined') {
throw new Error(`The provided NuGet.config seems invalid.`); throw new Error(`The provided NuGet.config seems invalid.`);
} }
if (typeof json.configuration.packageSources != 'undefined') { if (typeof json.configuration.packageSources != 'undefined') {
if (typeof json.configuration.packageSources.add != 'undefined') { if (typeof json.configuration.packageSources.add != 'undefined') {
// file has at least one <add> // file has at least one <add>
if (typeof json.configuration.packageSources.add[0] === 'undefined') { if (typeof json.configuration.packageSources.add[0] == 'undefined') {
// file has only one <add> // file has only one <add>
if ( if (
json.configuration.packageSources.add['@_value'] json.configuration.packageSources.add['@_value']
.toLowerCase() .toLowerCase()
.includes(feedUrl.toLowerCase()) .includes(feedUrl.toLowerCase())
) { ) {
const key = json.configuration.packageSources.add['@_key']; let key = json.configuration.packageSources.add['@_key'];
sourceKeys.push(key); sourceKeys.push(key);
core.debug(`Found a URL with key ${key}`); core.debug(`Found a URL with key ${key}`);
} }
@ -96,7 +97,7 @@ function writeFeedToFile(
const value = source['@_value']; const value = source['@_value'];
core.debug(`source '${value}'`); core.debug(`source '${value}'`);
if (value.toLowerCase().includes(feedUrl.toLowerCase())) { if (value.toLowerCase().includes(feedUrl.toLowerCase())) {
const key = source['@_key']; let key = source['@_key'];
sourceKeys.push(key); sourceKeys.push(key);
core.debug(`Found a URL with key ${key}`); core.debug(`Found a URL with key ${key}`);
} }
@ -113,7 +114,7 @@ function writeFeedToFile(
.up() .up()
.up(); .up();
if (!sourceKeys.length) { if (sourceKeys.length == 0) {
let keystring = 'Source'; let keystring = 'Source';
xml = xml xml = xml
.ele('packageSources') .ele('packageSources')
@ -149,6 +150,6 @@ function writeFeedToFile(
// ? '%NUGET_AUTH_TOKEN%' // ? '%NUGET_AUTH_TOKEN%'
// : '$NUGET_AUTH_TOKEN' // : '$NUGET_AUTH_TOKEN'
const output = xml.end({pretty: true}); var output = xml.end({pretty: true});
fs.writeFileSync(tempFileLocation, output); fs.writeFileSync(tempFileLocation, output);
} }

View File

@ -2,125 +2,174 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as io from '@actions/io'; import * as io from '@actions/io';
import * as hc from '@actions/http-client'; import hc = require('@actions/http-client');
import {chmodSync} from 'fs'; import {chmodSync} from 'fs';
import {readdir} from 'fs/promises'; import * as path from 'path';
import path from 'path'; import {ExecOptions} from '@actions/exec/lib/interfaces';
import semver from 'semver'; import * as semver from 'semver';
import {IS_LINUX, IS_WINDOWS} from './utils';
import {QualityOptions} from './setup-dotnet';
export interface DotnetVersion { const IS_WINDOWS = process.platform === 'win32';
type: string;
value: string;
qualityFlag: boolean;
}
export class DotnetVersionResolver { /**
private inputVersion: string; * Represents the inputted version information
private resolvedArgument: DotnetVersion; */
export class DotNetVersionInfo {
public inputVersion: string;
private fullversion: string;
private isExactVersionSet: boolean = false;
constructor(version: string) { constructor(version: string) {
this.inputVersion = version.trim(); this.inputVersion = version;
this.resolvedArgument = {type: '', value: '', qualityFlag: false};
// Check for exact match
if (semver.valid(semver.clean(version) || '') != null) {
this.fullversion = semver.clean(version) as string;
this.isExactVersionSet = true;
return;
}
const parts: string[] = version.split('.');
if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
this.throwInvalidVersionFormat();
}
const major = this.getVersionNumberOrThrow(parts[0]);
const minor = ['x', '*'].includes(parts[1])
? parts[1]
: this.getVersionNumberOrThrow(parts[1]);
this.fullversion = major + '.' + minor;
} }
private async resolveVersionInput(): Promise<void> { private getVersionNumberOrThrow(input: string): number {
if (!semver.validRange(this.inputVersion)) { try {
throw new Error( if (!input || input.trim() === '') this.throwInvalidVersionFormat();
`'dotnet-version' was supplied in invalid format: ${this.inputVersion}! Supported syntax: A.B.C, A.B, A.B.x, A, A.x`
);
}
if (semver.valid(this.inputVersion)) {
this.resolvedArgument.type = 'version';
this.resolvedArgument.value = this.inputVersion;
} else {
const [major, minor] = this.inputVersion.split('.');
if (this.isNumericTag(major)) { let number = Number(input);
this.resolvedArgument.type = 'channel';
if (this.isNumericTag(minor)) { if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
this.resolvedArgument.value = `${major}.${minor}`;
} else { return number;
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], { } catch {
allowRetries: true, this.throwInvalidVersionFormat();
maxRetries: 3 return -1;
});
this.resolvedArgument.value = await this.getLatestVersion(
httpClient,
[major, minor]
);
}
}
this.resolvedArgument.qualityFlag = +major >= 6 ? true : false;
} }
} }
private isNumericTag(versionTag): boolean { private throwInvalidVersionFormat() {
return /^\d+$/.test(versionTag); throw new Error(
} 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*'
public async createDotNetVersion(): Promise<{
type: string;
value: string;
qualityFlag: boolean;
}> {
await this.resolveVersionInput();
if (!this.resolvedArgument.type) {
return this.resolvedArgument;
}
if (IS_WINDOWS) {
this.resolvedArgument.type =
this.resolvedArgument.type === 'channel' ? '-Channel' : '-Version';
} else {
this.resolvedArgument.type =
this.resolvedArgument.type === 'channel' ? '--channel' : '--version';
}
return this.resolvedArgument;
}
private async getLatestVersion(
httpClient: hc.HttpClient,
versionParts: string[]
): Promise<string> {
const response = await httpClient.getJson<any>(
DotnetVersionResolver.DotNetCoreIndexUrl
); );
const result = response.result || {};
let releasesInfo: any[] = result['releases-index'];
let releaseInfo = releasesInfo.find(info => {
let sdkParts: string[] = info['channel-version'].split('.');
return sdkParts[0] === versionParts[0];
});
if (!releaseInfo) {
throw new Error(
`Could not find info for version ${versionParts.join('.')} at ${
DotnetVersionResolver.DotNetCoreIndexUrl
}`
);
}
return releaseInfo['channel-version'];
} }
static DotNetCoreIndexUrl: string = /**
'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json'; * If true exacatly one version should be resolved
*/
public isExactVersion(): boolean {
return this.isExactVersionSet;
}
public version(): string {
return this.fullversion;
}
} }
export class DotnetCoreInstaller { export class DotnetCoreInstaller {
private version: string; constructor(version: string, includePrerelease: boolean = false) {
private quality: QualityOptions; this.version = version;
private static readonly installationDirectoryWindows = path.join( this.includePrerelease = includePrerelease;
process.env['PROGRAMFILES'] + '', }
'dotnet'
); public async installDotnet() {
private static readonly installationDirectoryLinux = '/usr/share/dotnet'; let output = '';
private static readonly installationDirectoryMac = path.join( let resultCode = 0;
process.env['HOME'] + '',
'.dotnet' let calculatedVersion = await this.resolveVersion(
); new DotNetVersionInfo(this.version)
);
var envVariables: {[key: string]: string} = {};
for (let key in process.env) {
if (process.env[key]) {
let value: any = process.env[key];
envVariables[key] = value;
}
}
if (IS_WINDOWS) {
let escapedScript = path
.join(__dirname, '..', 'externals', 'install-dotnet.ps1')
.replace(/'/g, "''");
let command = `& '${escapedScript}'`;
if (calculatedVersion) {
command += ` -Version ${calculatedVersion}`;
}
if (process.env['https_proxy'] != null) {
command += ` -ProxyAddress ${process.env['https_proxy']}`;
}
// This is not currently an option
if (process.env['no_proxy'] != null) {
command += ` -ProxyBypassList ${process.env['no_proxy']}`;
}
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
const powershellPath =
(await io.which('pwsh', false)) || (await io.which('powershell', true));
var options: ExecOptions = {
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
}
},
env: envVariables
};
resultCode = await exec.exec(
`"${powershellPath}"`,
[
'-NoLogo',
'-Sta',
'-NoProfile',
'-NonInteractive',
'-ExecutionPolicy',
'Unrestricted',
'-Command',
command
],
options
);
} else {
let escapedScript = path
.join(__dirname, '..', 'externals', 'install-dotnet.sh')
.replace(/'/g, "''");
chmodSync(escapedScript, '777');
const scriptPath = await io.which(escapedScript, true);
let scriptArguments: string[] = [];
if (calculatedVersion) {
scriptArguments.push('--version', calculatedVersion);
}
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
resultCode = await exec.exec(`"${scriptPath}"`, scriptArguments, {
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
}
},
env: envVariables
});
}
if (resultCode != 0) {
throw new Error(`Failed to install dotnet ${resultCode}. ${output}`);
}
}
static addToPath() { static addToPath() {
if (process.env['DOTNET_INSTALL_DIR']) { if (process.env['DOTNET_INSTALL_DIR']) {
@ -128,145 +177,128 @@ export class DotnetCoreInstaller {
core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']); core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
} else { } else {
if (IS_WINDOWS) { if (IS_WINDOWS) {
core.addPath(DotnetCoreInstaller.installationDirectoryWindows); // This is the default set in install-dotnet.ps1
core.exportVariable( core.addPath(
'DOTNET_ROOT', path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
DotnetCoreInstaller.installationDirectoryWindows
); );
} else if (IS_LINUX) {
core.addPath(DotnetCoreInstaller.installationDirectoryLinux);
core.exportVariable( core.exportVariable(
'DOTNET_ROOT', 'DOTNET_ROOT',
DotnetCoreInstaller.installationDirectoryLinux path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
); );
} else { } else {
// This is the default set in install-dotnet.sh // This is the default set in install-dotnet.sh
core.addPath(DotnetCoreInstaller.installationDirectoryMac); core.addPath(path.join(process.env['HOME'] + '', '.dotnet'));
core.exportVariable( core.exportVariable(
'DOTNET_ROOT', 'DOTNET_ROOT',
DotnetCoreInstaller.installationDirectoryMac path.join(process.env['HOME'] + '', '.dotnet')
); );
} }
} }
console.log(process.env['PATH']);
} }
constructor(version: string, quality: QualityOptions) { // versionInfo - versionInfo of the SDK/Runtime
this.version = version; async resolveVersion(versionInfo: DotNetVersionInfo): Promise<string> {
this.quality = quality; if (versionInfo.isExactVersion()) {
} return versionInfo.version();
}
private setQuality( const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
dotnetVersion: DotnetVersion, allowRetries: true,
scriptArguments: string[] maxRetries: 3
): void { });
const option = IS_WINDOWS ? '-Quality' : '--quality';
if (dotnetVersion.qualityFlag) { const releasesJsonUrl: string = await this.getReleasesJsonUrl(
scriptArguments.push(option, this.quality); httpClient,
} else { versionInfo.version().split('.')
core.warning( );
`'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A and A.x formats where the major tag is higher than 5. You specified: ${this.version}. 'dotnet-quality' input is ignored.`
const releasesResponse = await httpClient.getJson<any>(releasesJsonUrl);
const releasesResult = releasesResponse.result || {};
let releasesInfo: any[] = releasesResult['releases'];
releasesInfo = releasesInfo.filter((releaseInfo: any) => {
return (
semver.satisfies(releaseInfo['sdk']['version'], versionInfo.version(), {
includePrerelease: this.includePrerelease
}) ||
semver.satisfies(
releaseInfo['sdk']['version-display'],
versionInfo.version(),
{
includePrerelease: this.includePrerelease
}
)
);
});
// Exclude versions that are newer than the latest if using not exact
let latestSdk: string = releasesResult['latest-sdk'];
releasesInfo = releasesInfo.filter((releaseInfo: any) =>
semver.lte(releaseInfo['sdk']['version'], latestSdk, {
includePrerelease: this.includePrerelease
})
);
// Sort for latest version
releasesInfo = releasesInfo.sort((a, b) =>
semver.rcompare(a['sdk']['version'], b['sdk']['version'], {
includePrerelease: this.includePrerelease
})
);
if (releasesInfo.length == 0) {
throw new Error(
`Could not find dotnet core version. Please ensure that specified version ${versionInfo.inputVersion} is valid.`
); );
} }
let release = releasesInfo[0];
return release['sdk']['version'];
} }
public async installDotnet(): Promise<string> { private async getReleasesJsonUrl(
const windowsDefaultOptions = [ httpClient: hc.HttpClient,
'-NoLogo', versionParts: string[]
'-Sta',
'-NoProfile',
'-NonInteractive',
'-ExecutionPolicy',
'Unrestricted',
'-Command'
];
const scriptName = IS_WINDOWS ? 'install-dotnet.ps1' : 'install-dotnet.sh';
const escapedScript = path
.join(__dirname, '..', 'externals', scriptName)
.replace(/'/g, "''");
let scriptArguments: string[];
let scriptPath = '';
const versionResolver = new DotnetVersionResolver(this.version);
const dotnetVersion = await versionResolver.createDotNetVersion();
if (IS_WINDOWS) {
scriptArguments = ['&', `'${escapedScript}'`];
if (dotnetVersion.type) {
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
}
if (this.quality) {
this.setQuality(dotnetVersion, scriptArguments);
}
if (process.env['https_proxy'] != null) {
scriptArguments.push(`-ProxyAddress ${process.env['https_proxy']}`);
}
// This is not currently an option
if (process.env['no_proxy'] != null) {
scriptArguments.push(`-ProxyBypassList ${process.env['no_proxy']}`);
}
if (!process.env['DOTNET_INSTALL_DIR']) {
process.env['DOTNET_INSTALL_DIR'] =
DotnetCoreInstaller.installationDirectoryWindows;
}
scriptPath =
(await io.which('pwsh', false)) || (await io.which('powershell', true));
scriptArguments = windowsDefaultOptions.concat(scriptArguments);
} else {
chmodSync(escapedScript, '777');
scriptPath = await io.which(escapedScript, true);
scriptArguments = [];
if (dotnetVersion.type) {
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
}
if (this.quality) {
this.setQuality(dotnetVersion, scriptArguments);
}
if (!process.env['DOTNET_INSTALL_DIR']) {
process.env['DOTNET_INSTALL_DIR'] = IS_LINUX
? DotnetCoreInstaller.installationDirectoryLinux
: DotnetCoreInstaller.installationDirectoryMac;
}
}
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
const getExecOutputOptions = {
ignoreReturnCode: true,
env: process.env as {string: string}
};
const {exitCode, stdout} = await exec.getExecOutput(
`"${scriptPath}"`,
scriptArguments,
getExecOutputOptions
);
if (exitCode) {
throw new Error(`Failed to install dotnet ${exitCode}. ${stdout}`);
}
return this.outputDotnetVersion(
dotnetVersion.value,
process.env['DOTNET_INSTALL_DIR']
);
}
private async outputDotnetVersion(
version,
installationPath
): Promise<string> { ): Promise<string> {
let versionsOnRunner: string[] = await readdir( const response = await httpClient.getJson<any>(DotNetCoreIndexUrl);
path.join(installationPath.replace(/'/g, ''), 'sdk') const result = response.result || {};
); let releasesInfo: any[] = result['releases-index'];
let installedVersion = semver.maxSatisfying(versionsOnRunner, version, { releasesInfo = releasesInfo.filter((info: any) => {
includePrerelease: true // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
})!; const sdkParts: string[] = info['channel-version'].split('.');
if (
versionParts.length >= 2 &&
!(versionParts[1] == 'x' || versionParts[1] == '*')
) {
return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
}
return versionParts[0] == sdkParts[0];
});
return installedVersion; if (releasesInfo.length === 0) {
throw new Error(
`Could not find info for version ${versionParts.join(
'.'
)} at ${DotNetCoreIndexUrl}`
);
}
const releaseInfo = releasesInfo[0];
if (releaseInfo['support-phase'] === 'eol') {
core.warning(
`${releaseInfo['product']} ${releaseInfo['channel-version']} is no longer supported and will not receive security updates in the future. Please refer to https://aka.ms/dotnet-core-support for more information about the .NET support policy.`
);
}
return releaseInfo['releases.json'];
} }
private version: string;
private includePrerelease: boolean;
} }
const DotNetCoreIndexUrl: string =
'https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json';

View File

@ -1,20 +1,9 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import {DotnetCoreInstaller} from './installer'; import * as installer from './installer';
import * as fs from 'fs'; import * as fs from 'fs';
import path from 'path'; import * as path from 'path';
import semver from 'semver';
import * as auth from './authutil'; import * as auth from './authutil';
const qualityOptions = [
'daily',
'signed',
'validated',
'preview',
'ga'
] as const;
export type QualityOptions = typeof qualityOptions[number];
export async function run() { export async function run() {
try { try {
// //
@ -26,8 +15,7 @@ export async function run() {
// If a valid version still can't be identified, nothing will be installed. // If a valid version still can't be identified, nothing will be installed.
// Proxy, auth, (etc) are still set up, even if no version is identified // Proxy, auth, (etc) are still set up, even if no version is identified
// //
const versions = core.getMultilineInput('dotnet-version'); let versions = core.getMultilineInput('dotnet-version');
const installedDotnetVersions: string[] = [];
const globalJsonFileInput = core.getInput('global-json-file'); const globalJsonFileInput = core.getInput('global-json-file');
if (globalJsonFileInput) { if (globalJsonFileInput) {
@ -50,22 +38,18 @@ export async function run() {
} }
if (versions.length) { if (versions.length) {
const quality = core.getInput('dotnet-quality') as QualityOptions; const includePrerelease: boolean = core.getBooleanInput(
'include-prerelease'
if (quality && !qualityOptions.includes(quality)) { );
throw new Error( let dotnetInstaller!: installer.DotnetCoreInstaller;
`${quality} is not a supported value for 'dotnet-quality' option. Supported values are: daily, signed, validated, preview, ga.` for (const version of new Set<string>(versions)) {
dotnetInstaller = new installer.DotnetCoreInstaller(
version,
includePrerelease
); );
await dotnetInstaller.installDotnet();
} }
installer.DotnetCoreInstaller.addToPath();
let dotnetInstaller: DotnetCoreInstaller;
const uniqueVersions = new Set<string>(versions);
for (const version of uniqueVersions) {
dotnetInstaller = new DotnetCoreInstaller(version, quality);
const installedVersion = await dotnetInstaller.installDotnet();
installedDotnetVersions.push(installedVersion);
}
DotnetCoreInstaller.addToPath();
} }
const sourceUrl: string = core.getInput('source-url'); const sourceUrl: string = core.getInput('source-url');
@ -74,22 +58,8 @@ export async function run() {
auth.configAuthentication(sourceUrl, configFile); auth.configAuthentication(sourceUrl, configFile);
} }
const comparisonRange: string = globalJsonFileInput
? versions[versions.length - 1]!
: '*';
const versionToOutput = semver.maxSatisfying(
installedDotnetVersions,
comparisonRange,
{
includePrerelease: true
}
);
core.setOutput('dotnet-version', versionToOutput);
const matchersPath = path.join(__dirname, '..', '.github'); const matchersPath = path.join(__dirname, '..', '.github');
core.info(`##[add-matcher]${path.join(matchersPath, 'csc.json')}`); console.log(`##[add-matcher]${path.join(matchersPath, 'csc.json')}`);
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }

View File

@ -1,2 +0,0 @@
export const IS_WINDOWS = process.platform === 'win32';
export const IS_LINUX = process.platform === 'linux';