Last active
August 24, 2019 02:34
-
-
Save RaschidJFR/d6d072d8d95e3f9b2ebd9729a8031f0b to your computer and use it in GitHub Desktop.
Deploy to FTP/SFTP server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// This script uploads automatically a folder's content to an ftp server. | |
// For this gist's latest version check https://gist.github.com/RaschidJFR/d6d072d8d95e3f9b2ebd9729a8031f0b | |
// | |
// 1. Make sure you've installed as devDependencies the packages you'll need: | |
// * [node-flags](https://www.npmjs.com/package/node-flags) (needed) | |
// * [ftp-deploy](https://www.npmjs.com/package/ftp-deploy) (for normal FTP upload) | |
// * [ftp-diff-deployer](https://www.npmjs.com/package/ftp-diff-deployer) (for uploading diffs on normal FTP) | |
// * [sftp-upload](https://www.npmjs.com/package/sftp-upload) (for SFTP) | |
// | |
// 2. Run this script: `$ node ftp-deploy`. | |
// 3. Optional: Add the flag `--diff` to use `ftp-diff-deployer` (instead of `ftp-deploy`) | |
// or `sftp` to use `sftp-upload`. | |
const FTP_OPTIONS_STRUCT = { | |
"localFolder": "www", | |
"host": "ftp.yourhost.com", | |
"user": "user@yourhost.com", | |
"password": "********", | |
"port": 21, | |
"remoteRoot": "/path/to/remote/folder", | |
"include": [ | |
"*" | |
], | |
"exclude": [ | |
"dist/**/*.map" | |
], | |
"privateKey (sftp only)": "path/to/private.key", | |
"basHref?": "public/path/in/domain/subfolder" | |
} | |
const fs = require('fs'); | |
const flags = require('node-flags'); | |
const useDiff = flags.get('diff'); | |
const useSftp = flags.get('sftp'); | |
const configFileName = flags.get('config') || 'ftp-config.json'; | |
let retries = Number(flags.get('retries')) || 5; | |
// Try inline config first | |
const configData = process.env.CONFIG; | |
if(configData){ | |
const data = JSON.parse(configData); | |
start(data); | |
process.exit(0); | |
} | |
// Read config from file | |
fs.readFile(configFileName, 'utf8', function(err, data) { | |
if (err) { | |
if (err.code == 'ENOENT') { | |
console.error(`\x1b[31mThe file\x1b[33m %o \x1b[31mhas not been found in the working directory.\n` + | |
`Create it or specify the path to your config file using the flag \x1b[0m\`--config="path/to/config/file.json"\`\x1b[31m.\n` + | |
`You may pass inline configuration as a process environmental, eg: \x1b[0mcross-env CONFIG="{\\"your\\": \\"configuration\\"}" node ftp-deploy\x1b[31m\n`+ | |
`Use the following structure:\x1b[0m\n\n %s \n`, | |
configFileName, JSON.stringify(FTP_OPTIONS_STRUCT, null, 2)); | |
process.exit(); | |
} | |
throw err; | |
} | |
start(JSON.parse(data)); | |
}); | |
function start(config) { | |
if (useDiff) | |
uploadWidhDiffDeployer(config); | |
else if (useSftp) | |
uploadWithSFTP(config); | |
else | |
uploadWithFtpDeploy(config); | |
} | |
async function uploadWithFtpDeploy(config) { | |
config.localRoot = `${process.cwd().replace(/\\/g, "/")}/${config.localFolder}`; | |
const FtpDeploy = require('ftp-deploy'); | |
const ftpDeploy = new FtpDeploy(); | |
ftpDeploy.on('uploading', function(data) { | |
console.log(`(${data.transferredFileCount}/${data.totalFilesCount}): ${data.filename}...`); | |
}); | |
console.log(`\x1b[33mDeploying '${config.localRoot}' folder to '${config.host}${config.remoteRoot}' over FTP...\x1b[0m`); | |
try { | |
await ftpDeploy.deploy(config); | |
console.log('\x1b[32mfinished\x1b[0m'); | |
} catch (err) { | |
console.error(err); | |
retries--; | |
if(retries) | |
uploadWithFtpDeploy(config); | |
else | |
process.exit(1); | |
} | |
} | |
async function uploadWidhDiffDeployer(config) { | |
const DiffDeployer = require('ftp-diff-deployer'); | |
config.localFolder = `${process.cwd().replace(/\\/g, "/")}/${config.localFolder}`; | |
const deployer = new DiffDeployer({ | |
host: config.host, | |
auth: { | |
username: config.user, | |
password: config.password | |
}, | |
port: config.port, | |
src: config.localFolder, | |
dest: config.remoteRoot, | |
exclude: config.exclude, | |
memory: 'ftp-deploy.cache.json', | |
retry: 4 | |
}); | |
console.log(`\x1b[33mDeploying '${config.localFolder}' folder to '${config.host}${config.remoteRoot}' over SFTP...\x1b[0m`); | |
try { | |
await new Promise((resolve, reject) => { | |
deployer.deploy(function(err) { | |
if (err) { | |
reject(err); | |
} else { | |
console.log('\x1b[32mfinished\x1b[0m'); | |
resolve(); | |
} | |
}); | |
}) | |
} catch (err) { | |
console.error(err); | |
retries--; | |
if(retries) | |
uploadWidhDiffDeployer(config); | |
else | |
process.exit(1); | |
} | |
} | |
async function uploadWithSFTP(config) { | |
const SftpUpload = require('sftp-upload'); | |
const options = { | |
host: config.host, | |
username: config.user, | |
path: config.localFolder, | |
remoteDir: config.remoteRoot, | |
excludedFolders: config.exclude, | |
privateKey: config.privateKey && fs.readFileSync(config.privateKey), | |
passphrase: config.passphrase && fs.readFileSync(config.passphrase) | |
}; | |
const sftp = new SftpUpload(options); | |
try { | |
await new Promise((resolve, reject) => { | |
sftp.on('error', function(err) { | |
reject(err); | |
}) | |
.on('uploading', function(progress) { | |
console.log('Uploading', progress.file); | |
console.log(progress.percent + '% completed'); | |
}) | |
.on('completed', function() { | |
console.log('Upload Completed'); | |
resolve(); | |
}) | |
.upload(); | |
}); | |
} catch (err) { | |
console.error(err); | |
retries--; | |
if(retries) | |
uploadWithSFTP(config); | |
else | |
process.exit(1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment