import * as core from '@actions/core' ; import * as exec from '@actions/exec' ; import * as io from '@actions/io' ; import hc = require ( '@actions/http-client' ) ; import { chmodSync } from 'fs' ; import * as path from 'path' ; import { ExecOptions } from '@actions/exec/lib/interfaces' ; import * as semver from 'semver' ; const IS_WINDOWS = process . platform === 'win32' ; /**
 * Represents the inputted version information
 */ export class DotNetVersionInfo { public inputVersion : string ; private fullversion : string ; private isExactVersionSet : boolean = false ; constructor ( version ) { this . inputVersion = version ; if ( semver . valid ( semver . clean ( version ) || '' ) != null ) { this . fullversion = semver . clean ( version ) as string ; this . isExactVersionSet = true ; return ; } const parts = version . split ( '.' ) ; if ( parts . length < 2 || parts . length > 3 ) this . throwInvalidVersionFormat ( ) ; if ( parts . length == 3 && parts [ 2 ] !== 'x' && parts [ 2 ] !== '*' ) { this . throwInvalidVersionFormat ( ) ; } const major = this . getVersionNumberOrThrow ( parts [ 0 ] ) ; const minor = [ 'x' , '*' ] . includes ( parts [ 1 ] ) ? parts [ 1 ] : this . getVersionNumberOrThrow ( parts [ 1 ] ) ; this . fullversion = major + '.' + minor ; } private getVersionNumberOrThrow ( input ) { 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 ( 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*' ) ; } /**
     * If true exacatly one version should be resolved
     */ public isExactVersion ( ) { return this . isExactVersionSet ; } public version ( ) { return this . fullversion ; } } export class DotnetCoreInstaller { constructor ( version , includePrerelease = false ) { this . version = version ; this . includePrerelease = includePrerelease ; } public async installDotnet ( ) { let output = '' ; let resultCode = 0 ; let calculatedVersion = await this . resolveVersion ( new DotNetVersionInfo ( this . version ) ) ; var envVariables = { } ; for ( let key in process . env ) { if ( process . env [ key ] ) { let value = process . env [ key ] ; envVariables [ key ] = value ; } } if ( IS_WINDOWS ) { let escapedScript = path . join ( __dirname , '..' , 'externals' , 'install-dotnet.ps1' ) . replace ( /'/g , "''" ) ; let command = `& '${ escapedScript }'` ; if ( calculatedVersion ) { command += ` -Version ${ calculatedVersion }` ; } if ( process . env [ 'https_proxy' ] != null ) { command += ` -ProxyAddress ${ process . env [ 'https_proxy' ] }` ; } if ( process . env [ 'no_proxy' ] != null ) { command += ` -ProxyBypassList ${ process . env [ 'no_proxy' ] }` ; } const powershellPath = await io . which ( 'powershell' , true ) ; var options = { listeners : { stdout : ( data ) => { output += data . toString ( ) ; } } , env : envVariables } ; resultCode = await exec . exec ( `"${ powershellPath }"` , [ '-NoLogo' , '-Sta' , '-NoProfile' , '-NonInteractive' , '-ExecutionPolicy' , 'Unrestricted' , '-Command' , command ] , options ) ; } else { let escapedScript = path . join ( __dirname , '..' , 'externals' , 'install-dotnet.sh' ) . replace ( /'/g , "''" ) ; chmodSync ( escapedScript , '777' ) ; const scriptPath = await io . which ( escapedScript , true ) ; let scriptArguments = [ ] ; if ( calculatedVersion ) { scriptArguments . push ( '--version' , calculatedVersion ) ; } resultCode = await exec . exec ( `"${ scriptPath }"` , scriptArguments , { listeners : { stdout : ( data ) => { 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 ) { core . addPath ( path . join ( process . env [ 'LocalAppData' ] + '' , 'Microsoft' , 'dotnet' ) ) ; core . exportVariable ( 'DOTNET_ROOT' , path . join ( process . env [ 'LocalAppData' ] + '' , 'Microsoft' , 'dotnet' ) ) ; } else { core . addPath ( path . join ( process . env [ 'HOME' ] + '' , '.dotnet' ) ) ; core . exportVariable ( 'DOTNET_ROOT' , path . join ( process . env [ 'HOME' ] + '' , '.dotnet' ) ) ; } } console . log ( process . env [ 'PATH' ] ) ; } async resolveVersion ( versionInfo ) { if ( versionInfo . isExactVersion ( ) ) { return versionInfo . version ( ) ; } const httpClient = new hc . HttpClient ( 'actions/setup-dotnet' , [ ] , { allowRetries : true , maxRetries : 3 } ) ; const releasesJsonUrl = await this . getReleasesJsonUrl ( httpClient , versionInfo . version ( ) . split ( '.' ) ) ; const releasesResponse = await httpClient . getJson < any > ( releasesJsonUrl ) ; const releasesResult = releasesResponse . result || { } ; let releasesInfo = releasesResult [ 'releases' ] ; releasesInfo = releasesInfo . filter ( ( releaseInfo ) => { return ( semver . satisfies ( releaseInfo [ 'sdk' ] [ 'version' ] , versionInfo . version ( ) , { includePrerelease : this . includePrerelease } ) || semver . satisfies ( releaseInfo [ 'sdk' ] [ 'version-display' ] , versionInfo . version ( ) , { includePrerelease : this . includePrerelease } ) ) ; } ) ; let latestSdk = releasesResult [ 'latest-sdk' ] ; releasesInfo = releasesInfo . filter ( ( releaseInfo ) => semver . lte ( releaseInfo [ 'sdk' ] [ 'version' ] , latestSdk , { includePrerelease : this . includePrerelease } ) ) ; releasesInfo = releasesInfo . sort ( ( a , b ) => semver . rcompare ( a [ 'sdk' ] [ 'version' ] , b [ 'sdk' ] [ 'version' ] , { includePrerelease : this . includePrerelease } ) ) ; if ( releasesInfo . length == 0 ) { throw new Error ( `Could not find dotnet core version. Please ensure that specified version ${ versionInfo . inputVersion } is valid.` ) ; } let release = releasesInfo [ 0 ] ; return release [ 'sdk' ] [ 'version' ] ; } private async getReleasesJsonUrl ( httpClient , versionParts ) { const response = await httpClient . getJson < any > ( DotNetCoreIndexUrl ) ; const result = response . result || { } ; let releasesInfo = result [ 'releases-index' ] ; releasesInfo = releasesInfo . filter ( ( info ) => { const sdkParts = info [ 'channel-version' ] . split ( '.' ) ; if ( versionParts . length >= 2 && ! ( versionParts [ 1 ] == 'x' || versionParts [ 1 ] == '*' ) ) { return versionParts [ 0 ] == sdkParts [ 0 ] && versionParts [ 1 ] == sdkParts [ 1 ] ; } return versionParts [ 0 ] == sdkParts [ 0 ] ; } ) ; 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 = 'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json' ;