Lots of little improvements
This commit is contained in:
Родитель
2d3437fad6
Коммит
a6e0f241e2
241
app.js
241
app.js
|
@ -1,18 +1,21 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const sleep = require('sleep');
|
const cookieParser = require('cookie-parser');
|
||||||
var cookieParser = require('cookie-parser')
|
const oauth2 = require('salesforce-oauth2');
|
||||||
|
const jsforce = require('jsforce');
|
||||||
|
const commands = require('./lib/commands.js');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
exec
|
exec
|
||||||
} = require('child_process');
|
} = require('child_process');
|
||||||
const oauth2 = require('salesforce-oauth2');
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
const callbackUrl = process.env.CALLBACKURL;
|
const callbackUrl = process.env.CALLBACKURL;
|
||||||
const consumerKey = process.env.CONSUMERKEY;
|
const consumerKey = process.env.CONSUMERKEY;
|
||||||
const consumerSecret = process.env.CONSUMERSECRET;
|
const consumerSecret = process.env.CONSUMERSECRET;
|
||||||
|
|
||||||
app.use('/scripts', express.static(__dirname + '/scripts'));
|
app.use('/scripts', express.static(`${__dirname}/scripts`));
|
||||||
|
|
||||||
app.use(bodyParser.urlencoded({
|
app.use(bodyParser.urlencoded({
|
||||||
extended: true
|
extended: true
|
||||||
|
@ -22,15 +25,27 @@ app.set('view engine', 'ejs');
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
|
||||||
app.get('/', function (req, res) {
|
app.get('/', (req, res) => {
|
||||||
res.render('pages/index', {});
|
res.render('pages/index', {});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/about', function (req, res) {
|
app.get('/about', (req, res) => {
|
||||||
res.render('pages/about');
|
res.render('pages/about');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/deploy', function (req, res) {
|
app.get('/notdevhub', (req, res) => {
|
||||||
|
const template = req.query.template;
|
||||||
|
res.cookie('template', template);
|
||||||
|
|
||||||
|
const user_name = req.cookies.user_name;
|
||||||
|
|
||||||
|
res.render('pages/notdevhub', {
|
||||||
|
template: template,
|
||||||
|
user_name: user_name
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/deploy', (req, res) => {
|
||||||
const template = req.query.template;
|
const template = req.query.template;
|
||||||
|
|
||||||
res.cookie('template', template);
|
res.cookie('template', template);
|
||||||
|
@ -51,145 +66,207 @@ app.get('/deploy', function (req, res) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/deploying', function (req, res) {
|
app.get('/deploying', (req, res) => {
|
||||||
const template = req.query.template;
|
const template = req.query.template;
|
||||||
res.render('pages/deploying', {
|
res.render('pages/deploying', {
|
||||||
template: template
|
template: template
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/login", function (req, res) {
|
app.get("/login", (req, res) => {
|
||||||
var uri = oauth2.getAuthorizationUrl({
|
const uri = oauth2.getAuthorizationUrl({
|
||||||
redirect_uri: callbackUrl,
|
redirect_uri: callbackUrl,
|
||||||
client_id: consumerKey,
|
client_id: consumerKey,
|
||||||
scope: 'id api refresh_token openid',
|
scope: 'id api refresh_token openid',
|
||||||
state: 'test123'
|
state: 'test123'
|
||||||
// You can change loginUrl to connect to sandbox or prerelease env.
|
|
||||||
//base_url: 'https://test.my.salesforce.com'
|
|
||||||
});
|
});
|
||||||
return res.redirect(uri);
|
return res.redirect(uri);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/logout', function (req, res) {
|
app.get('/logout', (req, res) => {
|
||||||
res.clearCookie('access_token');
|
|
||||||
res.clearCookie('instance_url');
|
|
||||||
|
|
||||||
return res.redirect('/');
|
const access_token = req.cookies.access_token;
|
||||||
|
const instance_url = req.cookies.instance_url;
|
||||||
|
|
||||||
|
const conn = new jsforce.Connection({
|
||||||
|
instanceUrl: instance_url,
|
||||||
|
accessToken: access_token
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.logout((err) => {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err);
|
||||||
|
}
|
||||||
|
res.clearCookie('access_token');
|
||||||
|
res.clearCookie('instance_url');
|
||||||
|
|
||||||
|
return res.redirect('/');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/oauth/callback', function (req, res) {
|
app.get('/oauth/callback', (req, res) => {
|
||||||
const authorizationCode = req.param('code');
|
const authorizationCode = req.param('code');
|
||||||
const state = req.param('state');
|
// const state = req.param('state'); // TODO: use state and query instead of cookies
|
||||||
console.log('state', state);
|
|
||||||
|
|
||||||
oauth2.authenticate({
|
oauth2.authenticate({
|
||||||
redirect_uri: callbackUrl,
|
redirect_uri: callbackUrl,
|
||||||
client_id: consumerKey,
|
client_id: consumerKey,
|
||||||
client_secret: consumerSecret,
|
client_secret: consumerSecret,
|
||||||
code: authorizationCode
|
code: authorizationCode
|
||||||
}, function (error, payload) {
|
}, (error, payload) => {
|
||||||
|
|
||||||
res.cookie('access_token', payload.access_token);
|
res.cookie('access_token', payload.access_token);
|
||||||
res.cookie('instance_url', payload.instance_url);
|
res.cookie('instance_url', payload.instance_url);
|
||||||
res.cookie('refresh_token', payload.refresh_token);
|
res.cookie('refresh_token', payload.refresh_token);
|
||||||
res.cookie('user_name', payload.id);
|
|
||||||
|
|
||||||
console.log(payload);
|
console.log(payload);
|
||||||
|
|
||||||
const template = req.cookies.template;
|
// check to see if org is a dev hub
|
||||||
return res.redirect(`/deploy?template=${template}`);
|
const conn = new jsforce.Connection({
|
||||||
|
instanceUrl: payload.instance_url,
|
||||||
|
accessToken: payload.access_token
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.identity((err, identity) => {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.cookie('user_name', identity.username);
|
||||||
|
|
||||||
|
conn.tooling.query("SELECT DurableId, SettingValue FROM OrganizationSettingsDetail WHERE SettingName = 'ScratchOrgManagementPref'", (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
return console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = req.cookies.template;
|
||||||
|
|
||||||
|
if (result.size > 0) {
|
||||||
|
const devHubEnabled = result.records[0].SettingValue;
|
||||||
|
|
||||||
|
if (devHubEnabled === true) {
|
||||||
|
return res.redirect(`/deploy?template=${template}`);
|
||||||
|
} else {
|
||||||
|
return res.redirect(`/notdevhub?template=${template}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return res.redirect(`/notdevhub?template=${template}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.post('/deploying', function (req, res) {
|
router.post('/deploying', (req, res) => {
|
||||||
|
|
||||||
var command = req.body.command;
|
|
||||||
var param = req.body.param;
|
|
||||||
|
|
||||||
|
const command = req.body.command;
|
||||||
|
const timestamp = req.body.timestamp;
|
||||||
|
const param = req.body.param;
|
||||||
const access_token = req.cookies.access_token;
|
const access_token = req.cookies.access_token;
|
||||||
const instance_url = req.cookies.instance_url;
|
const instance_url = req.cookies.instance_url;
|
||||||
const refresh_token = req.cookies.refresh_token;
|
const refresh_token = req.cookies.refresh_token;
|
||||||
|
|
||||||
if (command === 'clone') {
|
const tokenName = access_token.replace(/\W/g, '');
|
||||||
|
const startingDirectory = process.env.STARTINGDIRECTORY;
|
||||||
|
const directory = `${tokenName}-${timestamp}`;
|
||||||
|
|
||||||
exec(`cd /tmp;mkdir test;cd test;git clone ${param} repo`, (err, stdout, stderr) => {
|
let script;
|
||||||
res.json({
|
let sfdxurl;
|
||||||
message: `Successfully cloned ${param}`
|
|
||||||
|
switch (command) {
|
||||||
|
|
||||||
|
case 'clone':
|
||||||
|
|
||||||
|
script = `${startingDirectory}mkdir ${directory};cd ${directory};git clone ${param} .`;
|
||||||
|
|
||||||
|
commands.run(command, script, () => {
|
||||||
|
res.json({
|
||||||
|
message: `Successfully cloned ${param}`
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (command === 'auth') {
|
case 'auth':
|
||||||
|
|
||||||
const sfdxurl = `echo "force://${consumerKey}:${consumerSecret}:${refresh_token}@${instance_url}" > sfdx.key`;
|
sfdxurl = `echo "force://${consumerKey}:${consumerSecret}:${refresh_token}@${instance_url}" > sfdx.key`;
|
||||||
const commandScript = `cd /tmp/test/repo;export FORCE_SHOW_SPINNER=;${sfdxurl};sfdx force:auth:sfdxurl:store -f sfdx.key -d`;
|
script = `${startingDirectory}cd ${directory};export FORCE_SHOW_SPINNER=;${sfdxurl};sfdx force:auth:sfdxurl:store -f sfdx.key -d`;
|
||||||
console.log('auth', commandScript);
|
|
||||||
|
|
||||||
exec(commandScript, (err, stdout, stderr) => {
|
commands.run(command, script, (result) => {
|
||||||
console.log('create:stderr', stderr);
|
res.json({
|
||||||
res.json({
|
message: `Authenticated to dev hub: ${result}`
|
||||||
message: `Authenticated to dev hub: ${stdout}`
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command === 'create') {
|
break;
|
||||||
|
|
||||||
const commandScript = `cd /tmp/test/repo;export FORCE_SHOW_SPINNER=;sfdx force:org:create -s -f ${param}`;
|
case 'create':
|
||||||
console.log('create', commandScript);
|
|
||||||
|
|
||||||
exec(commandScript, (err, stdout, stderr) => {
|
script = `${startingDirectory}cd ${directory};export FORCE_SHOW_SPINNER=;sfdx force:config:set instanceUrl=${instance_url};sfdx force:org:create -v '${access_token}' -s -f ${param}`;
|
||||||
console.log('create:stderr', stderr);
|
|
||||||
res.json({
|
commands.run(command, script, (result) => {
|
||||||
message: `Created scratch org: ${stdout}`
|
res.json({
|
||||||
|
message: `Created scratch org: ${result}`
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command === 'push') {
|
break;
|
||||||
exec(`cd /tmp/test/repo;export FORCE_SHOW_SPINNER=;sfdx force:source:push`, (err, stdout, stderr) => {
|
|
||||||
res.json({
|
case 'push':
|
||||||
message: `Pushed source:\n\t${stdout}`
|
|
||||||
|
script = `${startingDirectory}cd ${directory};export FORCE_SHOW_SPINNER=;sfdx force:source:push`;
|
||||||
|
|
||||||
|
commands.run(command, script, (result) => {
|
||||||
|
res.json({
|
||||||
|
message: `Pushed source:\n\t${result}`
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command === 'test') {
|
break;
|
||||||
exec(`cd /tmp/test/repo;export FORCE_SHOW_SPINNER=;sfdx force:apex:test:run -r human --json | jq -r .result | jq -r .summary | jq -r .outcome`, (err, stdout, stderr) => {
|
|
||||||
res.json({
|
case 'test':
|
||||||
message: `Apex tests: ${stdout}`
|
|
||||||
|
script = `${startingDirectory}cd ${directory};export FORCE_SHOW_SPINNER=;sfdx force:apex:test:run -r human --json | jq -r .result | jq -r .summary | jq -r .outcome`;
|
||||||
|
|
||||||
|
commands.run(command, script, (result) => {
|
||||||
|
res.json({
|
||||||
|
message: `Apex tests: ${result}`
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command === 'url') {
|
break;
|
||||||
const commandScript = 'cd /tmp/test/repo;export FORCE_SHOW_SPINNER=;echo $(sfdx force:org:display --json | jq -r .result | jq -r .instanceUrl)"/secur/frontdoor.jsp?sid="$(sfdx force:org:display --json | jq -r .result | jq -r .accessToken)';
|
|
||||||
|
|
||||||
exec(commandScript, (err, stdout, stderr) => {
|
case 'url':
|
||||||
res.json({
|
|
||||||
message: `${stdout}`
|
script = `${startingDirectory}cd ${directory};export FORCE_SHOW_SPINNER=;echo $(sfdx force:org:display --json | jq -r .result | jq -r .instanceUrl)"/secur/frontdoor.jsp?sid="$(sfdx force:org:display --json | jq -r .result | jq -r .accessToken)`;
|
||||||
|
|
||||||
|
commands.run(command, script, (result) => {
|
||||||
|
res.json({
|
||||||
|
message: `${result}`
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command === 'clean') {
|
break;
|
||||||
|
|
||||||
const commandScript = 'rm -rf /tmp/test';
|
case 'clean':
|
||||||
exec(commandScript, (err, stdout, stderr) => {
|
|
||||||
res.json({
|
script = `${startingDirectory}rm -rf ${directory}`;
|
||||||
message: 'Removed temp files and cleaned up'
|
|
||||||
|
commands.run(command, script, () => {
|
||||||
|
res.json({
|
||||||
|
message: 'Removed temp files and cleaned up'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use('/api', router);
|
app.use('/api', router);
|
||||||
|
|
||||||
var port = process.env.PORT || 8080;
|
const port = process.env.PORT || 8080;
|
||||||
app.listen(port, function () {
|
app.listen(port, () => {
|
||||||
console.log(`Example app listening on port ${port}!`);
|
console.log(`Example app listening on port ${port}!`);
|
||||||
});
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
const {
|
||||||
|
exec
|
||||||
|
} = require('child_process');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
run: (command, commandScript, result) => {
|
||||||
|
exec(commandScript, (err, stdout, stderr) => {
|
||||||
|
if (stderr || err) {
|
||||||
|
console.log(`${command}:err`, err);
|
||||||
|
console.log(`${command}:stderr`, stderr);
|
||||||
|
}
|
||||||
|
result(stdout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
$(document).ready(function () {
|
$(document).ready(() => {
|
||||||
|
|
||||||
let actionCount = 0;
|
let actionCount = 0;
|
||||||
let message = '';
|
let message = '';
|
||||||
|
@ -10,13 +10,14 @@ $(document).ready(function () {
|
||||||
$('textarea#status').val(message);
|
$('textarea#status').val(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deployingApi(command, param) {
|
function deployingApi(command, timestamp, param) {
|
||||||
|
|
||||||
commandData = {};
|
const commandData = {};
|
||||||
commandData.command = command;
|
commandData.command = command;
|
||||||
|
commandData.timestamp = timestamp;
|
||||||
commandData.param = param;
|
commandData.param = param;
|
||||||
|
|
||||||
await $.ajax({
|
return $.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: '/api/deploying',
|
url: '/api/deploying',
|
||||||
data: JSON.stringify(commandData),
|
data: JSON.stringify(commandData),
|
||||||
|
@ -28,8 +29,7 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let githubRepo = $('input#template').val();
|
const githubRepo = $('input#template').val();
|
||||||
|
|
||||||
let yamlFile = githubRepo.replace('github.com', 'raw.githubusercontent.com');
|
let yamlFile = githubRepo.replace('github.com', 'raw.githubusercontent.com');
|
||||||
yamlFile += '/master/.salesforcedx.yaml';
|
yamlFile += '/master/.salesforcedx.yaml';
|
||||||
|
|
||||||
|
@ -42,7 +42,9 @@ $(document).ready(function () {
|
||||||
|
|
||||||
update_status(`Discovered ${yamlFile}`);
|
update_status(`Discovered ${yamlFile}`);
|
||||||
|
|
||||||
var doc = jsyaml.load(yamlFileDataResponse);
|
const doc = jsyaml.load(yamlFileDataResponse);
|
||||||
|
|
||||||
|
const timestamp = new Date().getTime().toString();
|
||||||
|
|
||||||
const assignPermset = doc['assign-permset'];
|
const assignPermset = doc['assign-permset'];
|
||||||
const deleteScratchOrg = doc['delete-scratch-org'];
|
const deleteScratchOrg = doc['delete-scratch-org'];
|
||||||
|
@ -57,27 +59,25 @@ $(document).ready(function () {
|
||||||
\tscratch-org-def: ${scratchOrgDef}
|
\tscratch-org-def: ${scratchOrgDef}
|
||||||
\tshow-scratch-org-url: ${showScratchOrgUrl}`);
|
\tshow-scratch-org-url: ${showScratchOrgUrl}`);
|
||||||
|
|
||||||
return deployingApi('clone', githubRepo)
|
return deployingApi('clone', timestamp, githubRepo)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return deployingApi('auth');
|
return deployingApi('auth', timestamp);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return deployingApi('create', scratchOrgDef);
|
return deployingApi('create', timestamp, scratchOrgDef);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return deployingApi('push');
|
return deployingApi('push', timestamp);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return deployingApi('auth');
|
return deployingApi('test', timestamp);
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
return deployingApi('test');
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
||||||
// generate url
|
// generate url
|
||||||
commandData = {};
|
let commandData = {};
|
||||||
commandData.command = 'url';
|
commandData.command = 'url';
|
||||||
|
commandData.timestamp = timestamp;
|
||||||
|
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
|
@ -86,23 +86,33 @@ $(document).ready(function () {
|
||||||
contentType: 'application/json; charset=utf-8',
|
contentType: 'application/json; charset=utf-8',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: (commandDataResponse) => {
|
success: (commandDataResponse) => {
|
||||||
update_status(`${commandDataResponse.message}`);
|
update_status(`Generated a login url: ${commandDataResponse.message}`);
|
||||||
|
|
||||||
const url = commandDataResponse.message;
|
const url = commandDataResponse.message;
|
||||||
|
|
||||||
$("#loginUrl").attr("href", url);
|
$('#loginUrl').attr('href', url);
|
||||||
$("#loginUrl").text(`${url.substring(0, 80)}...`);
|
$('#loginUrl').text(`${url.substring(0, 80)}...`);
|
||||||
$('#loginBlock').show();
|
$('#loginBlock').show();
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
commandData = {};
|
commandData = {};
|
||||||
commandData.command = 'clean';
|
commandData.command = 'clean';
|
||||||
|
commandData.timestamp = timestamp;
|
||||||
|
|
||||||
|
// return deployingApi('clean', timestamp).then(() => {
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
deployingApi(commandData);
|
|
||||||
|
|
||||||
message = `DONE!\n\n${message}`;
|
|
||||||
$('textarea#status').val(message);
|
|
||||||
}
|
}
|
||||||
|
}).then(() => {
|
||||||
|
return deployingApi('clean', timestamp)
|
||||||
|
.then(() => {
|
||||||
|
|
||||||
|
message = `Finished. You have deploy the app to Salesforce DX!\n\n${message}`;
|
||||||
|
$('textarea#status').val(message);
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<main>
|
<main>
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1>Deploy</h1>
|
<h1>Deploy</h1>
|
||||||
<p>Hello, <%= user_name %>! You've indicated you'd like to deploy: <strong><%= template %></strong>. Is that correct?</p>
|
<p>Hello, <strong><%= user_name %></strong>! You've indicated you'd like to deploy: <strong><%= template %></strong>. Is that correct?</p>
|
||||||
<button type="button" class="btn btn-primary" id="yes">Yes</button>
|
<button type="button" class="btn btn-primary" id="yes">Yes</button>
|
||||||
<button type="button" class="btn btn-default" id="no">No</button>
|
<button type="button" class="btn btn-default" id="no">No</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<% include ../partials/head %>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="container">
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<% include ../partials/header %>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>Not DevHub</h1><small>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Sorry, but it looks like the org you've logged into is not a <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth.htm" target="_blank">dev hub</a>.
|
||||||
|
Consequently, you cannot currently use <strong>Deploy to Salesforce DX</strong> to create a stratch org from a Github repo.
|
||||||
|
</p>
|
||||||
|
<p>To try this out, you have two options:</p>
|
||||||
|
<div>
|
||||||
|
<ol class="list-group">
|
||||||
|
<li class="list-group-item">Enable dev hub in a Production or Business Org (i.e. not a DE org). Search on “Dev Hub” from Setup and then click Enabled.</li>
|
||||||
|
<li class="list-group-item">Get a <a href="https://sfdc.co/DX-Trial-Org">30-day free trial.</a></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<p>Please try again once you've gotten this resolved.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<% include ../partials/footer %>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Загрузка…
Ссылка в новой задаче