17ec1e8937
ref GRO-54 fixes GRO-63 fixes GRO-62 fixes GRO-69 When the config `hostSettings:managedEmail:enabled` is enabled, or the new flag (`newEmailAddresses`) is enabled for self-hosters, we'll start to check the from addresses of all outgoing emails more strictly. - Current flow: nothing changes if the managedEmail config is not set or the `newEmailAddresses` feature flag is not set - When managedEmail is enabled: never allow to send an email from any chosen email. We always use `mail.from` for all outgoing emails. Custom addresses should be set as replyTo instead. Changing the newsletter sender_email is not allowed anymore (and ignored if it is set). - When managedEmail is enabled with a custom sending domain: if a from address doesn't match the sending domain, we'll default to mail.from and use the original as a replyTo if appropriate and only when no other replyTo was set. A newsletter sender email addresss can only be set to an email address on this domain. - When `newEmailAddresses` is enabled: self hosters are free to set all email addresses to whatever they want, without verification. In addition to that, we stop making up our own email addresses and send from `mail.from` by default instead of generating a `noreply`+ `@` + `sitedomain.com` address A more in depth example of all cases can be seen in `ghost/core/test/integration/services/email-addresses.test.js` Includes lots of new E2E tests for most new situations. Apart from that, all email snapshots are changed because the from and replyTo addresses are now included in snapshots (so we can see unexpected changes in the future). Dropped test coverage requirement, because tests were failing coverage locally, but not in CI Fixed settings test that set the site title to an array - bug tracked in GRO-68
226 lines
8.1 KiB
JavaScript
226 lines
8.1 KiB
JavaScript
const path = require('path');
|
|
const util = require('util');
|
|
const exec = util.promisify(require('child_process').exec);
|
|
|
|
const chalk = require('chalk');
|
|
const concurrently = require('concurrently');
|
|
|
|
// check we're running on Node 18 and above
|
|
const nodeVersion = parseInt(process.versions.node.split('.')[0]);
|
|
if (nodeVersion < 18) {
|
|
console.error('`yarn dev` requires Node v18 or above. Please upgrade your version of Node.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const config = require('../../ghost/core/core/shared/config/loader').loadNconf({
|
|
customConfigPath: path.join(__dirname, '../../ghost/core')
|
|
});
|
|
|
|
const liveReloadBaseUrl = config.getSubdir() || '/ghost/';
|
|
const siteUrl = config.getSiteUrl();
|
|
|
|
const DASH_DASH_ARGS = process.argv.filter(a => a.startsWith('--')).map(a => a.slice(2));
|
|
|
|
let commands = [];
|
|
|
|
const COMMAND_GHOST = {
|
|
name: 'ghost',
|
|
// Note: if this isn't working for you, please use Node 18 and above
|
|
command: 'nx run ghost:dev',
|
|
cwd: path.resolve(__dirname, '../../ghost/core'),
|
|
prefixColor: 'blue',
|
|
env: {
|
|
// In development mode, we allow self-signed certificates (for sending webmentions and oembeds)
|
|
NODE_TLS_REJECT_UNAUTHORIZED: '0',
|
|
}
|
|
};
|
|
|
|
const COMMAND_ADMIN = {
|
|
name: 'admin',
|
|
command: `nx run ghost-admin:dev --live-reload-base-url=${liveReloadBaseUrl} --live-reload-port=4201`,
|
|
cwd: path.resolve(__dirname, '../../ghost/admin'),
|
|
prefixColor: 'green',
|
|
env: {}
|
|
};
|
|
|
|
const COMMAND_TYPESCRIPT = {
|
|
name: 'ts',
|
|
command: 'nx watch --projects=ghost/collections,ghost/in-memory-repository,ghost/bookshelf-repository,ghost/mail-events,ghost/model-to-domain-event-interceptor,ghost/post-revisions,ghost/nql-filter-expansions,ghost/post-events,ghost/donations,ghost/recommendations,ghost/email-addresses -- nx run \\$NX_PROJECT_NAME:build:ts',
|
|
cwd: path.resolve(__dirname, '../../'),
|
|
prefixColor: 'cyan',
|
|
env: {}
|
|
};
|
|
|
|
const adminXApps = '@tryghost/admin-x-demo,@tryghost/admin-x-settings';
|
|
|
|
const COMMANDS_ADMINX = [{
|
|
name: 'adminXDeps',
|
|
command: 'nx watch --projects=apps/admin-x-design-system,apps/admin-x-framework -- nx run \\$NX_PROJECT_NAME:build --skip-nx-cache',
|
|
cwd: path.resolve(__dirname, '../..'),
|
|
prefixColor: '#C35831',
|
|
env: {}
|
|
}, {
|
|
name: 'adminX',
|
|
command: `nx run-many --projects=${adminXApps} --targets=build && nx run-many --projects=${adminXApps} --parallel=${adminXApps.length} --targets=dev`,
|
|
cwd: path.resolve(__dirname, '../../apps/admin-x-settings'),
|
|
prefixColor: '#C35831',
|
|
env: {}
|
|
}];
|
|
|
|
if (DASH_DASH_ARGS.includes('ghost')) {
|
|
commands = [COMMAND_GHOST, COMMAND_TYPESCRIPT];
|
|
} else if (DASH_DASH_ARGS.includes('admin')) {
|
|
commands = [COMMAND_ADMIN, ...COMMANDS_ADMINX];
|
|
} else {
|
|
commands = [COMMAND_GHOST, COMMAND_TYPESCRIPT, COMMAND_ADMIN, ...COMMANDS_ADMINX];
|
|
}
|
|
|
|
if (DASH_DASH_ARGS.includes('portal') || DASH_DASH_ARGS.includes('all')) {
|
|
commands.push({
|
|
name: 'portal',
|
|
command: 'nx run @tryghost/portal:dev',
|
|
cwd: path.resolve(__dirname, '../../apps/portal'),
|
|
prefixColor: 'magenta',
|
|
env: {}
|
|
});
|
|
|
|
if (DASH_DASH_ARGS.includes('https')) {
|
|
// Safari needs HTTPS for it to work
|
|
// To make this work, you'll need a CADDY server running in front
|
|
// Note the port is different because of this extra layer. Use the following Caddyfile:
|
|
// https://localhost:4176 {
|
|
// reverse_proxy http://localhost:4175
|
|
// }
|
|
|
|
COMMAND_GHOST.env['portal__url'] = 'https://localhost:4176/portal.min.js';
|
|
} else {
|
|
COMMAND_GHOST.env['portal__url'] = 'http://localhost:4175/portal.min.js';
|
|
}
|
|
}
|
|
|
|
if (DASH_DASH_ARGS.includes('signup') || DASH_DASH_ARGS.includes('all')) {
|
|
commands.push({
|
|
name: 'signup-form',
|
|
command: DASH_DASH_ARGS.includes('signup') ? 'nx run @tryghost/signup-form:dev' : 'nx run @tryghost/signup-form:preview',
|
|
cwd: path.resolve(__dirname, '../../apps/signup-form'),
|
|
prefixColor: 'magenta',
|
|
env: {}
|
|
});
|
|
COMMAND_GHOST.env['signupForm__url'] = 'http://localhost:6174/signup-form.min.js';
|
|
}
|
|
|
|
if (DASH_DASH_ARGS.includes('announcement-bar') || DASH_DASH_ARGS.includes('announcementBar') || DASH_DASH_ARGS.includes('announcementbar') || DASH_DASH_ARGS.includes('all')) {
|
|
commands.push({
|
|
name: 'announcement-bar',
|
|
command: 'nx run @tryghost/announcement-bar:dev',
|
|
cwd: path.resolve(__dirname, '../../apps/announcement-bar'),
|
|
prefixColor: '#DC9D00',
|
|
env: {}
|
|
});
|
|
COMMAND_GHOST.env['announcementBar__url'] = 'http://localhost:4177/announcement-bar.min.js';
|
|
}
|
|
|
|
if (DASH_DASH_ARGS.includes('search') || DASH_DASH_ARGS.includes('all')) {
|
|
commands.push({
|
|
name: 'search',
|
|
command: 'nx run @tryghost/sodo-search:dev',
|
|
cwd: path.resolve(__dirname, '../../apps/sodo-search'),
|
|
prefixColor: '#23de43',
|
|
env: {}
|
|
});
|
|
COMMAND_GHOST.env['sodoSearch__url'] = 'http://localhost:4178/sodo-search.min.js';
|
|
COMMAND_GHOST.env['sodoSearch__styles'] = 'http://localhost:4178/main.css';
|
|
}
|
|
|
|
if (DASH_DASH_ARGS.includes('lexical')) {
|
|
if (DASH_DASH_ARGS.includes('https')) {
|
|
// Safari needs HTTPS for it to work
|
|
// To make this work, you'll need a CADDY server running in front
|
|
// Note the port is different because of this extra layer. Use the following Caddyfile:
|
|
// https://localhost:41730 {
|
|
// reverse_proxy http://127.0.0.1:4173
|
|
// }
|
|
|
|
COMMAND_ADMIN.env['EDITOR_URL'] = 'https://localhost:41730/';
|
|
} else {
|
|
COMMAND_ADMIN.env['EDITOR_URL'] = 'http://localhost:4173/';
|
|
}
|
|
}
|
|
|
|
if (DASH_DASH_ARGS.includes('comments') || DASH_DASH_ARGS.includes('all')) {
|
|
if (DASH_DASH_ARGS.includes('https')) {
|
|
// Safari needs HTTPS for it to work
|
|
// To make this work, you'll need a CADDY server running in front
|
|
// Note the port is different because of this extra layer. Use the following Caddyfile:
|
|
// https://localhost:7174 {
|
|
// reverse_proxy http://127.0.0.1:7173
|
|
// }
|
|
COMMAND_GHOST.env['comments__url'] = 'https://localhost:7174/comments-ui.min.js';
|
|
} else {
|
|
COMMAND_GHOST.env['comments__url'] = 'http://localhost:7173/comments-ui.min.js';
|
|
}
|
|
|
|
commands.push({
|
|
name: 'comments',
|
|
command: 'nx run @tryghost/comments-ui:dev',
|
|
cwd: path.resolve(__dirname, '../../apps/comments-ui'),
|
|
prefixColor: '#E55137',
|
|
env: {}
|
|
});
|
|
}
|
|
|
|
async function handleStripe() {
|
|
if (DASH_DASH_ARGS.includes('stripe') || DASH_DASH_ARGS.includes('all')) {
|
|
if (DASH_DASH_ARGS.includes('offline')) {
|
|
return;
|
|
}
|
|
|
|
let stripeSecret;
|
|
try {
|
|
stripeSecret = await exec('stripe listen --print-secret');
|
|
} catch (err) {
|
|
console.error('Failed to fetch Stripe secret token, do you need to connect Stripe CLI?', err);
|
|
return;
|
|
}
|
|
|
|
if (!stripeSecret || !stripeSecret.stdout) {
|
|
console.error('No Stripe secret was present');
|
|
return;
|
|
}
|
|
|
|
COMMAND_GHOST.env['WEBHOOK_SECRET'] = stripeSecret.stdout.trim();
|
|
commands.push({
|
|
name: 'stripe',
|
|
command: `stripe listen --forward-to ${siteUrl}members/webhooks/stripe/`,
|
|
prefixColor: 'yellow',
|
|
env: {}
|
|
});
|
|
}
|
|
}
|
|
|
|
(async () => {
|
|
await handleStripe();
|
|
|
|
if (!commands.length) {
|
|
console.log(`No commands provided`);
|
|
process.exit(0);
|
|
}
|
|
|
|
console.log(`Running projects: ${commands.map(c => chalk.green(c.name)).join(', ')}`);
|
|
|
|
const {result} = concurrently(commands, {
|
|
prefix: 'name',
|
|
killOthers: ['failure', 'success']
|
|
});
|
|
|
|
try {
|
|
await result;
|
|
} catch (err) {
|
|
console.error();
|
|
console.error(chalk.red(`Executing dev command failed:`) + `\n`);
|
|
console.error(chalk.red(`If you've recently done a \`yarn main\`, dependencies might be out of sync. Try running \`${chalk.green('yarn fix')}\` to fix this.`));
|
|
console.error(chalk.red(`If not, something else went wrong. Please report this to the Ghost team.`));
|
|
console.error();
|
|
}
|
|
})();
|