2019-09-09 10:27:23 -07:00
import * as fs from 'fs' ;
import * as path from 'path' ;
import * as core from '@actions/core' ;
import * as github from '@actions/github' ;
2022-09-30 01:54:05 +02:00
import { XMLParser , XMLBuilder } from 'fast-xml-parser' ;
2019-09-09 10:27:23 -07:00
export function configAuthentication (
feedUrl : string ,
2020-09-02 11:11:56 -07:00
existingFileLocation : string = '' ,
processRoot : string = process . cwd ()
2019-09-09 10:27:23 -07:00
) {
const existingNuGetConfig : string = path . resolve (
2020-09-02 11:11:56 -07:00
processRoot ,
2021-04-19 16:11:14 +03:00
existingFileLocation === ''
2021-04-19 14:26:05 +03:00
? getExistingNugetConfig ( processRoot )
: existingFileLocation
2019-09-09 10:27:23 -07:00
);
const tempNuGetConfig : string = path . resolve (
2020-09-02 11:11:56 -07:00
processRoot ,
2019-09-09 10:27:23 -07:00
'../' ,
'nuget.config'
);
writeFeedToFile ( feedUrl , existingNuGetConfig , tempNuGetConfig );
}
2021-04-15 13:30:04 +03:00
function isValidKey ( key : string ) : boolean {
2021-04-15 13:44:48 +03:00
return /^[\w\-\.]+$/i . test ( key );
2021-04-15 13:28:24 +03:00
}
2021-04-19 14:25:42 +03:00
function getExistingNugetConfig ( processRoot : string ) {
2021-04-19 16:16:44 +03:00
const defaultConfigName = 'nuget.config' ;
2021-04-19 14:26:05 +03:00
const configFileNames = fs
. readdirSync ( processRoot )
2021-04-19 16:16:44 +03:00
. filter ( filename => filename . toLowerCase () === defaultConfigName );
2021-04-19 14:25:42 +03:00
if ( configFileNames . length ) {
return configFileNames [ 0 ];
}
2021-04-19 16:16:44 +03:00
return defaultConfigName ;
2021-04-19 14:25:42 +03:00
}
2019-09-09 10:27:23 -07:00
function writeFeedToFile (
feedUrl : string ,
existingFileLocation : string ,
tempFileLocation : string
) {
2022-09-27 14:47:12 +02:00
core . info (
2019-09-09 10:27:23 -07:00
`dotnet-auth: Finding any source references in ${ existingFileLocation } , writing a new temporary configuration file with credentials to ${ tempFileLocation } `
);
2019-10-03 17:29:20 -07:00
let sourceKeys : string [] = [];
2019-09-09 10:27:23 -07:00
let owner : string = core . getInput ( 'owner' );
2019-10-03 17:29:20 -07:00
let sourceUrl : string = feedUrl ;
if ( ! owner ) {
2019-09-09 10:27:23 -07:00
owner = github . context . repo . owner ;
}
2022-09-27 14:47:12 +02:00
if ( ! process . env . NUGET_AUTH_TOKEN ) {
2019-09-09 10:27:23 -07:00
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}}'
);
}
if ( fs . existsSync ( existingFileLocation )) {
// get key from existing NuGet.config so NuGet/dotnet can match credentials
const curContents : string = fs . readFileSync ( existingFileLocation , 'utf8' );
2022-09-29 18:23:42 +02:00
const parserOptions = {
ignoreAttributes : false
};
const parser = new XMLParser ( parserOptions );
const json = parser . parse ( curContents );
2019-09-09 10:27:23 -07:00
2022-09-27 14:47:12 +02:00
if ( typeof json . configuration === 'undefined' ) {
2019-09-09 10:27:23 -07:00
throw new Error ( `The provided NuGet.config seems invalid.` );
}
2022-09-28 15:30:56 +02:00
if ( json . configuration ? . packageSources ? . add ) {
const packageSources = json . configuration . packageSources . add ;
if ( Array . isArray ( packageSources )) {
packageSources . forEach ( source => {
const value = source [ '@_value' ];
core . debug ( `source ' ${ value } '` );
if ( value . toLowerCase (). includes ( feedUrl . toLowerCase ())) {
const key = source [ '@_key' ];
2019-10-03 17:29:20 -07:00
sourceKeys . push ( key );
core . debug ( `Found a URL with key ${ key } ` );
2019-09-09 10:27:23 -07:00
}
2022-09-28 15:30:56 +02:00
});
} else {
if (
packageSources [ '@_value' ]
. toLowerCase ()
. includes ( feedUrl . toLowerCase ())
) {
const key = packageSources [ '@_key' ];
sourceKeys . push ( key );
core . debug ( `Found a URL with key ${ key } ` );
2019-09-09 10:27:23 -07:00
}
}
}
}
2022-09-30 01:54:05 +02:00
const xmlSource : any [] = [
{
'?xml version="1.0"' : [
{
'#text' : ''
}
]
},
{
configuration : [
{
config : [
{
add : [],
':@' : {
'@_key' : 'defaultPushSource' ,
'@_value' : sourceUrl
}
}
]
}
]
}
];
2019-09-09 10:27:23 -07:00
2022-09-27 14:47:12 +02:00
if ( ! sourceKeys . length ) {
2019-10-03 17:29:20 -07:00
let keystring = 'Source' ;
2022-09-30 01:54:05 +02:00
xmlSource [ 1 ]. configuration . push ({
packageSources : [
{
add : [],
':@' : {
'@_key' : keystring ,
'@_value' : sourceUrl
}
}
]
});
2019-10-03 17:29:20 -07:00
sourceKeys . push ( keystring );
2019-09-09 10:27:23 -07:00
}
2019-10-03 17:29:20 -07:00
2022-09-30 01:54:05 +02:00
const packageSourceCredentials : any [] = [];
2019-10-03 17:29:20 -07:00
sourceKeys . forEach ( key => {
2021-04-15 13:28:24 +03:00
if ( ! isValidKey ( key )) {
2019-09-09 10:27:23 -07:00
throw new Error (
2021-04-15 13:43:20 +03:00
"Source name can contain letters, numbers, and '-', '_', '.' symbols only. Please, fix source name in NuGet.config and try again."
2019-09-09 10:27:23 -07:00
);
}
2022-09-30 01:54:05 +02:00
packageSourceCredentials . push ({
[ key ] : [
{
add : [],
':@' : {
'@_key' : 'Username' ,
'@_value' : owner
}
},
{
add : [],
':@' : {
'@_key' : 'ClearTextPassword' ,
'@_value' : process . env . NUGET_AUTH_TOKEN
}
}
]
});
2019-09-09 10:27:23 -07:00
});
2022-09-30 02:19:09 +02:00
xmlSource [ 1 ]. configuration . push ({
packageSourceCredentials
});
2019-09-09 10:27:23 -07:00
// 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),
// use this for the value above
// process.platform == 'win32'
// ? '%NUGET_AUTH_TOKEN%'
// : '$NUGET_AUTH_TOKEN'
2022-09-30 01:54:05 +02:00
const xmlBuilderOptions = {
format : true ,
ignoreAttributes : false ,
preserveOrder : true ,
allowBooleanAttributes : true ,
suppressBooleanAttributes : true ,
suppressEmptyNode : true
};
const builder = new XMLBuilder ( xmlBuilderOptions );
const output = builder . build ( xmlSource );
2022-09-30 02:05:09 +02:00
core . debug ( output );
2022-09-30 02:04:34 +02:00
2019-09-09 10:27:23 -07:00
fs . writeFileSync ( tempFileLocation , output );
}