Skip to content

Commit

Permalink
Merge branch 'main' into theme-i18n
Browse files Browse the repository at this point in the history
  • Loading branch information
cathysarisky authored Oct 30, 2024
2 parents 2ed00b6 + 98c06f8 commit fcc6314
Show file tree
Hide file tree
Showing 27 changed files with 682 additions and 353 deletions.
92 changes: 0 additions & 92 deletions .devcontainer/createLocalConfig.js

This file was deleted.

23 changes: 19 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
{
"name": "Ghost Local DevContainer",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/nils-geistmann/devcontainers-features/zsh:0": {
"plugins": "git yarn gh"
}
},
"dockerComposeFile": ["./.docker/base.compose.yml", "./.docker/base-devcontainer.compose.yml"],
"service": "ghost",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"shutdownAction": "stopCompose",
"onCreateCommand": ["./.devcontainer/onCreateCommand.sh"],
"onCreateCommand": ["node", "./.devcontainer/onCreateCommand.js"],
"updateContentCommand": ["git", "submodule", "update", "--init", "--recursive"],
"postCreateCommand": ["yarn", "knex-migrator", "init"],
"remoteEnv": {
Expand All @@ -14,8 +20,13 @@
"STRIPE_ACCOUNT_ID": "${localEnv:STRIPE_ACCOUNT_ID}",
"MAILGUN_SMTP_USER": "${localEnv:MAILGUN_SMTP_USER}",
"MAILGUN_SMTP_PASS": "${localEnv:MAILGUN_SMTP_PASS}",
"MAILGUN_FROM_ADDRESS": "${localEnv:MAILGUN_FROM_ADDRESS}",
"MAILGUN_API_KEY": "${localEnv:MAILGUN_API_KEY}",
"MAILGUN_DOMAIN": "${localEnv:MAILGUN_DOMAIN}"
"MAILGUN_DOMAIN": "${localEnv:MAILGUN_DOMAIN}",
"GHOST_UPSTREAM": "${localEnv:GHOST_UPSTREAM}",
"GHOST_FORK_REMOTE_URL": "${localEnv:GHOST_FORK_REMOTE_URL}",
"GHOST_FORK_REMOTE_NAME": "${localEnv:GHOST_FORK_REMOTE_NAME}",
"GHOST_FORCE_SSH": "${localEnv:GHOST_FORCE_SSH}"
},
"forwardPorts": [2368,4200],
"portsAttributes": {
Expand Down Expand Up @@ -127,13 +138,17 @@
"description": "Your Mailgun account's SMTP password",
"documentationUrl": "https://app.mailgun.com/mg/sending/domains"
},
"MAILGUN_FROM_ADDRESS": {
"description": "The email address that will be used as the `from` address when sending emails via Mailgun",
"documentationUrl": "https://app.mailgun.com/mg/sending/domains"
},
"MAILGUN_API_KEY": {
"description": "Your Mailgun account's API key",
"documentationUrl": ""
"documentationUrl": "https://app.mailgun.com/mg/sending/domains"
},
"MAILGUN_DOMAIN": {
"description": "Your Mailgun account's domain, e.g. sandbox1234567890.mailgun.org",
"documentationUrl": ""
"documentationUrl": "https://app.mailgun.com/mg/sending/domains"
}
}
}
243 changes: 243 additions & 0 deletions .devcontainer/onCreateCommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
// This script is run in the Dev Container right after it is created
// No dependencies are installed at this point so we can't use any npm packages
const fs = require('fs');
const path = require('path');
const assert = require('node:assert/strict');
const { execSync } = require('child_process');

// Main function that runs all the setup steps
function main() {
setupGitRemotes();
setupLocalConfig();
runCleanHard();
runInstall();
runSubmoduleUpdate();
runTypescriptBuild();
}

// Basic color constants for console output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
dim: '\x1b[2m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
};

function log(message, color = colors.reset) {
console.log(`${color}${message}${colors.reset}`);
}

function logError(message, error) {
console.error(`${colors.red}${message}${colors.reset}`, error);
}

// Sets up the git remotes for the dev container based on environment variables
function setupGitRemotes() {
log('Configuring git remotes...', colors.blue);
try {
const GHOST_UPSTREAM = process.env.GHOST_UPSTREAM;
const GHOST_FORK_REMOTE_URL = process.env.GHOST_FORK_REMOTE_URL;
const GHOST_FORK_REMOTE_NAME = process.env.GHOST_FORK_REMOTE_NAME;
const GHOST_FORCE_SSH = process.env.GHOST_FORCE_SSH;
let remotes = execSync('git remote').toString().trim().split('\n');

if (GHOST_UPSTREAM) {
// Check if the upstream remote already exists
if (!remotes.includes(GHOST_UPSTREAM) && remotes.includes('origin')) {
log(`Renaming the default remote from origin to ${GHOST_UPSTREAM}...`, colors.blue);
execSync(`git remote rename origin ${GHOST_UPSTREAM}`);
}
}

remotes = execSync('git remote').toString().trim().split('\n');
if (GHOST_FORK_REMOTE_URL) {
const remoteName = GHOST_FORK_REMOTE_NAME || 'origin';
// Check if the fork remote already exists
if (!remotes.includes(remoteName)) {
log(`Adding fork remote ${GHOST_FORK_REMOTE_URL} as ${remoteName}...`, colors.blue);
execSync(`git remote add ${remoteName} ${GHOST_FORK_REMOTE_URL}`);
}
}

if (GHOST_FORCE_SSH) {
log('Forcing SSH for all remotes...', colors.blue);
// Get all remotes
remotes = execSync('git remote').toString().trim().split('\n');

for (const remote of remotes) {
// Get the current URL for this remote
const url = execSync(`git remote get-url ${remote}`).toString().trim();

// Only convert if it's an HTTPS URL
if (url.startsWith('https://')) {
// Convert HTTPS to SSH format
// https://github.com/user/repo.git -> git@github.com:user/repo.git
const sshUrl = url
.replace(/^https:\/\//, 'git@')
.replace(/\//, ':');

log(`Converting ${remote} from HTTPS to SSH...`, colors.dim);
execSync(`git remote set-url ${remote} ${sshUrl}`);
}
}
}

} catch (error) {
logError('Error setting up git remotes:', error);
}
}

// Creates config.local.json file with the correct values for the devcontainer
function setupLocalConfig() {
log('Setting up local config file...', colors.blue);
// Reads the config.local.json file and updates it with environments variables for devcontainer setup
const configBasePath = path.join(__dirname, '..', 'ghost', 'core');
const configFile = path.join(configBasePath, 'config.local.json');
let originalConfig = {};
if (fs.existsSync(configFile)) {
try {
// Backup the user's config.local.json file just in case
// This won't be used by Ghost but can be useful to switch back to local development
const backupFile = path.join(configBasePath, 'config.local-backup.json');
fs.copyFileSync(configFile, backupFile);

// Read the current config.local.json file into memory
const fileContent = fs.readFileSync(configFile, 'utf8');
originalConfig = JSON.parse(fileContent);
} catch (error) {
logError('Error reading or parsing config file:', error);
process.exit(1);
}
} else {
log('Config file does not exist. Creating a new one.', colors.dim);
}

let newConfig = {};
// Change the url if we're in a codespace
if (process.env.CODESPACES === 'true') {
assert.ok(process.env.CODESPACE_NAME, 'CODESPACE_NAME is not defined');
assert.ok(process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN, 'GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN is not defined');
const url = `https://${process.env.CODESPACE_NAME}-2368.${process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}`;
newConfig.url = url;
}

newConfig.database = {
client: 'mysql2',
connection: {
host: 'mysql',
user: 'root',
password: 'root',
database: 'ghost'
}
}
newConfig.adapters = {
Redis: {
host: 'redis',
port: 6379
}
}

// Only update the mail settings if they aren't already set
if (!originalConfig.mail && process.env.MAILGUN_SMTP_PASS && process.env.MAILGUN_SMTP_USER && process.env.MAILGUN_FROM_ADDRESS) {
newConfig.mail = {
transport: 'SMTP',
from: process.env.MAILGUN_FROM_ADDRESS,
options: {
service: 'Mailgun',
host: 'smtp.mailgun.org',
secure: true,
port: 465,
auth: {
user: process.env.MAILGUN_SMTP_USER,
pass: process.env.MAILGUN_SMTP_PASS
}
}
}
}

// Only update the bulk email settings if they aren't already set
if (!originalConfig.bulkEmail && process.env.MAILGUN_API_KEY && process.env.MAILGUN_DOMAIN) {
newConfig.bulkEmail = {
mailgun: {
baseUrl: 'https://api.mailgun.net/v3',
apiKey: process.env.MAILGUN_API_KEY,
domain: process.env.MAILGUN_DOMAIN,
tag: 'bulk-email'
}
}
}

// Merge the original config with the new config
const config = {...originalConfig, ...newConfig};

// Write the updated config.local.json file
try {
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
log('Config file updated successfully.', colors.dim);
} catch (error) {
logError('Error writing config file:', error);
process.exit(1);
}
}

// Deletes node_modules and clears yarn & nx caches
function runCleanHard() {
try {
log('Cleaning up node_modules and yarn/nx caches...', colors.blue);
execSync('yarn clean:hard', { stdio: 'inherit' });
log('Successfully ran yarn clean:hard', colors.dim);
} catch (error) {
logError('Error running yarn clean:hard:', error);
process.exit(1);
}
}

// Installs dependencies
function runInstall() {
try {
log('Installing dependencies...', colors.blue);
execSync('yarn install --frozen-lockfile', { stdio: 'inherit' });
log('Successfully ran yarn install', colors.dim);
} catch (error) {
logError('Error running yarn install:', error);
process.exit(1);
}
}

// Initializes and updates git submodules
function runSubmoduleUpdate() {
try {
log('Updating git submodules...', colors.blue);
execSync('git submodule update --init --recursive', { stdio: 'inherit' });
// Rename the default remote to $GHOST_UPSTREAM if it's set
// Otherwise `yarn main:submodules` will fail
const GHOST_UPSTREAM = process.env.GHOST_UPSTREAM;
if (GHOST_UPSTREAM) {
execSync(`git submodule foreach "git remote | grep -q '^${GHOST_UPSTREAM}$' || (git remote | grep -q '^origin$' && git remote rename origin ${GHOST_UPSTREAM})"`);
}

log('Successfully ran git submodule update', colors.dim);
} catch (error) {
logError('Error running git submodule update:', error);
process.exit(1);
}
}

// Builds the typescript packages
function runTypescriptBuild() {
try {
log('Building typescript packages...', colors.blue);
execSync('yarn nx run-many -t build:ts', { stdio: 'inherit' });
log('Successfully ran yarn nx run-many -t build:ts', colors.dim);
} catch (error) {
logError('Error running yarn nx run-many -t build:ts:', error);
process.exit(1);
}
}

main();
Loading

0 comments on commit fcc6314

Please sign in to comment.