import path = require ( "path" ) ; import * as fs from "fs-extra" ; import SFPLogger , { Logger , LoggerLevel } from "../logger/SFPLogger" ; const glob = require ( "glob" ) ; import AdmZip = require ( "adm-zip" ) ; import semver = require ( "semver" ) ; import tar = require ( "tar" ) ; export default class ArtifactFilePathFetcher { param artifactDirectory param sfdx_package public static fetchArtifactFilePaths ( artifactDirectory , sfdx_package ? , logger ? ) { let result = [ ] ; if ( ! fs . existsSync ( artifactDirectory ) ) { throw new Error ( `Artifact directory ${ path . resolve ( artifactDirectory ) } does not exist` ) ; } let artifacts = this . findArtifacts ( artifactDirectory , sfdx_package ) ; if ( artifacts . length === 0 ) { artifacts = ArtifactFilePathFetcher . findArtifactMetadata ( artifactDirectory , sfdx_package ) ; } SFPLogger . log ( `Artifacts: ${ JSON . stringify ( artifacts ) }` , LoggerLevel . TRACE , logger ) ; for ( let artifact of artifacts ) { let artifactFilePaths ; if ( path . basename ( artifact ) === "artifact_metadata.json" ) { artifactFilePaths = ArtifactFilePathFetcher . fetchArtifactFilePathsFromFolder ( artifact ) ; } else if ( path . extname ( artifact ) === ".zip" ) { artifactFilePaths = ArtifactFilePathFetcher . fetchArtifactFilePathsFromZipFile ( artifact ) ; } else if ( path . extname ( artifact ) === ".tgz" ) { artifactFilePaths = ArtifactFilePathFetcher . fetchArtifactFilePathsFromTarball ( artifact ) ; } else { throw new Error ( `Unhandled artifact format ${ artifact }, neither folder or zip file` ) ; } result . push ( artifactFilePaths ) ; } return result ; } param packageMetadataFilePath private static fetchArtifactFilePathsFromFolder ( packageMetadataFilePath ) { let sourceDirectory = path . join ( path . dirname ( packageMetadataFilePath ) , `source` ) ; let changelogFilePath = path . join ( path . dirname ( packageMetadataFilePath ) , `changelog.json` ) ; let artifactFilePaths = { packageMetadataFilePath : packageMetadataFilePath , sourceDirectoryPath : sourceDirectory , changelogFilePath : changelogFilePath } ; ArtifactFilePathFetcher . existsArtifactFilepaths ( artifactFilePaths ) ; return artifactFilePaths ; } param artifact private static fetchArtifactFilePathsFromZipFile ( artifact ) { let unzippedArtifactsDirectory = `.sfpowerscripts/unzippedArtifacts/${ this . makefolderid ( 8 ) }` ; fs . mkdirpSync ( unzippedArtifactsDirectory ) ; let zip = new AdmZip ( artifact ) ; zip . extractAllTo ( unzippedArtifactsDirectory , true ) ; let artifactName = path . basename ( artifact ) . match ( /.*sfpowerscripts_artifact/ ) ?. [ 0 ] ; if ( artifactName == null ) { throw new Error ( `Failed to fetch artifact file paths for ${ artifact }` ) ; } let packageMetadataFilePath = path . join ( unzippedArtifactsDirectory , artifactName , "artifact_metadata.json" ) ; let sourceDirectory = path . join ( unzippedArtifactsDirectory , artifactName , `source` ) ; let changelogFilePath = path . join ( unzippedArtifactsDirectory , artifactName , `changelog.json` ) ; let artifactFilePaths = { packageMetadataFilePath : packageMetadataFilePath , sourceDirectoryPath : sourceDirectory , changelogFilePath : changelogFilePath } ; ArtifactFilePathFetcher . existsArtifactFilepaths ( artifactFilePaths ) ; return artifactFilePaths ; } param artifact private static fetchArtifactFilePathsFromTarball ( artifact ) { let unzippedArtifactsDirectory = `.sfpowerscripts/unzippedArtifacts/${ this . makefolderid ( 8 ) }` ; fs . mkdirpSync ( unzippedArtifactsDirectory ) ; tar . x ( { file : artifact , cwd : unzippedArtifactsDirectory , sync : true } ) ; let packageMetadataFilePath = path . join ( unzippedArtifactsDirectory , "package" , "artifact_metadata.json" ) ; let sourceDirectory = path . join ( unzippedArtifactsDirectory , "package" , `source` ) ; let changelogFilePath = path . join ( unzippedArtifactsDirectory , "package" , `changelog.json` ) ; let artifactFilePaths = { packageMetadataFilePath : packageMetadataFilePath , sourceDirectoryPath : sourceDirectory , changelogFilePath : changelogFilePath } ; ArtifactFilePathFetcher . existsArtifactFilepaths ( artifactFilePaths ) ; return artifactFilePaths ; } /**
     * Find zip and tarball artifacts
     * Artifact format/s:
     * sfpowerscripts_artifact_<version>.zip,
     * [sfdx_package]_sfpowerscripts_artifact_[version].zip,
     * [sfdx_package]_sfpowerscripts_artifact_[version].tgz
     */ public static findArtifacts ( artifactDirectory , sfdx_package ? ) { let pattern ; if ( sfdx_package ) { pattern = `**/${ sfdx_package }_sfpowerscripts_artifact*.@(zip|tgz)` ; } else { pattern = `**/*sfpowerscripts_artifact*.@(zip|tgz)` ; } let artifacts = glob . sync ( pattern , { cwd : artifactDirectory , absolute : true , } ) ; if ( sfdx_package && artifacts . length > 1 ) { SFPLogger . log ( `Found more than one artifact for ${ sfdx_package }` , LoggerLevel . INFO ) ; let latestArtifact = ArtifactFilePathFetcher . getLatestArtifact ( artifacts ) ; SFPLogger . log ( `Using latest artifact ${ latestArtifact }` , LoggerLevel . INFO ) ; return [ latestArtifact ] ; } else return artifacts ; } param artifacts private static getLatestArtifact ( artifacts ) { artifacts = artifacts . filter ( ( artifact ) => { let ext = path . extname ( artifact ) ; return ext === ".zip" || ext === ".tgz" ; } ) ; let pattern = new RegExp ( "(?:^.*)(?:_sfpowerscripts_artifact[_-])(?<version>.*)(?:\\.zip|\\.tgz)$" ) ; let versions = artifacts . map ( ( artifact ) => { let match = path . basename ( artifact ) . match ( pattern ) ; let version = match ?. groups . version ; if ( version ) return version ; else throw new Error ( "Corrupted artifact detected with no version number" ) ; } ) ; let sortedVersions = semver . sort ( versions ) ; let latestVersion = sortedVersions . pop ( ) ; return artifacts . find ( ( artifact ) => artifact . includes ( latestVersion ) ) ; } param artifactDirectory param sfdx_package private static findArtifactMetadata ( artifactDirectory , sfdx_package ? ) { let packageMetadataFilepaths = glob . sync ( `**/artifact_metadata.json` , { cwd : artifactDirectory , absolute : true , } ) ; if ( sfdx_package ) { packageMetadataFilepaths = packageMetadataFilepaths . filter ( ( filepath ) => { let artifactMetadata = JSON . parse ( fs . readFileSync ( filepath , "utf8" ) ) ; return artifactMetadata [ "package_name" ] === sfdx_package ; } ) ; } return packageMetadataFilepaths ; } param artifactFilePaths private static existsArtifactFilepaths ( artifactFilePaths ) { Object . values ( artifactFilePaths ) . forEach ( ( filepath ) => { if ( ! fs . existsSync ( filepath ) ) throw new Error ( `Artifact filepath ${ filepath } does not exist` ) ; } ) ; } param artifacts_filepaths param isToSkipOnMissingArtifact public static missingArtifactDecider ( artifacts , isToSkipOnMissingArtifact ) { if ( artifacts . length === 0 && ! isToSkipOnMissingArtifact ) { throw new Error ( `Artifact not found, Please check the inputs` ) ; } else if ( artifacts . length === 0 && isToSkipOnMissingArtifact ) { SFPLogger . log ( `Skipping task as artifact is missing, and 'Skip If no artifact is found' ${ isToSkipOnMissingArtifact }` ) ; return true ; } } private static makefolderid ( length ) { var result = "" ; var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ; var charactersLength = characters . length ; for ( var i = 0 ; i < length ; i ++ ) { result += characters . charAt ( Math . floor ( Math . random ( ) * charactersLength ) ) ; } return result ; } } export interface ArtifactFilePaths { packageMetadataFilePath : string ; sourceDirectoryPath ? : string ; changelogFilePath ? : string ; }