2021-07-15 20:39:32 +00:00
|
|
|
const path = require( 'path' );
|
|
|
|
const getAppRoot = require( './app-root' );
|
2021-10-28 19:32:31 +00:00
|
|
|
const fs = require( 'fs' );
|
2021-07-15 20:39:32 +00:00
|
|
|
const mkdirp = require( 'mkdirp' );
|
2021-10-28 19:32:31 +00:00
|
|
|
const request = require( 'request' );
|
|
|
|
const StreamZip = require( 'node-stream-zip' );
|
2021-07-15 20:39:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Upload a plugin zip from a remote location, such as a GitHub URL or other hosted location.
|
|
|
|
*
|
|
|
|
* @param {string} fileUrl The URL where the zip file is located.
|
2021-10-28 19:32:31 +00:00
|
|
|
* @return {string} The path where the zip file is located.
|
2021-07-15 20:39:32 +00:00
|
|
|
*/
|
|
|
|
const getRemotePluginZip = async ( fileUrl ) => {
|
|
|
|
const appPath = getAppRoot();
|
2021-10-28 19:32:31 +00:00
|
|
|
const savePath = path.resolve(
|
|
|
|
appPath,
|
|
|
|
'plugins/woocommerce/tests/e2e/plugins'
|
|
|
|
);
|
2021-07-15 20:39:32 +00:00
|
|
|
mkdirp.sync( savePath );
|
|
|
|
|
|
|
|
// Pull the filename from the end of the URL
|
2021-10-28 19:32:31 +00:00
|
|
|
const fileName = fileUrl.split( '/' ).pop();
|
2021-07-15 20:39:32 +00:00
|
|
|
let filePath = path.join( savePath, fileName );
|
|
|
|
|
|
|
|
// First, download the zip file
|
|
|
|
await downloadZip( fileUrl, filePath );
|
|
|
|
|
|
|
|
// Check for a nested zip and update the filepath
|
2021-07-21 16:22:50 +00:00
|
|
|
filePath = await checkNestedZip( filePath, savePath );
|
2021-07-15 20:39:32 +00:00
|
|
|
|
|
|
|
return filePath;
|
|
|
|
};
|
|
|
|
|
2021-08-11 02:29:36 +00:00
|
|
|
/**
|
|
|
|
* Get the latest release zip for a plugin from a GiHub repository.
|
|
|
|
*
|
|
|
|
* @param {string} owner The owner of the plugin repository.
|
|
|
|
* @param {string} repository The repository name.
|
|
|
|
* @param {boolean} getPrerelease Flag on whether to get a prelease or not.
|
|
|
|
* @param {number} perPage Limit of entries returned from the latest releases list, defaults to 3.
|
2021-10-28 19:32:31 +00:00
|
|
|
* @return {Promise<string>}} Returns the URL for the release zip file.
|
2021-08-11 02:29:36 +00:00
|
|
|
*/
|
2021-10-28 19:32:31 +00:00
|
|
|
const getLatestReleaseZipUrl = async (
|
|
|
|
owner,
|
|
|
|
repository,
|
|
|
|
getPrerelease = false,
|
|
|
|
perPage = 3
|
|
|
|
) => {
|
2021-08-11 02:29:36 +00:00
|
|
|
let requesturl;
|
|
|
|
|
|
|
|
if ( getPrerelease ) {
|
2021-10-28 19:32:31 +00:00
|
|
|
requesturl = `https://api.github.com/repos/${ owner }/${ repository }/releases?per_page=${ perPage }`;
|
2021-08-11 02:29:36 +00:00
|
|
|
} else {
|
2021-10-28 19:32:31 +00:00
|
|
|
requesturl = `https://api.github.com/repos/${ owner }/${ repository }/releases/latest`;
|
2021-08-11 02:29:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const options = {
|
|
|
|
url: requesturl,
|
|
|
|
method: 'GET',
|
|
|
|
json: true,
|
2021-10-28 19:32:31 +00:00
|
|
|
headers: { 'user-agent': 'node.js' },
|
2021-08-11 02:29:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Wrap in a promise to make the request async
|
2021-10-28 19:32:31 +00:00
|
|
|
return new Promise( function ( resolve, reject ) {
|
|
|
|
request.get( options, function ( err, resp, body ) {
|
2021-08-11 02:29:36 +00:00
|
|
|
if ( err ) {
|
|
|
|
reject( err );
|
2021-10-28 19:32:31 +00:00
|
|
|
} else if ( getPrerelease ) {
|
|
|
|
// Loop until we find the first pre-release, then return it.
|
|
|
|
body.forEach( ( release ) => {
|
|
|
|
if ( release.prerelease ) {
|
|
|
|
resolve( release.assets[ 0 ].browser_download_url );
|
|
|
|
}
|
|
|
|
} );
|
2021-08-11 02:29:36 +00:00
|
|
|
} else {
|
2021-10-28 19:32:31 +00:00
|
|
|
resolve( body.assets[ 0 ].browser_download_url );
|
2021-08-11 02:29:36 +00:00
|
|
|
}
|
2021-10-28 19:32:31 +00:00
|
|
|
} );
|
|
|
|
} );
|
|
|
|
};
|
2021-08-11 02:29:36 +00:00
|
|
|
|
2021-07-15 20:39:32 +00:00
|
|
|
/**
|
|
|
|
* Check the zip file for any nested zips. If one is found, extract it.
|
|
|
|
*
|
|
|
|
* @param {string} zipFilePath The location of the zip file.
|
|
|
|
* @param {string} savePath The location where to save a nested zip if found.
|
2021-10-28 19:32:31 +00:00
|
|
|
* @return {string} The path where the zip file is located.
|
2021-07-15 20:39:32 +00:00
|
|
|
*/
|
2021-07-21 16:22:50 +00:00
|
|
|
const checkNestedZip = async ( zipFilePath, savePath ) => {
|
2021-07-15 20:39:32 +00:00
|
|
|
const zip = new StreamZip.async( { file: zipFilePath } );
|
|
|
|
const entries = await zip.entries();
|
|
|
|
|
2021-10-28 19:32:31 +00:00
|
|
|
for ( const entry of Object.values( entries ) ) {
|
|
|
|
if ( entry.name.match( /.zip/ ) ) {
|
2021-07-15 20:39:32 +00:00
|
|
|
await zip.extract( null, savePath );
|
|
|
|
await zip.close();
|
|
|
|
return path.join( savePath, entry.name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return zipFilePath;
|
2021-10-28 19:32:31 +00:00
|
|
|
};
|
2021-07-15 20:39:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Download the zip file from a remote location.
|
|
|
|
*
|
|
|
|
* @param {string} fileUrl The URL where the zip file is located.
|
|
|
|
* @param {string} downloadPath The location where to download the zip to.
|
2021-10-28 19:32:31 +00:00
|
|
|
* @return {Promise<void>}
|
2021-07-15 20:39:32 +00:00
|
|
|
*/
|
|
|
|
const downloadZip = async ( fileUrl, downloadPath ) => {
|
|
|
|
const options = {
|
|
|
|
url: fileUrl,
|
|
|
|
method: 'GET',
|
|
|
|
encoding: null,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Wrap in a promise to make the request async
|
2021-10-28 19:32:31 +00:00
|
|
|
return new Promise( function ( resolve, reject ) {
|
|
|
|
request
|
|
|
|
.get( options, function ( err, resp, body ) {
|
|
|
|
if ( err ) {
|
|
|
|
reject( err );
|
|
|
|
} else {
|
|
|
|
resolve( body );
|
|
|
|
}
|
|
|
|
} )
|
|
|
|
.pipe( fs.createWriteStream( downloadPath ) );
|
|
|
|
} );
|
2021-07-15 20:39:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
getRemotePluginZip,
|
2021-08-11 02:29:36 +00:00
|
|
|
getLatestReleaseZipUrl,
|
2021-07-21 16:22:50 +00:00
|
|
|
checkNestedZip,
|
|
|
|
downloadZip,
|
2021-07-15 20:39:32 +00:00
|
|
|
};
|