You've already forked setup-dotnet
mirror of
https://github.com/actions/setup-dotnet.git
synced 2025-07-10 17:10:32 +07:00
Compare commits
109 Commits
Author | SHA1 | Date | |
---|---|---|---|
aa983c550d | |||
b891376106 | |||
b05a3f26b3 | |||
5fdecd2063 | |||
38b49fb717 | |||
3cf3e230c1 | |||
83a1653fa3 | |||
898aa0ce4d | |||
2f028bc044 | |||
21cf89aa73 | |||
fefaa59d2e | |||
e8501859aa | |||
426d75d071 | |||
0f534f5829 | |||
fbdbede901 | |||
0bc43909e0 | |||
c5a57b219c | |||
6adeb768ce | |||
f425be78f5 | |||
fc8786b149 | |||
7d08dc7593 | |||
e0a32d6459 | |||
255362be61 | |||
50b46b3b1d | |||
e8ac21d503 | |||
a79ce57e6b | |||
180a15970f | |||
b72f430d36 | |||
559e47b01b | |||
7358a44590 | |||
34c30d0e81 | |||
5f570676c2 | |||
aa34a3ceaa | |||
12f70884d7 | |||
0318091611 | |||
f199d27aa1 | |||
660c25a321 | |||
4f6b2f576a | |||
920b830bd1 | |||
abdd14ee80 | |||
1d9f0dad5b | |||
2699274f6e | |||
ca579e0fb2 | |||
c82240598b | |||
926f442022 | |||
c41fd15071 | |||
0c8652569e | |||
3cf27f13bb | |||
ae8edb8fff | |||
82b2b40816 | |||
fe74f1cb7d | |||
e94d154672 | |||
fe67d2f8db | |||
023f7252a0 | |||
3f3ad54c0c | |||
e1d35446fe | |||
11aaa65761 | |||
13abe4777e | |||
aefe5b483f | |||
047f06d086 | |||
014f8c8384 | |||
80c862dc38 | |||
e21107efbd | |||
d8f1ab14a7 | |||
f05a62b1cc | |||
338d4e3bbf | |||
228eec3014 | |||
c483e03222 | |||
a35f420124 | |||
4214866121 | |||
0681939502 | |||
ba8a1f9c02 | |||
09d024bd02 | |||
8ae4c080ce | |||
c5d2f92cae | |||
069c35efca | |||
6a2cd88ae8 | |||
9984a6fa87 | |||
607fce577a | |||
501b34e8f6 | |||
b827fcce4d | |||
239baf3c5b | |||
4d4a70f4a5 | |||
70c3f4d098 | |||
9260643816 | |||
45c9f236cf | |||
6d6c7c9313 | |||
e753bbf2ff | |||
629365b26e | |||
942a0bea39 | |||
26db2473e9 | |||
467621733d | |||
bdd38d13dc | |||
1d2f8f9eaf | |||
354d280fa3 | |||
0ff311b0d0 | |||
bc65ba63d3 | |||
90642fa8c5 | |||
c7e7147fd3 | |||
cf081e76a2 | |||
4ca3c96b49 | |||
0705ef0281 | |||
cc76dfab99 | |||
1f2c90bb99 | |||
251997c37d | |||
5d7bc0454b | |||
792e988dae | |||
e5034212c9 | |||
0997db20d4 |
6
.eslintignore
Normal file
6
.eslintignore
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Ignore list
|
||||||
|
/*
|
||||||
|
|
||||||
|
# Do not ignore these folders:
|
||||||
|
!__tests__/
|
||||||
|
!src/
|
50
.eslintrc.js
Normal file
50
.eslintrc.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
|
||||||
|
module.exports = {
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:eslint-plugin-jest/recommended',
|
||||||
|
'eslint-config-prettier'
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
plugins: ['@typescript-eslint', 'eslint-plugin-jest'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-require-imports': 'error',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
|
'@typescript-eslint/ban-ts-comment': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
'ts-ignore': 'allow-with-description'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-console': 'error',
|
||||||
|
'yoda': 'error',
|
||||||
|
'prefer-const': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
destructuring: 'all'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-control-regex': 'off',
|
||||||
|
'no-constant-condition': ['error', {checkLoops: false}]
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['**/*{test,spec}.ts'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-unused-vars': 'off',
|
||||||
|
'jest/no-standalone-expect': 'off',
|
||||||
|
'jest/no-conditional-expect': 'off',
|
||||||
|
'no-console': 'off',
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
es6: true,
|
||||||
|
'jest/globals': true
|
||||||
|
}
|
||||||
|
};
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +1,2 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
.licenses/** -diff linguist-generated=true
|
.licenses/** -diff linguist-generated=true
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -1 +1 @@
|
|||||||
* @actions/virtual-environments-owners
|
* @actions/setup-actions-team
|
||||||
|
17
.github/workflows/basic-validation.yml
vendored
Normal file
17
.github/workflows/basic-validation.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: Basic validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- releases/*
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
call-basic-validation:
|
||||||
|
name: Basic validation
|
||||||
|
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main
|
41
.github/workflows/check-dist.yml
vendored
41
.github/workflows/check-dist.yml
vendored
@ -1,8 +1,3 @@
|
|||||||
# `dist/index.js` is a special file in Actions.
|
|
||||||
# When you reference an action with `uses:` in a workflow,
|
|
||||||
# `index.js` is the code that will run.
|
|
||||||
# For our project, we generate this file through a build process from other source files.
|
|
||||||
# We need to make sure the checked-in `index.js` actually matches what we expect it to be.
|
|
||||||
name: Check dist/
|
name: Check dist/
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@ -17,36 +12,6 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-dist:
|
call-check-dist:
|
||||||
runs-on: ubuntu-latest
|
name: Check dist/
|
||||||
|
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set Node.js 16
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 16.x
|
|
||||||
cache: npm
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci --ignore-scripts
|
|
||||||
|
|
||||||
- name: Rebuild the dist/ directory
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Compare the expected and actual dist/ directories
|
|
||||||
run: |
|
|
||||||
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
|
|
||||||
echo "Detected uncommitted changes after build. See status below:"
|
|
||||||
git diff
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
id: diff
|
|
||||||
|
|
||||||
# If index.js was different than expected, upload the expected version as an artifact
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
|
|
||||||
with:
|
|
||||||
name: dist
|
|
||||||
path: dist/
|
|
||||||
|
66
.github/workflows/codeql-analysis.yml
vendored
66
.github/workflows/codeql-analysis.yml
vendored
@ -1,70 +1,14 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
name: CodeQL analysis
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [main]
|
branches: [main]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '23 19 * * 0'
|
- cron: '0 3 * * 0'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
call-codeQL-analysis:
|
||||||
name: Analyze
|
name: CodeQL analysis
|
||||||
runs-on: ubuntu-latest
|
uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'javascript' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v2
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v2
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
||||||
|
368
.github/workflows/e2e-tests.yml
vendored
Normal file
368
.github/workflows/e2e-tests.yml
vendored
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
name: e2e tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- releases/*
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-setup-multiple-versions:
|
||||||
|
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.402, 3.1.404 and 3.0.x
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: |
|
||||||
|
2.2.402
|
||||||
|
3.1.404
|
||||||
|
3.0.x
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^2.2.402$", "^3.1.404$", "^3.0"
|
||||||
|
|
||||||
|
test-setup-full-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 }}
|
||||||
|
# Side-by-side install of 2.2 and 3.1 used for the test project
|
||||||
|
- name: Setup dotnet 2.2.402
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 2.2.402
|
||||||
|
- name: Setup dotnet 3.1.201
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
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
|
||||||
|
source-url: https://api.nuget.org/v3/index.json
|
||||||
|
env:
|
||||||
|
NUGET_AUTH_TOKEN: NOTATOKEN
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^3.1.201$", "^2.2.402$" -CheckNugetConfig
|
||||||
|
|
||||||
|
test-setup-without-patch-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 }}
|
||||||
|
# 2.0, 3.0, 5.0 needs to be in single quotes to interpret as a string instead of as an integer
|
||||||
|
- name: Setup dotnet '3.1'
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: '3.1'
|
||||||
|
- name: Setup dotnet '2.2'
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: '2.2'
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^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 '3.1.100-preview1-014459'
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: '3.1.100-preview1-014459'
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "3.1.100-preview1-014459"
|
||||||
|
|
||||||
|
test-setup-latest-patch-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 3.1.x
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 3.1.x
|
||||||
|
- name: Setup dotnet 2.2.X
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 2.2.X
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^2.2", "^3.1"
|
||||||
|
|
||||||
|
test-ABCxx-syntax:
|
||||||
|
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.4xx
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: '6.0.4xx'
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^6\.0\.4\d{2}"
|
||||||
|
|
||||||
|
test-setup-with-wildcard:
|
||||||
|
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 3.1.*
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 3.1.*
|
||||||
|
- name: Setup dotnet 2.2.*
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 2.2.*
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^3.1", "^2.2"
|
||||||
|
|
||||||
|
test-setup-global-json-specified-and-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: Write global.json
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir subdirectory
|
||||||
|
echo '{"sdk":{"version": "2.2.207","rollForward": "latestFeature"}}' > ./subdirectory/global.json
|
||||||
|
- name: Setup dotnet
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 3.1
|
||||||
|
global-json-file: ./subdirectory/global.json
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^2.2", "^3.1"
|
||||||
|
|
||||||
|
test-setup-global-json-only:
|
||||||
|
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: Write global.json
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir subdirectory
|
||||||
|
echo '{"sdk":{"version": "2.2.207","rollForward": "latestFeature"}}' > ./subdirectory/global.json
|
||||||
|
- name: Setup dotnet
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
global-json-file: ./subdirectory/global.json
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^2.2"
|
||||||
|
|
||||||
|
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 dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^7\.0\.\d+-"
|
||||||
|
|
||||||
|
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:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ubuntu:latest
|
||||||
|
options: --dns 127.0.0.1
|
||||||
|
services:
|
||||||
|
squid-proxy:
|
||||||
|
image: ubuntu/squid:latest
|
||||||
|
ports:
|
||||||
|
- 3128:3128
|
||||||
|
env:
|
||||||
|
https_proxy: http://squid-proxy:3128
|
||||||
|
http_proxy: http://squid-proxy:3128
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install Powershell
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y wget apt-transport-https software-properties-common
|
||||||
|
wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb"
|
||||||
|
dpkg -i packages-microsoft-prod.deb
|
||||||
|
rm packages-microsoft-prod.deb
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y powershell
|
||||||
|
- name: Clear toolcache
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
|
||||||
|
- name: Setup dotnet 6.0
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 6.0
|
||||||
|
source-url: https://api.nuget.org/v3/index.json
|
||||||
|
env:
|
||||||
|
NUGET_AUTH_TOKEN: NOTATOKEN
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
__tests__/verify-dotnet.ps1 -Patterns "^6.0" -CheckNugetConfig
|
||||||
|
|
||||||
|
test-bypass-proxy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
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
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Clear toolcache
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
|
||||||
|
- name: Setup dotnet 3.1.201
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
dotnet-version: 3.1.201
|
||||||
|
source-url: https://api.nuget.org/v3/index.json
|
||||||
|
env:
|
||||||
|
NUGET_AUTH_TOKEN: NOTATOKEN
|
||||||
|
- name: Verify dotnet
|
||||||
|
shell: pwsh
|
||||||
|
run: __tests__/verify-dotnet.ps1 -Patterns "^3.1.201$" -CheckNugetConfig
|
16
.github/workflows/licensed.yml
vendored
16
.github/workflows/licensed.yml
vendored
@ -10,16 +10,6 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
call-licensed:
|
||||||
runs-on: ubuntu-latest
|
name: Licensed
|
||||||
name: Check licenses
|
uses: actions/reusable-workflows/.github/workflows/licensed.yml@main
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: npm ci --ignore-scripts
|
|
||||||
- name: Install licensed
|
|
||||||
run: |
|
|
||||||
cd $RUNNER_TEMP
|
|
||||||
curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.4.4/licensed-3.4.4-linux-x64.tar.gz
|
|
||||||
sudo tar -xzf licensed.tar.gz
|
|
||||||
sudo mv licensed /usr/local/bin/licensed
|
|
||||||
- run: licensed status
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
name: Release new action version
|
name: Release new action version
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [released]
|
types: [released]
|
||||||
@ -22,7 +23,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.1.0
|
uses: actions/publish-action@v0.2.2
|
||||||
with:
|
with:
|
||||||
source-tag: ${{ env.TAG_NAME }}
|
source-tag: ${{ env.TAG_NAME }}
|
||||||
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
10
.github/workflows/test-dotnet.yml
vendored
10
.github/workflows/test-dotnet.yml
vendored
@ -17,8 +17,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
|
operating-system: [ubuntu-latest, 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', '6.0', '7.0', '8.0']
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@ -29,9 +29,7 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
dotnet-version: ${{ matrix.dotnet-version }}
|
dotnet-version: ${{ matrix.dotnet-version }}
|
||||||
- name: Check installed version
|
- name: Verify installed version
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$version = & dotnet --version
|
__tests__/verify-dotnet.ps1 -Patterns "^${{ matrix.dotnet-version }}"
|
||||||
Write-Host "Installed version: $version"
|
|
||||||
if (-not $version.StartsWith("${{ matrix.dotnet-version }}")) { throw "Unexpected version" }
|
|
||||||
|
11
.github/workflows/update-config-files.yml
vendored
Normal file
11
.github/workflows/update-config-files.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
name: Update configuration files
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 3 * * 0'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
call-update-configuration-files:
|
||||||
|
name: Update configuration files
|
||||||
|
uses: actions/reusable-workflows/.github/workflows/update-config-files.yml@main
|
244
.github/workflows/workflow.yml
vendored
244
.github/workflows/workflow.yml
vendored
@ -1,244 +0,0 @@
|
|||||||
name: Main workflow
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths-ignore:
|
|
||||||
- '**.md'
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- releases/*
|
|
||||||
paths-ignore:
|
|
||||||
- '**.md'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
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: Set Node.js 16
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 16.x
|
|
||||||
cache: npm
|
|
||||||
- run: npm ci --ignore-scripts
|
|
||||||
- run: npm run build
|
|
||||||
- run: npm run format-check
|
|
||||||
- run: npm test
|
|
||||||
- name: Verify no unstaged changes
|
|
||||||
if: runner.os != 'windows'
|
|
||||||
run: __tests__/verify-no-unstaged-changes.sh
|
|
||||||
|
|
||||||
test-setup-multiple-versions:
|
|
||||||
runs-on: ${{ matrix.operating-system }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
operating-system: [ubuntu-22.04, 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.402 and 3.1.404
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: |
|
|
||||||
2.2.402
|
|
||||||
3.1.404
|
|
||||||
3.0.x
|
|
||||||
- name: Verify dotnet
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/verify-dotnet.ps1 2.2.402 3.1.404 '3.0'
|
|
||||||
|
|
||||||
test-setup-full-version:
|
|
||||||
runs-on: ${{ matrix.operating-system }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
operating-system: [ubuntu-22.04, windows-latest, macos-13]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Clear toolcache
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
|
|
||||||
# Side-by-side install of 2.2 and 3.1 used for the test project
|
|
||||||
- name: Setup dotnet 2.2.402
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 2.2.402
|
|
||||||
- name: Setup dotnet 3.1.201
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 3.1.201
|
|
||||||
# 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
|
|
||||||
env:
|
|
||||||
NUGET_AUTH_TOKEN: NOTATOKEN
|
|
||||||
- name: Verify nuget config file
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
if (-Not (Test-Path "../nuget.config")) { throw "nuget file not generated correctly" }
|
|
||||||
- name: Verify dotnet
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/verify-dotnet.ps1 3.1.201 2.2.402
|
|
||||||
|
|
||||||
test-setup-without-patch-version:
|
|
||||||
runs-on: ${{ matrix.operating-system }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Clear toolcache
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
|
|
||||||
# 2.0, 3.0, 5.0 needs to be in single quotes to interpret as a string instead of as an integer
|
|
||||||
- name: Setup dotnet '3.1'
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: '3.1'
|
|
||||||
- name: Setup dotnet '2.2'
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: '2.2'
|
|
||||||
- name: Verify dotnet
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/verify-dotnet.ps1 3.1 2.2
|
|
||||||
|
|
||||||
test-setup-latest-patch-version:
|
|
||||||
runs-on: ${{ matrix.operating-system }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
operating-system: [ubuntu-22.04, 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 3.1.x
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 3.1.x
|
|
||||||
- name: Setup dotnet 2.2.x
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 2.2.x
|
|
||||||
- name: Verify dotnet
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/verify-dotnet.ps1 3.1 2.2
|
|
||||||
|
|
||||||
test-setup-with-wildcard:
|
|
||||||
runs-on: ${{ matrix.operating-system }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
operating-system: [ubuntu-22.04, 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 3.1.*
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 3.1.*
|
|
||||||
- name: Setup dotnet 2.2.*
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 2.2.*
|
|
||||||
- name: Verify dotnet
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/verify-dotnet.ps1 3.1 2.2
|
|
||||||
|
|
||||||
test-setup-global-json-specified-and-version:
|
|
||||||
runs-on: ${{ matrix.operating-system }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Clear toolcache
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/clear-toolcache.ps1 ${{ runner.os }}
|
|
||||||
- name: Write global.json
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir subdirectory
|
|
||||||
echo '{"sdk":{"version": "2.2","rollForward": "latestFeature"}}' > ./subdirectory/global.json
|
|
||||||
- name: Setup dotnet
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 3.1
|
|
||||||
global-json-file: ./subdirectory/global.json
|
|
||||||
- name: Verify dotnet
|
|
||||||
shell: pwsh
|
|
||||||
run: __tests__/verify-dotnet.ps1 2.2 3.1
|
|
||||||
|
|
||||||
test-proxy:
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
container:
|
|
||||||
image: ubuntu:20.04
|
|
||||||
options: --dns 127.0.0.1
|
|
||||||
services:
|
|
||||||
squid-proxy:
|
|
||||||
image: ubuntu/squid:latest
|
|
||||||
ports:
|
|
||||||
- 3128:3128
|
|
||||||
env:
|
|
||||||
https_proxy: http://squid-proxy:3128
|
|
||||||
http_proxy: http://squid-proxy:3128
|
|
||||||
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: true
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Clear tool cache
|
|
||||||
run: rm -rf "/usr/share/dotnet"
|
|
||||||
- name: Install curl
|
|
||||||
run: |
|
|
||||||
apt update
|
|
||||||
apt -y install curl libssl1.1 libssl-dev
|
|
||||||
- name: Setup dotnet 3.1.201
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 3.1.201
|
|
||||||
source-url: https://api.nuget.org/v3/index.json
|
|
||||||
env:
|
|
||||||
NUGET_AUTH_TOKEN: NOTATOKEN
|
|
||||||
- name: Verify dotnet
|
|
||||||
run: __tests__/verify-dotnet.sh 3.1.201
|
|
||||||
|
|
||||||
test-bypass-proxy:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
env:
|
|
||||||
https_proxy: http://no-such-proxy:3128
|
|
||||||
no_proxy: github.com,download.visualstudio.microsoft.com,api.nuget.org,builds.dotnet.microsoft.com,ci.dot.net
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Clear tool cache
|
|
||||||
run: rm -rf "/usr/share/dotnet"
|
|
||||||
- name: Setup dotnet 3.1.201
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
dotnet-version: 3.1.201
|
|
||||||
source-url: https://api.nuget.org/v3/index.json
|
|
||||||
env:
|
|
||||||
NUGET_AUTH_TOKEN: NOTATOKEN
|
|
||||||
- name: Verify dotnet
|
|
||||||
run: __tests__/verify-dotnet.sh 3.1.201
|
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -3,8 +3,8 @@ global.json
|
|||||||
lib/
|
lib/
|
||||||
node_modules/
|
node_modules/
|
||||||
__tests__/runner/*
|
__tests__/runner/*
|
||||||
__tests__/sample-csproj/bin/
|
__tests__/e2e-test-csproj/bin/
|
||||||
__tests__/sample-csproj/obj/
|
__tests__/e2e-test-csproj/obj/
|
||||||
|
|
||||||
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||||
# Logs
|
# Logs
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
. "$(dirname -- "$0")/_/husky.sh"
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
npm run format
|
npm run format
|
||||||
|
npm run lint:fix
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
|
|
||||||
# Tests are not run at push time since they can take 2-4 minutes to complete
|
# Tests are not run at push time since they can take 2-4 minutes to complete
|
||||||
npm run format-check
|
npm run format-check
|
||||||
|
npm run lint
|
||||||
|
2
.licenses/npm/@actions/core.dep.yml
generated
2
.licenses/npm/@actions/core.dep.yml
generated
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/core"
|
name: "@actions/core"
|
||||||
version: 1.6.0
|
version: 1.10.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
|
||||||
|
30
.licenses/npm/@actions/exec.dep.yml
generated
30
.licenses/npm/@actions/exec.dep.yml
generated
@ -1,30 +1,20 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/exec"
|
name: "@actions/exec"
|
||||||
version: 1.0.4
|
version: 1.1.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Actions exec lib
|
summary: Actions exec lib
|
||||||
homepage: https://github.com/actions/toolkit/tree/master/packages/exec
|
homepage: https://github.com/actions/toolkit/tree/main/packages/exec
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: Auto-generated MIT license text
|
- sources: LICENSE.md
|
||||||
text: |
|
text: |-
|
||||||
MIT License
|
The MIT License (MIT)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Copyright 2019 GitHub
|
||||||
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
|
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:
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
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.
|
||||||
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: []
|
||||||
|
32
.licenses/npm/@actions/http-client-1.0.8.dep.yml
generated
32
.licenses/npm/@actions/http-client-1.0.8.dep.yml
generated
@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
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: []
|
|
@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/http-client"
|
name: "@actions/http-client"
|
||||||
version: 1.0.11
|
version: 2.0.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Actions Http Client
|
summary: Actions Http Client
|
||||||
homepage: https://github.com/actions/http-client#readme
|
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
30
.licenses/npm/@actions/io.dep.yml
generated
30
.licenses/npm/@actions/io.dep.yml
generated
@ -1,30 +1,20 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/io"
|
name: "@actions/io"
|
||||||
version: 1.0.2
|
version: 1.1.2
|
||||||
type: npm
|
type: npm
|
||||||
summary: Actions io lib
|
summary: Actions io lib
|
||||||
homepage: https://github.com/actions/toolkit/tree/master/packages/io
|
homepage: https://github.com/actions/toolkit/tree/main/packages/io
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: Auto-generated MIT license text
|
- sources: LICENSE.md
|
||||||
text: |
|
text: |-
|
||||||
MIT License
|
The MIT License (MIT)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Copyright 2019 GitHub
|
||||||
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
|
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:
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
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.
|
||||||
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: []
|
||||||
|
22
.licenses/npm/fast-xml-parser.dep.yml
generated
22
.licenses/npm/fast-xml-parser.dep.yml
generated
@ -1,27 +1,11 @@
|
|||||||
---
|
---
|
||||||
name: fast-xml-parser
|
name: fast-xml-parser
|
||||||
version: 3.17.4
|
version: 4.0.10
|
||||||
type: npm
|
type: npm
|
||||||
summary: Validate XML or Parse XML to JS/JSON very fast without C/C++ based libraries
|
summary: Validate XML, Parse XML to JS Object, or Build XML from JS Object without C/C++ based libraries and no callback.
|
||||||
homepage: https://github.com/NaturalIntelligence/fast-xml-parser#readme
|
homepage: https://github.com/NaturalIntelligence/fast-xml-parser#readme
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
text: "MIT License\n\nCopyright (c) 2017 Amit Kumar Gupta\n\nPermission is hereby
|
text: "MIT License\n\nCopyright (c) 2017 Amit Kumar Gupta\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
|
||||||
granted, free of charge, to any person obtaining a copy\nof this software and
|
|
||||||
associated documentation files (the \"Software\"), to deal\nin the Software without
|
|
||||||
restriction, including without limitation the rights\nto use, copy, modify, merge,
|
|
||||||
publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit
|
|
||||||
persons to whom the Software is\nfurnished to do so, subject to the following
|
|
||||||
conditions:\n\nIf you use this library in a public repository then you give us
|
|
||||||
the right to mention your company name and logo in user's list without further
|
|
||||||
permission required, but you can request them to be taken down within 30 days.
|
|
||||||
\n\nThe above copyright notice and this permission notice shall be included in
|
|
||||||
all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED
|
|
||||||
\"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT
|
|
||||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
||||||
FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
||||||
THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
|
|
||||||
notices: []
|
notices: []
|
||||||
|
11
.licenses/npm/strnum.dep.yml
generated
Normal file
11
.licenses/npm/strnum.dep.yml
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: strnum
|
||||||
|
version: 1.0.5
|
||||||
|
type: npm
|
||||||
|
summary: Parse string into Number based on configuration
|
||||||
|
homepage: https://github.com/NaturalIntelligence/strnum
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: "MIT License\n\nCopyright (c) 2021 Natural Intelligence\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
|
||||||
|
notices: []
|
20
.licenses/npm/uuid.dep.yml
generated
Normal file
20
.licenses/npm/uuid.dep.yml
generated
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
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: []
|
24
.licenses/npm/xmlbuilder.dep.yml
generated
24
.licenses/npm/xmlbuilder.dep.yml
generated
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
name: xmlbuilder
|
|
||||||
version: 13.0.2
|
|
||||||
type: npm
|
|
||||||
summary: An XML builder for node.js
|
|
||||||
homepage: http://github.com/oozcitak/xmlbuilder-js
|
|
||||||
license: mit
|
|
||||||
licenses:
|
|
||||||
- sources: LICENSE
|
|
||||||
text: "The MIT License (MIT)\r\n\r\nCopyright (c) 2013 Ozgur Ozcitak\r\n\r\nPermission
|
|
||||||
is hereby granted, free of charge, to any person obtaining a copy\r\nof this software
|
|
||||||
and associated documentation files (the \"Software\"), to deal\r\nin the Software
|
|
||||||
without restriction, including without limitation the rights\r\nto use, copy,
|
|
||||||
modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software,
|
|
||||||
and to permit persons to whom the Software is\r\nfurnished to do so, subject to
|
|
||||||
the following conditions:\r\n\r\nThe above copyright notice and this permission
|
|
||||||
notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE
|
|
||||||
SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED,
|
|
||||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE.\r\n"
|
|
||||||
notices: []
|
|
7
.prettierignore
Normal file
7
.prettierignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Ignore list
|
||||||
|
/*
|
||||||
|
|
||||||
|
# Do not ignore these folders:
|
||||||
|
!__tests__/
|
||||||
|
!.github/
|
||||||
|
!src/
|
11
.prettierrc.js
Normal file
11
.prettierrc.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
|
||||||
|
module.exports = {
|
||||||
|
printWidth: 80,
|
||||||
|
tabWidth: 2,
|
||||||
|
useTabs: false,
|
||||||
|
semi: true,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'none',
|
||||||
|
bracketSpacing: false,
|
||||||
|
arrowParens: 'avoid'
|
||||||
|
};
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"bracketSpacing": false,
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"parser": "typescript"
|
|
||||||
}
|
|
189
README.md
189
README.md
@ -1,6 +1,7 @@
|
|||||||
# setup-dotnet
|
# setup-dotnet
|
||||||
|
|
||||||
[](https://github.com/actions/setup-dotnet)
|
[](https://github.com/actions/setup-dotnet/actions/workflows/basic-validation.yml)
|
||||||
|
[](https://github.com/actions/setup-dotnet/actions/workflows/e2e-tests.yml)
|
||||||
|
|
||||||
This action sets up a [.NET CLI](https://github.com/dotnet/sdk) environment for use in actions by:
|
This action sets up a [.NET CLI](https://github.com/dotnet/sdk) environment for use in actions by:
|
||||||
|
|
||||||
@ -8,62 +9,82 @@ 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
|
||||||
|
|
||||||
Please Note: GitHub hosted runners have some versions of the .NET SDK
|
> **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@v2
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: '3.1.x' # SDK Version to use; x will use the latest version of the 3.1 channel
|
dotnet-version: '3.1.x'
|
||||||
- run: dotnet build <my project>
|
- run: dotnet build <my project>
|
||||||
```
|
```
|
||||||
Multiple versions:
|
> **Warning**: Unless a concrete version is specified in the [`global.json`](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json) file, **_the latest .NET version installed on the runner (including preinstalled versions) will be used [by default](https://learn.microsoft.com/en-us/dotnet/core/versions/selection#the-sdk-uses-the-latest-installed-version)_**. Please refer to the [documentation](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software) for the currently preinstalled .NET SDK 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@v2
|
uses: actions/setup-dotnet@v3
|
||||||
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>
|
||||||
```
|
```
|
||||||
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)
|
||||||
|
- **A.B.Cxx** (e.g. 6.0.4xx) - available since `.NET 5.0` release. Installs the latest version of the specific SDK release, 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', 'A.x' and 'A.B.Cxx' 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@v2
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: '6.0.x'
|
dotnet-version: '6.0.x'
|
||||||
include-prerelease: true
|
dotnet-quality: 'preview'
|
||||||
- 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@v2
|
- uses: actions/setup-dotnet@v3
|
||||||
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
|
||||||
```yaml
|
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:
|
||||||
|
```yml
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -74,38 +95,44 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: ${{ matrix.dotnet }}
|
dotnet-version: ${{ matrix.dotnet }}
|
||||||
- run: dotnet build <my project>
|
- name: Execute dotnet
|
||||||
|
run: dotnet build <my project>
|
||||||
```
|
```
|
||||||
|
>**Note**: Unless a concrete version is specified in the [`global.json`](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json) file, the latest .NET version installed on the runner (including preinstalled versions) will be used [by default](https://learn.microsoft.com/en-us/dotnet/core/versions/selection#the-sdk-uses-the-latest-installed-version). To control this behavior you may want to use temporary `global.json` files:
|
||||||
|
|
||||||
Side by Side Testing:
|
**Matrix testing with temporary global.json creation**
|
||||||
```yaml
|
```yml
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Dotnet Side by Side testing sample
|
strategy:
|
||||||
|
matrix:
|
||||||
|
dotnet: [ '2.1.x', '3.1.x', '5.0.x' ]
|
||||||
|
name: Dotnet ${{ matrix.dotnet }} sample
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
|
id: stepid
|
||||||
with:
|
with:
|
||||||
dotnet-version: |
|
dotnet-version: ${{ matrix.dotnet }}
|
||||||
2.1.x
|
- name: Create temporary global.json
|
||||||
3.1.x
|
run: echo '{"sdk":{"version": "${{ steps.stepid.outputs.dotnet-version }}"}}' > ./global.json
|
||||||
- run: dotnet build <my project>
|
- name: Execute dotnet
|
||||||
- run: dotnet test <my project>
|
run: dotnet build <my project>
|
||||||
```
|
```
|
||||||
|
## Setting up authentication for nuget feeds
|
||||||
|
|
||||||
Authentication for nuget feeds:
|
### Github Package Registry (GPR)
|
||||||
```yaml
|
```yml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# Authenticates packages to push to GPR
|
- uses: actions/setup-dotnet@v3
|
||||||
- uses: actions/setup-dotnet@v2
|
|
||||||
with:
|
with:
|
||||||
dotnet-version: '3.1.x' # SDK Version to use.
|
dotnet-version: '3.1.x'
|
||||||
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}}
|
||||||
@ -114,19 +141,22 @@ 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
|
||||||
|
```
|
||||||
|
|
||||||
# Authenticates packages to push to Azure Artifacts
|
### Azure Artifacts
|
||||||
- uses: actions/setup-dotnet@v2
|
```yml
|
||||||
|
- 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
|
||||||
|
```
|
||||||
|
|
||||||
# Authenticates packages to push to nuget.org.
|
### nuget.org
|
||||||
# It's only the way to push a package to nuget.org feed for macOS/Linux machines due to API key config store limitations.
|
```yml
|
||||||
- uses: actions/setup-dotnet@v2
|
- uses: actions/setup-dotnet@v3
|
||||||
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
|
||||||
@ -134,32 +164,91 @@ 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.
|
||||||
|
|
||||||
## Environment Variables to use with dotnet
|
# Outputs and environment variables
|
||||||
|
|
||||||
|
## 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: stepid
|
||||||
|
with:
|
||||||
|
dotnet-version: 3.1.422
|
||||||
|
- run: echo '${{ steps.stepid.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: stepid
|
||||||
|
with:
|
||||||
|
dotnet-version: |
|
||||||
|
3.1.422
|
||||||
|
5.0.408
|
||||||
|
- run: echo '${{ steps.stepid.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: stepid
|
||||||
|
with:
|
||||||
|
dotnet-version: |
|
||||||
|
3.1.422
|
||||||
|
5.0.408
|
||||||
|
global-json-file: "./global.json" # contains version 2.2.207
|
||||||
|
- run: echo '${{ steps.stepid.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
|
||||||
|
|
||||||
- DOTNET_NOLOGO - removes logo and telemetry message from first run of dotnet cli (default: false)
|
| **Env.variable** | **Description** | **Default value** |
|
||||||
- DOTNET_CLI_TELEMETRY_OPTOUT - opt-out of telemetry being sent to Microsoft (default: false)
|
| ----------- | ----------- | ----------- |
|
||||||
- DOTNET_MULTILEVEL_LOOKUP - configures whether the global install location is used as a fall-back (default: true)
|
| DOTNET_INSTALL_DIR |Specifies a directory where .NET SDKs should be installed by the action.|*default value for each OS* |
|
||||||
|
| 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:
|
The default value of the `DOTNET_INSTALL_DIR` environment variable depends on the operation system which is used on a runner:
|
||||||
```yaml
|
| **Operation system** | **Default value** |
|
||||||
|
| ----------- | ----------- |
|
||||||
|
| **Windows** | `C:\Program Files\dotnet` |
|
||||||
|
| **Ubuntu** | `/usr/share/dotnet` |
|
||||||
|
| **macOS** | `/Users/runner/.dotnet` |
|
||||||
|
|
||||||
|
**Example usage**:
|
||||||
|
```yml
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
DOTNET_NOLOGO: true
|
DOTNET_INSTALL_DIR: "path/to/directory"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@main
|
- uses: actions/checkout@main
|
||||||
- uses: actions/setup-dotnet@v2
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: '3.1.x' # SDK Version to use.
|
dotnet-version: '3.1.x'
|
||||||
```
|
```
|
||||||
|
|
||||||
# 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)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`authutil tests Existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -15,7 +15,7 @@ exports[`authutil tests Existing config not in repo root, sets up a partial NuGe
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -30,7 +30,7 @@ exports[`authutil tests Existing config w/ Azure Artifacts source and NuGet.org,
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -45,7 +45,7 @@ exports[`authutil tests Existing config w/ GPR source and NuGet.org, sets up a p
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -63,7 +63,7 @@ exports[`authutil tests Existing config w/ no GPR sources, sets up a full NuGet.
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -81,7 +81,7 @@ exports[`authutil tests Existing config w/ no sources, sets up a full NuGet.conf
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -96,7 +96,7 @@ exports[`authutil tests Existing config w/ only Azure Artifacts source, sets up
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -111,7 +111,7 @@ exports[`authutil tests Existing config w/ only GPR source, sets up a partial Nu
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests Existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
exports[`authutil tests existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -130,7 +130,7 @@ exports[`authutil tests Existing config w/ two GPR sources, sets up a partial Nu
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests No existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR 1`] = `
|
exports[`authutil tests no existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -148,7 +148,7 @@ exports[`authutil tests No existing config, sets up a full NuGet.config with URL
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests No existing config, sets up a full NuGet.config with URL and token for other source 1`] = `
|
exports[`authutil tests no existing config, sets up a full NuGet.config with URL and token for other source 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
@ -166,7 +166,7 @@ exports[`authutil tests No existing config, sets up a full NuGet.config with URL
|
|||||||
</configuration>"
|
</configuration>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`authutil tests No existing config, sets up a full NuGet.config with URL and user/PAT for GPR 1`] = `
|
exports[`authutil tests no existing config, sets up a full NuGet.config with URL and user/PAT for GPR 1`] = `
|
||||||
"<?xml version=\\"1.0\\"?>
|
"<?xml version=\\"1.0\\"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<config>
|
<config>
|
||||||
|
@ -1,32 +1,28 @@
|
|||||||
import io = require('@actions/io');
|
import * as io from '@actions/io';
|
||||||
import fs = require('fs');
|
import fs from 'fs';
|
||||||
import path = require('path');
|
import path from 'path';
|
||||||
|
|
||||||
const fakeSourcesDirForTesting = path.join(
|
const fakeSourcesDirForTesting = path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
'runner',
|
'runner',
|
||||||
path.join(
|
path.join(Math.random().toString(36).substring(7)),
|
||||||
Math.random()
|
|
||||||
.toString(36)
|
|
||||||
.substring(7)
|
|
||||||
),
|
|
||||||
's'
|
's'
|
||||||
);
|
);
|
||||||
|
|
||||||
const invalidNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>`;
|
const invalidNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>`;
|
||||||
|
|
||||||
const emptyNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const emptyNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const nugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const nugetorgNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const gprnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const gprnugetorgNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
<add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
||||||
@ -34,14 +30,14 @@ const gprnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
|||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const gprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const gprNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
<add key="GPR" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const twogprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const twogprNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="GPR-GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
<add key="GPR-GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
||||||
@ -49,21 +45,21 @@ const twogprNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
|||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const spaceNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const spaceNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="GPR GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
<add key="GPR GitHub" value="https://nuget.pkg.github.com/OwnerName/index.json" protocolVersion="3" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const azureartifactsNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const azureartifactsNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
|
<add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>`;
|
</configuration>`;
|
||||||
|
|
||||||
const azureartifactsnugetorgNuGetConfig: string = `<?xml version="1.0" encoding="utf-8"?>
|
const azureartifactsnugetorgNuGetConfig = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
|
<add key="AzureArtifacts" value="https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json" protocolVersion="3" />
|
||||||
@ -95,9 +91,9 @@ describe('authutil tests', () => {
|
|||||||
process.env['NUGET_AUTH_TOKEN'] = '';
|
process.env['NUGET_AUTH_TOKEN'] = '';
|
||||||
});
|
});
|
||||||
|
|
||||||
it('No existing config, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
|
it('no existing config, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -108,10 +104,10 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('No existing config, auth token environment variable not provided, throws', async () => {
|
it('no existing config, auth token environment variable not provided, throws', async () => {
|
||||||
let thrown = false;
|
let thrown = false;
|
||||||
try {
|
try {
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -122,10 +118,10 @@ describe('authutil tests', () => {
|
|||||||
expect(thrown).toBe(true);
|
expect(thrown).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('No existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR', async () => {
|
it('no existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
process.env['INPUT_OWNER'] = 'otherorg';
|
process.env['INPUT_OWNER'] = 'otherorg';
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/otherorg/index.json',
|
'https://nuget.pkg.github.com/otherorg/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -136,7 +132,7 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config (invalid), tries to parse an invalid NuGet.config and throws', async () => {
|
it('existing config (invalid), tries to parse an invalid NuGet.config and throws', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
@ -145,7 +141,7 @@ describe('authutil tests', () => {
|
|||||||
fs.writeFileSync(inputNuGetConfigPath, invalidNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, invalidNuGetConfig);
|
||||||
let thrown = false;
|
let thrown = false;
|
||||||
try {
|
try {
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -156,14 +152,14 @@ describe('authutil tests', () => {
|
|||||||
expect(thrown).toBe(true);
|
expect(thrown).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
|
it('existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, emptyNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, emptyNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -174,14 +170,14 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
|
it('existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, nugetorgNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, nugetorgNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -192,14 +188,14 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
it('existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -210,14 +206,14 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
it('existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, gprnugetorgNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, gprnugetorgNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -228,14 +224,14 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
it('existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, twogprNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, twogprNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com',
|
'https://nuget.pkg.github.com',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -246,7 +242,7 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ spaces in key, throws for now', async () => {
|
it('existing config w/ spaces in key, throws for now', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
@ -255,7 +251,7 @@ describe('authutil tests', () => {
|
|||||||
fs.writeFileSync(inputNuGetConfigPath, spaceNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, spaceNuGetConfig);
|
||||||
let thrown = false;
|
let thrown = false;
|
||||||
try {
|
try {
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -266,7 +262,7 @@ describe('authutil tests', () => {
|
|||||||
expect(thrown).toBe(true);
|
expect(thrown).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
it('existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigDirectory: string = path.join(
|
const inputNuGetConfigDirectory: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
@ -278,7 +274,7 @@ describe('authutil tests', () => {
|
|||||||
);
|
);
|
||||||
fs.mkdirSync(inputNuGetConfigDirectory, {recursive: true});
|
fs.mkdirSync(inputNuGetConfigDirectory, {recursive: true});
|
||||||
fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://nuget.pkg.github.com/OwnerName/index.json',
|
'https://nuget.pkg.github.com/OwnerName/index.json',
|
||||||
'subfolder/nuget.config',
|
'subfolder/nuget.config',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -289,14 +285,14 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
it('existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, azureartifactsNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, azureartifactsNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
|
'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -307,14 +303,14 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
it('existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
const inputNuGetConfigPath: string = path.join(
|
const inputNuGetConfigPath: string = path.join(
|
||||||
fakeSourcesDirForTesting,
|
fakeSourcesDirForTesting,
|
||||||
'nuget.config'
|
'nuget.config'
|
||||||
);
|
);
|
||||||
fs.writeFileSync(inputNuGetConfigPath, azureartifactsnugetorgNuGetConfig);
|
fs.writeFileSync(inputNuGetConfigPath, azureartifactsnugetorgNuGetConfig);
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
|
'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
@ -325,9 +321,9 @@ describe('authutil tests', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('No existing config, sets up a full NuGet.config with URL and token for other source', async () => {
|
it('no existing config, sets up a full NuGet.config with URL and token for other source', async () => {
|
||||||
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
|
||||||
await auth.configAuthentication(
|
auth.configAuthentication(
|
||||||
'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
|
'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json',
|
||||||
'',
|
'',
|
||||||
fakeSourcesDirForTesting
|
fakeSourcesDirForTesting
|
||||||
|
@ -1,23 +1,45 @@
|
|||||||
import fs = require('fs');
|
import cscFile from '../.github/csc.json';
|
||||||
|
|
||||||
describe('csc tests', () => {
|
describe('csc tests', () => {
|
||||||
it('Valid regular expression', async () => {
|
test('regular expression in csc.json is valid', async () => {
|
||||||
var cscFile = require('../.github/csc.json');
|
const regexPattern = cscFile['problemMatcher'][0]['pattern'][0]['regexp'];
|
||||||
var regex = cscFile['problemMatcher'][0]['pattern'][0]['regexp'];
|
const regexResultsMap = cscFile['problemMatcher'][0]['pattern'][0];
|
||||||
|
|
||||||
console.log(regex);
|
const regex = new RegExp(regexPattern);
|
||||||
var re = new RegExp(regex);
|
|
||||||
|
|
||||||
// Ideally we would verify that this
|
const stringsToMatch = [
|
||||||
var stringsToMatch = [
|
|
||||||
'Program.cs(10,79): error CS1002: ; expected [/Users/zacharyeisinger/Documents/repo/setup-dotnet/__tests__/sample-broken-csproj/sample.csproj]',
|
'Program.cs(10,79): error CS1002: ; expected [/Users/zacharyeisinger/Documents/repo/setup-dotnet/__tests__/sample-broken-csproj/sample.csproj]',
|
||||||
"S:\\Msbuild\\src\\Build\\Evaluation\\ExpressionShredder.cs(33,7): error CS1003: Syntax error, ',' expected [S:\\msbuild\\src\\Build\\Microsoft.Build.csproj > Properties:prop]"
|
"S:\\Msbuild\\src\\Build\\Evaluation\\ExpressionShredder.cs(33,7): error CS1003: Syntax error, ',' expected [S:\\msbuild\\src\\Build\\Microsoft.Build.csproj > Properties:prop]"
|
||||||
];
|
];
|
||||||
|
// Expected results are calculated according to the csc matcher located in csc.json file
|
||||||
|
const expectedResults = [
|
||||||
|
{
|
||||||
|
file: 'Program.cs',
|
||||||
|
line: '10',
|
||||||
|
severity: 'error',
|
||||||
|
code: 'CS1002',
|
||||||
|
message: '; expected',
|
||||||
|
fromPath:
|
||||||
|
'/Users/zacharyeisinger/Documents/repo/setup-dotnet/__tests__/sample-broken-csproj/sample.csproj'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: 'S:\\Msbuild\\src\\Build\\Evaluation\\ExpressionShredder.cs',
|
||||||
|
line: '33',
|
||||||
|
severity: 'error',
|
||||||
|
code: 'CS1003',
|
||||||
|
message: "Syntax error, ',' expected",
|
||||||
|
fromPath:
|
||||||
|
'S:\\msbuild\\src\\Build\\Microsoft.Build.csproj > Properties:prop'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
stringsToMatch.forEach(string => {
|
stringsToMatch.map((string, index) => {
|
||||||
var matchStr = string.match(re);
|
const matchedResultsArray = string.match(regex);
|
||||||
console.log(matchStr);
|
for (const propName in expectedResults[index]) {
|
||||||
expect(matchStr).toEqual(expect.anything());
|
const propertyIndex = regexResultsMap[propName];
|
||||||
|
const expectedPropValue = expectedResults[index][propName];
|
||||||
|
const matchedPropValue = matchedResultsArray![propertyIndex];
|
||||||
|
expect(matchedPropValue).toEqual(expectedPropValue);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, 10000);
|
}, 10000);
|
||||||
});
|
});
|
||||||
|
18
__tests__/e2e-test-csproj/Test.cs
Normal file
18
__tests__/e2e-test-csproj/Test.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace test_csproj
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class Test
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestMethod()
|
||||||
|
{
|
||||||
|
Console.WriteLine("TestMethod");
|
||||||
|
int calculatedResult = 1000 / 25;
|
||||||
|
int expectedResult = 40;
|
||||||
|
Assert.AreEqual(calculatedResult, expectedResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
__tests__/e2e-test-csproj/test.csproj
Normal file
15
__tests__/e2e-test-csproj/test.csproj
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>$(TEST_TARGET_FRAMEWORK)</TargetFramework>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- These packages will be downloaded over the network for testing proxy settings -->
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20170810-02" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="1.1.18" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="1.1.18" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
65
__tests__/installation-scripts.test.ts
Normal file
65
__tests__/installation-scripts.test.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import * as hc from '@actions/http-client';
|
||||||
|
|
||||||
|
const HTTP_CLIENT_OPTIONS = {allowRetries: true, maxRetries: 10} as const;
|
||||||
|
const TEST_TIMEOUT = 30000;
|
||||||
|
|
||||||
|
describe('Dotnet installation scripts tests', () => {
|
||||||
|
it(
|
||||||
|
'Uses an up to date bash download script',
|
||||||
|
async () => {
|
||||||
|
const httpCallbackClient = new hc.HttpClient(
|
||||||
|
'setup-dotnet-test',
|
||||||
|
[],
|
||||||
|
HTTP_CLIENT_OPTIONS
|
||||||
|
);
|
||||||
|
const response: hc.HttpClientResponse = await httpCallbackClient.get(
|
||||||
|
'https://dot.net/v1/dotnet-install.sh'
|
||||||
|
);
|
||||||
|
expect(response.message.statusCode).toBe(200);
|
||||||
|
const upToDateContents: string = await response.readBody();
|
||||||
|
const currentContents: string = fs
|
||||||
|
.readFileSync(
|
||||||
|
path.join(__dirname, '..', 'externals', 'install-dotnet.sh')
|
||||||
|
)
|
||||||
|
.toString();
|
||||||
|
expect(normalizeFileContents(currentContents)).toBe(
|
||||||
|
normalizeFileContents(upToDateContents)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
TEST_TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
'Uses an up to date powershell download script',
|
||||||
|
async () => {
|
||||||
|
const httpCallbackClient = new hc.HttpClient(
|
||||||
|
'setup-dotnet-test',
|
||||||
|
[],
|
||||||
|
HTTP_CLIENT_OPTIONS
|
||||||
|
);
|
||||||
|
const response: hc.HttpClientResponse = await httpCallbackClient.get(
|
||||||
|
'https://dot.net/v1/dotnet-install.ps1'
|
||||||
|
);
|
||||||
|
expect(response.message.statusCode).toBe(200);
|
||||||
|
const upToDateContents: string = await response.readBody();
|
||||||
|
const currentContents: string = fs
|
||||||
|
.readFileSync(
|
||||||
|
path.join(__dirname, '..', 'externals', 'install-dotnet.ps1')
|
||||||
|
)
|
||||||
|
.toString();
|
||||||
|
expect(normalizeFileContents(currentContents)).toBe(
|
||||||
|
normalizeFileContents(upToDateContents)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
TEST_TIMEOUT
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function normalizeFileContents(contents: string): string {
|
||||||
|
return contents
|
||||||
|
.trim()
|
||||||
|
.replace(new RegExp('\r\n', 'g'), '\n')
|
||||||
|
.replace(new RegExp('\r', 'g'), '\n');
|
||||||
|
}
|
@ -1,151 +1,443 @@
|
|||||||
import io = require('@actions/io');
|
import each from 'jest-each';
|
||||||
import fs = require('fs');
|
import semver from 'semver';
|
||||||
import os = require('os');
|
import * as exec from '@actions/exec';
|
||||||
import path = require('path');
|
import * as core from '@actions/core';
|
||||||
import hc = require('@actions/http-client');
|
import * as io from '@actions/io';
|
||||||
|
|
||||||
const toolDir = path.join(__dirname, 'runner', 'tools');
|
|
||||||
const tempDir = path.join(__dirname, 'runner', 'temp');
|
|
||||||
|
|
||||||
process.env['RUNNER_TOOL_CACHE'] = toolDir;
|
|
||||||
process.env['RUNNER_TEMP'] = tempDir;
|
|
||||||
import * as installer from '../src/installer';
|
import * as installer from '../src/installer';
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
import {IS_WINDOWS} from '../src/utils';
|
||||||
|
import {QualityOptions} from '../src/setup-dotnet';
|
||||||
|
|
||||||
describe('installer tests', () => {
|
describe('installer tests', () => {
|
||||||
beforeAll(async () => {
|
const env = process.env;
|
||||||
process.env.RUNNER_TOOL_CACHE = toolDir;
|
|
||||||
process.env.DOTNET_INSTALL_DIR = toolDir;
|
beforeEach(() => {
|
||||||
process.env.RUNNER_TEMP = tempDir;
|
jest.resetModules();
|
||||||
process.env.DOTNET_ROOT = '';
|
process.env = {...env};
|
||||||
await io.rmRF(toolDir);
|
|
||||||
await io.rmRF(tempDir);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
describe('DotnetCoreInstaller tests', () => {
|
||||||
try {
|
const getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
await io.rmRF(toolDir);
|
const warningSpy = jest.spyOn(core, 'warning');
|
||||||
await io.rmRF(tempDir);
|
const whichSpy = jest.spyOn(io, 'which');
|
||||||
} catch {
|
const maxSatisfyingSpy = jest.spyOn(semver, 'maxSatisfying');
|
||||||
console.log('Failed to remove test directories');
|
|
||||||
}
|
|
||||||
}, 30000);
|
|
||||||
|
|
||||||
it('Aquires multiple versions of dotnet', async () => {
|
describe('installDotnet() tests', () => {
|
||||||
const versions = ['2.2.207', '3.1.120'];
|
whichSpy.mockImplementation(() => Promise.resolve('PathToShell'));
|
||||||
|
|
||||||
for (const version of versions) {
|
it('should throw the error in case of non-zero exit code of the installation script. The error message should contain logs.', async () => {
|
||||||
await getDotnet(version);
|
const inputVersion = '3.1.100';
|
||||||
}
|
const inputQuality = '' as QualityOptions;
|
||||||
expect(fs.existsSync(path.join(toolDir, 'sdk', '2.2.207'))).toBe(true);
|
const errorMessage = 'fictitious error message!';
|
||||||
expect(fs.existsSync(path.join(toolDir, 'sdk', '3.1.120'))).toBe(true);
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
if (IS_WINDOWS) {
|
exitCode: 1,
|
||||||
expect(fs.existsSync(path.join(toolDir, 'dotnet.exe'))).toBe(true);
|
stdout: '',
|
||||||
} else {
|
stderr: errorMessage
|
||||||
expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(process.env.DOTNET_ROOT).toBeDefined;
|
|
||||||
expect(process.env.PATH).toBeDefined;
|
|
||||||
expect(process.env.DOTNET_ROOT).toBe(toolDir);
|
|
||||||
expect(process.env.PATH?.startsWith(toolDir)).toBe(true);
|
|
||||||
}, 600000);
|
|
||||||
|
|
||||||
it('Acquires version of dotnet if no matching version is installed', async () => {
|
|
||||||
await getDotnet('3.1.201');
|
|
||||||
expect(fs.existsSync(path.join(toolDir, 'sdk', '3.1.201'))).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);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(process.env.DOTNET_ROOT).toBeDefined;
|
|
||||||
expect(process.env.PATH).toBeDefined;
|
|
||||||
expect(process.env.DOTNET_ROOT).toBe(toolDir);
|
|
||||||
expect(process.env.PATH?.startsWith(toolDir)).toBe(true);
|
|
||||||
}, 600000); //This needs some time to download on "slower" internet connections
|
|
||||||
|
|
||||||
it('Acquires generic version of dotnet if no matching version is installed', async () => {
|
|
||||||
await getDotnet('3.1');
|
|
||||||
var directory = fs
|
|
||||||
.readdirSync(path.join(toolDir, 'sdk'))
|
|
||||||
.filter(fn => fn.startsWith('3.1.'));
|
|
||||||
expect(directory.length > 0).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);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(process.env.DOTNET_ROOT).toBeDefined;
|
|
||||||
expect(process.env.PATH).toBeDefined;
|
|
||||||
expect(process.env.DOTNET_ROOT).toBe(toolDir);
|
|
||||||
expect(process.env.PATH?.startsWith(toolDir)).toBe(true);
|
|
||||||
}, 600000); //This needs some time to download on "slower" internet connections
|
|
||||||
|
|
||||||
it('Throws if no location contains correct dotnet version', async () => {
|
|
||||||
let thrown = false;
|
|
||||||
try {
|
|
||||||
await getDotnet('1000.0.0');
|
|
||||||
} catch {
|
|
||||||
thrown = true;
|
|
||||||
}
|
|
||||||
expect(thrown).toBe(true);
|
|
||||||
}, 30000);
|
|
||||||
|
|
||||||
it('Uses an up to date bash download script', async () => {
|
|
||||||
const httpCallbackClient = new hc.HttpClient('setup-dotnet-test', [], {
|
|
||||||
allowRetries: true,
|
|
||||||
maxRetries: 3
|
|
||||||
});
|
});
|
||||||
const response: hc.HttpClientResponse = await httpCallbackClient.get(
|
|
||||||
'https://dot.net/v1/dotnet-install.sh'
|
|
||||||
);
|
|
||||||
expect(response.message.statusCode).toBe(200);
|
|
||||||
const upToDateContents: string = await response.readBody();
|
|
||||||
const currentContents: string = fs
|
|
||||||
.readFileSync(
|
|
||||||
path.join(__dirname, '..', 'externals', 'install-dotnet.sh')
|
|
||||||
)
|
|
||||||
.toString();
|
|
||||||
expect(normalizeFileContents(currentContents)).toBe(
|
|
||||||
normalizeFileContents(upToDateContents)
|
|
||||||
);
|
|
||||||
}, 30000);
|
|
||||||
|
|
||||||
it('Uses an up to date powershell download script', async () => {
|
|
||||||
var httpCallbackClient = new hc.HttpClient('setup-dotnet-test', [], {
|
|
||||||
allowRetries: true,
|
|
||||||
maxRetries: 3
|
|
||||||
});
|
});
|
||||||
const response: hc.HttpClientResponse = await httpCallbackClient.get(
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
'https://dot.net/v1/dotnet-install.ps1'
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
);
|
);
|
||||||
expect(response.message.statusCode).toBe(200);
|
await expect(dotnetInstaller.installDotnet()).rejects.toThrow(
|
||||||
const upToDateContents: string = await response.readBody();
|
`Failed to install dotnet, exit code: 1. ${errorMessage}`
|
||||||
const currentContents: string = fs
|
|
||||||
.readFileSync(
|
|
||||||
path.join(__dirname, '..', 'externals', 'install-dotnet.ps1')
|
|
||||||
)
|
|
||||||
.toString();
|
|
||||||
expect(normalizeFileContents(currentContents)).toBe(
|
|
||||||
normalizeFileContents(upToDateContents)
|
|
||||||
);
|
);
|
||||||
}, 30000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function normalizeFileContents(contents: string): string {
|
it('should return version of .NET SDK after installation complete', async () => {
|
||||||
return contents
|
const inputVersion = '3.1.100';
|
||||||
.trim()
|
const inputQuality = '' as QualityOptions;
|
||||||
.replace(new RegExp('\r\n', 'g'), '\n')
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
.replace(new RegExp('\r', 'g'), '\n');
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
}
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
const installedVersion = await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
expect(installedVersion).toBe(inputVersion);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should supply 'version' argument to the installation script if supplied version is in A.B.C syntax`, async () => {
|
||||||
|
const inputVersion = '6.0.300';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
async function getDotnet(version: string): Promise<void> {
|
|
||||||
const dotnetInstaller = new installer.DotnetCoreInstaller(version);
|
|
||||||
await dotnetInstaller.installDotnet();
|
await dotnetInstaller.installDotnet();
|
||||||
installer.DotnetCoreInstaller.addToPath();
|
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[0][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
const expectedArgument = IS_WINDOWS
|
||||||
|
? `-Version ${inputVersion}`
|
||||||
|
: `--version ${inputVersion}`;
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(expectedArgument);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should warn if the 'quality' input is set and the supplied version is in A.B.C syntax`, async () => {
|
||||||
|
const inputVersion = '6.0.300';
|
||||||
|
const inputQuality = 'ga' as QualityOptions;
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
`The 'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A, A.x and A.B.Cxx formats where the major tag is higher than 5. You specified: ${inputVersion}. 'dotnet-quality' input is ignored.`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should warn if the 'quality' input is set and version isn't in A.B.C syntax but major tag is lower then 6`, async () => {
|
||||||
|
const inputVersion = '3.1';
|
||||||
|
const inputQuality = 'ga' as QualityOptions;
|
||||||
|
const stdout = `Fictitious dotnet version 3.1.100 is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
`The 'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A, A.x and A.B.Cxx formats where the major tag is higher than 5. You specified: ${inputVersion}. 'dotnet-quality' input is ignored.`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
each(['6', '6.0', '6.0.x', '6.0.*', '6.0.X']).test(
|
||||||
|
`should supply 'quality' argument to the installation script if quality input is set and version (%s) is not in A.B.C syntax`,
|
||||||
|
async inputVersion => {
|
||||||
|
const inputQuality = 'ga' as QualityOptions;
|
||||||
|
const exitCode = 0;
|
||||||
|
const stdout = `Fictitious dotnet version 6.0.0 is installed`;
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: exitCode,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[0][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
const expectedArgument = IS_WINDOWS
|
||||||
|
? `-Quality ${inputQuality}`
|
||||||
|
: `--quality ${inputQuality}`;
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(expectedArgument);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
each(['6', '6.0', '6.0.x', '6.0.*', '6.0.X']).test(
|
||||||
|
`should supply 'channel' argument to the installation script if version (%s) isn't in A.B.C syntax`,
|
||||||
|
async inputVersion => {
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const exitCode = 0;
|
||||||
|
const stdout = `Fictitious dotnet version 6.0.0 is installed`;
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: exitCode,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[0][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
const expectedArgument = IS_WINDOWS
|
||||||
|
? `-Channel 6.0`
|
||||||
|
: `--channel 6.0`;
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(expectedArgument);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
it(`should supply '-ProxyAddress' argument to the installation script if env.variable 'https_proxy' is set`, async () => {
|
||||||
|
process.env['https_proxy'] = 'https://proxy.com';
|
||||||
|
const inputVersion = '6.0.100';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const stdout = `Fictitious dotnet version ${inputVersion} is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[0][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(
|
||||||
|
`-ProxyAddress ${process.env['https_proxy']}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should supply '-ProxyBypassList' argument to the installation script if env.variable 'no_proxy' is set`, async () => {
|
||||||
|
process.env['no_proxy'] = 'first.url,second.url';
|
||||||
|
const inputVersion = '6.0.100';
|
||||||
|
const inputQuality = '' as QualityOptions;
|
||||||
|
const stdout = `Fictitious dotnet version 6.0.0 is installed`;
|
||||||
|
|
||||||
|
getExecOutputSpy.mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: `${stdout}`,
|
||||||
|
stderr: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => inputVersion);
|
||||||
|
|
||||||
|
const dotnetInstaller = new installer.DotnetCoreInstaller(
|
||||||
|
inputVersion,
|
||||||
|
inputQuality
|
||||||
|
);
|
||||||
|
|
||||||
|
await dotnetInstaller.installDotnet();
|
||||||
|
|
||||||
|
const scriptArguments = (
|
||||||
|
getExecOutputSpy.mock.calls[0][1] as string[]
|
||||||
|
).join(' ');
|
||||||
|
|
||||||
|
expect(scriptArguments).toContain(
|
||||||
|
`-ProxyBypassList ${process.env['no_proxy']}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addToPath() tests', () => {
|
||||||
|
it(`should export DOTNET_ROOT env.var with value from DOTNET_INSTALL_DIR env.var`, async () => {
|
||||||
|
process.env['DOTNET_INSTALL_DIR'] = 'fictitious/dotnet/install/dir';
|
||||||
|
installer.DotnetCoreInstaller.addToPath();
|
||||||
|
const dotnet_root = process.env['DOTNET_ROOT'];
|
||||||
|
expect(dotnet_root).toBe(process.env['DOTNET_INSTALL_DIR']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should export value from DOTNET_INSTALL_DIR env.var to the PATH`, async () => {
|
||||||
|
process.env['DOTNET_INSTALL_DIR'] = 'fictitious/dotnet/install/dir';
|
||||||
|
installer.DotnetCoreInstaller.addToPath();
|
||||||
|
const path = process.env['PATH'];
|
||||||
|
expect(path).toContain(process.env['DOTNET_INSTALL_DIR']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DotnetVersionResolver tests', () => {
|
||||||
|
describe('createDotNetVersion() tests', () => {
|
||||||
|
each([
|
||||||
|
'3.1',
|
||||||
|
'3.x',
|
||||||
|
'3.1.x',
|
||||||
|
'3.1.*',
|
||||||
|
'3.1.X',
|
||||||
|
'3.1.2',
|
||||||
|
'3.1.0-preview1',
|
||||||
|
'6.0.2xx'
|
||||||
|
]).test(
|
||||||
|
'if valid version is supplied (%s), it should return version object with some value',
|
||||||
|
async version => {
|
||||||
|
const dotnetVersionResolver = new installer.DotnetVersionResolver(
|
||||||
|
version
|
||||||
|
);
|
||||||
|
const versionObject =
|
||||||
|
await dotnetVersionResolver.createDotNetVersion();
|
||||||
|
|
||||||
|
expect(!!versionObject.value).toBe(true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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 is supplied (%s), it should throw',
|
||||||
|
async version => {
|
||||||
|
const dotnetVersionResolver = new installer.DotnetVersionResolver(
|
||||||
|
version
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
async () => await dotnetVersionResolver.createDotNetVersion()
|
||||||
|
).rejects.toThrow();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
each(['3', '3.1', '3.1.x', '3.1.*', '3.1.X', '6.0.2xx']).test(
|
||||||
|
"if version that can be resolved to 'channel' option is supplied (%s), it should set 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')).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
each(['6.0', '6.0.x', '6.0.*', '6.0.X', '6.0.2xx']).test(
|
||||||
|
"if version that can be resolved to 'channel' option is supplied and its major tag is >= 6 (%s), it should set type to 'channel' and qualityFlag to 'true' in version object",
|
||||||
|
async version => {
|
||||||
|
const dotnetVersionResolver = new installer.DotnetVersionResolver(
|
||||||
|
version
|
||||||
|
);
|
||||||
|
const versionObject =
|
||||||
|
await dotnetVersionResolver.createDotNetVersion();
|
||||||
|
|
||||||
|
expect(versionObject.type.toLowerCase().includes('channel')).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(versionObject.qualityFlag).toBe(true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
each(['3.1.2', '3.1.0-preview1']).test(
|
||||||
|
"if version that can be resolved to 'version' option is supplied (%s), 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')).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(versionObject.qualityFlag).toBe(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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(/^-(Version|Channel)/);
|
||||||
|
const nonWindowsRegEx = new RegExp(/^--(version|channel)/);
|
||||||
|
|
||||||
|
if (IS_WINDOWS) {
|
||||||
|
expect(windowsRegEx.test(versionObject.type)).toBe(true);
|
||||||
|
expect(nonWindowsRegEx.test(versionObject.type)).toBe(false);
|
||||||
|
} else {
|
||||||
|
expect(nonWindowsRegEx.test(versionObject.type)).toBe(true);
|
||||||
|
expect(windowsRegEx.test(versionObject.type)).toBe(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(`should throw if dotnet-version is supplied in A.B.Cxx syntax with major tag lower that 5`, async () => {
|
||||||
|
const version = '3.0.1xx';
|
||||||
|
const dotnetVersionResolver = new installer.DotnetVersionResolver(
|
||||||
|
version
|
||||||
|
);
|
||||||
|
await expect(
|
||||||
|
async () => await dotnetVersionResolver.createDotNetVersion()
|
||||||
|
).rejects.toThrow(
|
||||||
|
`'dotnet-version' was supplied in invalid format: ${version}! The A.B.Cxx syntax is available since the .NET 5.0 release.`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace sample_csproj
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
public void TestMethod1()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Hello, World!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>netcoreapp3.1;netcoreapp3.0;netcoreapp2.2</TargetFrameworks>
|
|
||||||
<RootNamespace>sample_csproj</RootNamespace>
|
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<!-- These packages will be downloaded over the network for testing proxy settings -->
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
|
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
|
|
||||||
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,71 +1,173 @@
|
|||||||
import io = require('@actions/io');
|
import * as core from '@actions/core';
|
||||||
import fs = require('fs');
|
import fs from 'fs';
|
||||||
import os = require('os');
|
import semver from 'semver';
|
||||||
import path = require('path');
|
import * as auth from '../src/authutil';
|
||||||
|
|
||||||
const toolDir = path.join(__dirname, 'runner', 'tools2');
|
|
||||||
const tempDir = path.join(__dirname, 'runner', 'temp2');
|
|
||||||
|
|
||||||
import * as setup from '../src/setup-dotnet';
|
import * as setup from '../src/setup-dotnet';
|
||||||
import * as dotnetInstaller from '../src/installer';
|
import {DotnetCoreInstaller} from '../src/installer';
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
|
||||||
|
|
||||||
describe('setup-dotnet tests', () => {
|
describe('setup-dotnet tests', () => {
|
||||||
beforeAll(async () => {
|
const inputs = {} as any;
|
||||||
process.env.RUNNER_TOOL_CACHE = toolDir;
|
|
||||||
process.env.DOTNET_INSTALL_DIR = toolDir;
|
|
||||||
process.env.RUNNER_TEMP = tempDir;
|
|
||||||
process.env['INPUT_INCLUDE-PRERELEASE'] = 'false';
|
|
||||||
await io.rmRF(toolDir);
|
|
||||||
await io.rmRF(tempDir);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
const getInputSpy = jest.spyOn(core, 'getInput');
|
||||||
try {
|
const getMultilineInputSpy = jest.spyOn(core, 'getMultilineInput');
|
||||||
await io.rmRF(path.join(process.cwd(), 'global.json'));
|
const setFailedSpy = jest.spyOn(core, 'setFailed');
|
||||||
await io.rmRF(toolDir);
|
const warningSpy = jest.spyOn(core, 'warning');
|
||||||
await io.rmRF(tempDir);
|
const debugSpy = jest.spyOn(core, 'debug');
|
||||||
} catch {
|
const infoSpy = jest.spyOn(core, 'info');
|
||||||
console.log('Failed to remove test directories');
|
const setOutputSpy = jest.spyOn(core, 'setOutput');
|
||||||
}
|
|
||||||
}, 30000);
|
|
||||||
|
|
||||||
it('Acquires version of dotnet from global.json if no matching version is installed', async () => {
|
const existsSyncSpy = jest.spyOn(fs, 'existsSync');
|
||||||
const globalJsonPath = path.join(process.cwd(), 'global.json');
|
|
||||||
const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version": "3.1.201"${os.EOL}}${os.EOL}}`;
|
|
||||||
if (!fs.existsSync(globalJsonPath)) {
|
|
||||||
fs.writeFileSync(globalJsonPath, jsonContents);
|
|
||||||
}
|
|
||||||
await setup.run();
|
|
||||||
|
|
||||||
expect(fs.existsSync(path.join(toolDir, 'sdk', '3.1.201'))).toBe(true);
|
const maxSatisfyingSpy = jest.spyOn(semver, 'maxSatisfying');
|
||||||
if (IS_WINDOWS) {
|
|
||||||
expect(fs.existsSync(path.join(toolDir, 'dotnet.exe'))).toBe(true);
|
|
||||||
} else {
|
|
||||||
expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true);
|
|
||||||
}
|
|
||||||
}, 400000);
|
|
||||||
|
|
||||||
it('Acquires version of dotnet from global.json with rollForward option, install the latest patch', async () => {
|
const installDotnetSpy = jest.spyOn(
|
||||||
const globalJsonPath = path.join(process.cwd(), 'global.json');
|
DotnetCoreInstaller.prototype,
|
||||||
const jsonContents = `{${os.EOL}"sdk": {${os.EOL}"version":"3.1.201",${os.EOL}"rollForward":"latestFeature"${os.EOL}}${os.EOL}}`;
|
'installDotnet'
|
||||||
if (!fs.existsSync(globalJsonPath)) {
|
|
||||||
fs.writeFileSync(globalJsonPath, jsonContents);
|
|
||||||
}
|
|
||||||
|
|
||||||
const version = '3.1';
|
|
||||||
const installer = new dotnetInstaller.DotnetCoreInstaller(version);
|
|
||||||
const patchVersion = await installer.resolveVersion(
|
|
||||||
new dotnetInstaller.DotNetVersionInfo(version)
|
|
||||||
);
|
);
|
||||||
|
const addToPathSpy = jest.spyOn(DotnetCoreInstaller, 'addToPath');
|
||||||
|
|
||||||
|
const configAuthenticationSpy = jest.spyOn(auth, 'configAuthentication');
|
||||||
|
|
||||||
|
describe('run() tests', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
getMultilineInputSpy.mockImplementation(input => inputs[input as string]);
|
||||||
|
getInputSpy.mockImplementation(input => inputs[input as string]);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail the action if global-json-file input is present, but the file does not exist in the file system', async () => {
|
||||||
|
inputs['global-json-file'] = 'fictitious.json';
|
||||||
|
inputs['dotnet-version'] = [];
|
||||||
|
|
||||||
|
const expectedErrorMessage = `The specified global.json file '${inputs['global-json-file']}' does not exist`;
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(`if 'dotnet-version' and 'global-json-file' inputs aren't present, should log into debug output, try to find global.json in the repo root, fail and log message into info output`, async () => {
|
||||||
|
inputs['global-json-file'] = '';
|
||||||
|
inputs['dotnet-version'] = [];
|
||||||
|
|
||||||
|
maxSatisfyingSpy.mockImplementation(() => null);
|
||||||
|
setOutputSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const expectedDebugMessage =
|
||||||
|
'No version found, trying to find version from global.json';
|
||||||
|
const expectedInfoMessage = `The global.json wasn't found in the root directory. No .NET version will be installed.`;
|
||||||
|
|
||||||
await setup.run();
|
await setup.run();
|
||||||
|
|
||||||
expect(fs.existsSync(path.join(toolDir, 'sdk', patchVersion))).toBe(true);
|
expect(debugSpy).toHaveBeenCalledWith(expectedDebugMessage);
|
||||||
if (IS_WINDOWS) {
|
expect(existsSyncSpy).toHaveBeenCalled();
|
||||||
expect(fs.existsSync(path.join(toolDir, 'dotnet.exe'))).toBe(true);
|
expect(infoSpy).toHaveBeenCalledWith(expectedInfoMessage);
|
||||||
} else {
|
});
|
||||||
expect(fs.existsSync(path.join(toolDir, 'dotnet'))).toBe(true);
|
|
||||||
}
|
it('should fail the action if quality is supplied but its value is not supported', async () => {
|
||||||
}, 400000);
|
inputs['global-json-file'] = '';
|
||||||
|
inputs['dotnet-version'] = ['6.0'];
|
||||||
|
inputs['dotnet-quality'] = 'fictitiousQuality';
|
||||||
|
|
||||||
|
const expectedErrorMessage = `Value '${inputs['dotnet-quality']}' is not supported for the 'dotnet-quality' option. Supported values are: daily, signed, validated, preview, ga.`;
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call installDotnet() multiple times if dotnet-version multiline input is provided', async () => {
|
||||||
|
inputs['global-json-file'] = '';
|
||||||
|
inputs['dotnet-version'] = ['6.0', '7.0'];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
|
||||||
|
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(installDotnetSpy).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call addToPath() after installation complete', async () => {
|
||||||
|
inputs['global-json-file'] = '';
|
||||||
|
inputs['dotnet-version'] = ['6.0', '7.0'];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
|
||||||
|
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
|
||||||
|
addToPathSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(addToPathSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call auth.configAuthentication() if source-url input is provided', async () => {
|
||||||
|
inputs['global-json-file'] = '';
|
||||||
|
inputs['dotnet-version'] = [];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
inputs['source-url'] = 'fictitious.source.url';
|
||||||
|
|
||||||
|
configAuthenticationSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(configAuthenticationSpy).toHaveBeenCalledWith(
|
||||||
|
inputs['source-url'],
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call auth.configAuthentication() with proper parameters if source-url and config-file inputs are provided', async () => {
|
||||||
|
inputs['global-json-file'] = '';
|
||||||
|
inputs['dotnet-version'] = [];
|
||||||
|
inputs['dotnet-quality'] = '';
|
||||||
|
inputs['source-url'] = 'fictitious.source.url';
|
||||||
|
inputs['config-file'] = 'fictitious.path';
|
||||||
|
|
||||||
|
configAuthenticationSpy.mockImplementation(() => {});
|
||||||
|
setOutputSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(configAuthenticationSpy).toHaveBeenCalledWith(
|
||||||
|
inputs['source-url'],
|
||||||
|
inputs['config-file']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setOutput() after installation complete successfully', async () => {
|
||||||
|
inputs['dotnet-version'] = ['6.0.300'];
|
||||||
|
|
||||||
|
installDotnetSpy.mockImplementation(() =>
|
||||||
|
Promise.resolve(`${inputs['dotnet-version']}`)
|
||||||
|
);
|
||||||
|
addToPathSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`shouldn't call setOutput() if parsing dotnet-installer logs failed`, async () => {
|
||||||
|
inputs['dotnet-version'] = ['6.0.300'];
|
||||||
|
const warningMessage = `Failed to output the installed version of .NET. The 'dotnet-version' output will not be set.`;
|
||||||
|
|
||||||
|
installDotnetSpy.mockImplementation(() => Promise.resolve(null));
|
||||||
|
addToPathSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(warningMessage);
|
||||||
|
expect(setOutputSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`shouldn't call setOutput() if actions didn't install .NET`, async () => {
|
||||||
|
inputs['dotnet-version'] = [];
|
||||||
|
const warningMessage = `The 'dotnet-version' output will not be set.`;
|
||||||
|
|
||||||
|
addToPathSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
await setup.run();
|
||||||
|
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith(warningMessage);
|
||||||
|
expect(setOutputSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,73 +1,117 @@
|
|||||||
if (!$args[0])
|
<#
|
||||||
{
|
.DESCRIPTION
|
||||||
throw "Must supply dotnet version argument"
|
Verifies that installed on the machine .NET SDK versions match the input patterns.
|
||||||
|
Optionally checks that the nuget.config file is generated correctly.
|
||||||
|
|
||||||
|
.PARAMETER Patterns
|
||||||
|
Specifies the regular expression patterns that should be matched with the installed
|
||||||
|
on the machine .NET SDK versions. The number of patterns should be equal to the number
|
||||||
|
of installed .NET versions.
|
||||||
|
|
||||||
|
.PARAMETER CheckNugetConfig
|
||||||
|
Switches the check for the existence of the nuget.config file.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
PS> .\verify-dotnet.ps1 -Paterns "^3.1.200$", "^6.0" -CheckNugetConfig
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string[]]$Patterns,
|
||||||
|
[switch]$CheckNugetConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
$PatternsList = [System.Collections.ArrayList]($Patterns)
|
||||||
|
|
||||||
|
if ($CheckNugetConfig.IsPresent -and !(Test-Path "../nuget.config")) {
|
||||||
|
throw "The nuget.config file is not generated correctly."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Write-Host "These patterns were supplied to the script: $($PatternsList -join ', ')."
|
||||||
$dotnet = Get-Command dotnet | Select-Object -First 1 | ForEach-Object { $_.Path }
|
$dotnet = Get-Command dotnet | Select-Object -First 1 | ForEach-Object { $_.Path }
|
||||||
Write-Host "Found '$dotnet'"
|
Write-Host "Found: '$dotnet'"
|
||||||
|
|
||||||
if($args.count -eq 1)
|
|
||||||
{
|
|
||||||
$version = & $dotnet --version | Out-String | ForEach-Object { $_.Trim() }
|
|
||||||
Write-Host "Version $version"
|
|
||||||
if (-not ($version.StartsWith($args[0].ToString())))
|
|
||||||
{
|
|
||||||
Write-Host "PATH='$env:PATH'"
|
|
||||||
throw "Unexpected version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($args[1])
|
|
||||||
{
|
|
||||||
# SDKs are listed on multiple lines with the path afterwards in square brackets
|
# SDKs are listed on multiple lines with the path afterwards in square brackets
|
||||||
$versions = & $dotnet --list-sdks | ForEach-Object { $_.SubString(0, $_.IndexOf('[')).Trim() }
|
$Versions = & $dotnet --list-sdks | ForEach-Object { $_.SubString(0, $_.IndexOf('[')).Trim() }
|
||||||
Write-Host "Installed versions: $versions"
|
Write-Host "Found installed versions: $($Versions -join ', ')."
|
||||||
$InstalledVersionCount = 0
|
$InstalledVersionCount = $Versions.Count
|
||||||
foreach($arg in $args){
|
|
||||||
foreach ($version in $versions)
|
foreach($version in $Versions)
|
||||||
{
|
{
|
||||||
if ($version.StartsWith($arg.ToString()))
|
foreach($pattern in $PatternsList)
|
||||||
{
|
{
|
||||||
$InstalledVersionCount++
|
if ($version -match $pattern)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( $InstalledVersionCount -ne $args.Count)
|
|
||||||
{
|
{
|
||||||
Write-Host "PATH='$env:PATH'"
|
$PatternsList.Remove($pattern)
|
||||||
throw "Unexpected version"
|
$InstalledVersionCount--
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Building sample csproj"
|
if ( $InstalledVersionCount -ne 0)
|
||||||
& $dotnet build __tests__/sample-csproj/ --no-cache
|
{
|
||||||
|
throw "An unexpected version of Dotnet is found on the machine, please check the correctness of the -Patterns input."
|
||||||
|
}
|
||||||
|
|
||||||
|
$workingDir = Get-Location
|
||||||
|
$testProjectDir = "./__tests__/e2e-test-csproj"
|
||||||
|
Write-Host "Changing directory to the $testProjectDir"
|
||||||
|
Set-Location $testProjectDir
|
||||||
|
|
||||||
|
$targetFrameworkVersionMap = @{
|
||||||
|
"1.0" = "netcoreapp1.0";
|
||||||
|
"1.1" = "netcoreapp1.1";
|
||||||
|
"2.0" = "netcoreapp2.0";
|
||||||
|
"2.1" = "netcoreapp2.1";
|
||||||
|
"2.2" = "netcoreapp2.2";
|
||||||
|
"3.0" = "netcoreapp3.0";
|
||||||
|
"3.1" = "netcoreapp3.1";
|
||||||
|
"5.0" = "net5.0";
|
||||||
|
"6.0" = "net6.0";
|
||||||
|
"7.0" = "net7.0";
|
||||||
|
"8.0" = "net8.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($version in $Versions)
|
||||||
|
{
|
||||||
|
# Creating temporary global.json file inside e2e-test-csproj dir and setting exact version of .NET inside allows to override default behavior of .NET and run build and tests on that exact version.
|
||||||
|
Write-Host "Creating temporary global.json file for $version .NET version."
|
||||||
|
& $dotnet new globaljson --sdk-version $version --force | Out-Null
|
||||||
|
if (!(Test-Path "./global.json"))
|
||||||
|
{
|
||||||
|
throw "An error occured while creating the global.json file. Exit code: $LASTEXITCODE"
|
||||||
|
}
|
||||||
|
Write-Host "The global.json file for the version $version is created. Currently used .NET version is: $(& $dotnet --version)."
|
||||||
|
|
||||||
|
# Environment variable TEST_TARGET_FRAMEWORK is used inside the test.csproj file to target required framework version
|
||||||
|
$version -match "^(?<key>\d+\.\d+)" | Out-Null
|
||||||
|
if (!($targetFrameworkVersionMap.ContainsKey($Matches.key)))
|
||||||
|
{
|
||||||
|
throw "The map with the framework targets doesn't contain a target name for the version $version."
|
||||||
|
}
|
||||||
|
Write-Host "Setting the TEST_TARGET_FRAMEWORK environment variable to $($targetFrameworkVersionMap[$Matches.key])"
|
||||||
|
[Environment]::SetEnvironmentVariable('TEST_TARGET_FRAMEWORK', $($targetFrameworkVersionMap[$Matches.key]))
|
||||||
|
|
||||||
|
Write-Host "Building test C# project with $version .NET version."
|
||||||
|
& $dotnet build --no-cache
|
||||||
if ($LASTEXITCODE -ne 0)
|
if ($LASTEXITCODE -ne 0)
|
||||||
{
|
{
|
||||||
throw "Unexpected exit code $LASTEXITCODE"
|
throw "Building process is not successful, exit code: $LASTEXITCODE"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Testing compiled app"
|
Write-Host "Testing compiled C# project with $version .NET version."
|
||||||
$sample_output = "$(dotnet test __tests__/sample-csproj/ --no-build)"
|
& $dotnet test --no-build
|
||||||
Write-Host "Sample output: $sample_output"
|
if ($LASTEXITCODE -ne 0)
|
||||||
# For Side-by-Side installs we want to run the tests twice, for a single install the tests will run once
|
|
||||||
if ($args[1])
|
|
||||||
{
|
{
|
||||||
if ($sample_output -notlike "*Test Run Successful.*Test Run Successful.*")
|
throw "Testing process is not successful, exit code: $LASTEXITCODE"
|
||||||
{
|
|
||||||
throw "Unexpected output"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($args[2])
|
|
||||||
{
|
|
||||||
if ($sample_output -notlike "*Test Run Successful.*Test Run Successful.*Test Run Successful.*")
|
|
||||||
{
|
|
||||||
throw "Unexpected output"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($sample_output -notlike "*Test Run Successful.*")
|
|
||||||
{
|
|
||||||
throw "Unexpected output"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Write-Host "Tests are completed successfully!"
|
||||||
|
|
||||||
|
Write-Host "Removing temporary global.json file."
|
||||||
|
Remove-Item ./global.json
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set-Location $workingDir
|
@ -1,44 +0,0 @@
|
|||||||
if [ -z "$1" ]; then
|
|
||||||
echo "Must supply dotnet version argument"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "../nuget.config" ]; then
|
|
||||||
echo "nuget file not generated correctly"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
dotnet_version="$(dotnet --version)"
|
|
||||||
echo "Found dotnet version '$dotnet_version'"
|
|
||||||
if [ -z "$(echo $dotnet_version | grep $1)" ]; then
|
|
||||||
echo "Unexpected version"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
dotnet_version="$(dotnet --list-sdks)"
|
|
||||||
echo "Found dotnet version '$dotnet_version'"
|
|
||||||
if [ -z "$(echo $dotnet_version | grep $2)" ]; then
|
|
||||||
echo "Unexpected version"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Building sample csproj"
|
|
||||||
dotnet build __tests__/sample-csproj/ --no-cache || exit 1
|
|
||||||
|
|
||||||
echo "Testing compiled app"
|
|
||||||
sample_output=$(dotnet test __tests__/sample-csproj/ --no-build)
|
|
||||||
echo "Sample output: $sample_output"
|
|
||||||
# For Side-by-Side installs we want to run the tests twice, for a single install the tests will run once
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
if [ -z "$(echo $sample_output | grep "Test Run Successful.*Test Run Successful.")" ]; then
|
|
||||||
echo "Unexpected output"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ -z "$(echo $sample_output | grep "Test Run Successful.")" ]; then
|
|
||||||
echo "Unexpected output"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ "$(git status --porcelain)" != "" ]]; then
|
|
||||||
echo ----------------------------------------
|
|
||||||
echo git status
|
|
||||||
echo ----------------------------------------
|
|
||||||
git status
|
|
||||||
echo ----------------------------------------
|
|
||||||
echo git diff
|
|
||||||
echo ----------------------------------------
|
|
||||||
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
|
|
||||||
fi
|
|
@ -1,91 +0,0 @@
|
|||||||
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);
|
|
||||||
});
|
|
11
action.yml
11
action.yml
@ -6,7 +6,9 @@ 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'
|
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, 6.0.2xx'
|
||||||
|
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:
|
||||||
@ -15,10 +17,9 @@ 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.'
|
||||||
include-prerelease:
|
outputs:
|
||||||
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.'
|
dotnet-version:
|
||||||
required: False
|
description: 'Contains the installed by action .NET SDK version for reuse.'
|
||||||
default: 'false'
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
10812
dist/index.js
vendored
10812
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
@ -61,12 +61,13 @@ Pull requests are the easiest way to contribute changes to git repos at GitHub.
|
|||||||
|
|
||||||
- To implement new features or fix bugs, you need to make changes to the `.ts` files, which are located in the `src` folder
|
- To implement new features or fix bugs, you need to make changes to the `.ts` files, which are located in the `src` folder
|
||||||
- To comply with the code style, **you need to run the `format` script**
|
- To comply with the code style, **you need to run the `format` script**
|
||||||
|
- To lint the code, **you need to run the `lint:fix` script**
|
||||||
- To transpile source code to `javascript` we use [NCC](https://github.com/vercel/ncc). **It is very important to run the `build` script after making changes**, otherwise your changes will not get into the final `javascript` build
|
- To transpile source code to `javascript` we use [NCC](https://github.com/vercel/ncc). **It is very important to run the `build` script after making changes**, otherwise your changes will not get into the final `javascript` build
|
||||||
|
|
||||||
**Learn more about how to implement tests:**
|
**Learn more about how to implement tests:**
|
||||||
|
|
||||||
Adding or changing tests is an integral part of making a change to the code.
|
Adding or changing tests is an integral part of making a change to the code.
|
||||||
Unit tests are in the `__tests__` folder, and end-to-end tests are in the `workflows` folder, particularly in the [workflow.yml](https://github.com/actions/setup-dotnet/blob/main/.github/workflows/workflow.yml).
|
Unit tests are in the `__tests__` folder, and end-to-end tests are in the `workflows` folder, particularly in the [e2e-tests.yml](https://github.com/actions/setup-dotnet/blob/main/.github/workflows/e2e-tests.yml).
|
||||||
|
|
||||||
- The contributor can add various types of tests (like unit tests or end-to-end tests), which, in his opinion, will be necessary and sufficient for testing new or changed functionality
|
- The contributor can add various types of tests (like unit tests or end-to-end tests), which, in his opinion, will be necessary and sufficient for testing new or changed functionality
|
||||||
- Tests should cover a successful execution, as well as some edge cases and possible errors
|
- Tests should cover a successful execution, as well as some edge cases and possible errors
|
||||||
|
563
externals/install-dotnet.ps1
vendored
563
externals/install-dotnet.ps1
vendored
@ -72,12 +72,14 @@
|
|||||||
.PARAMETER Verbose
|
.PARAMETER Verbose
|
||||||
Displays diagnostics information.
|
Displays diagnostics information.
|
||||||
.PARAMETER AzureFeed
|
.PARAMETER AzureFeed
|
||||||
Default: https://builds.dotnet.microsoft.com/dotnet
|
Default: https://dotnetcli.azureedge.net/dotnet
|
||||||
For internal use only.
|
For internal use only.
|
||||||
Allows using a different storage to download SDK archives from.
|
Allows using a different storage to download SDK archives from.
|
||||||
|
This parameter is only used if $NoCdn is false.
|
||||||
.PARAMETER UncachedFeed
|
.PARAMETER UncachedFeed
|
||||||
For internal use only.
|
For internal use only.
|
||||||
Allows using a different storage to download SDK archives from.
|
Allows using a different storage to download SDK archives from.
|
||||||
|
This parameter is only used if $NoCdn is true.
|
||||||
.PARAMETER ProxyAddress
|
.PARAMETER ProxyAddress
|
||||||
If set, the installer will use the proxy when making web requests
|
If set, the installer will use the proxy when making web requests
|
||||||
.PARAMETER ProxyUseDefaultCredentials
|
.PARAMETER ProxyUseDefaultCredentials
|
||||||
@ -88,22 +90,14 @@
|
|||||||
.PARAMETER SkipNonVersionedFiles
|
.PARAMETER SkipNonVersionedFiles
|
||||||
Default: false
|
Default: false
|
||||||
Skips installing non-versioned files if they already exist, such as dotnet.exe.
|
Skips installing non-versioned files if they already exist, such as dotnet.exe.
|
||||||
|
.PARAMETER NoCdn
|
||||||
|
Disable downloading from the Azure CDN, and use the uncached feed directly.
|
||||||
.PARAMETER JSonFile
|
.PARAMETER JSonFile
|
||||||
Determines the SDK version from a user specified global.json file
|
Determines the SDK version from a user specified global.json file
|
||||||
Note: global.json must have a value for 'SDK:Version'
|
Note: global.json must have a value for 'SDK:Version'
|
||||||
.PARAMETER DownloadTimeout
|
.PARAMETER DownloadTimeout
|
||||||
Determines timeout duration in seconds for dowloading of the SDK file
|
Determines timeout duration in seconds for dowloading of the SDK file
|
||||||
Default: 1200 seconds (20 minutes)
|
Default: 1200 seconds (20 minutes)
|
||||||
.PARAMETER KeepZip
|
|
||||||
If set, downloaded file is kept
|
|
||||||
.PARAMETER ZipPath
|
|
||||||
Use that path to store installer, generated by default
|
|
||||||
.EXAMPLE
|
|
||||||
dotnet-install.ps1 -Version 7.0.401
|
|
||||||
Installs the .NET SDK version 7.0.401
|
|
||||||
.EXAMPLE
|
|
||||||
dotnet-install.ps1 -Channel 8.0 -Quality GA
|
|
||||||
Installs the latest GA (general availability) version of the .NET 8.0 SDK
|
|
||||||
#>
|
#>
|
||||||
[cmdletbinding()]
|
[cmdletbinding()]
|
||||||
param(
|
param(
|
||||||
@ -126,10 +120,8 @@ param(
|
|||||||
[switch]$ProxyUseDefaultCredentials,
|
[switch]$ProxyUseDefaultCredentials,
|
||||||
[string[]]$ProxyBypassList=@(),
|
[string[]]$ProxyBypassList=@(),
|
||||||
[switch]$SkipNonVersionedFiles,
|
[switch]$SkipNonVersionedFiles,
|
||||||
[int]$DownloadTimeout = 1200,
|
[switch]$NoCdn,
|
||||||
[switch]$KeepZip,
|
[int]$DownloadTimeout=1200
|
||||||
[string]$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()),
|
|
||||||
[switch]$Help
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
@ -181,24 +173,7 @@ function Say-Verbose($str) {
|
|||||||
function Measure-Action($name, $block) {
|
function Measure-Action($name, $block) {
|
||||||
$time = Measure-Command $block
|
$time = Measure-Command $block
|
||||||
$totalSeconds = $time.TotalSeconds
|
$totalSeconds = $time.TotalSeconds
|
||||||
Say-Verbose "Action '$name' took $totalSeconds seconds"
|
Say-Verbose "⏱ Action '$name' took $totalSeconds seconds"
|
||||||
}
|
|
||||||
|
|
||||||
function Get-Remote-File-Size($zipUri) {
|
|
||||||
try {
|
|
||||||
$response = Invoke-WebRequest -Uri $zipUri -Method Head
|
|
||||||
$fileSize = $response.Headers["Content-Length"]
|
|
||||||
if ((![string]::IsNullOrEmpty($fileSize))) {
|
|
||||||
Say "Remote file $zipUri size is $fileSize bytes."
|
|
||||||
|
|
||||||
return $fileSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Say-Verbose "Content-Length header was not extracted for $zipUri."
|
|
||||||
}
|
|
||||||
|
|
||||||
return $null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Say-Invocation($Invocation) {
|
function Say-Invocation($Invocation) {
|
||||||
@ -244,7 +219,8 @@ function Get-Machine-Architecture() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if( ((Get-CimInstance -ClassName CIM_OperatingSystem).OSArchitecture) -like "ARM*") {
|
if( ((Get-CimInstance -ClassName CIM_OperatingSystem).OSArchitecture) -like "ARM*") {
|
||||||
if ( [Environment]::Is64BitOperatingSystem ) {
|
if( [Environment]::Is64BitOperatingSystem )
|
||||||
|
{
|
||||||
return "arm64"
|
return "arm64"
|
||||||
}
|
}
|
||||||
return "arm"
|
return "arm"
|
||||||
@ -273,13 +249,13 @@ function Get-CLIArchitecture-From-Architecture([string]$Architecture) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ValidateFeedCredential([string] $FeedCredential) {
|
function ValidateFeedCredential([string] $FeedCredential)
|
||||||
|
{
|
||||||
if ($Internal -and [string]::IsNullOrWhitespace($FeedCredential)) {
|
if ($Internal -and [string]::IsNullOrWhitespace($FeedCredential)) {
|
||||||
$message = "Provide credentials via -FeedCredential parameter."
|
$message = "Provide credentials via -FeedCredential parameter."
|
||||||
if ($DryRun) {
|
if ($DryRun) {
|
||||||
Say-Warning "$message"
|
Say-Warning "$message"
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw "$message"
|
throw "$message"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,7 +347,8 @@ function Load-Assembly([string] $Assembly) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect, [bool]$DisableFeedCredential) {
|
function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect, [bool]$DisableFeedCredential)
|
||||||
|
{
|
||||||
$cts = New-Object System.Threading.CancellationTokenSource
|
$cts = New-Object System.Threading.CancellationTokenSource
|
||||||
|
|
||||||
$downloadScript = {
|
$downloadScript = {
|
||||||
@ -389,14 +366,12 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
|
|||||||
if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))) {
|
if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))) {
|
||||||
if ($null -ne $DefaultProxy.GetProxy($Uri)) {
|
if ($null -ne $DefaultProxy.GetProxy($Uri)) {
|
||||||
$ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString
|
$ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$ProxyAddress = $null
|
$ProxyAddress = $null
|
||||||
}
|
}
|
||||||
$ProxyUseDefaultCredentials = $true
|
$ProxyUseDefaultCredentials = $true
|
||||||
}
|
}
|
||||||
}
|
} catch {
|
||||||
catch {
|
|
||||||
# Eat the exception and move forward as the above code is an attempt
|
# Eat the exception and move forward as the above code is an attempt
|
||||||
# at resolving the DefaultProxy that may not have been a problem.
|
# at resolving the DefaultProxy that may not have been a problem.
|
||||||
$ProxyAddress = $null
|
$ProxyAddress = $null
|
||||||
@ -412,7 +387,8 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
|
|||||||
BypassList = $ProxyBypassList;
|
BypassList = $ProxyBypassList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($DisableRedirect) {
|
if ($DisableRedirect)
|
||||||
|
{
|
||||||
$HttpClientHandler.AllowAutoRedirect = $false
|
$HttpClientHandler.AllowAutoRedirect = $false
|
||||||
}
|
}
|
||||||
$HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler
|
$HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler
|
||||||
@ -446,7 +422,8 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
|
|||||||
$DownloadException.Data["StatusCode"] = [int] $Response.StatusCode
|
$DownloadException.Data["StatusCode"] = [int] $Response.StatusCode
|
||||||
$DownloadException.Data["ErrorMessage"] = "Unable to download $Uri. Returned HTTP status code: " + $DownloadException.Data["StatusCode"]
|
$DownloadException.Data["ErrorMessage"] = "Unable to download $Uri. Returned HTTP status code: " + $DownloadException.Data["StatusCode"]
|
||||||
|
|
||||||
if (404 -eq [int] $Response.StatusCode) {
|
if (404 -eq [int] $Response.StatusCode)
|
||||||
|
{
|
||||||
$cts.Cancel()
|
$cts.Cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,8 +462,10 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
|
|||||||
try {
|
try {
|
||||||
return Invoke-With-Retry $downloadScript $cts.Token
|
return Invoke-With-Retry $downloadScript $cts.Token
|
||||||
}
|
}
|
||||||
finally {
|
finally
|
||||||
if ($null -ne $cts) {
|
{
|
||||||
|
if ($null -ne $cts)
|
||||||
|
{
|
||||||
$cts.Dispose()
|
$cts.Dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -604,9 +583,11 @@ function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string
|
|||||||
elseif ($Runtime -eq "windowsdesktop") {
|
elseif ($Runtime -eq "windowsdesktop") {
|
||||||
# The windows desktop runtime is part of the core runtime layout prior to 5.0
|
# The windows desktop runtime is part of the core runtime layout prior to 5.0
|
||||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
||||||
if ($SpecificVersion -match '^(\d+)\.(.*)$') {
|
if ($SpecificVersion -match '^(\d+)\.(.*)$')
|
||||||
|
{
|
||||||
$majorVersion = [int]$Matches[1]
|
$majorVersion = [int]$Matches[1]
|
||||||
if ($majorVersion -ge 5) {
|
if ($majorVersion -ge 5)
|
||||||
|
{
|
||||||
$PayloadURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
$PayloadURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -656,7 +637,8 @@ function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion, [stri
|
|||||||
|
|
||||||
if ($productVersionResponse.StatusCode -eq 200) {
|
if ($productVersionResponse.StatusCode -eq 200) {
|
||||||
$productVersion = $productVersionResponse.Content.ReadAsStringAsync().Result.Trim()
|
$productVersion = $productVersionResponse.Content.ReadAsStringAsync().Result.Trim()
|
||||||
if ($productVersion -ne $SpecificVersion) {
|
if ($productVersion -ne $SpecificVersion)
|
||||||
|
{
|
||||||
Say "Using alternate version $productVersion found in $ProductVersionTxtURL"
|
Say "Using alternate version $productVersion found in $ProductVersionTxtURL"
|
||||||
}
|
}
|
||||||
return $productVersion
|
return $productVersion
|
||||||
@ -671,7 +653,8 @@ function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion, [stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Getting the version number with productVersion.txt has failed. Try parsing the download link for a version number.
|
# Getting the version number with productVersion.txt has failed. Try parsing the download link for a version number.
|
||||||
if ([string]::IsNullOrEmpty($PackageDownloadLink)) {
|
if ([string]::IsNullOrEmpty($PackageDownloadLink))
|
||||||
|
{
|
||||||
Say-Verbose "Using the default value '$SpecificVersion' as the product version."
|
Say-Verbose "Using the default value '$SpecificVersion' as the product version."
|
||||||
return $SpecificVersion
|
return $SpecificVersion
|
||||||
}
|
}
|
||||||
@ -731,14 +714,16 @@ function Get-Product-Version-Url([string]$AzureFeed, [string]$SpecificVersion, [
|
|||||||
return $ProductVersionTxtURL
|
return $ProductVersionTxtURL
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-ProductVersionFromDownloadLink([string]$PackageDownloadLink, [string]$SpecificVersion) {
|
function Get-ProductVersionFromDownloadLink([string]$PackageDownloadLink, [string]$SpecificVersion)
|
||||||
|
{
|
||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
#product specific version follows the product name
|
#product specific version follows the product name
|
||||||
#for filename 'dotnet-sdk-3.1.404-win-x64.zip': the product version is 3.1.400
|
#for filename 'dotnet-sdk-3.1.404-win-x64.zip': the product version is 3.1.400
|
||||||
$filename = $PackageDownloadLink.Substring($PackageDownloadLink.LastIndexOf("/") + 1)
|
$filename = $PackageDownloadLink.Substring($PackageDownloadLink.LastIndexOf("/") + 1)
|
||||||
$filenameParts = $filename.Split('-')
|
$filenameParts = $filename.Split('-')
|
||||||
if ($filenameParts.Length -gt 2) {
|
if ($filenameParts.Length -gt 2)
|
||||||
|
{
|
||||||
$productVersion = $filenameParts[2]
|
$productVersion = $filenameParts[2]
|
||||||
Say-Verbose "Extracted product version '$productVersion' from download link '$PackageDownloadLink'."
|
Say-Verbose "Extracted product version '$productVersion' from download link '$PackageDownloadLink'."
|
||||||
}
|
}
|
||||||
@ -756,9 +741,6 @@ function Get-User-Share-Path() {
|
|||||||
if (!$InstallRoot) {
|
if (!$InstallRoot) {
|
||||||
$InstallRoot = "$env:LocalAppData\Microsoft\dotnet"
|
$InstallRoot = "$env:LocalAppData\Microsoft\dotnet"
|
||||||
}
|
}
|
||||||
elseif ($InstallRoot -like "$env:ProgramFiles\dotnet\?*") {
|
|
||||||
Say-Warning "The install root specified by the environment variable DOTNET_INSTALL_DIR points to the sub folder of $env:ProgramFiles\dotnet which is the default dotnet install root using .NET SDK installer. It is better to keep aligned with .NET SDK installer."
|
|
||||||
}
|
|
||||||
return $InstallRoot
|
return $InstallRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,19 +753,6 @@ function Resolve-Installation-Path([string]$InstallDir) {
|
|||||||
return $InstallDir
|
return $InstallDir
|
||||||
}
|
}
|
||||||
|
|
||||||
function Test-User-Write-Access([string]$InstallDir) {
|
|
||||||
try {
|
|
||||||
$tempFileName = [guid]::NewGuid().ToString()
|
|
||||||
$tempFilePath = Join-Path -Path $InstallDir -ChildPath $tempFileName
|
|
||||||
New-Item -Path $tempFilePath -ItemType File -Force
|
|
||||||
Remove-Item $tempFilePath -Force
|
|
||||||
return $true
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return $false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) {
|
function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) {
|
||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
@ -867,7 +836,8 @@ function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch
|
||||||
|
{
|
||||||
Say-Error "Failed to extract package. Exception: $_"
|
Say-Error "Failed to extract package. Exception: $_"
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@ -899,8 +869,6 @@ function DownloadFile($Source, [string]$OutPath) {
|
|||||||
$File = [System.IO.File]::Create($OutPath)
|
$File = [System.IO.File]::Create($OutPath)
|
||||||
$Stream.CopyTo($File)
|
$Stream.CopyTo($File)
|
||||||
$File.Close()
|
$File.Close()
|
||||||
|
|
||||||
ValidateRemoteLocalFileSizes -LocalFileOutPath $OutPath -SourceUri $Source
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if ($null -ne $Stream) {
|
if ($null -ne $Stream) {
|
||||||
@ -909,40 +877,19 @@ function DownloadFile($Source, [string]$OutPath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ValidateRemoteLocalFileSizes([string]$LocalFileOutPath, $SourceUri) {
|
|
||||||
try {
|
|
||||||
$remoteFileSize = Get-Remote-File-Size -zipUri $SourceUri
|
|
||||||
$fileSize = [long](Get-Item $LocalFileOutPath).Length
|
|
||||||
Say "Downloaded file $SourceUri size is $fileSize bytes."
|
|
||||||
|
|
||||||
if ((![string]::IsNullOrEmpty($remoteFileSize)) -and !([string]::IsNullOrEmpty($fileSize)) ) {
|
|
||||||
if ($remoteFileSize -ne $fileSize) {
|
|
||||||
Say "The remote and local file sizes are not equal. Remote file size is $remoteFileSize bytes and local size is $fileSize bytes. The local package may be corrupted."
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Say "The remote and local file sizes are equal."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Say "Either downloaded or local package size can not be measured. One of them may be corrupted."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Say "Either downloaded or local package size can not be measured. One of them may be corrupted."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function SafeRemoveFile($Path) {
|
function SafeRemoveFile($Path) {
|
||||||
try {
|
try {
|
||||||
if (Test-Path $Path) {
|
if (Test-Path $Path) {
|
||||||
Remove-Item $Path
|
Remove-Item $Path
|
||||||
Say-Verbose "The temporary file `"$Path`" was removed."
|
Say-Verbose "The temporary file `"$Path`" was removed."
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
Say-Verbose "The temporary file `"$Path`" does not exist, therefore is not removed."
|
Say-Verbose "The temporary file `"$Path`" does not exist, therefore is not removed."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch
|
||||||
|
{
|
||||||
Say-Warning "Failed to remove the temporary file: `"$Path`", remove it manually."
|
Say-Warning "Failed to remove the temporary file: `"$Path`", remove it manually."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -954,8 +901,7 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot) {
|
|||||||
if (-Not $env:path.Contains($SuffixedBinPath)) {
|
if (-Not $env:path.Contains($SuffixedBinPath)) {
|
||||||
Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process."
|
Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process."
|
||||||
$env:path = $SuffixedBinPath + $env:path
|
$env:path = $SuffixedBinPath + $env:path
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Say-Verbose "Current process PATH already contains `"$BinPath`""
|
Say-Verbose "Current process PATH already contains `"$BinPath`""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -964,7 +910,8 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function PrintDryRunOutput($Invocation, $DownloadLinks) {
|
function PrintDryRunOutput($Invocation, $DownloadLinks)
|
||||||
|
{
|
||||||
Say "Payload URLs:"
|
Say "Payload URLs:"
|
||||||
|
|
||||||
for ($linkIndex=0; $linkIndex -lt $DownloadLinks.count; $linkIndex++) {
|
for ($linkIndex=0; $linkIndex -lt $DownloadLinks.count; $linkIndex++) {
|
||||||
@ -987,37 +934,12 @@ function PrintDryRunOutput($Invocation, $DownloadLinks) {
|
|||||||
$RepeatableCommand+=" -FeedCredential `"<feedCredential>`""
|
$RepeatableCommand+=" -FeedCredential `"<feedCredential>`""
|
||||||
}
|
}
|
||||||
Say "Repeatable invocation: $RepeatableCommand"
|
Say "Repeatable invocation: $RepeatableCommand"
|
||||||
if ($SpecificVersion -ne $EffectiveVersion) {
|
if ($SpecificVersion -ne $EffectiveVersion)
|
||||||
|
{
|
||||||
Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'"
|
Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# grab the 'stem' of the redirect and check it against all of our configured feeds,
|
|
||||||
# if it matches, we can be sure that the redirect is valid and we should use it for
|
|
||||||
# subsequent processing
|
|
||||||
function Sanitize-RedirectUrl([string]$url) {
|
|
||||||
$urlSegments = ([System.Uri]$url).Segments;
|
|
||||||
$urlStem = $urlSegments[2..($urlSegments.Length - 1)] -join "";
|
|
||||||
Write-Verbose "Checking configured feeds for the asset at $urlStem"
|
|
||||||
foreach ($prospectiveFeed in $feeds) {
|
|
||||||
$trialUrl = "$prospectiveFeed/$urlStem";
|
|
||||||
Write-Verbose "Checking $trialUrl"
|
|
||||||
try {
|
|
||||||
$trialResponse = Invoke-WebRequest -Uri $trialUrl -Method HEAD
|
|
||||||
if ($trialResponse.StatusCode -eq 200) {
|
|
||||||
Write-Verbose "Found a match at $trialUrl"
|
|
||||||
return $trialUrl;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Verbose "No match at $trialUrl"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Verbose "Failed to check $trialUrl"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Internal, [string]$Product, [string]$Architecture) {
|
function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Internal, [string]$Product, [string]$Architecture) {
|
||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
@ -1041,7 +963,8 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
|
|||||||
Say-Verbose "Constructed aka.ms link: '$akaMsLink'."
|
Say-Verbose "Constructed aka.ms link: '$akaMsLink'."
|
||||||
$akaMsDownloadLink=$null
|
$akaMsDownloadLink=$null
|
||||||
|
|
||||||
for ($maxRedirections = 9; $maxRedirections -ge 0; $maxRedirections--) {
|
for ($maxRedirections = 9; $maxRedirections -ge 0; $maxRedirections--)
|
||||||
|
{
|
||||||
#get HTTP response
|
#get HTTP response
|
||||||
#do not pass credentials as a part of the $akaMsLink and do not apply credentials in the GetHTTPResponse function
|
#do not pass credentials as a part of the $akaMsLink and do not apply credentials in the GetHTTPResponse function
|
||||||
#otherwise the redirect link would have credentials as well
|
#otherwise the redirect link would have credentials as well
|
||||||
@ -1055,7 +978,8 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HTTP code is 301 (Moved Permanently), the redirect link exists
|
#if HTTP code is 301 (Moved Permanently), the redirect link exists
|
||||||
if ($Response.StatusCode -eq 301) {
|
if ($Response.StatusCode -eq 301)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$akaMsDownloadLink = $Response.Headers.GetValues("Location")[0]
|
$akaMsDownloadLink = $Response.Headers.GetValues("Location")[0]
|
||||||
|
|
||||||
@ -1074,13 +998,9 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
|
|||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ((($Response.StatusCode -lt 300) -or ($Response.StatusCode -ge 400)) -and (-not [string]::IsNullOrEmpty($akaMsDownloadLink))) {
|
elseif ((($Response.StatusCode -lt 300) -or ($Response.StatusCode -ge 400)) -and (-not [string]::IsNullOrEmpty($akaMsDownloadLink)))
|
||||||
|
{
|
||||||
# Redirections have ended.
|
# Redirections have ended.
|
||||||
$actualRedirectUrl = Sanitize-RedirectUrl $akaMsDownloadLink
|
|
||||||
if ($null -ne $actualRedirectUrl) {
|
|
||||||
$akaMsDownloadLink = $actualRedirectUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
return $akaMsDownloadLink
|
return $akaMsDownloadLink
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1129,21 +1049,27 @@ function Get-AkaMsLink-And-Version([string] $NormalizedChannel, [string] $Normal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-Feeds-To-Use() {
|
function Get-Feeds-To-Use()
|
||||||
|
{
|
||||||
$feeds = @(
|
$feeds = @(
|
||||||
"https://builds.dotnet.microsoft.com/dotnet"
|
"https://dotnetcli.azureedge.net/dotnet",
|
||||||
"https://ci.dot.net/public"
|
"https://dotnetbuilds.azureedge.net/public"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (-not [string]::IsNullOrEmpty($AzureFeed)) {
|
if (-not [string]::IsNullOrEmpty($AzureFeed)) {
|
||||||
$feeds = @($AzureFeed)
|
$feeds = @($AzureFeed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($NoCdn) {
|
||||||
|
$feeds = @(
|
||||||
|
"https://dotnetcli.blob.core.windows.net/dotnet",
|
||||||
|
"https://dotnetbuilds.blob.core.windows.net/public"
|
||||||
|
)
|
||||||
|
|
||||||
if (-not [string]::IsNullOrEmpty($UncachedFeed)) {
|
if (-not [string]::IsNullOrEmpty($UncachedFeed)) {
|
||||||
$feeds = @($UncachedFeed)
|
$feeds = @($UncachedFeed)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Write-Verbose "Initialized feeds: $feeds"
|
|
||||||
|
|
||||||
return $feeds
|
return $feeds
|
||||||
}
|
}
|
||||||
@ -1174,13 +1100,6 @@ function Resolve-AssetName-And-RelativePath([string] $Runtime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Prepare-Install-Directory {
|
function Prepare-Install-Directory {
|
||||||
$diskSpaceWarning = "Failed to check the disk space. Installation will continue, but it may fail if you do not have enough disk space.";
|
|
||||||
|
|
||||||
if ($PSVersionTable.PSVersion.Major -lt 7) {
|
|
||||||
Say-Verbose $diskSpaceWarning
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
|
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
|
||||||
|
|
||||||
$installDrive = $((Get-Item $InstallRoot -Force).PSDrive.Name);
|
$installDrive = $((Get-Item $InstallRoot -Force).PSDrive.Name);
|
||||||
@ -1189,20 +1108,14 @@ function Prepare-Install-Directory {
|
|||||||
$diskInfo = Get-PSDrive -Name $installDrive
|
$diskInfo = Get-PSDrive -Name $installDrive
|
||||||
}
|
}
|
||||||
catch{
|
catch{
|
||||||
Say-Warning $diskSpaceWarning
|
Say-Warning "Failed to check the disk space. Installation will continue, but it may fail if you do not have enough disk space."
|
||||||
}
|
}
|
||||||
|
|
||||||
# The check is relevant for PS version >= 7, the result can be irrelevant for older versions. See https://github.com/PowerShell/PowerShell/issues/12442.
|
|
||||||
if ( ($null -ne $diskInfo) -and ($diskInfo.Free / 1MB -le 100)) {
|
if ( ($null -ne $diskInfo) -and ($diskInfo.Free / 1MB -le 100)) {
|
||||||
throw "There is not enough disk space on drive ${installDrive}:"
|
throw "There is not enough disk space on drive ${installDrive}:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Help) {
|
|
||||||
Get-Help $PSCommandPath -Examples
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
Say-Verbose "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-Verbose "- 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-Verbose "- 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."
|
||||||
@ -1226,10 +1139,6 @@ Measure-Action "Product discovery" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$InstallRoot = Resolve-Installation-Path $InstallDir
|
$InstallRoot = Resolve-Installation-Path $InstallDir
|
||||||
if (-not (Test-User-Write-Access $InstallRoot)) {
|
|
||||||
Say-Error "The current user doesn't have write access to the installation root '$InstallRoot' to install .NET. Please try specifying a different installation directory using the -InstallDir parameter, or ensure the selected directory has the appropriate permissions."
|
|
||||||
throw
|
|
||||||
}
|
|
||||||
Say-Verbose "InstallRoot: $InstallRoot"
|
Say-Verbose "InstallRoot: $InstallRoot"
|
||||||
$ScriptName = $MyInvocation.MyCommand.Name
|
$ScriptName = $MyInvocation.MyCommand.Name
|
||||||
($assetName, $dotnetPackageRelativePath) = Resolve-AssetName-And-RelativePath -Runtime $Runtime
|
($assetName, $dotnetPackageRelativePath) = Resolve-AssetName-And-RelativePath -Runtime $Runtime
|
||||||
@ -1251,7 +1160,8 @@ if ([string]::IsNullOrEmpty($JSonFile) -and ($Version -eq "latest")) {
|
|||||||
|
|
||||||
if (-Not $DryRun) {
|
if (-Not $DryRun) {
|
||||||
Say-Verbose "Checking if the version $EffectiveVersion is already installed"
|
Say-Verbose "Checking if the version $EffectiveVersion is already installed"
|
||||||
if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion) {
|
if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion)
|
||||||
|
{
|
||||||
Say "$assetName with version '$EffectiveVersion' is already installed."
|
Say "$assetName with version '$EffectiveVersion' is already installed."
|
||||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
|
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
|
||||||
return
|
return
|
||||||
@ -1262,7 +1172,8 @@ if ([string]::IsNullOrEmpty($JSonFile) -and ($Version -eq "latest")) {
|
|||||||
|
|
||||||
# Primary and legacy links cannot be used if a quality was specified.
|
# Primary and legacy links cannot be used if a quality was specified.
|
||||||
# If we already have an aka.ms link, no need to search the blob feeds.
|
# If we already have an aka.ms link, no need to search the blob feeds.
|
||||||
if ([string]::IsNullOrEmpty($NormalizedQuality) -and 0 -eq $DownloadLinks.count) {
|
if ([string]::IsNullOrEmpty($NormalizedQuality) -and 0 -eq $DownloadLinks.count)
|
||||||
|
{
|
||||||
foreach ($feed in $feeds) {
|
foreach ($feed in $feeds) {
|
||||||
try {
|
try {
|
||||||
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $feed -Channel $Channel -Version $Version -JSonFile $JSonFile
|
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $feed -Channel $Channel -Version $Version -JSonFile $JSonFile
|
||||||
@ -1279,14 +1190,16 @@ if ([string]::IsNullOrEmpty($NormalizedQuality) -and 0 -eq $DownloadLinks.count)
|
|||||||
|
|
||||||
if (-Not $DryRun) {
|
if (-Not $DryRun) {
|
||||||
Say-Verbose "Checking if the version $EffectiveVersion is already installed"
|
Say-Verbose "Checking if the version $EffectiveVersion is already installed"
|
||||||
if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion) {
|
if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion)
|
||||||
|
{
|
||||||
Say "$assetName with version '$EffectiveVersion' is already installed."
|
Say "$assetName with version '$EffectiveVersion' is already installed."
|
||||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
|
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch
|
||||||
|
{
|
||||||
Say-Verbose "Failed to acquire download links from feed $feed. Exception: $_"
|
Say-Verbose "Failed to acquire download links from feed $feed. Exception: $_"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1303,13 +1216,15 @@ if ($DryRun) {
|
|||||||
|
|
||||||
Measure-Action "Installation directory preparation" { Prepare-Install-Directory }
|
Measure-Action "Installation directory preparation" { Prepare-Install-Directory }
|
||||||
|
|
||||||
|
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
|
||||||
Say-Verbose "Zip path: $ZipPath"
|
Say-Verbose "Zip path: $ZipPath"
|
||||||
|
|
||||||
$DownloadSucceeded = $false
|
$DownloadSucceeded = $false
|
||||||
$DownloadedLink = $null
|
$DownloadedLink = $null
|
||||||
$ErrorMessages = @()
|
$ErrorMessages = @()
|
||||||
|
|
||||||
foreach ($link in $DownloadLinks) {
|
foreach ($link in $DownloadLinks)
|
||||||
|
{
|
||||||
Say-Verbose "Downloading `"$($link.type)`" link $($link.downloadLink)"
|
Say-Verbose "Downloading `"$($link.type)`" link $($link.downloadLink)"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1329,8 +1244,7 @@ foreach ($link in $DownloadLinks) {
|
|||||||
|
|
||||||
if ($PSItem.Exception.Data.Contains("ErrorMessage")) {
|
if ($PSItem.Exception.Data.Contains("ErrorMessage")) {
|
||||||
$ErrorMessage = $PSItem.Exception.Data["ErrorMessage"]
|
$ErrorMessage = $PSItem.Exception.Data["ErrorMessage"]
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$ErrorMessage = $PSItem.Exception.Message
|
$ErrorMessage = $PSItem.Exception.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,54 +1289,51 @@ if (!$isAssetInstalled) {
|
|||||||
throw "`"$assetName`" with version = $($DownloadedLink.effectiveVersion) failed to install with an unknown error."
|
throw "`"$assetName`" with version = $($DownloadedLink.effectiveVersion) failed to install with an unknown error."
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-not $KeepZip) {
|
|
||||||
SafeRemoveFile -Path $ZipPath
|
SafeRemoveFile -Path $ZipPath
|
||||||
}
|
|
||||||
|
|
||||||
Measure-Action "Setting up shell environment" { Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot }
|
Measure-Action "Setting up shell environment" { Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot }
|
||||||
|
|
||||||
Say "Note that the script does not ensure your Windows version is supported during the installation."
|
Say "Note that the script does not resolve dependencies during installation."
|
||||||
Say "To check the list of supported versions, go to https://learn.microsoft.com/dotnet/core/install/windows#supported-versions"
|
Say "To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install/windows#dependencies"
|
||||||
Say "Installed version is $($DownloadedLink.effectiveVersion)"
|
Say "Installed version is $($DownloadedLink.effectiveVersion)"
|
||||||
Say "Installation finished"
|
Say "Installation finished"
|
||||||
|
|
||||||
# SIG # Begin signature block
|
# SIG # Begin signature block
|
||||||
# MIIoRgYJKoZIhvcNAQcCoIIoNzCCKDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
# MIInvwYJKoZIhvcNAQcCoIInsDCCJ6wCAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
||||||
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
||||||
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAA6hOL3sfG/4jH
|
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBhfTi3SRn7+vyy
|
||||||
# iO4VqZoOTVqC+yp2rOhb1M2cc+ic7KCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
|
# uCXKPjhiawegWZ493EcaOEycbgkZcKCCDXYwggX0MIID3KADAgECAhMzAAACy7d1
|
||||||
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
# OfsCcUI2AAAAAALLMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
||||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
||||||
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
||||||
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
|
# bmcgUENBIDIwMTEwHhcNMjIwNTEyMjA0NTU5WhcNMjMwNTExMjA0NTU5WjB0MQsw
|
||||||
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
|
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
|
||||||
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
|
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
|
||||||
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||||
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
|
# AQC3sN0WcdGpGXPZIb5iNfFB0xZ8rnJvYnxD6Uf2BHXglpbTEfoe+mO//oLWkRxA
|
||||||
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
|
# wppditsSVOD0oglKbtnh9Wp2DARLcxbGaW4YanOWSB1LyLRpHnnQ5POlh2U5trg4
|
||||||
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
|
# 3gQjvlNZlQB3lL+zrPtbNvMA7E0Wkmo+Z6YFnsf7aek+KGzaGboAeFO4uKZjQXY5
|
||||||
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
|
# RmMzE70Bwaz7hvA05jDURdRKH0i/1yK96TDuP7JyRFLOvA3UXNWz00R9w7ppMDcN
|
||||||
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
|
# lXtrmbPigv3xE9FfpfmJRtiOZQKd73K72Wujmj6/Su3+DBTpOq7NgdntW2lJfX3X
|
||||||
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
|
# a6oe4F9Pk9xRhkwHsk7Ju9E/AgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
|
||||||
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
|
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUrg/nt/gj+BBLd1jZWYhok7v5/w4w
|
||||||
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
|
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
|
||||||
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
|
# MBQGA1UEBRMNMjMwMDEyKzQ3MDUyODAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
|
||||||
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
|
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
|
||||||
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
|
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
|
||||||
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
|
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
|
||||||
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
|
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
|
||||||
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
|
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAJL5t6pVjIRlQ8j4dAFJ
|
||||||
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
|
# ZnMke3rRHeQDOPFxswM47HRvgQa2E1jea2aYiMk1WmdqWnYw1bal4IzRlSVf4czf
|
||||||
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
|
# zx2vjOIOiaGllW2ByHkfKApngOzJmAQ8F15xSHPRvNMmvpC3PFLvKMf3y5SyPJxh
|
||||||
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
|
# 922TTq0q5epJv1SgZDWlUlHL/Ex1nX8kzBRhHvc6D6F5la+oAO4A3o/ZC05OOgm4
|
||||||
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
|
# EJxZP9MqUi5iid2dw4Jg/HvtDpCcLj1GLIhCDaebKegajCJlMhhxnDXrGFLJfX8j
|
||||||
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
|
# 7k7LUvrZDsQniJZ3D66K+3SZTLhvwK7dMGVFuUUJUfDifrlCTjKG9mxsPDllfyck
|
||||||
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
|
# 4zGnRZv8Jw9RgE1zAghnU14L0vVUNOzi/4bE7wIsiRyIcCcVoXRneBA3n/frLXvd
|
||||||
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
|
# jDsbb2lpGu78+s1zbO5N0bhHWq4j5WMutrspBxEhqG2PSBjC5Ypi+jhtfu3+x76N
|
||||||
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
|
# mBvsyKuxx9+Hm/ALnlzKxr4KyMR3/z4IRMzA1QyppNk65Ui+jB14g+w4vole33M1
|
||||||
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
|
# pVqVckrmSebUkmjnCshCiH12IFgHZF7gRwE4YZrJ7QjxZeoZqHaKsQLRMp653beB
|
||||||
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
|
# fHfeva9zJPhBSdVcCW7x9q0c2HVPLJHX9YCUU714I+qtLpDGrdbZxD9mikPqL/To
|
||||||
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
|
# /1lDZ0ch8FtePhME7houuoPcMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
|
||||||
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
|
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
|
||||||
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
|
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
|
||||||
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
||||||
@ -1462,144 +1373,142 @@ Say "Installation finished"
|
|||||||
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
|
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
|
||||||
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
|
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
|
||||||
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
|
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
|
||||||
# /Xmfwb1tbWrJUnMTDXpQzTGCGiYwghoiAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
|
# /Xmfwb1tbWrJUnMTDXpQzTGCGZ8wghmbAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
|
||||||
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
|
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
|
||||||
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
|
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
|
||||||
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
|
# Z25pbmcgUENBIDIwMTECEzMAAALLt3U5+wJxQjYAAAAAAsswDQYJYIZIAWUDBAIB
|
||||||
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
|
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
|
||||||
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIL7Zm9jjqasUipeS7XNbT5Gz
|
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFmuaTXYQ37AFvsEol24fdW+
|
||||||
# uhEwSf09z2Ab+694mR/3MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
|
# nRqHcc1fr+VQVdqhXc/vMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
|
||||||
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
|
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
|
||||||
# BQAEggEAfTNcpMwgkFxkb0hBch2MCvTb1mGCFv8rZWTkR/aRZTyzuAIEb2GfL4qB
|
# BQAEggEAjY5XW5Ly7TJ1OTbeIR98xU+2dmtw7L71ws+ICnQCGhj2xJDUK+5yrTfO
|
||||||
# rPycLC2+q4gaksj1Cv+mRTEq+ysl0aWbXgPiRNiijlnuWKRPZ4nlcGkeXu5zxJ1W
|
# 8C98l/P4ynFi33Dl8z2YElqUCuqEXbiCzz06lIL4NuibC5DV/X80ZmICR/NYd2v1
|
||||||
# uUOCIe03s6eJCUZseRZkNHB1/CqIlk/YB5yqB38cfq6ct+lWKoSCbSwRVh3Du6am
|
# ww7IH+7dpsHAowBBindCYpVwQ3Ea3kDWgsjPAinAysFFushSOnNWFvrF6vi2smrs
|
||||||
# jxnQRa4njduu1xywcKZYp9NGGeAgRDpMNbvFKF4Qf3krbTAn3vIVDBay6oeiHo2I
|
# smbrAAhEhSfLd1Pxxdw73hQ0YjM/D3F3opaybMQ0blpHhOaqtbiyYzvk0doIzBEc
|
||||||
# x1RLrRC/CEYZ7oJ8tyc3SUE2/Jd00M4EKax+z3xTIkOmyMBZjEe1el92WVcUWukT
|
# trSH4NDIc3yLNj5VbjSczpexE+hyQNY4xCtwco4bVtXhONUihv08AIKR8+sIaI7A
|
||||||
# ACoQjF5jPyXnfYGH7rjevjpI5u2T66GCF7AwghesBgorBgEEAYI3AwMBMYIXnDCC
|
# mM/SWrrwGYSSSxydKqDei7biKG4jDqGCFykwghclBgorBgEEAYI3AwMBMYIXFTCC
|
||||||
# F5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsq
|
# FxEGCSqGSIb3DQEHAqCCFwIwghb+AgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFZBgsq
|
||||||
# hkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
|
# hkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
|
||||||
# AwQCAQUABCBjHcYL0Rw5C6IE3Lyb3B0i9qsTzN6j8bzChm+bMp97RgIGZ2Ld17Jt
|
# AwQCAQUABCB6Hzt2gUb/WZK8fvVnOocriE4rYr6mscZi3gZnBCpiigIGZBr2iMZU
|
||||||
# GBMyMDI1MDExMjAwNDMxNy4yNTZaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJV
|
# GBMyMDIzMDMzMTE1MjEwNi41MTZaMASAAgH0oIHYpIHVMIHSMQswCQYDVQQGEwJV
|
||||||
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
|
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
|
||||||
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
|
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
|
||||||
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
|
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO
|
||||||
# Tjo0MzFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
|
# OjA4NDItNEJFNi1DMjlBMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
|
||||||
# U2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB+vs7RNN3M8bTAAEAAAH6MA0G
|
# ZXJ2aWNloIIReDCCBycwggUPoAMCAQICEzMAAAGybkADf26plJIAAQAAAbIwDQYJ
|
||||||
# CSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
|
# KoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
|
||||||
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
|
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
|
||||||
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI0
|
# bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjIw
|
||||||
# MDcyNTE4MzExMVoXDTI1MTAyMjE4MzExMVowgdMxCzAJBgNVBAYTAlVTMRMwEQYD
|
# OTIwMjAyMjAxWhcNMjMxMjE0MjAyMjAxWjCB0jELMAkGA1UEBhMCVVMxEzARBgNV
|
||||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
|
||||||
# b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w
|
# c29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3Bl
|
||||||
# ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjQzMUEt
|
# cmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjowODQyLTRC
|
||||||
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
|
# RTYtQzI5QTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC
|
||||||
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyhZVBM3PZcBfEpAf7fII
|
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMqiZTIde/lQ4rC+Bml5f/Wu
|
||||||
# hygwYVVP64USeZbSlRR3pvJebva0LQCDW45yOrtpwIpGyDGX+EbCbHhS5Td4J0Yl
|
# q/xKTxrfbG23HofmQ+qZAN4GyO73PF3y9OAfpt7Qf2jcldWOGUB+HzBuwllYyP3f
|
||||||
# c83ztLEbbQD7M6kqR0Xj+n82cGse/QnMH0WRZLnwggJdenpQ6UciM4nMYZvdQjyb
|
# x4MY8zvuAuB37FvoytnNC2DKnVrVlHOVcGUL9CnmhDNMA2/nskjIf2IoiG9J0qLY
|
||||||
# A4qejOe9Y073JlXv3VIbdkQH2JGyT8oB/LsvPL/kAnJ45oQIp7Sx57RPQ/0O6qay
|
# r8duvHdQJ9Li2Pq9guySb9mvUL60ogslCO9gkh6FiEDwMrwUr8Wja6jFpUTny8tg
|
||||||
# J2SJrwcjA8auMdAnZKOixFlzoooh7SyycI7BENHTpkVKrRV5YelRvWNTg1pH4EC2
|
# 0N0cnCN2w4fKkp5qZcbUYFYicLSb/6A7pHCtX6xnjqwhmJoib3vkKJyVxbuFLRhV
|
||||||
# KO2bxsBN23btMeTvZFieGIr+D8mf1lQQs0Ht/tMOVdah14t7Yk+xl5P4Tw3xfAGg
|
# XxH95b0LHeNhifn3jvo2j+/4QV10jEpXVW+iC9BsTtR69xvTjU51ZgP7BR4YDEWq
|
||||||
# Hsvsa6ugrxwmKTTX1kqXH5XCdw3TVeKCax6JV+ygM5i1NroJKwBCW11Pwi0z/ki9
|
# 7JsylSOv5B5THTDXRf184URzFhTyb8OZQKY7mqMh7c8J8w1sEM4XDUF2UZNy829N
|
||||||
# 0ZeO6XfEE9mCnJm76Qcxi3tnW/Y/3ZumKQ6X/iVIJo7Lk0Z/pATRwAINqwdvzpdt
|
# VCzG2tfdEXZaHxF8RmxpQYBxyhZwY1rotuIS+gfN2eq+hkAT3ipGn8/KmDwDtzAb
|
||||||
# X2hOJib4GR8is2bpKks04GurfweWPn9z6jY7GBC+js8pSwGewrffwgAbNKm82ZDF
|
# nfuXjApgeZqwgcYJ8pDJ+y/xU6ouzJz1Bve5TTihkiA7wQsQe6R60Zk9dPdNzw0M
|
||||||
# vqBGQQVJwIHSXpjkS+G39eyYOG2rcILBIDlzUzMFFJbNh5tDv3GeJ3EKvC4vNSAx
|
# K5niRzuQZAt4GI96FhjhlUWcUZOCkv/JXM/OGu/rgSplYwdmPLzzfDtXyuy/GCU5
|
||||||
# tGfaG/mQhK43YjevsB72LouU78rxtNhuMXSzaHq5fFiG3zcsYHaa4+w+YmMrhTEz
|
# I4l08g6iifXypMgoYkkceOAAz4vx1x0BOnZWfI3fSwqNUvoN7ncTT+MB4Vpvf1QB
|
||||||
# D4SAish35BjoXP1P1Ct4Va0CAwEAAaOCAUkwggFFMB0GA1UdDgQWBBRjjHKbL5WV
|
# ppjBAQUuvui6eCG0MCVNAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQUmfIngFzZEZlP
|
||||||
# 6kd06KocQHphK9U/vzAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf
|
# kjDOVluBSDDaanEwHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYD
|
||||||
# BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
|
# VR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
|
||||||
# L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww
|
# cmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwG
|
||||||
# bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m
|
# CCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQu
|
||||||
# dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
|
# Y29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIw
|
||||||
# MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
|
# MjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
|
||||||
# BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAuFbCorFrvodG
|
# CDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBANxHtu3FzIabaDbW
|
||||||
# +ZNJH3Y+Nz5QpUytQVObOyYFrgcGrxq6MUa4yLmxN4xWdL1kygaW5BOZ3xBlPY7V
|
# qswdKBlAhKXRCN+5CSMiv2TYa4i2QuWIm+99piwAhDhADfbqor1zyLi95Y6GQnvI
|
||||||
# puf5b5eaXP7qRq61xeOrX3f64kGiSWoRi9EJawJWCzJfUQRThDL4zxI2pYc1wnPp
|
# WUgdeC7oL1ZtZye92zYK+EIfwYZmhS+CH4infAzUvscHZF3wlrJUfPUIDGVP0lCY
|
||||||
# 7Q695bHqwZ02eaOBudh/IfEkGe0Ofj6IS3oyZsJP1yatcm4kBqIH6db1+weM4q46
|
# Vse9mguvG0dqkY4ayQPEHOvJubgZZaOdg/N8dInd6fGeOc+0DoGzB+LieObJ2Q0A
|
||||||
# NhAfAf070zF6F+IpUHyhtMbQg5+QHfOuyBzrt67CiMJSKcJ3nMVyfNlnv6yvttYz
|
# tEt3XN3iX8Cp6+dZTX8xwE/LvhRwPpb/+nKshO7TVuvenwdTwqB/LT6CNPaElwFe
|
||||||
# LK3wS+0QwJUibLYJMI6FGcSuRxKlq6RjOhK9L3QOjh0VCM11rHM11ZmN0euJbbBC
|
# KxKrqRTPMbHeg+i+KnBLfwmhEXsMg2s1QX7JIxfvT96md0eiMjiMEO22LbOzmLMN
|
||||||
# VfQEufOLNkG88MFCUNE10SSbM/Og/CbTko0M5wbVvQJ6CqLKjtHSoeoAGPeeX24f
|
# d3LINowAnRBAJtX+3/e390B9sMGMHp+a1V+hgs62AopBl0p/00li30DN5wEQ5If3
|
||||||
# 5cPYyTcKlbM6LoUdO2P5JSdI5s1JF/On6LiUT50adpRstZajbYEeX/N7RvSbkn0d
|
# 5Zk7b/T6pEx6rJUDYCti7zCbikjKTanBnOc99zGMlej5X+fC/k5ExUCrOs3/VzGR
|
||||||
# jD3BvT2Of3Wf9gIeaQIHbv1J2O/P5QOPQiVo8+0AKm6M0TKOduihhKxAt/6Yyk17
|
# CZt5LvVQSdWqq/QMzTEmim4sbzASK9imEkjNtZZyvC1CsUcD1voFktld4mKMjE+u
|
||||||
# Fv3RIdjT6wiL2qRIEsgOJp3fILw4mQRPu3spRfakSoQe5N0e4HWFf8WW2ZL0+c83
|
# DEV3IddD+DrRk94nVzNPSuZXewfVOnXHSeqG7xM3V7fl2aL4v1OhL2+JwO1Tx3B0
|
||||||
# Qzh3VtEPI6Y2e2BO/eWhTYbIbHpqYDfAtAYtaYIde87ZymXG3MO2wUjhL9HvSQzj
|
# irO1O9qbNdJk355bntd1RSVKgM22KFBHnoL7Js7pRhBiaKmVTQGoOb+j1Qa7q+ci
|
||||||
# oquq+OoUmvfBUcB2e5L6QCHO6qTO7WowggdxMIIFWaADAgECAhMzAAAAFcXna54C
|
# xGo48Vh9k35BDsJS/DLoXFSPDl4mMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJ
|
||||||
# m0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
|
# mQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
|
||||||
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
|
|
||||||
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp
|
|
||||||
# Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMy
|
|
||||||
# MjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
|
|
||||||
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
|
|
||||||
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0B
|
|
||||||
# AQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51
|
|
||||||
# yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY
|
|
||||||
# 6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9
|
|
||||||
# cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN
|
|
||||||
# 7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDua
|
|
||||||
# Rr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74
|
|
||||||
# kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2
|
|
||||||
# K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5
|
|
||||||
# TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk
|
|
||||||
# i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q
|
|
||||||
# BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3Pmri
|
|
||||||
# Lq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUC
|
|
||||||
# BBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJl
|
|
||||||
# pxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB
|
|
||||||
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y
|
|
||||||
# eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA
|
|
||||||
# YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
|
|
||||||
# 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
|
|
||||||
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw
|
|
||||||
# MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
|
|
||||||
# L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w
|
|
||||||
# Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/yp
|
|
||||||
# b+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulm
|
|
||||||
# ZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM
|
|
||||||
# 9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECW
|
|
||||||
# OKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4
|
|
||||||
# FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3Uw
|
|
||||||
# xTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPX
|
|
||||||
# fx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVX
|
|
||||||
# VAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGC
|
|
||||||
# onsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU
|
|
||||||
# 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG
|
|
||||||
# ahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJV
|
|
||||||
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
|
|
||||||
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
|
|
||||||
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
|
|
||||||
# Tjo0MzFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
|
|
||||||
# U2VydmljZaIjCgEBMAcGBSsOAwIaAxUA94Z+bUJn+nKwBvII6sg0Ny7aPDaggYMw
|
|
||||||
# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
|
|
||||||
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
|
|
||||||
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsF
|
|
||||||
# AAIFAOss/ykwIhgPMjAyNTAxMTExNDMxMDVaGA8yMDI1MDExMjE0MzEwNVowdzA9
|
|
||||||
# BgorBgEEAYRZCgQBMS8wLTAKAgUA6yz/KQIBADAKAgEAAgIpggIB/zAHAgEAAgIT
|
|
||||||
# XjAKAgUA6y5QqQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow
|
|
||||||
# CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQCHE6DSGdY4
|
|
||||||
# KF25iAsxQP9F9Lz6ye/vrWGv+j0aSzSbjHVM3kMcEmX9278XgAKgAYII/f16uDtE
|
|
||||||
# 7VlEwnKGXujGF249I864U50QFt9hIxqCeuvrshDq8a4Q4KVmuDTosYjS114IJeBK
|
|
||||||
# LMOBRgLQCIC+wmvdP4EeYH1tnMIEASFvptE+XBro44/A5pmx5UiDJRL1AG4+aO3x
|
|
||||||
# 13psQu7H3thmbGy7Sf0Azjx0PZ+1QUVI7jWNk9DWjGd18G4SQD8Uxeh0v73/dQx1
|
|
||||||
# XsFhsyvnrw6uUrxkoAdurif9kyKS+ppo4j9ZkPXzzuc95s1bPcPAyjXCu07Tlunj
|
|
||||||
# sXttGVEPQIeXMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
|
|
||||||
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
|
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
|
||||||
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
|
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh
|
||||||
# IDIwMTACEzMAAAH6+ztE03czxtMAAQAAAfowDQYJYIZIAWUDBAIBBQCgggFKMBoG
|
# dGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1
|
||||||
# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgxenDb/df
|
# WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
||||||
# q8XJS+q7Oxyca1ryDMmDRA0I3mtr+xYHGZQwgfoGCyqGSIb3DQEJEAIvMYHqMIHn
|
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
|
||||||
# MIHkMIG9BCB98n8tya8+B2jjU/dpJRIwHwHHpco5ogNStYocbkOeVjCBmDCBgKR+
|
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEB
|
||||||
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
|
# BQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjK
|
||||||
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
|
# NVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhg
|
||||||
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB+vs7RNN3M8bTAAEA
|
# fWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJp
|
||||||
# AAH6MCIEIC8gtQ6HRW7jzwlpg15qoYopXwF01KaO1EM5tYzqJwx/MA0GCSqGSIb3
|
# rx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/d
|
||||||
# DQEBCwUABIICAIsSn8x3zVS870Zf4pa+jfZjdOq++5dHpeLg46sujQ3w+xj3RyhB
|
# vI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka9
|
||||||
# nRa3kjWyU9nNF6hrt0Q+ILOxUt3jCd3hbB1ZuspwbXdoRtRLfuLPvGiSmINdgFR4
|
# 7aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKR
|
||||||
# LD/jXLrq9USAHYXHzhuYhaVLIpn7M87TbFuGFVaByjmohZRcPCE8y8b7/RIlGm7B
|
# Hh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9itu
|
||||||
# wgx0thZA4lHWFyj8j7CwjmueOJSSZ9an4P9VHFKJ63kYub4J1VxbeApGAeeS32SD
|
# qBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyO
|
||||||
# oI3zDdC+iI+IetR9BUHGcR3Vg7j7c0T+NcrIoPPNb4Ff90Ue24h5RDJMQWrM56ak
|
# ArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItb
|
||||||
# VEWgVlzhf8CeyeO7/ButBUZu8VLkH0DQraK9UKptZFKOXMELoi/oZL6IJftHp5vU
|
# oKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6
|
||||||
# +sPpF3NuuXw8Z5eL9jZ7A1y+H7nMhdXP2pojHDN213VZqeoUoOZlbFl6spDF1hFP
|
# bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6t
|
||||||
# 44Fu7TPGEwUNS213Pwln2SJ8SayeVUxsreo4pTvhDl/xZ+B7WNuLL7hatWFGrcf3
|
# AgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQW
|
||||||
# w/HiVCoTfsY49SaN6zAK6akS3KI6KZHfzjaxDw+4LHo8gL68Ik1HZe4W1jaLYaED
|
# BBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacb
|
||||||
# LWvKIinaH2vwU0J4a+oX+64eSh0tI9Ef3aM6jn9LgqubY36TzptUTWcsM3vv3YGB
|
# UzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYz
|
||||||
# Dnf7LPxSt4/s5bUgAHvkWTjESdtIbt6Pxqz4BRha+ckPYBj968t3mSh6
|
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnku
|
||||||
|
# aHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA
|
||||||
|
# QwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2
|
||||||
|
# VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu
|
||||||
|
# bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEw
|
||||||
|
# LTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93
|
||||||
|
# d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYt
|
||||||
|
# MjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/q
|
||||||
|
# XBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6
|
||||||
|
# U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVt
|
||||||
|
# I1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis
|
||||||
|
# 9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTp
|
||||||
|
# kbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0
|
||||||
|
# sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138e
|
||||||
|
# W0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJ
|
||||||
|
# sWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7
|
||||||
|
# Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0
|
||||||
|
# dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQ
|
||||||
|
# tB1VM1izoXBm8qGCAtQwggI9AgEBMIIBAKGB2KSB1TCB0jELMAkGA1UEBhMCVVMx
|
||||||
|
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
|
||||||
|
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxh
|
||||||
|
# bmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjow
|
||||||
|
# ODQyLTRCRTYtQzI5QTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
|
||||||
|
# dmljZaIjCgEBMAcGBSsOAwIaAxUAjhJ+EeySRfn2KCNsjn9cF9AUSTqggYMwgYCk
|
||||||
|
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
||||||
|
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
|
||||||
|
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF
|
||||||
|
# AOfRUdUwIhgPMjAyMzAzMzEyMDM0MjlaGA8yMDIzMDQwMTIwMzQyOVowdDA6Bgor
|
||||||
|
# BgEEAYRZCgQBMSwwKjAKAgUA59FR1QIBADAHAgEAAgIKJDAHAgEAAgIRLzAKAgUA
|
||||||
|
# 59KjVQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAID
|
||||||
|
# B6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAJlOESCa/uRR1x6GunE8
|
||||||
|
# K/WgHWTpSE31EITDOfTMvDcF4ptngCS5aOc4gfzmhNNehWfP6EOrgoSQzJYZ4YCh
|
||||||
|
# fYbHNMk56f18sq8t7y2hgR7KixcEo/4HVzeSdaOclHNc4Gn7kCGpMvpT3Xz9Lzc7
|
||||||
|
# UKWDZ0zkNKnbS8TZLNueVQwfMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMx
|
||||||
|
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
|
||||||
|
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt
|
||||||
|
# U3RhbXAgUENBIDIwMTACEzMAAAGybkADf26plJIAAQAAAbIwDQYJYIZIAWUDBAIB
|
||||||
|
# BQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQx
|
||||||
|
# IgQgXhJRuHCXk3arJvifIY3DBe9Ce9EmlP1y6U4XkgL31DkwgfoGCyqGSIb3DQEJ
|
||||||
|
# EAIvMYHqMIHnMIHkMIG9BCBTeM485+E+t4PEVieUoFKX7PVyLo/nzu+htJPCG04+
|
||||||
|
# NTCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
|
||||||
|
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
|
||||||
|
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABsm5A
|
||||||
|
# A39uqZSSAAEAAAGyMCIEIGGWlnNnYHrB5HguWG0/nJd/WvSrCogze+QCpenu3IM5
|
||||||
|
# MA0GCSqGSIb3DQEBCwUABIICADVOLTuNxeEnBOfZpb7Nv4uf91W/Ho5i99zenDSJ
|
||||||
|
# x5QHVs+bKXmgc3a7/SSsliAT3zygHc7cH4zARbCZePLTivByKmeG08Ka35eyR+FK
|
||||||
|
# awSNrI/X+eVIC6nw/egCwviBC1NAG8jHGkuScbHeiiGajvS6lp3ORML7UexMuE4w
|
||||||
|
# 9SEumoghljCLZMwCSvw+3WxhQoBEZroR8u+PID2RdD0vi85FjKPWcZZijVLqHeFi
|
||||||
|
# TnuFqwRCLTV0MV+dDCbjwXneIqV+AVlnqb9iDMr3ZhISlRcy9XJNpY5vQBj/wqUW
|
||||||
|
# vefrmpdz0LNkdtXYThPkyl3mha2KsoQi5SA9zSjlAjFgY3ppmXvi3Frbfqk+iL+f
|
||||||
|
# l/Qc4+B71jG4t28lTWKteJiHqo+6AUXK2rlAl0d74yvhO6N8lMMtXhdJc8JABYn1
|
||||||
|
# v2/KKZn5RvPFF8QP7Ac1saIe1+gUFNcsYOLaMm/xl8E6kefWwZnm5Rhm606g1AC/
|
||||||
|
# N5Wo08aAs0ymTPH91dEbmOURXLbA3vCyG7kbfgnhCs/j7oQHWaFDzEYuXDIA4ICT
|
||||||
|
# dxPUTltbq3OWdp0PAS8JSEKPQFaOoQEnPa4adrXWxMvOmel8IGqJiQ+BPOaLQG64
|
||||||
|
# Qu2tMkH/5szb1fsEnCe8SJmy5ESF+kmpnLBtJ17Y9o+9nJHF5ddFmvzy+LUaIqDN
|
||||||
|
# cOfH
|
||||||
# SIG # End signature block
|
# SIG # End signature block
|
288
externals/install-dotnet.sh
vendored
288
externals/install-dotnet.sh
vendored
@ -298,20 +298,11 @@ 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
|
||||||
;;
|
;;
|
||||||
@ -319,22 +310,6 @@ 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
|
||||||
|
|
||||||
@ -351,13 +326,7 @@ get_normalized_architecture_from_architecture() {
|
|||||||
local architecture="$(to_lowercase "$1")"
|
local architecture="$(to_lowercase "$1")"
|
||||||
|
|
||||||
if [[ $architecture == \<auto\> ]]; then
|
if [[ $architecture == \<auto\> ]]; then
|
||||||
machine_architecture="$(get_machine_architecture)"
|
echo "$(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
|
||||||
|
|
||||||
@ -378,14 +347,6 @@ 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"
|
||||||
@ -423,17 +384,11 @@ get_normalized_architecture_for_specific_sdk_version() {
|
|||||||
# args:
|
# args:
|
||||||
# version or channel - $1
|
# version or channel - $1
|
||||||
is_arm64_supported() {
|
is_arm64_supported() {
|
||||||
# Extract the major version by splitting on the dot
|
#any channel or version that starts with the specified versions
|
||||||
major_version="${1%%.*}"
|
case "$1" in
|
||||||
|
( "1"* | "2"* | "3"* | "4"* | "5"*)
|
||||||
# Check if the major version is a valid number and less than 6
|
|
||||||
case "$major_version" in
|
|
||||||
[0-9]*)
|
|
||||||
if [ "$major_version" -lt 6 ]; then
|
|
||||||
echo false
|
echo false
|
||||||
return 0
|
return 0
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo true
|
echo true
|
||||||
@ -452,13 +407,8 @@ 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, macos, 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, 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
|
||||||
@ -588,40 +538,6 @@ 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
|
||||||
@ -956,37 +872,6 @@ 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
|
||||||
@ -998,7 +883,15 @@ 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 override_switch="$(get_cp_options "$override")"
|
local osname="$(get_current_os_name)"
|
||||||
|
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}")"
|
||||||
@ -1013,39 +906,14 @@ 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")"
|
||||||
|
|
||||||
@ -1056,12 +924,8 @@ extract_dotnet_package() {
|
|||||||
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"
|
||||||
if [ -z ${keep_zip+x} ]; then
|
rm -f "$zip_path" && say_verbose "Temporary zip file $zip_path was removed"
|
||||||
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"
|
||||||
@ -1272,61 +1136,6 @@ 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
|
||||||
|
|
||||||
@ -1363,12 +1172,6 @@ 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
|
||||||
@ -1379,11 +1182,6 @@ 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
|
||||||
@ -1395,17 +1193,24 @@ get_download_link_from_aka_ms() {
|
|||||||
get_feeds_to_use()
|
get_feeds_to_use()
|
||||||
{
|
{
|
||||||
feeds=(
|
feeds=(
|
||||||
"https://builds.dotnet.microsoft.com/dotnet"
|
"https://dotnetcli.azureedge.net/dotnet"
|
||||||
"https://ci.dot.net/public"
|
"https://dotnetbuilds.azureedge.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
|
||||||
|
feeds=(
|
||||||
|
"https://dotnetcli.blob.core.windows.net/dotnet"
|
||||||
|
"https://dotnetbuilds.blob.core.windows.net/public"
|
||||||
|
)
|
||||||
|
|
||||||
if [[ -n "$uncached_feed" ]]; then
|
if [[ -n "$uncached_feed" ]]; then
|
||||||
feeds=("$uncached_feed")
|
feeds=("$uncached_feed")
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# THIS FUNCTION MAY EXIT (if the determined version is already installed).
|
# THIS FUNCTION MAY EXIT (if the determined version is already installed).
|
||||||
@ -1536,7 +1341,7 @@ generate_regular_links() {
|
|||||||
link_types+=("legacy")
|
link_types+=("legacy")
|
||||||
else
|
else
|
||||||
legacy_download_link=""
|
legacy_download_link=""
|
||||||
say_verbose "Could not construct a legacy_download_link; omitting..."
|
say_verbose "Cound 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.
|
||||||
@ -1614,11 +1419,10 @@ 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="${zip_path:-$(mktemp "$temporary_file_template")}"
|
zip_path="$(mktemp "$temporary_file_template")"
|
||||||
say_verbose "Archive path: $zip_path"
|
say_verbose "Zip path: $zip_path"
|
||||||
|
|
||||||
for link_index in "${!download_links[@]}"
|
for link_index in "${!download_links[@]}"
|
||||||
do
|
do
|
||||||
@ -1639,10 +1443,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': $http_code $download_error_msg"
|
say "Failed to download $link_type link '$download_link': $download_error_msg"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
rm -f "$zip_path" 2>&1 && say_verbose "Temporary archive file $zip_path was removed"
|
rm -f "$zip_path" 2>&1 && say_verbose "Temporary zip file $zip_path was removed"
|
||||||
else
|
else
|
||||||
download_completed=true
|
download_completed=true
|
||||||
break
|
break
|
||||||
@ -1655,10 +1459,8 @@ install_dotnet() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
remote_file_size="$(get_remote_file_size "$download_link")"
|
say "Extracting zip from $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.
|
||||||
@ -1700,6 +1502,7 @@ 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=""
|
||||||
@ -1772,6 +1575,10 @@ 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"
|
||||||
@ -1803,22 +1610,10 @@ 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="dotnet-install.sh"
|
script_name="$(basename "$0")"
|
||||||
echo ".NET Tools Installer"
|
echo ".NET Tools Installer"
|
||||||
echo "Usage:"
|
echo "Usage: $script_name [-c|--channel <CHANNEL>] [-v|--version <VERSION>] [-p|--prefix <DESTINATION>]"
|
||||||
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."
|
||||||
@ -1860,7 +1655,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, s390x, ppc64le and loongarch64"
|
echo " Possible values: x64, arm, arm64 and s390x"
|
||||||
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."
|
||||||
@ -1876,14 +1671,15 @@ 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:"
|
||||||
|
2535
package-lock.json
generated
2535
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -1,15 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "setup-dotnet",
|
"name": "setup-dotnet",
|
||||||
"version": "2.1.0",
|
"version": "3.0.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "setup dotnet action",
|
"description": "setup dotnet action",
|
||||||
"main": "lib/setup-dotnet.js",
|
"main": "lib/setup-dotnet.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && ncc build",
|
"build": "tsc && ncc build",
|
||||||
"format": "prettier --write **/*.ts",
|
"format": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write \"**/*.{ts,yml,yaml}\"",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check \"**/*.{ts,yml,yaml}\"",
|
||||||
|
"lint": "eslint --config ./.eslintrc.js \"**/*.ts\"",
|
||||||
|
"lint:fix": "eslint --config ./.eslintrc.js \"**/*.ts\" --fix",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"test": "jest",
|
"test": "jest --coverage --config ./jest.config.js",
|
||||||
"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,26 +26,30 @@
|
|||||||
"author": "GitHub",
|
"author": "GitHub",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.6.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.0.4",
|
"@actions/exec": "^1.0.4",
|
||||||
"@actions/github": "^1.1.0",
|
"@actions/github": "^1.1.0",
|
||||||
"@actions/http-client": "^1.0.8",
|
"@actions/http-client": "^2.0.1",
|
||||||
"@actions/io": "^1.0.2",
|
"@actions/io": "^1.0.2",
|
||||||
"fast-xml-parser": "^3.15.1",
|
"fast-xml-parser": "^4.0.10",
|
||||||
"semver": "^6.3.0",
|
"semver": "^6.3.0"
|
||||||
"xmlbuilder": "^13.0.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.0.2",
|
"@types/jest": "^27.0.2",
|
||||||
"@types/node": "^16.11.25",
|
"@types/node": "^16.11.25",
|
||||||
"@types/semver": "^6.2.2",
|
"@types/semver": "^6.2.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||||
|
"@typescript-eslint/parser": "^5.54.0",
|
||||||
"@vercel/ncc": "^0.33.4",
|
"@vercel/ncc": "^0.33.4",
|
||||||
|
"eslint": "^8.35.0",
|
||||||
|
"eslint-config-prettier": "^8.6.0",
|
||||||
|
"eslint-plugin-jest": "^27.2.1",
|
||||||
"husky": "^8.0.1",
|
"husky": "^8.0.1",
|
||||||
"jest": "^27.2.5",
|
"jest": "^27.2.5",
|
||||||
"jest-circus": "^27.2.5",
|
"jest-circus": "^27.2.5",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^2.8.4",
|
||||||
"ts-jest": "^27.0.5",
|
"ts-jest": "^27.0.5",
|
||||||
"typescript": "^3.9.7",
|
"typescript": "^4.8.4",
|
||||||
"wget-improved": "^3.2.1"
|
"wget-improved": "^3.2.1"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
|
171
src/authutil.ts
171
src/authutil.ts
@ -2,13 +2,11 @@ import * as fs from 'fs';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as github from '@actions/github';
|
import * as github from '@actions/github';
|
||||||
import * as xmlbuilder from 'xmlbuilder';
|
import {XMLParser, XMLBuilder} 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,
|
||||||
existingFileLocation: string = '',
|
existingFileLocation = '',
|
||||||
processRoot: string = process.cwd()
|
processRoot: string = process.cwd()
|
||||||
) {
|
) {
|
||||||
const existingNuGetConfig: string = path.resolve(
|
const existingNuGetConfig: string = path.resolve(
|
||||||
@ -28,7 +26,7 @@ export function configAuthentication(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isValidKey(key: string): boolean {
|
function isValidKey(key: string): boolean {
|
||||||
return /^[\w\-\.]+$/i.test(key);
|
return /^[\w\-.]+$/i.test(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExistingNugetConfig(processRoot: string) {
|
function getExistingNugetConfig(processRoot: string) {
|
||||||
@ -47,18 +45,17 @@ function writeFeedToFile(
|
|||||||
existingFileLocation: string,
|
existingFileLocation: string,
|
||||||
tempFileLocation: string
|
tempFileLocation: string
|
||||||
) {
|
) {
|
||||||
console.log(
|
core.info(
|
||||||
`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;
|
const sourceKeys: string[] = [];
|
||||||
let sourceKeys: string[] = [];
|
|
||||||
let owner: string = core.getInput('owner');
|
let owner: string = core.getInput('owner');
|
||||||
let sourceUrl: string = feedUrl;
|
const sourceUrl: string = feedUrl;
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
owner = github.context.repo.owner;
|
owner = github.context.repo.owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.env.NUGET_AUTH_TOKEN || process.env.NUGET_AUTH_TOKEN == '') {
|
if (!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}}'
|
||||||
);
|
);
|
||||||
@ -67,64 +64,90 @@ 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');
|
||||||
var json = xmlParser.parse(curContents, {ignoreAttributes: false});
|
|
||||||
|
|
||||||
if (typeof json.configuration == 'undefined') {
|
const parserOptions = {
|
||||||
|
ignoreAttributes: false
|
||||||
|
};
|
||||||
|
const parser = new XMLParser(parserOptions);
|
||||||
|
const json = parser.parse(curContents);
|
||||||
|
|
||||||
|
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 (json.configuration?.packageSources?.add) {
|
||||||
if (typeof json.configuration.packageSources.add != 'undefined') {
|
const packageSources = json.configuration.packageSources.add;
|
||||||
// file has at least one <add>
|
|
||||||
if (typeof json.configuration.packageSources.add[0] == 'undefined') {
|
if (Array.isArray(packageSources)) {
|
||||||
// file has only one <add>
|
packageSources.forEach(source => {
|
||||||
if (
|
|
||||||
json.configuration.packageSources.add['@_value']
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(feedUrl.toLowerCase())
|
|
||||||
) {
|
|
||||||
let key = json.configuration.packageSources.add['@_key'];
|
|
||||||
sourceKeys.push(key);
|
|
||||||
core.debug(`Found a URL with key ${key}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// file has 2+ <add>
|
|
||||||
for (
|
|
||||||
let i = 0;
|
|
||||||
i < json.configuration.packageSources.add.length;
|
|
||||||
i++
|
|
||||||
) {
|
|
||||||
const source = json.configuration.packageSources.add[i];
|
|
||||||
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())) {
|
||||||
let key = source['@_key'];
|
const key = source['@_key'];
|
||||||
|
sourceKeys.push(key);
|
||||||
|
core.debug(`Found a URL with key ${key}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
packageSources['@_value']
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(feedUrl.toLowerCase())
|
||||||
|
) {
|
||||||
|
const key = packageSources['@_key'];
|
||||||
sourceKeys.push(key);
|
sourceKeys.push(key);
|
||||||
core.debug(`Found a URL with key ${key}`);
|
core.debug(`Found a URL with key ${key}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const xmlSource: any[] = [
|
||||||
|
{
|
||||||
|
'?xml': [
|
||||||
|
{
|
||||||
|
'#text': ''
|
||||||
|
}
|
||||||
|
],
|
||||||
|
':@': {
|
||||||
|
'@_version': '1.0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
configuration: [
|
||||||
|
{
|
||||||
|
config: [
|
||||||
|
{
|
||||||
|
add: [],
|
||||||
|
':@': {
|
||||||
|
'@_key': 'defaultPushSource',
|
||||||
|
'@_value': sourceUrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
xml = xmlbuilder
|
if (!sourceKeys.length) {
|
||||||
.create('configuration')
|
const keystring = 'Source';
|
||||||
.ele('config')
|
|
||||||
.ele('add', {key: 'defaultPushSource', value: sourceUrl})
|
xmlSource[1].configuration.push({
|
||||||
.up()
|
packageSources: [
|
||||||
.up();
|
{
|
||||||
|
add: [],
|
||||||
|
':@': {
|
||||||
|
'@_key': keystring,
|
||||||
|
'@_value': sourceUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
if (sourceKeys.length == 0) {
|
|
||||||
let keystring = 'Source';
|
|
||||||
xml = xml
|
|
||||||
.ele('packageSources')
|
|
||||||
.ele('add', {key: keystring, value: sourceUrl})
|
|
||||||
.up()
|
|
||||||
.up();
|
|
||||||
sourceKeys.push(keystring);
|
sourceKeys.push(keystring);
|
||||||
}
|
}
|
||||||
xml = xml.ele('packageSourceCredentials');
|
|
||||||
|
|
||||||
|
const packageSourceCredentials: any[] = [];
|
||||||
sourceKeys.forEach(key => {
|
sourceKeys.forEach(key => {
|
||||||
if (!isValidKey(key)) {
|
if (!isValidKey(key)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -132,24 +155,42 @@ function writeFeedToFile(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
xml = xml
|
packageSourceCredentials.push({
|
||||||
.ele(key)
|
[key]: [
|
||||||
.ele('add', {key: 'Username', value: owner})
|
{
|
||||||
.up()
|
add: [],
|
||||||
.ele('add', {
|
':@': {
|
||||||
key: 'ClearTextPassword',
|
'@_key': 'Username',
|
||||||
value: process.env.NUGET_AUTH_TOKEN
|
'@_value': owner
|
||||||
})
|
}
|
||||||
.up()
|
},
|
||||||
.up();
|
{
|
||||||
|
add: [],
|
||||||
|
':@': {
|
||||||
|
'@_key': 'ClearTextPassword',
|
||||||
|
'@_value': process.env.NUGET_AUTH_TOKEN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// If NuGet fixes itself such that on Linux it can look for environment variables in the config file (it doesn't seem to work today),
|
xmlSource[1].configuration.push({
|
||||||
// use this for the value above
|
packageSourceCredentials
|
||||||
// process.platform == 'win32'
|
});
|
||||||
// ? '%NUGET_AUTH_TOKEN%'
|
|
||||||
// : '$NUGET_AUTH_TOKEN'
|
const xmlBuilderOptions = {
|
||||||
|
format: true,
|
||||||
|
ignoreAttributes: false,
|
||||||
|
preserveOrder: true,
|
||||||
|
allowBooleanAttributes: true,
|
||||||
|
suppressBooleanAttributes: true,
|
||||||
|
suppressEmptyNode: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const builder = new XMLBuilder(xmlBuilderOptions);
|
||||||
|
|
||||||
|
const output = builder.build(xmlSource).trim();
|
||||||
|
|
||||||
var output = xml.end({pretty: true});
|
|
||||||
fs.writeFileSync(tempFileLocation, output);
|
fs.writeFileSync(tempFileLocation, output);
|
||||||
}
|
}
|
||||||
|
472
src/installer.ts
472
src/installer.ts
@ -2,303 +2,277 @@
|
|||||||
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 hc = require('@actions/http-client');
|
import * as hc from '@actions/http-client';
|
||||||
import {chmodSync} from 'fs';
|
import {chmodSync} from 'fs';
|
||||||
import * as path from 'path';
|
import path from 'path';
|
||||||
import {ExecOptions} from '@actions/exec/lib/interfaces';
|
import os from 'os';
|
||||||
import * as semver from 'semver';
|
import semver from 'semver';
|
||||||
|
import {IS_LINUX, IS_WINDOWS} from './utils';
|
||||||
|
import {QualityOptions} from './setup-dotnet';
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
export interface DotnetVersion {
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
qualityFlag: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
const QUALITY_INPUT_MINIMAL_MAJOR_TAG = 6;
|
||||||
* Represents the inputted version information
|
const LATEST_PATCH_SYNTAX_MINIMAL_MAJOR_TAG = 5;
|
||||||
*/
|
export class DotnetVersionResolver {
|
||||||
export class DotNetVersionInfo {
|
private inputVersion: string;
|
||||||
public inputVersion: string;
|
private resolvedArgument: DotnetVersion;
|
||||||
private fullversion: string;
|
|
||||||
private isExactVersionSet: boolean = false;
|
|
||||||
|
|
||||||
constructor(version: string) {
|
constructor(version: string) {
|
||||||
this.inputVersion = version;
|
this.inputVersion = version.trim();
|
||||||
|
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('.');
|
private async resolveVersionInput(): Promise<void> {
|
||||||
|
if (!semver.validRange(this.inputVersion) && !this.isLatestPatchSyntax()) {
|
||||||
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 getVersionNumberOrThrow(input: string): number {
|
|
||||||
try {
|
|
||||||
if (!input || input.trim() === '') this.throwInvalidVersionFormat();
|
|
||||||
|
|
||||||
let number = Number(input);
|
|
||||||
|
|
||||||
if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
|
|
||||||
|
|
||||||
return number;
|
|
||||||
} catch {
|
|
||||||
this.throwInvalidVersionFormat();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private throwInvalidVersionFormat() {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*'
|
`The 'dotnet-version' was supplied in invalid format: ${this.inputVersion}! Supported syntax: A.B.C, A.B, A.B.x, A, A.x, A.B.Cxx`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (semver.valid(this.inputVersion)) {
|
||||||
|
this.createVersionArgument();
|
||||||
|
} else {
|
||||||
|
await this.createChannelArgument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isNumericTag(versionTag): boolean {
|
||||||
|
return /^\d+$/.test(versionTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isLatestPatchSyntax() {
|
||||||
|
const majorTag = this.inputVersion.match(
|
||||||
|
/^(?<majorTag>\d+)\.\d+\.\d{1}x{2}$/
|
||||||
|
)?.groups?.majorTag;
|
||||||
|
if (
|
||||||
|
majorTag &&
|
||||||
|
parseInt(majorTag) < LATEST_PATCH_SYNTAX_MINIMAL_MAJOR_TAG
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`The 'dotnet-version' was supplied in invalid format: ${this.inputVersion}! The A.B.Cxx syntax is available since the .NET 5.0 release.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return majorTag ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createVersionArgument() {
|
||||||
|
this.resolvedArgument.type = 'version';
|
||||||
|
this.resolvedArgument.value = this.inputVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createChannelArgument() {
|
||||||
|
this.resolvedArgument.type = 'channel';
|
||||||
|
const [major, minor] = this.inputVersion.split('.');
|
||||||
|
if (this.isLatestPatchSyntax()) {
|
||||||
|
this.resolvedArgument.value = this.inputVersion;
|
||||||
|
} else if (this.isNumericTag(major) && this.isNumericTag(minor)) {
|
||||||
|
this.resolvedArgument.value = `${major}.${minor}`;
|
||||||
|
} else if (this.isNumericTag(major)) {
|
||||||
|
this.resolvedArgument.value = await this.getLatestByMajorTag(major);
|
||||||
|
} else {
|
||||||
|
// If "dotnet-version" is specified as *, x or X resolve latest version of .NET explicitly from LTS channel. The version argument will default to "latest" by install-dotnet script.
|
||||||
|
this.resolvedArgument.value = 'LTS';
|
||||||
|
}
|
||||||
|
this.resolvedArgument.qualityFlag =
|
||||||
|
parseInt(major) >= QUALITY_INPUT_MINIMAL_MAJOR_TAG ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createDotNetVersion(): Promise<DotnetVersion> {
|
||||||
|
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 getLatestByMajorTag(majorTag: string): Promise<string> {
|
||||||
|
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
|
||||||
|
allowRetries: true,
|
||||||
|
maxRetries: 3
|
||||||
|
});
|
||||||
|
const response = await httpClient.getJson<any>(
|
||||||
|
DotnetVersionResolver.DotNetCoreIndexUrl
|
||||||
|
);
|
||||||
|
const result = response.result || {};
|
||||||
|
const releasesInfo: any[] = result['releases-index'];
|
||||||
|
|
||||||
|
const releaseInfo = releasesInfo.find(info => {
|
||||||
|
const sdkParts: string[] = info['channel-version'].split('.');
|
||||||
|
return sdkParts[0] === majorTag;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!releaseInfo) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find info for version with major tag: "${majorTag}" at ${DotnetVersionResolver.DotNetCoreIndexUrl}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return releaseInfo['channel-version'];
|
||||||
* If true exacatly one version should be resolved
|
|
||||||
*/
|
|
||||||
public isExactVersion(): boolean {
|
|
||||||
return this.isExactVersionSet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public version(): string {
|
static DotNetCoreIndexUrl =
|
||||||
return this.fullversion;
|
'https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json';
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DotnetCoreInstaller {
|
export class DotnetCoreInstaller {
|
||||||
constructor(version: string, includePrerelease: boolean = false) {
|
private version: string;
|
||||||
this.version = version;
|
private quality: QualityOptions;
|
||||||
this.includePrerelease = includePrerelease;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async installDotnet() {
|
static {
|
||||||
let output = '';
|
const installationDirectoryWindows = path.join(
|
||||||
let resultCode = 0;
|
process.env['PROGRAMFILES'] + '',
|
||||||
|
'dotnet'
|
||||||
let calculatedVersion = await this.resolveVersion(
|
|
||||||
new DotNetVersionInfo(this.version)
|
|
||||||
);
|
);
|
||||||
|
const installationDirectoryLinux = '/usr/share/dotnet';
|
||||||
var envVariables: {[key: string]: string} = {};
|
const installationDirectoryMac = path.join(
|
||||||
for (let key in process.env) {
|
process.env['HOME'] + '',
|
||||||
if (process.env[key]) {
|
'.dotnet'
|
||||||
let value: any = process.env[key];
|
);
|
||||||
envVariables[key] = value;
|
const dotnetInstallDir: string | undefined =
|
||||||
}
|
process.env['DOTNET_INSTALL_DIR'];
|
||||||
}
|
if (dotnetInstallDir) {
|
||||||
|
process.env['DOTNET_INSTALL_DIR'] =
|
||||||
|
this.convertInstallPathToAbsolute(dotnetInstallDir);
|
||||||
|
} else {
|
||||||
if (IS_WINDOWS) {
|
if (IS_WINDOWS) {
|
||||||
let escapedScript = path
|
process.env['DOTNET_INSTALL_DIR'] = installationDirectoryWindows;
|
||||||
.join(__dirname, '..', 'externals', 'install-dotnet.ps1')
|
} else {
|
||||||
.replace(/'/g, "''");
|
process.env['DOTNET_INSTALL_DIR'] = IS_LINUX
|
||||||
let command = `& '${escapedScript}'`;
|
? installationDirectoryLinux
|
||||||
if (calculatedVersion) {
|
: installationDirectoryMac;
|
||||||
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
|
constructor(version: string, quality: QualityOptions) {
|
||||||
const powershellPath =
|
this.version = version;
|
||||||
(await io.which('pwsh', false)) || (await io.which('powershell', true));
|
this.quality = quality;
|
||||||
|
|
||||||
var options: ExecOptions = {
|
|
||||||
listeners: {
|
|
||||||
stdout: (data: Buffer) => {
|
|
||||||
output += data.toString();
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
env: envVariables
|
|
||||||
};
|
|
||||||
|
|
||||||
resultCode = await exec.exec(
|
private static convertInstallPathToAbsolute(installDir: string): string {
|
||||||
`"${powershellPath}"`,
|
let transformedPath;
|
||||||
[
|
if (path.isAbsolute(installDir)) {
|
||||||
|
transformedPath = installDir;
|
||||||
|
} else {
|
||||||
|
transformedPath = installDir.startsWith('~')
|
||||||
|
? path.join(os.homedir(), installDir.slice(1))
|
||||||
|
: (transformedPath = path.join(process.cwd(), installDir));
|
||||||
|
}
|
||||||
|
return path.normalize(transformedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static addToPath() {
|
||||||
|
core.addPath(process.env['DOTNET_INSTALL_DIR']!);
|
||||||
|
core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setQuality(
|
||||||
|
dotnetVersion: DotnetVersion,
|
||||||
|
scriptArguments: string[]
|
||||||
|
): void {
|
||||||
|
const option = IS_WINDOWS ? '-Quality' : '--quality';
|
||||||
|
if (dotnetVersion.qualityFlag) {
|
||||||
|
scriptArguments.push(option, this.quality);
|
||||||
|
} else {
|
||||||
|
core.warning(
|
||||||
|
`The 'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A, A.x and A.B.Cxx formats where the major tag is higher than 5. You specified: ${this.version}. 'dotnet-quality' input is ignored.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async installDotnet(): Promise<string | null> {
|
||||||
|
const windowsDefaultOptions = [
|
||||||
'-NoLogo',
|
'-NoLogo',
|
||||||
'-Sta',
|
'-Sta',
|
||||||
'-NoProfile',
|
'-NoProfile',
|
||||||
'-NonInteractive',
|
'-NonInteractive',
|
||||||
'-ExecutionPolicy',
|
'-ExecutionPolicy',
|
||||||
'Unrestricted',
|
'Unrestricted',
|
||||||
'-Command',
|
'-Command'
|
||||||
command
|
];
|
||||||
],
|
const scriptName = IS_WINDOWS ? 'install-dotnet.ps1' : 'install-dotnet.sh';
|
||||||
options
|
const escapedScript = path
|
||||||
);
|
.join(__dirname, '..', 'externals', scriptName)
|
||||||
} else {
|
|
||||||
let escapedScript = path
|
|
||||||
.join(__dirname, '..', 'externals', 'install-dotnet.sh')
|
|
||||||
.replace(/'/g, "''");
|
.replace(/'/g, "''");
|
||||||
chmodSync(escapedScript, '777');
|
let scriptArguments: string[];
|
||||||
|
let scriptPath = '';
|
||||||
|
|
||||||
const scriptPath = await io.which(escapedScript, true);
|
const versionResolver = new DotnetVersionResolver(this.version);
|
||||||
|
const dotnetVersion = await versionResolver.createDotNetVersion();
|
||||||
|
|
||||||
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() {
|
|
||||||
if (process.env['DOTNET_INSTALL_DIR']) {
|
|
||||||
core.addPath(process.env['DOTNET_INSTALL_DIR']);
|
|
||||||
core.exportVariable('DOTNET_ROOT', process.env['DOTNET_INSTALL_DIR']);
|
|
||||||
} else {
|
|
||||||
if (IS_WINDOWS) {
|
if (IS_WINDOWS) {
|
||||||
// This is the default set in install-dotnet.ps1
|
scriptArguments = ['&', `'${escapedScript}'`];
|
||||||
core.addPath(
|
|
||||||
path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
|
if (dotnetVersion.type) {
|
||||||
);
|
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
|
||||||
core.exportVariable(
|
}
|
||||||
'DOTNET_ROOT',
|
|
||||||
path.join(process.env['LocalAppData'] + '', 'Microsoft', 'dotnet')
|
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']}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptPath =
|
||||||
|
(await io.which('pwsh', false)) || (await io.which('powershell', true));
|
||||||
|
scriptArguments = windowsDefaultOptions.concat(scriptArguments);
|
||||||
} else {
|
} else {
|
||||||
// This is the default set in install-dotnet.sh
|
chmodSync(escapedScript, '777');
|
||||||
core.addPath(path.join(process.env['HOME'] + '', '.dotnet'));
|
scriptPath = await io.which(escapedScript, true);
|
||||||
core.exportVariable(
|
scriptArguments = [];
|
||||||
'DOTNET_ROOT',
|
|
||||||
path.join(process.env['HOME'] + '', '.dotnet')
|
if (dotnetVersion.type) {
|
||||||
);
|
scriptArguments.push(dotnetVersion.type, dotnetVersion.value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(process.env['PATH']);
|
if (this.quality) {
|
||||||
|
this.setQuality(dotnetVersion, scriptArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// versionInfo - versionInfo of the SDK/Runtime
|
|
||||||
async resolveVersion(versionInfo: DotNetVersionInfo): Promise<string> {
|
|
||||||
if (versionInfo.isExactVersion()) {
|
|
||||||
return versionInfo.version();
|
|
||||||
}
|
}
|
||||||
|
// process.env must be explicitly passed in for DOTNET_INSTALL_DIR to be used
|
||||||
const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
|
const getExecOutputOptions = {
|
||||||
allowRetries: true,
|
ignoreReturnCode: true,
|
||||||
maxRetries: 3
|
env: process.env as {string: string}
|
||||||
});
|
};
|
||||||
|
const {exitCode, stdout, stderr} = await exec.getExecOutput(
|
||||||
const releasesJsonUrl: string = await this.getReleasesJsonUrl(
|
`"${scriptPath}"`,
|
||||||
httpClient,
|
scriptArguments,
|
||||||
versionInfo.version().split('.')
|
getExecOutputOptions
|
||||||
);
|
);
|
||||||
|
if (exitCode) {
|
||||||
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(
|
throw new Error(
|
||||||
`Could not find dotnet core version. Please ensure that specified version ${versionInfo.inputVersion} is valid.`
|
`Failed to install dotnet, exit code: ${exitCode}. ${stderr}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let release = releasesInfo[0];
|
return this.parseInstalledVersion(stdout);
|
||||||
return release['sdk']['version'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getReleasesJsonUrl(
|
private parseInstalledVersion(stdout: string): string | null {
|
||||||
httpClient: hc.HttpClient,
|
const regex = /(?<version>\d+\.\d+\.\d+[a-z0-9._-]*)/gm;
|
||||||
versionParts: string[]
|
const matchedResult = regex.exec(stdout);
|
||||||
): Promise<string> {
|
|
||||||
const response = await httpClient.getJson<any>(DotNetCoreIndexUrl);
|
|
||||||
const result = response.result || {};
|
|
||||||
let releasesInfo: any[] = result['releases-index'];
|
|
||||||
|
|
||||||
releasesInfo = releasesInfo.filter((info: any) => {
|
if (!matchedResult) {
|
||||||
// channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
|
core.warning(`Failed to parse installed by the script version of .NET`);
|
||||||
const sdkParts: string[] = info['channel-version'].split('.');
|
return null;
|
||||||
if (
|
|
||||||
versionParts.length >= 2 &&
|
|
||||||
!(versionParts[1] == 'x' || versionParts[1] == '*')
|
|
||||||
) {
|
|
||||||
return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
|
|
||||||
}
|
}
|
||||||
return versionParts[0] == sdkParts[0];
|
return matchedResult.groups!.version;
|
||||||
});
|
|
||||||
|
|
||||||
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';
|
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as installer from './installer';
|
import {DotnetCoreInstaller} from './installer';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import 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 {
|
||||||
//
|
//
|
||||||
@ -15,11 +26,12 @@ 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
|
||||||
//
|
//
|
||||||
let versions = core.getMultilineInput('dotnet-version');
|
const versions = core.getMultilineInput('dotnet-version');
|
||||||
|
const installedDotnetVersions: (string | null)[] = [];
|
||||||
|
|
||||||
const globalJsonFileInput = core.getInput('global-json-file');
|
const globalJsonFileInput = core.getInput('global-json-file');
|
||||||
if (globalJsonFileInput) {
|
if (globalJsonFileInput) {
|
||||||
const globalJsonPath = path.join(process.cwd(), globalJsonFileInput);
|
const globalJsonPath = path.resolve(process.cwd(), globalJsonFileInput);
|
||||||
if (!fs.existsSync(globalJsonPath)) {
|
if (!fs.existsSync(globalJsonPath)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The specified global.json file '${globalJsonFileInput}' does not exist`
|
`The specified global.json file '${globalJsonFileInput}' does not exist`
|
||||||
@ -34,22 +46,30 @@ export async function run() {
|
|||||||
const globalJsonPath = path.join(process.cwd(), 'global.json');
|
const globalJsonPath = path.join(process.cwd(), 'global.json');
|
||||||
if (fs.existsSync(globalJsonPath)) {
|
if (fs.existsSync(globalJsonPath)) {
|
||||||
versions.push(getVersionFromGlobalJson(globalJsonPath));
|
versions.push(getVersionFromGlobalJson(globalJsonPath));
|
||||||
|
} else {
|
||||||
|
core.info(
|
||||||
|
`The global.json wasn't found in the root directory. No .NET version will be installed.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (versions.length) {
|
if (versions.length) {
|
||||||
const includePrerelease: boolean = core.getBooleanInput(
|
const quality = core.getInput('dotnet-quality') as QualityOptions;
|
||||||
'include-prerelease'
|
|
||||||
|
if (quality && !qualityOptions.includes(quality)) {
|
||||||
|
throw new Error(
|
||||||
|
`Value '${quality}' is not supported for the 'dotnet-quality' option. Supported values are: daily, signed, validated, preview, ga.`
|
||||||
);
|
);
|
||||||
let dotnetInstaller!: installer.DotnetCoreInstaller;
|
|
||||||
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');
|
||||||
@ -58,15 +78,17 @@ export async function run() {
|
|||||||
auth.configAuthentication(sourceUrl, configFile);
|
auth.configAuthentication(sourceUrl, configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outputInstalledVersion(installedDotnetVersions, globalJsonFileInput);
|
||||||
|
|
||||||
const matchersPath = path.join(__dirname, '..', '.github');
|
const matchersPath = path.join(__dirname, '..', '.github');
|
||||||
console.log(`##[add-matcher]${path.join(matchersPath, 'csc.json')}`);
|
core.info(`##[add-matcher]${path.join(matchersPath, 'csc.json')}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVersionFromGlobalJson(globalJsonPath: string): string {
|
function getVersionFromGlobalJson(globalJsonPath: string): string {
|
||||||
let version: string = '';
|
let version = '';
|
||||||
const globalJson = JSON.parse(
|
const globalJson = JSON.parse(
|
||||||
// .trim() is necessary to strip BOM https://github.com/nodejs/node/issues/20649
|
// .trim() is necessary to strip BOM https://github.com/nodejs/node/issues/20649
|
||||||
fs.readFileSync(globalJsonPath, {encoding: 'utf8'}).trim()
|
fs.readFileSync(globalJsonPath, {encoding: 'utf8'}).trim()
|
||||||
@ -82,4 +104,37 @@ function getVersionFromGlobalJson(globalJsonPath: string): string {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function outputInstalledVersion(
|
||||||
|
installedVersions: (string | null)[],
|
||||||
|
globalJsonFileInput: string
|
||||||
|
): void {
|
||||||
|
if (!installedVersions.length) {
|
||||||
|
core.info(`The 'dotnet-version' output will not be set.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (installedVersions.includes(null)) {
|
||||||
|
core.warning(
|
||||||
|
`Failed to output the installed version of .NET. The 'dotnet-version' output will not be set.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalJsonFileInput) {
|
||||||
|
const versionToOutput = installedVersions.at(-1); // .NET SDK version parsed from the global.json file is installed last
|
||||||
|
core.setOutput('dotnet-version', versionToOutput);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionToOutput = semver.maxSatisfying(
|
||||||
|
installedVersions as string[],
|
||||||
|
'*',
|
||||||
|
{
|
||||||
|
includePrerelease: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
core.setOutput('dotnet-version', versionToOutput);
|
||||||
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
2
src/utils.ts
Normal file
2
src/utils.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
export const IS_LINUX = process.platform === 'linux';
|
@ -35,6 +35,7 @@
|
|||||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
|
||||||
/* Additional Checks */
|
/* Additional Checks */
|
||||||
|
"useUnknownInCatchVariables": false, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
@ -48,7 +49,8 @@
|
|||||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
// "types": [], /* Type declaration files to be included in compilation. */
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
|
"resolveJsonModule": true, /* Allows importing modules with a '.json' extension, which is a common practice in node projects. */
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user