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 util = require ( 'util' ) ;
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 ;
2018-03-29 20:40:21 +03:00
const jsonStableStringify = require ( 'json-stable-stringify' ) ;
2016-02-28 06:30:26 +03:00
2017-08-26 04:53:43 +03:00
const defaultAutoRestVersion = '1.2.2' ;
2016-03-01 10:11:50 +03:00
var usingAutoRestVersion ;
2018-03-31 00:13:05 +03:00
let azureRestAPISpecsRoot = args [ 'azure-rest-api-specs-root' ] || path . resolve ( _ _dirname , '..' , 'azure-rest-api-specs' ) ;
const package = args [ 'package' ] ;
2018-03-20 22:49:27 +03:00
const use = args [ 'use' ] ;
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:13:05 +03:00
gulp . task ( 'default' , function ( ) {
console . log ( 'Usage: gulp codegen [--azure-rest-api-specs-root <azure-rest-api-specs root>] [--use <autorest.nodejs root>] [--package <package name>]\n' ) ;
console . log ( '--azure-rest-api-specs-root' ) ;
console . log ( '\tRoot location of the local clone of the azure-rest-api-specs-root repository.' ) ;
console . log ( '--use' ) ;
console . log ( '\tRoot 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 ( '\tNPM package to regenerate. If no package is specified, then all packages will be regenerated.' ) ;
} ) ;
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.
gulp . task ( 'codegen' , function ( cb ) {
const nodejsReadmeFilePaths = [ ] ;
2017-03-25 22:59:14 +03:00
2018-03-31 00:13:05 +03:00
// Find all of the readme.nodejs.md files within the azure-rest-api-specs/specification folder.
const specificationFolderPath = path . resolve ( azureRestAPISpecsRoot , 'specification' ) ;
const folderPathsToSearch = [ specificationFolderPath ] ;
while ( folderPathsToSearch . length > 0 ) {
const folderPathToSearch = folderPathsToSearch . pop ( ) ;
const folderEntryPaths = fs . readdirSync ( folderPathToSearch ) ;
for ( let i = 0 ; i < folderEntryPaths . length ; ++ i ) {
const folderEntryPath = path . resolve ( folderPathToSearch , folderEntryPaths [ i ] ) ;
const folderEntryStats = fs . lstatSync ( folderEntryPath ) ;
if ( folderEntryStats . isDirectory ( ) ) {
folderPathsToSearch . push ( folderEntryPath ) ;
}
else if ( folderEntryStats . isFile ( ) ) {
const fileName = path . basename ( folderEntryPath ) ;
if ( fileName === 'readme.nodejs.md' ) {
nodejsReadmeFilePaths . push ( folderEntryPath ) ;
}
}
2017-03-25 22:15:52 +03:00
}
2016-03-01 10:11:50 +03:00
}
2018-03-22 20:14:42 +03:00
2018-03-31 00:13:05 +03:00
let packageName ;
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' ) ;
const packageName = nodejsReadmeFileContents . match ( /package-name: (\S*)/ ) [ 1 ] ;
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:13:05 +03:00
let cmd = ` autorest --nodejs --node-sdks-folder= ${ _ _dirname } --license-header=MICROSOFT_MIT_NO_VERSION ${ readmeFilePath } ` ;
if ( use ) {
cmd += ` --use= ${ use } ` ;
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 ) => {
2017-12-29 03:38:48 +03:00
let packagePaths = glob . sync ( path . join ( _ _dirname , '/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
let packagePaths = glob . sync ( path . join ( _ _dirname , './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' } ) ;
} ) ;
//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 ) => {
2017-11-13 01:34:13 +03:00
let packagePaths = glob . sync ( path . join ( _ _dirname , './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-03-31 00:13:05 +03:00
gulp . task ( 'publish-packages' , ( cb ) => {
const mappings = require ( './codegen_mappings.json' ) ;
const packageFolderPaths = [ ] ;
function findDirProperties ( codegenMappingObject , packageFolderPaths ) {
if ( codegenMappingObject && typeof codegenMappingObject === 'object' ) {
for ( const propertyName in codegenMappingObject ) {
if ( propertyName ) {
const propertyValue = codegenMappingObject [ propertyName ] ;
if ( propertyValue ) {
if ( propertyName == 'dir' && typeof propertyValue === 'string' ) {
if ( ! packageFolderPaths . includes ( propertyValue ) ) {
packageFolderPaths . push ( propertyValue ) ;
2018-03-22 20:21:42 +03:00
}
2017-10-05 20:14:07 +03:00
}
2018-03-31 00:13:05 +03:00
else if ( propertyValue ) {
findDirProperties ( propertyValue , packageFolderPaths ) ;
2018-03-29 19:51:24 +03:00
}
}
}
}
}
}
findDirProperties ( mappings , packageFolderPaths ) ;
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-03-29 19:51:24 +03:00
for ( const index in packageFolderPaths ) {
if ( true ) {
const packageFolderPath = ` ./lib/services/ ${ packageFolderPaths [ index ] } ` ;
2018-03-29 20:40:21 +03:00
const packageJsonFilePath = ` ${ packageFolderPath } /package.json ` ;
if ( ! fs . existsSync ( packageJsonFilePath ) ) {
2018-03-29 21:51:15 +03:00
console . log ( ` ERROR: Package folder ${ packageFolderPath } is missing a package.json file. ` ) ;
errorPackages ++ ;
2018-03-29 20:40:21 +03:00
}
else {
const packageJson = require ( packageJsonFilePath ) ;
const packageName = packageJson . name ;
const localPackageVersion = packageJson . version ;
2018-03-29 21:51:15 +03:00
if ( ! localPackageVersion ) {
console . log ( ` ERROR: " ${ packageJsonFilePath } " doesn't have a non-empty version property. ` ) ;
errorPackages ++ ;
}
else {
let npmPackageVersion ;
try {
const npmViewResult = JSON . parse ( execSync ( ` npm view ${ packageName } --json ` , { stdio : [ 'pipe' , 'pipe' , 'ignore' ] } ) ) ;
npmPackageVersion = npmViewResult [ 'dist-tags' ] [ 'latest' ] ;
}
catch ( error ) {
// This happens if the package doesn't exist in NPM.
}
2018-03-29 19:51:24 +03:00
2018-03-29 21:51:15 +03:00
if ( localPackageVersion === npmPackageVersion ) {
upToDatePackages ++ ;
}
else {
console . log ( ` Publishing package " ${ packageName } " with version " ${ localPackageVersion } "... ` ) ;
2018-03-29 22:23:40 +03:00
try {
execSync ( ` npm publish ` , { cwd : packageFolderPath } ) ;
publishedPackages ++ ;
}
catch ( error ) {
errorPackages ++ ;
}
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-03-29 21:51:15 +03:00
console . log ( ` Error packages: ${ errorPackages } ` ) ;
console . log ( ` Up to date packages: ${ upToDatePackages } ` ) ;
console . log ( ` Published packages: ${ publishedPackages } ` ) ;
2017-08-26 04:53:43 +03:00
} ) ;