2017-04-18 18:18:22 +03:00
/ *
* Copyright ( c ) Microsoft Corporation . All rights reserved .
* Licensed under the MIT License . See License . txt in the project root for
* license information .
* /
2016-02-28 06:30:26 +03:00
2017-03-18 21:43:33 +03:00
const gulp = require ( 'gulp' ) ;
const args = require ( 'yargs' ) . argv ;
const fs = require ( 'fs' ) ;
const path = require ( 'path' ) ;
2017-03-25 22:15:52 +03:00
const glob = require ( 'glob' ) ;
2017-03-18 21:43:33 +03:00
const execSync = require ( 'child_process' ) . execSync ;
2016-02-28 06:30:26 +03:00
2018-03-31 00:52:47 +03:00
const azureSDKForNodeRepoRoot = _ _dirname ;
2018-04-02 22:33:17 +03:00
const azureRestAPISpecsRoot = args [ 'azure-rest-api-specs-root' ] || path . resolve ( azureSDKForNodeRepoRoot , '..' , 'azure-rest-api-specs' ) ;
2018-03-31 00:13:05 +03:00
const package = args [ 'package' ] ;
2018-03-20 22:49:27 +03:00
const use = args [ 'use' ] ;
2018-09-04 19:19:19 +03:00
const whatif = args [ 'whatif' ] ;
2017-09-29 21:41:15 +03:00
const regexForExcludedServices = /\/(intune|documentdbManagement|insightsManagement|insights|search)\//i ;
2016-03-01 05:32:11 +03:00
2018-03-31 00:52:47 +03:00
function findReadmeNodejsMdFilePaths ( azureRestAPISpecsRoot ) {
const specificationFolderPath = path . resolve ( azureRestAPISpecsRoot , 'specification' ) ;
2018-04-02 20:38:24 +03:00
return glob . sync ( '**/readme.nodejs.md' , { absolute : true , cwd : specificationFolderPath } ) ;
2018-03-31 00:52:47 +03:00
}
function getPackageNameFromReadmeNodejsMdFileContents ( readmeNodejsMdFileContents ) {
return readmeNodejsMdFileContents . match ( /package-name: (\S*)/ ) [ 1 ] ;
}
2018-04-02 22:33:17 +03:00
function getOutputFolderFromReadmeNodeJsMdFileContents ( readmeNodejsMdFileContents ) {
return readmeNodejsMdFileContents . match ( /output-folder: (\S*)/ ) [ 1 ] ;
}
function getServiceNameFromOutputFolderValue ( outputFolderValue ) {
const outputFolderSegments = outputFolderValue . split ( '/' ) ;
return outputFolderSegments [ outputFolderSegments . length - 1 ] ;
}
2018-03-31 00:13:05 +03:00
gulp . task ( 'default' , function ( ) {
2018-04-16 18:34:31 +03:00
console . log ( 'gulp codegen [--azure-rest-api-specs-root <azure-rest-api-specs root>] [--use <autorest.nodejs root>] [--package <package name>]' ) ;
console . log ( ' --azure-rest-api-specs-root' ) ;
console . log ( ' Root location of the local clone of the azure-rest-api-specs-root repository.' ) ;
console . log ( ' --use' ) ;
console . log ( ' Root location of autorest.nodejs repository. If this is not specified, then the latest installed generator for NodeJS will be used.' ) ;
console . log ( ' --package' ) ;
console . log ( ' NPM package to regenerate. If no package is specified, then all packages will be regenerated.' ) ;
console . log ( ) ;
console . log ( 'gulp publish [--package <package name>]' ) ;
console . log ( ' --package' ) ;
console . log ( ' The name of the package to publish. If no package is specified, then all packages will be published.' ) ;
2018-03-31 00:13:05 +03:00
} ) ;
2016-03-01 10:11:50 +03:00
2018-03-31 00:13:05 +03:00
//This task is used to generate libraries based on the mappings specified above.
2018-08-29 22:19:58 +03:00
gulp . task ( 'codegen' , function ( ) {
2018-03-31 00:52:47 +03:00
const nodejsReadmeFilePaths = findReadmeNodejsMdFilePaths ( azureRestAPISpecsRoot ) ;
2017-03-25 22:59:14 +03:00
2018-03-31 00:13:05 +03:00
for ( let i = 0 ; i < nodejsReadmeFilePaths . length ; ++ i ) {
const nodejsReadmeFilePath = nodejsReadmeFilePaths [ i ] ;
2018-03-22 20:14:42 +03:00
2018-03-31 00:13:05 +03:00
const nodejsReadmeFileContents = fs . readFileSync ( nodejsReadmeFilePath , 'utf8' ) ;
2018-03-31 00:52:47 +03:00
const packageName = getPackageNameFromReadmeNodejsMdFileContents ( nodejsReadmeFileContents ) ;
2018-04-16 18:34:31 +03:00
2018-03-31 00:13:05 +03:00
if ( ! package || package === packageName || packageName . endsWith ( ` - ${ package } ` ) ) {
console . log ( ` >>>>>>>>>>>>>>>>>>> Start: " ${ packageName } " >>>>>>>>>>>>>>>>>>>>>>>>> ` ) ;
2017-08-26 04:53:43 +03:00
2018-03-31 00:13:05 +03:00
const readmeFilePath = path . resolve ( path . dirname ( nodejsReadmeFilePath ) , 'readme.md' ) ;
2017-08-26 04:53:43 +03:00
2018-03-31 00:52:47 +03:00
let cmd = ` autorest --nodejs --node-sdks-folder= ${ azureSDKForNodeRepoRoot } --license-header=MICROSOFT_MIT_NO_VERSION ${ readmeFilePath } ` ;
2018-03-31 00:13:05 +03:00
if ( use ) {
cmd += ` --use= ${ use } ` ;
2017-08-26 04:53:43 +03:00
}
2018-04-05 19:30:39 +03:00
else {
2018-04-05 19:28:26 +03:00
const localAutorestNodejsFolderPath = path . resolve ( azureSDKForNodeRepoRoot , '..' , 'autorest.nodejs' ) ;
2018-04-05 19:30:39 +03:00
if ( fs . existsSync ( localAutorestNodejsFolderPath ) && fs . lstatSync ( localAutorestNodejsFolderPath ) . isDirectory ( ) ) {
cmd += ` --use= ${ localAutorestNodejsFolderPath } ` ;
}
2018-04-05 19:28:26 +03:00
}
2017-08-26 04:53:43 +03:00
2018-03-31 00:13:05 +03:00
try {
console . log ( 'Executing command:' ) ;
console . log ( '------------------------------------------------------------' ) ;
console . log ( cmd ) ;
console . log ( '------------------------------------------------------------' ) ;
const result = execSync ( cmd , { encoding : 'utf8' } ) ;
console . log ( 'Output:' ) ;
console . log ( result ) ;
} catch ( err ) {
console . log ( 'Error:' ) ;
console . log ( ` An error occurred while generating client for package: " ${ packageName } ": \n ${ err . stderr } ` ) ;
2017-08-26 04:53:43 +03:00
}
2016-02-28 06:30:26 +03:00
2018-03-31 00:13:05 +03:00
console . log ( ` >>>>>>>>>>>>>>>>>>> End: " ${ packageName } " >>>>>>>>>>>>>>>>>>>>>>>>> ` ) ;
console . log ( ) ;
2017-06-30 21:17:03 +03:00
}
2017-03-18 21:43:33 +03:00
}
2017-04-02 00:47:59 +03:00
} ) ;
2017-04-03 21:00:32 +03:00
//This task validates that the entry in "main" and "types" in package.json points to a file that exists on the disk.
// for best results run on mac or linux. Windows is case insenstive for file paths. Hence it will not catch those issues.
//If not tested this will cause "module not found" errors for customers when they try to use the package.
2017-04-02 00:47:59 +03:00
gulp . task ( 'validate-each-packagejson' , ( cb ) => {
2018-03-31 00:52:47 +03:00
let packagePaths = glob . sync ( path . join ( azureSDKForNodeRepoRoot , '/lib/services' , '/**/package.json' ) , { ignore : '**/node_modules/**' } ) ;
2017-04-02 00:47:59 +03:00
packagePaths . forEach ( ( packagePath ) => {
const package = require ( packagePath ) ;
//console.log(package);
2017-12-29 03:38:48 +03:00
if ( ! package . name . startsWith ( 'azure-asm-' ) ) {
2017-04-02 00:47:59 +03:00
console . log ( ` Validating package: ${ package . name } ` ) ;
if ( package . main ) {
let mainPath = path . resolve ( path . dirname ( packagePath ) , package . main ) ;
if ( ! fs . existsSync ( mainPath ) ) console . log ( ` \t > ${ mainPath } does not exist. ` ) ;
} else {
console . log ( ` \t >Could not find "main" entry in package.json for ${ packagePath } . ` ) ;
}
if ( package . types ) {
let typesPath = path . resolve ( path . dirname ( packagePath ) , package . types ) ;
if ( ! fs . existsSync ( typesPath ) ) console . log ( ` \t > ${ typesPath } does not exist. ` ) ;
} else {
console . log ( ` \t >Could not find "types" entry in package.json for ${ packagePath } . ` ) ;
}
}
} ) ;
} ) ;
2017-04-03 21:00:32 +03:00
//This task updates the dependencies in package.json to the relative service libraries inside lib/services directory.
2017-04-02 00:47:59 +03:00
gulp . task ( 'update-deps-rollup' , ( cb ) => {
2017-11-13 01:34:13 +03:00
2018-03-31 00:52:47 +03:00
let packagePaths = glob . sync ( path . join ( azureSDKForNodeRepoRoot , './lib/services' , '/**/package.json' ) ) . filter ( ( packagePath ) => {
2017-09-29 21:41:15 +03:00
return packagePath . match ( regexForExcludedServices ) === null ;
2017-09-29 01:48:38 +03:00
} ) ;
2017-04-02 00:47:59 +03:00
let rollupPackage = require ( './package.json' ) ;
let rollupDependencies = rollupPackage . dependencies ;
rollupDependencies [ 'ms-rest' ] = './runtime/ms-rest' ;
rollupDependencies [ 'ms-rest-azure' ] = './runtime/ms-rest-azure' ;
packagePaths . forEach ( ( packagePath ) => {
const package = require ( packagePath ) ;
//console.log(package);
2018-03-22 20:21:42 +03:00
let packageName = package . name ;
const packageDir = path . dirname ( packagePath ) ;
2017-04-02 00:47:59 +03:00
if ( rollupDependencies [ packageName ] ) {
rollupDependencies [ packageName ] = packageDir ;
} else {
console . log ( ` Could not find ${ packageName } as a dependecy in rollup package.json file.. ` ) ;
2016-02-28 06:30:26 +03:00
}
} ) ;
2017-04-03 21:00:32 +03:00
fs . writeFileSync ( './package.json' , JSON . stringify ( rollupPackage , null , 2 ) , { 'encoding' : 'utf8' } ) ;
} ) ;
2018-04-02 22:33:17 +03:00
gulp . task ( 'sync-package-service-mapping' , ( cb ) => {
let packageMapping = require ( './package_service_mapping' ) ;
for ( const readmeNodeJsMdFilePath of findReadmeNodejsMdFilePaths ( azureRestAPISpecsRoot ) ) {
const readmeNodeJsMdFileContents = fs . readFileSync ( readmeNodeJsMdFilePath , 'utf8' ) ;
const packageName = getPackageNameFromReadmeNodejsMdFileContents ( readmeNodeJsMdFileContents ) ;
if ( packageName && ! packageMapping [ packageName ] ) {
const category = readmeNodeJsMdFilePath . includes ( 'resource-manager' ) ? 'Management' : 'Client' ;
const outputFolder = getOutputFolderFromReadmeNodeJsMdFileContents ( readmeNodeJsMdFileContents ) ;
packageMapping [ packageName ] = {
category : 'Management' ,
'service_name' : getServiceNameFromOutputFolderValue ( outputFolder )
} ;
}
}
packageMapping = Object . keys ( packageMapping ) . sort ( ) . reduce ( ( r , k ) => ( r [ k ] = packageMapping [ k ] , r ) , { } ) ;
fs . writeFileSync ( './package_service_mapping.json' , JSON . stringify ( packageMapping , null , 2 ) , { 'encoding' : 'utf8' } ) ;
} ) ;
2017-04-03 21:00:32 +03:00
//This task ensures that all the exposed createSomeClient() methods, can correctly instantiate clients. By doing this we test,
//that the "main" entry in package.json points to a file at the correct location. We test the signature of the client constructor
//is as expected. As of now HD Isnight is expected to fail as it is still using the Hyak generator. Once it moves to Autorest, it should
2017-09-28 06:01:40 +03:00
//not fail. Before executing this task, execute `gulp update-deps-rollup`, `rm -rf node_modules` and `npm install` so that the changes inside the sdks in lib/services
//are installed inside the node_modules folder.
2017-04-03 21:00:32 +03:00
gulp . task ( 'test-create-rollup' , ( cb ) => {
const azure = require ( './lib/azure' ) ;
2018-03-22 20:21:42 +03:00
const keys = Object . keys ( azure ) . filter ( ( key ) => { return key . startsWith ( 'create' ) && ! key . startsWith ( 'createASM' ) && key . endsWith ( 'Client' ) && key !== 'createSchedulerClient' ; } ) ;
2017-04-03 21:00:32 +03:00
//console.dir(keys);
//console.log(keys.length);
const creds = { signRequest : { } } ;
const subId = '1234556' ;
keys . forEach ( ( key ) => {
console . log ( key ) ;
const Client = azure [ key ] ;
var c ;
try {
if ( key === 'createKeyVaultClient' || key === 'createSubscriptionManagementClient' ||
key === 'createDataLakeAnalyticsJobManagementClient' || key === 'createDataLakeStoreFileSystemManagementClient' ||
key === 'createDataLakeAnalyticsCatalogManagementClient' ) {
c = new Client ( creds ) ;
2017-09-28 06:01:40 +03:00
} else if ( key === 'createServiceFabricClient' ) {
c = new Client ( ) ;
2017-04-03 21:00:32 +03:00
} else {
c = new Client ( creds , subId ) ;
}
//console.dir(Object.keys(c));
} catch ( err ) {
console . dir ( err ) ;
}
} ) ;
2017-04-18 18:18:22 +03:00
} ) ;
2017-08-26 04:53:43 +03:00
2017-09-28 06:01:40 +03:00
// This task synchronizes the dependencies in package.json to the versions of relative service libraries inside lib/services directory.
// This should be done in the end to ensure that all the package dependencies have the correct version.
gulp . task ( 'sync-deps-rollup' , ( cb ) => {
2018-03-31 00:52:47 +03:00
let packagePaths = glob . sync ( path . join ( azureSDKForNodeRepoRoot , './lib/services' , '/**/package.json' ) ) . filter ( ( packagePath ) => {
2017-09-29 21:41:15 +03:00
return packagePath . match ( regexForExcludedServices ) === null ;
2017-09-28 06:01:40 +03:00
} ) ;
//console.log(packagePaths);
console . log ( ` Total packages found under lib/services: ${ packagePaths . length } ` ) ;
let rollupPackage = require ( './package.json' ) ;
let rollupDependencies = rollupPackage . dependencies ;
rollupDependencies [ 'ms-rest' ] = '^2.2.2' ;
2017-09-29 19:54:18 +03:00
rollupDependencies [ 'ms-rest-azure' ] = '^2.3.4' ;
2017-09-28 06:01:40 +03:00
packagePaths . forEach ( ( packagePath ) => {
const package = require ( packagePath ) ;
//console.log(package);
let packageName = package . name ;
let packageVersion = package . version ;
rollupDependencies [ packageName ] = packageVersion ;
} ) ;
rollupPackage . dependencies = Object . keys ( rollupDependencies ) . sort ( ) . reduce ( ( r , k ) => ( r [ k ] = rollupDependencies [ k ] , r ) , { } ) ;
console . log ( ` Total number of dependencies in the rollup package: ${ Object . keys ( rollupPackage . dependencies ) . length } ` ) ;
fs . writeFileSync ( './package.json' , JSON . stringify ( rollupPackage , null , 2 ) , { 'encoding' : 'utf8' } ) ;
2017-10-05 20:14:07 +03:00
} ) ;
2018-04-16 18:34:31 +03:00
gulp . task ( 'publish' , ( cb ) => {
2018-03-31 00:52:47 +03:00
const nodejsReadmeFilePaths = findReadmeNodejsMdFilePaths ( azureRestAPISpecsRoot ) ;
2018-03-29 00:08:00 +03:00
2018-03-29 21:51:15 +03:00
let errorPackages = 0 ;
let upToDatePackages = 0 ;
let publishedPackages = 0 ;
2018-09-04 19:19:19 +03:00
let publishedPackagesSkipped = 0 ;
2018-03-31 00:52:47 +03:00
2018-09-06 20:23:12 +03:00
const currentDirectoryPath = _ _dirname ;
2018-09-06 20:16:10 +03:00
2018-09-06 20:31:52 +03:00
const npmrcFileName = ".npmrc" ;
const npmrcRootFilePath = path . join ( currentDirectoryPath , npmrcFileName ) ;
2018-09-06 20:27:42 +03:00
const npmrcRootFileExists = fs . existsSync ( npmrcRootFilePath ) ;
2018-09-06 20:08:41 +03:00
if ( npmrcRootFileExists ) {
2018-09-06 20:23:12 +03:00
console . log ( ` Found ".npmrc" auth file at " ${ npmrcRootFilePath } ". Using it to authenticate with NPM for publish. ` ) ;
2018-09-06 19:56:17 +03:00
}
2018-09-06 19:32:13 +03:00
2018-03-31 00:52:47 +03:00
for ( let i = 0 ; i < nodejsReadmeFilePaths . length ; ++ i ) {
const nodejsReadmeFilePath = nodejsReadmeFilePaths [ i ] ;
const nodejsReadmeFileContents = fs . readFileSync ( nodejsReadmeFilePath , 'utf8' ) ;
const relativeOutputFolderPath = nodejsReadmeFileContents . match ( /output\-folder: \$\(node\-sdks\-folder\)\/(lib\/services\/\S+)/ ) [ 1 ] ;
const packageFolderPath = path . resolve ( azureSDKForNodeRepoRoot , relativeOutputFolderPath ) ;
if ( ! fs . existsSync ( packageFolderPath ) ) {
2018-09-06 20:27:42 +03:00
console . log ( ` WARNING: Package folder ${ packageFolderPath } has not been generated. ` ) ;
2018-03-31 00:52:47 +03:00
errorPackages ++ ;
}
else {
2018-03-29 20:40:21 +03:00
const packageJsonFilePath = ` ${ packageFolderPath } /package.json ` ;
if ( ! fs . existsSync ( packageJsonFilePath ) ) {
2018-09-06 20:27:42 +03:00
console . log ( ` WARNING: Package folder ${ packageFolderPath } is missing its package.json file. ` ) ;
2018-03-29 21:51:15 +03:00
errorPackages ++ ;
2018-03-29 20:40:21 +03:00
}
else {
const packageJson = require ( packageJsonFilePath ) ;
const packageName = packageJson . name ;
2018-03-29 19:51:24 +03:00
2018-04-16 18:34:31 +03:00
if ( ! package || package === packageName || packageName . endsWith ( ` - ${ package } ` ) ) {
const localPackageVersion = packageJson . version ;
if ( ! localPackageVersion ) {
console . log ( ` ERROR: " ${ packageJsonFilePath } " doesn't have a version specified. ` ) ;
errorPackages ++ ;
2018-03-29 21:51:15 +03:00
}
else {
2018-04-16 18:34:31 +03:00
let npmPackageVersion ;
2018-03-29 22:23:40 +03:00
try {
2018-04-16 18:34:31 +03:00
const npmViewResult = JSON . parse ( execSync ( ` npm view ${ packageName } --json ` , { stdio : [ 'pipe' , 'pipe' , 'ignore' ] } ) ) ;
npmPackageVersion = npmViewResult [ 'dist-tags' ] [ 'latest' ] ;
2018-03-29 22:23:40 +03:00
}
catch ( error ) {
2018-04-16 18:34:31 +03:00
// This happens if the package doesn't exist in NPM.
}
if ( localPackageVersion === npmPackageVersion ) {
upToDatePackages ++ ;
}
else {
2018-09-04 19:19:19 +03:00
console . log ( ` Publishing package " ${ packageName } " with version " ${ localPackageVersion } "... ${ whatif ? " (SKIPPED)" : "" } ` ) ;
if ( ! whatif ) {
try {
2018-09-06 20:31:52 +03:00
const npmrcPackageFilePath = path . join ( packageFolderPath , npmrcFileName ) ;
2018-09-06 20:08:41 +03:00
if ( npmrcRootFileExists ) {
fs . copyFileSync ( npmrcRootFilePath , npmrcPackageFilePath ) ;
2018-09-06 19:32:13 +03:00
}
execSync ( ` npm publish --access public ` , { cwd : packageFolderPath } ) ;
2018-09-04 19:19:19 +03:00
publishedPackages ++ ;
}
catch ( error ) {
2018-09-06 20:31:52 +03:00
console . log ( ` ERROR: ${ JSON . stringify ( error ) } ` ) ;
2018-09-04 19:19:19 +03:00
errorPackages ++ ;
}
} else {
publishedPackagesSkipped ++ ;
2018-04-16 18:34:31 +03:00
}
2018-03-29 22:23:40 +03:00
}
2018-03-29 21:51:15 +03:00
}
}
2018-03-29 20:40:21 +03:00
}
2018-03-29 00:08:00 +03:00
}
}
2018-03-29 19:51:24 +03:00
2018-03-29 22:23:40 +03:00
console . log ( ) ;
2018-09-04 19:19:19 +03:00
console . log ( ` Error packages: ${ errorPackages } ` ) ;
console . log ( ` Up to date packages: ${ upToDatePackages } ` ) ;
console . log ( ` Published packages: ${ publishedPackages } ` ) ;
console . log ( ` Published packages skipped: ${ publishedPackagesSkipped } ` ) ;
2017-08-26 04:53:43 +03:00
} ) ;