Коммит
eef27abd67
|
@ -39,8 +39,7 @@ cp -a $SALESFORCE_CACHE_DIR/node $SALESFORCE_DIR/node
|
|||
export PATH="$SALESFORCE_DIR/node/bin":$PATH
|
||||
|
||||
status "Coping deploy script to .salesforce/deploy"
|
||||
cp $BP_DIR/lib/deploy.js $SALESFORCE_DIR/deploy.js
|
||||
cp $BP_DIR/lib/auth.js $SALESFORCE_DIR/auth.js
|
||||
cp -R $BP_DIR/lib/* $SALESFORCE_DIR/
|
||||
cp $BP_DIR/package.json $SALESFORCE_DIR/package.json
|
||||
|
||||
echo ".salesforce/node/bin/node .salesforce/deploy.js" > $SALESFORCE_DIR/deploy
|
||||
|
|
74
lib/auth.js
74
lib/auth.js
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
force://<clientId>:<clientSecret>:<refreshToken>@<instanceUrl>
|
||||
*/
|
||||
var URL_REGEX = /force:\/\/(.*):(.*):(.*)@(.*)/;
|
||||
var TOKEN_REGEX = /.*\"access_token\":\"([A-Za-z0-9.!_]*)\".*/;
|
||||
|
||||
const forceApiVersion = '37.0';
|
||||
|
||||
function parseUrl(oauth_url) {
|
||||
if(oauth_url) {
|
||||
const matcher = oauth_url.match(URL_REGEX);
|
||||
if(matcher) {
|
||||
return {
|
||||
clientId : matcher[1],
|
||||
clientSecret : matcher[2],
|
||||
refreshToken : matcher[3],
|
||||
instance : matcher[4]
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
function oauthConfig(addonInfo) {
|
||||
|
||||
const oauth2 = {
|
||||
clientId: addonInfo.clientId,
|
||||
clientSecret: addonInfo.clientSecret,
|
||||
redirectUri: 'https://www.example.com' // we don't care what this is but it has to match the Salesforce Connected App config set in the Environment Hub
|
||||
};
|
||||
|
||||
const instanceUrl = `https://${addonInfo.instance}`;
|
||||
|
||||
return {
|
||||
oauth2,
|
||||
instanceUrl,
|
||||
loginUrl: instanceUrl,
|
||||
serverUrl: `https://${instanceUrl}/services/Soap/u/${forceApiVersion}`,
|
||||
refreshToken: addonInfo.refreshToken,
|
||||
version: forceApiVersion
|
||||
}
|
||||
}
|
||||
|
||||
const request = require('request');
|
||||
const refreshAuth = function(oauth) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request
|
||||
.post(`https://${oauth.instance}/services/oauth2/token`, {
|
||||
qs: {
|
||||
grant_type: 'refresh_token',
|
||||
client_id: oauth.clientId,
|
||||
client_secret: oauth.clientSecret,
|
||||
refresh_token: oauth.refreshToken
|
||||
},
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
}
|
||||
}, function (error, response, body) {
|
||||
if (error != null) {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
console.log('-----> Refresh auth', response.statusCode, body);
|
||||
resolve(JSON.parse(response.body).access_token);
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
parseUrl,
|
||||
oauthConfig,
|
||||
refreshAuth
|
||||
};
|
|
@ -1,9 +1,7 @@
|
|||
const zipPath = '.salesforce/src.zip';
|
||||
|
||||
const fs = require('fs');
|
||||
const jsforce = require('jsforce');
|
||||
const Promise = require('bluebird');
|
||||
const { parseUrl, oauthConfig } = require('./auth');
|
||||
const jsforceConnection = require('./jsforce-connection');
|
||||
|
||||
const prompt = function(message) {
|
||||
console.log(`-----> ${message}`);
|
||||
|
@ -17,37 +15,33 @@ const error = function(message) {
|
|||
console.error(` ! ${message}`);
|
||||
};
|
||||
|
||||
const addonInfo = parseUrl(process.env.SALESFORCE_URL);
|
||||
return jsforceConnection()
|
||||
.then( conn => {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('-----> Deploying metadata');
|
||||
const zipStream = fs.createReadStream(zipPath);
|
||||
conn.metadata.pollTimeout = 240*1000;
|
||||
const deployLocator = conn.metadata.deploy(zipStream, {});
|
||||
deployLocator.complete(true, function(err, result) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
})
|
||||
})
|
||||
.then( result => {
|
||||
info('done ? :' + result.done);
|
||||
info('success ? : ' + result.true);
|
||||
info('state : ' + result.state);
|
||||
info('component errors: ' + result.numberComponentErrors);
|
||||
info('components deployed: ' + result.numberComponentsDeployed);
|
||||
info('tests completed: ' + result.numberTestsCompleted);
|
||||
info(' ' + (result.success ? 'Success' : 'Failed'));
|
||||
})
|
||||
.catch( err => {
|
||||
error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
if(!addonInfo) {
|
||||
error(`Didn't find a valid SALESFORCE_URL: ${process.env.SALESFORCE_URL}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = oauthConfig(addonInfo);
|
||||
const conn = new jsforce.Connection(config);
|
||||
|
||||
conn.on('refresh', function(accessToken, res) {
|
||||
info(`refreshed access token`);
|
||||
});
|
||||
|
||||
console.log('-----> Deploying metadata');
|
||||
const zipStream = fs.createReadStream(zipPath);
|
||||
conn.metadata.pollTimeout = 240*1000;
|
||||
const deployLocator = conn.metadata.deploy(zipStream, {});
|
||||
deployLocator.on('progress', function(results) {
|
||||
info('polling...');
|
||||
});
|
||||
deployLocator.complete(true, function(err, result) {
|
||||
if (err) {
|
||||
error(err);
|
||||
return;
|
||||
}
|
||||
info('done ? :' + result.done);
|
||||
info('success ? : ' + result.true);
|
||||
info('state : ' + result.state);
|
||||
info('component errors: ' + result.numberComponentErrors);
|
||||
info('components deployed: ' + result.numberComponentsDeployed);
|
||||
info('tests completed: ' + result.numberTestsCompleted);
|
||||
info(' ' + (result.success ? 'Success' : 'Failed'));
|
||||
});
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const fetch = require('node-fetch');
|
||||
|
||||
module.exports = function getSalesforceIdentity(accessToken, idUrl) {
|
||||
console.log('-----> Get Salesforce identity');
|
||||
return fetch(idUrl, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then( response => {
|
||||
const status = response.status;
|
||||
if (status >= 300) { throw new Error(`Request status ${status} for ${idUrl}`) }
|
||||
//console.log(' response status', status);
|
||||
return response.json();
|
||||
})
|
||||
.then( salesforceIdentity => {
|
||||
//console.log(' Identity', salesforceIdentity);
|
||||
return salesforceIdentity;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
const url = require('url');
|
||||
const jsforce = require('jsforce');
|
||||
const requireEnvVar = require('./require-env-var');
|
||||
const refreshSalesforceAuth = require('./refresh-salesforce-auth');
|
||||
const getSalesforceIdentity = require('./get-salesforce-identity');
|
||||
|
||||
// Return Promise of authenticated jsForce connection.
|
||||
module.exports = function createJsforceConnection(forceComVersion = '37.0') {
|
||||
|
||||
const forceComAlmUrl = url.parse(requireEnvVar('SALESFORCE_URL'));
|
||||
const forceComAuth = forceComAlmUrl.auth.split(':');
|
||||
const forceComId = forceComAuth[0];
|
||||
const forceComSecret = forceComAuth[1];
|
||||
const forceComRefreshToken = forceComAuth[2];
|
||||
const forceComHost = forceComAlmUrl.host;
|
||||
const forceComUrl = `https://${forceComHost}`;
|
||||
|
||||
console.log('-----> Force.com connecting', forceComUrl);
|
||||
|
||||
// Dynamic assignments with top-level scope
|
||||
let forceComAuthToken;
|
||||
let forceComUserId;
|
||||
let forceComUsername;
|
||||
|
||||
let connection;
|
||||
|
||||
return refreshSalesforceAuth(forceComHost, forceComId, forceComSecret, forceComRefreshToken)
|
||||
.then( ({accessToken, idUrl}) => {
|
||||
forceComAuthToken = accessToken;
|
||||
connection = new jsforce.Connection({
|
||||
accessToken: accessToken,
|
||||
loginUrl: forceComUrl,
|
||||
instanceUrl: forceComUrl,
|
||||
serverUrl: `${forceComUrl}/services/Soap/u/${forceComVersion}`,
|
||||
version: forceComVersion
|
||||
});
|
||||
return getSalesforceIdentity(accessToken, idUrl);
|
||||
})
|
||||
.then( res => {
|
||||
console.log('-----> Salesforce org ID', res.organization_id);
|
||||
console.log('-----> Salesforce admin user ID', res.user_id);
|
||||
console.log('-----> Salesforce admin username', res.username);
|
||||
return connection;
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
const url = require('url');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
module.exports = function refreshSalesforceAuth(forceComHost, forceComId, forceComSecret, forceComRefreshToken) {
|
||||
if (forceComHost == null || forceComId == null || forceComSecret == null || forceComRefreshToken == null) {
|
||||
throw new Error('Requires arguments `forceComHost, forceComId, forceComSecret, forceComRefreshToken`');
|
||||
}
|
||||
const query = `grant_type=refresh_token&client_id=${
|
||||
encodeURIComponent(forceComId)}&client_secret=${
|
||||
encodeURIComponent(forceComSecret)}&refresh_token=${
|
||||
encodeURIComponent(forceComRefreshToken)}`;
|
||||
const refreshAuthUrl = `https://${forceComHost}/services/oauth2/token?${query}`;
|
||||
|
||||
console.log('-----> Refresh Salesforce auth');
|
||||
return fetch(refreshAuthUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
}
|
||||
})
|
||||
.then( response => {
|
||||
const status = response.status;
|
||||
if (status >= 300) { throw new Error(`Request status ${status} for ${refreshAuthUrl}`) }
|
||||
//console.log(' response status', status);
|
||||
return response.json();
|
||||
})
|
||||
.then( salesforceAuth => {
|
||||
// Reset the identity URL to the specified instance host, otherwise Salesforce always uses "login.salesforce.com"
|
||||
const salesforceIdentityUrl = url.parse(salesforceAuth.id);
|
||||
salesforceIdentityUrl.host = forceComHost;
|
||||
const idUrl = url.format(salesforceIdentityUrl);
|
||||
//console.log(` instance identity URL ${idUrl}`);
|
||||
return {
|
||||
accessToken: salesforceAuth.access_token,
|
||||
idUrl
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = function requireEnvVar(name) {
|
||||
var value = process.env[name];
|
||||
|
||||
if (value != null) {
|
||||
return value;
|
||||
} else {
|
||||
throw new Error(`! Environment variable "${name}" is required`);
|
||||
}
|
||||
}
|
|
@ -13,8 +13,7 @@
|
|||
},
|
||||
"homepage": "https://github.com/forcedotcom/force-com-buildpack#readme",
|
||||
"dependencies": {
|
||||
"bluebird": "^3.4.0",
|
||||
"jsforce": "^1.6.5",
|
||||
"request": "^2.72.0"
|
||||
"node-fetch": "^1.5.3"
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче