Skip to content

Instantly share code, notes, and snippets.

@RaschidJFR
Last active August 24, 2019 02:34
Show Gist options
  • Save RaschidJFR/d6d072d8d95e3f9b2ebd9729a8031f0b to your computer and use it in GitHub Desktop.
Save RaschidJFR/d6d072d8d95e3f9b2ebd9729a8031f0b to your computer and use it in GitHub Desktop.
Deploy to FTP/SFTP server
#!/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