Skip to content

Commit

Permalink
Refactored source theme changes to remove dependency on instance version
Browse files Browse the repository at this point in the history
  • Loading branch information
cmraible committed Oct 2, 2023
1 parent eb3bfdb commit 7dbf62c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 59 deletions.
34 changes: 14 additions & 20 deletions lib/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ class InstallCommand extends Command {
title: 'Linking latest Ghost and recording versions',
task: this.link.bind(this)
}, {
title: 'Linking latest default theme',
task: this.defaultTheme
title: 'Installing default themes',
task: this.defaultThemes
}], false)
}], {
argv: {...argv, version},
Expand Down Expand Up @@ -129,24 +129,18 @@ class InstallCommand extends Command {
ctx.installPath = path.join(process.cwd(), 'versions', resolvedVersion); // eslint-disable-line require-atomic-updates
}

defaultTheme(ctx) {
const semver = require('semver');
const version = ctx.version;

// Starting with version 5.67.0, we are shipping an updated version of Casper with breaking changes under a new name
// If installing a version < 5.67.0, we need to symlink Casper
// We don't want the theme to outpace Ghost (e.g. try to use features that don't exist in Ghost yet)
if (semver.gte(version, '5.67.0')) {
// Create a symlink to the theme from the current version
return symlinkSync(
path.join(process.cwd(), 'current', 'content', 'themes', 'source'),
path.join(process.cwd(), 'content', 'themes', 'source')
);
} else {
return symlinkSync(
path.join(process.cwd(), 'current', 'content', 'themes', 'casper'),
path.join(process.cwd(), 'content', 'themes', 'casper')
);
defaultThemes() {
if (fs.existsSync(path.join(process.cwd(), 'current', 'content', 'themes'))) {
const symlinkSync = require('symlink-or-copy').sync;
const defaultThemes = fs.readdirSync(path.join(process.cwd(), 'current', 'content', 'themes'));
for (const theme of defaultThemes) {
if (!fs.existsSync(path.join(process.cwd(), 'content', 'themes', theme))) {
symlinkSync(
path.join(process.cwd(), 'current', 'content', 'themes', theme),
path.join(process.cwd(), 'content', 'themes', theme)
);
}
}
}
}

Expand Down
42 changes: 33 additions & 9 deletions lib/commands/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class UpdateCommand extends Command {
}, {
title: 'Linking latest Ghost and recording versions',
task: this.link
}, {
title: 'Installing default themes',
task: this.linkDefaultThemes
}, {
title: 'Running database migrations',
skip: ({rollback}) => rollback,
Expand Down Expand Up @@ -219,23 +222,44 @@ class UpdateCommand extends Command {

link({instance, installPath, version, rollback}) {
const symlinkSync = require('symlink-or-copy').sync;
const semver = require('semver');

fs.removeSync(path.join(process.cwd(), 'current'));
symlinkSync(installPath, path.join(process.cwd(), 'current'));

// If upgrading from a version < 5.67.0, we need to symlink source so it is installed and available to update
if (semver.lt(instance.version, '5.67.0') && semver.gte(version, '5.67.0')) {
symlinkSync(
path.join(process.cwd(), 'current', 'content', 'themes', 'source'),
path.join(process.cwd(), 'content', 'themes', 'source')
);
}

instance.previousVersion = rollback ? null : instance.version;
instance.version = version;
instance.nodeVersion = process.versions.node;
}

linkDefaultThemes({rollback}) {
const currentThemesDir = path.join(process.cwd(), 'current', 'content', 'themes');
const contentThemesDir = path.join(process.cwd(), 'content', 'themes');
// remove any broken symlinks caused by default themes no longer existing in previous version
if (rollback) {
if (fs.existsSync(currentThemesDir)) {
const installedThemes = fs.readdirSync(contentThemesDir);
for (const theme of installedThemes) {
if (!fs.existsSync(path.join(contentThemesDir, theme))) {
fs.rmSync(path.join(contentThemesDir, theme));
}
}
}
}

// ensure all default themes (e.g. themes shipped with Ghost) are symlinked to /content/themes directory
if (fs.existsSync(path.join(process.cwd(), 'current', 'content', 'themes'))) {
const symlinkSync = require('symlink-or-copy').sync;
const defaultThemes = fs.readdirSync(path.join(process.cwd(), 'current', 'content', 'themes'));
for (const theme of defaultThemes) {
if (!fs.existsSync(path.join(process.cwd(), 'content', 'themes', theme))) {
symlinkSync(
path.join(process.cwd(), 'current', 'content', 'themes', theme),
path.join(process.cwd(), 'content', 'themes', theme)
);
}
}
}
}
}

UpdateCommand.description = 'Update a Ghost instance';
Expand Down
41 changes: 17 additions & 24 deletions test/unit/commands/install-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ describe('Unit: Commands > Install', function () {
const runCommandStub = sinon.stub(testInstance, 'runCommand').resolves();
const versionStub = sinon.stub(testInstance, 'version').resolves();
const linkStub = sinon.stub(testInstance, 'link').resolves();
const defaultThemeStub = sinon.stub(testInstance, 'defaultTheme').resolves();
const defaultThemesStub = sinon.stub(testInstance, 'defaultThemes').resolves();

return testInstance.run({version: '1.0.0', setup: false, 'check-empty': true}).then(() => {
expect(dirEmptyStub.calledOnce).to.be.true;
Expand All @@ -216,7 +216,7 @@ describe('Unit: Commands > Install', function () {
expect(ensureStructureStub.calledOnce).to.be.true;
expect(versionStub.calledOnce).to.be.true;
expect(linkStub.calledOnce).to.be.true;
expect(defaultThemeStub.calledOnce).to.be.true;
expect(defaultThemesStub.calledOnce).to.be.true;
expect(runCommandStub.calledOnce).to.be.true;
});
});
Expand Down Expand Up @@ -412,38 +412,31 @@ describe('Unit: Commands > Install', function () {
});
});

describe('tasks > defaultTheme', function () {
it('links source version correctly if version >= 5.67.0', function () {
describe('tasks > defaultThemes', function () {
it('creates a symlink to all themes shipped with Ghost', function () {
const symlinkSyncStub = sinon.stub();
const readdirSyncStub = sinon.stub().returns(['casper', 'source']);
const existsSyncStub = sinon.stub();
existsSyncStub.onCall(0).returns(true);
existsSyncStub.onCall(1).returns(false);
existsSyncStub.onCall(2).returns(false);
const InstallCommand = proxyquire(modulePath, {
'symlink-or-copy': {sync: symlinkSyncStub}
'symlink-or-copy': {sync: symlinkSyncStub},
'fs-extra': {readdirSync: readdirSyncStub, existsSync: existsSyncStub}
});

const testInstance = new InstallCommand({}, {});

const context = {version: '5.67.0'};
testInstance.defaultTheme(context);
expect(symlinkSyncStub.calledOnce).to.be.true;
testInstance.defaultThemes(context);
expect(symlinkSyncStub.callCount).to.equal(2);
expect(symlinkSyncStub.calledWithExactly(
path.join(process.cwd(), 'current/content/themes/source'),
path.join(process.cwd(), 'content/themes/source')
path.join(process.cwd(), 'current', 'content', 'themes', 'casper'),
path.join(process.cwd(), 'content', 'themes', 'casper')
));
});

it('links casper version correctly if version < 5.67.0', function () {
const symlinkSyncStub = sinon.stub();
const InstallCommand = proxyquire(modulePath, {
'symlink-or-copy': {sync: symlinkSyncStub}
});

const testInstance = new InstallCommand({}, {});

const context = {version: '5.62.0'};
testInstance.defaultTheme(context);
expect(symlinkSyncStub.calledOnce).to.be.true;
expect(symlinkSyncStub.calledWithExactly(
path.join(process.cwd(), 'current/content/themes/casper'),
path.join(process.cwd(), 'content/themes/casper')
path.join(process.cwd(), 'current', 'content', 'themes', 'source'),
path.join(process.cwd(), 'content', 'themes', 'source')
));
});
});
Expand Down
39 changes: 33 additions & 6 deletions test/unit/commands/update-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1068,11 +1068,15 @@ describe('Unit: Commands > Update', function () {
expect(instance.previousVersion).to.be.null;
expect(instance.nodeVersion).to.equal(process.versions.node);
});
});

describe('linkDefaultThemes', function () {
const UpdateCommand = require(modulePath);

it('installs source theme when upgrading from < 5.67.0 to >= 5.67.0', function () {
it('links all default themes bundled with Ghost', function () {
const command = new UpdateCommand({}, {});
const envCfg = {
dirs: ['versions/5.62.0', 'versions/5.67.0', 'versions/5.67.0/content/themes/source', 'content/themes'],
dirs: ['versions/5.62.0', 'versions/5.67.0', 'versions/5.67.0/content/themes/source', 'versions/5.67.0/content/themes/casper', 'content/themes'],
links: [['versions/5.62.0', 'current']]
};
const env = setupTestFolder(envCfg);
Expand All @@ -1088,10 +1092,33 @@ describe('Unit: Commands > Update', function () {
};

command.link(context);
expect(fs.readlinkSync(path.join(env.dir, 'current'))).to.equal(path.join(env.dir, 'versions/5.67.0'));
expect(instance.version).to.equal('5.67.0');
expect(instance.previousVersion).to.equal('5.62.0');
expect(instance.nodeVersion).to.equal(process.versions.node);
command.linkDefaultThemes(context);
expect(fs.readlinkSync(path.join(env.dir, 'content', 'themes', 'source'))).to.equal(path.join(env.dir, 'current', 'content', 'themes', 'source'));
expect(fs.readlinkSync(path.join(env.dir, 'content', 'themes', 'casper'))).to.equal(path.join(env.dir, 'current', 'content', 'themes', 'casper'));
});

it('removes invalid symlinks when rolling back', function () {
const command = new UpdateCommand({}, {});
const envCfg = {
dirs: ['versions/5.62.0', 'versions/5.67.0', 'versions/5.62.0/content/themes/casper', 'versions/5.67.0/content/themes/source', 'versions/5.67.0/content/themes/casper', 'content/themes'],
links: [['versions/5.67.0', 'current']]
};
const env = setupTestFolder(envCfg);
sinon.stub(process, 'cwd').returns(env.dir);
const instance = {
version: '5.67.0'
};
const context = {
installPath: path.join(env.dir, 'versions/5.62.0'),
version: '5.62.0',
rollback: true,
instance
};

command.link(context);
command.linkDefaultThemes(context);
expect(fs.existsSync(path.join(env.dir, 'content', 'themes', 'source'))).to.equal(false);
expect(fs.readlinkSync(path.join(env.dir, 'content', 'themes', 'casper'))).to.equal(path.join(env.dir, 'current', 'content', 'themes', 'casper'));
});
});
});

0 comments on commit 7dbf62c

Please sign in to comment.