Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance(publish): track templateVersion on initialization #3036

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/common-all/data/dendron-yml.validator.json
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,9 @@
},
"apiEndpoint": {
"type": "string"
},
"templateHierarchy": {
"type": "string"
}
},
"required": [
Expand Down Expand Up @@ -1173,6 +1176,9 @@
},
"enablePrettyLinks": {
"type": "boolean"
},
"publishTemplateVersion": {
"type": "number"
}
},
"required": [
Expand Down
4 changes: 4 additions & 0 deletions packages/common-all/src/constants/configs/publishing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,8 @@ export const PUBLISHING: DendronConfigEntryCollection<DendronPublishingConfig> =
label: "Enable special formatting for task notes.",
desc: "Task notes will have checkboxes, owner information and more displayed on links leading to them. This applies both in preview and publishing.",
},
templateVersion: {
label: "Version of publishing template",
desc: "What version of the publishing template to use",
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type DendronPublishingConfig = {
cognitoUserPoolId?: string;
cognitoClientId?: string;
enablePrettyLinks: boolean;
templateVersion?: string;
};

export type CleanDendronPublishingConfig = DendronPublishingConfig &
Expand Down
73 changes: 46 additions & 27 deletions packages/dendron-cli/src/commands/publishCLICommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,30 @@ import {
DendronError,
DendronSiteConfig,
error2PlainObject,
ErrorFactory,
getStage,
Stage,
} from "@dendronhq/common-all";
import { SiteUtils } from "@dendronhq/engine-server";
import { GitUtils } from "@dendronhq/common-server";
import { DConfig, SiteUtils, VersionProvider } from "@dendronhq/engine-server";
import {
BuildOverrides,
NextjsExportConfig,
NextjsExportPod,
NextjsExportPodUtils,
BuildOverrides,
PublishTarget,
} from "@dendronhq/pods-core";
import fs from "fs-extra";
import _ from "lodash";
import ora from "ora";
import path from "path";
import prompts from "prompts";
import yargs from "yargs";
import { CLIUtils, SpinnerUtils } from "../utils/cli";
import { CLICommand } from "./base";
import { ExportPodCLICommand } from "./exportPod";
import { PodSource } from "./pod";
import { SetupEngineCLIOpts } from "./utils";
import prompts from "prompts";
import fs from "fs-extra";
import ora from "ora";
import { GitUtils } from "@dendronhq/common-server";

type CommandCLIOpts = {
cmd: PublishCommands;
Expand Down Expand Up @@ -325,27 +326,20 @@ export class PublishCLICommand extends CLICommand<CommandOpts, CommandOutput> {
});

if (nextPathExists) {
try {
await this._updateNextTemplate({
nextPath,
spinner,
});
} catch (err) {
SpinnerUtils.renderAndContinue({
spinner,
text: `failed to update next NextJS template working copy (${err}); cloning fresh`,
});
await this._removeNextPath({
nextPath,
spinner,
});
await this._initialize({ nextPath, spinner });
}
} else {
await this._initialize({ nextPath, spinner });
this.print("Nextjs template already exists. Skipping initialization");
return {
error: ErrorFactory.createInvalidStateError({
message: "template exists",
}),
};
}

return { error: null };
const { templateVersion } = await this._initialize({
nextPath,
spinner,
wsRoot,
});
return { data: { templateVersion } };
}

async _isInitialized(opts: { wsRoot: string; spinner: ora.Ora }) {
Expand Down Expand Up @@ -414,14 +408,39 @@ export class PublishCLICommand extends CLICommand<CommandOpts, CommandOutput> {
});
}

async _initialize(opts: { nextPath: string; spinner: ora.Ora }) {
const { spinner } = opts;
/**
* Clone template
* If templateVersion is set in dendron.yml, clone at version
* Otherwise, get same version as engine
* @param opts
* @return: string, version of template
*/
async _initialize(opts: {
jonathanyeung marked this conversation as resolved.
Show resolved Hide resolved
nextPath: string;
spinner: ora.Ora;
wsRoot: string;
}) {
const { spinner, wsRoot } = opts;
SpinnerUtils.renderAndContinue({
spinner,
text: "Initializing NextJS template.",
});
const config = DConfig.readConfigAndApplyLocalOverrideSync(opts.wsRoot);
await this._cloneTemplate(opts);
const templateVersion =
NextjsExportPodUtils.templateVersion(config) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if config version exceeds engine Version? Shouldn't we do Math.min(configVersion?, engineVersion) ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to do a min in this case because configVersion is source of truth. if the engineVersion is lower, we need to ask the user to update the engine because they've published using a higher version. i've done a writeup of this here, will also share as an async > https://docs.google.com/document/d/1dZ3X039TqQyUMaRYx9KJSFVpJMEHgtjRbqdAdFDGWX8/edit

VersionProvider.engineVersion();
await NextjsExportPodUtils.switchToBranch({
version: templateVersion,
nextPath: opts.nextPath,
});
await this._installDependencies(opts);

if (!NextjsExportPodUtils.templateVersion(config)) {
ConfigUtils.setPublishProp(config, "templateVersion", templateVersion);
await DConfig.writeConfig({ wsRoot, config });
}
return { templateVersion, error: null };
}

async _cloneTemplate(opts: { nextPath: string; spinner: ora.Ora }) {
Expand Down
6 changes: 6 additions & 0 deletions packages/dendron-next-server/data/dendron-yml.validator.json
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,9 @@
},
"apiEndpoint": {
"type": "string"
},
"templateHierarchy": {
"type": "string"
}
},
"required": [
Expand Down Expand Up @@ -1173,6 +1176,9 @@
},
"enablePrettyLinks": {
"type": "boolean"
},
"publishTemplateVersion": {
"type": "number"
}
},
"required": [
Expand Down
1 change: 1 addition & 0 deletions packages/engine-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export * from "./doctor";
export * from "./backup";
export * from "./backfillV2";
export * from "./cache";
export * from "./services";
1 change: 1 addition & 0 deletions packages/engine-server/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./version-provider";
7 changes: 7 additions & 0 deletions packages/engine-server/src/services/version-provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NodeJSUtils } from "@dendronhq/common-server";

export class VersionProvider {
static engineVersion(): string {
return NodeJSUtils.getVersionFromPkg();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ConfigUtils,
IntermediateDendronConfig,
RespV3,
URI,
} from "@dendronhq/common-all";
import {
Expand All @@ -9,6 +10,7 @@ import {
PublishCLICommandOpts,
PublishCommands,
} from "@dendronhq/dendron-cli";
import { DConfig, VersionProvider } from "@dendronhq/engine-server";
import { NextjsExportPodUtils, PublishTarget } from "@dendronhq/pods-core";
import fs from "fs-extra";
import _ from "lodash";
Expand Down Expand Up @@ -47,18 +49,109 @@ describe("WHEN run `dendron publish init`", () => {
afterEach(() => {
sinon.restore();
});
test("THEN succeed", async () => {
await runEngineTestV5(
async ({ wsRoot }) => {
const cli = new PublishCLICommand();
const initStub = stub(cli, "init").resolves({ error: null });
await runPublishCmd({ cli, cmd, wsRoot });
expect(initStub.calledOnce).toBeTruthy();
},
{
expect,
}
);

const getData = (resp: RespV3<any>) => {
if (!_.isUndefined(resp.error)) {
throw Error("error is not undefined");
}
return resp.data;
};

describe("AND WHEN no templateVersion set", () => {
test("THEN clone with latest version", async () => {
await runEngineTestV5(
async ({ wsRoot }) => {
const cli = new PublishCLICommand();
const latestVersion = VersionProvider.engineVersion();
const stubClone = stub(cli, "_cloneTemplate").resolves();
const stubSwitch = stub(
NextjsExportPodUtils,
"switchToBranch"
).resolves();
const stubInstall = stub(cli, "_installDependencies").resolves();
const resp = await runPublishCmd({ cli, cmd, wsRoot });

// cloned
expect(stubClone.calledOn).toBeTruthy();
// switch to latest branch
expect(
stubSwitch.calledWith({
version: latestVersion,
nextPath: path.join(wsRoot, ".next"),
})
).toBeTruthy();
// install dependencies
expect(stubInstall.calledOn).toBeTruthy();
// templateVersion set to latest
expect(getData(resp).templateVersion).toEqual(latestVersion);
// templateVersion written to config
const newConfig = DConfig.getOrCreate(wsRoot);
expect(NextjsExportPodUtils.templateVersion(newConfig)).toEqual(
latestVersion
);
},
{
expect,
}
);
});
});

describe("AND WHEN templateVersion set", () => {
const templateVersion = "0.95.0";
test("THEN clone with templateVersion", async () => {
await runEngineTestV5(
async ({ wsRoot }) => {
const cli = new PublishCLICommand();
const latestVersion = templateVersion;
const stubClone = stub(cli, "_cloneTemplate").resolves();
const stubSwitch = stub(
NextjsExportPodUtils,
"switchToBranch"
).resolves();
const stubInstall = stub(cli, "_installDependencies").resolves();
const resp = await runPublishCmd({ cli, cmd, wsRoot });

expect(stubClone.calledOn).toBeTruthy();
expect(
stubSwitch.calledWith({
version: latestVersion,
nextPath: path.join(wsRoot, ".next"),
})
).toBeTruthy();
expect(stubInstall.calledOn).toBeTruthy();
expect(getData(resp).templateVersion).toEqual(latestVersion);
// template version unchanged
const newConfig = DConfig.getOrCreate(wsRoot);
expect(NextjsExportPodUtils.templateVersion(newConfig)).toEqual(
templateVersion
);
},
{
expect,
modConfigCb: (config: IntermediateDendronConfig) => {
config.publishing!.templateVersion = templateVersion;
return config;
},
}
);
});
});

describe("AND WHEN template exists", () => {
test("THEN do not clone", async () => {
await runEngineTestV5(
async ({ wsRoot }) => {
const cli = new PublishCLICommand();
stub(cli, "_nextPathExists").resolves(true);
const resp = await runPublishCmd({ cli, cmd, wsRoot });
expect(resp.error.message).toEqual("template exists");
},
{
expect,
}
);
});
});
});

Expand Down Expand Up @@ -202,7 +295,9 @@ describe("WHEN run `dendron publish dev`", () => {
await runEngineTestV5(
async ({ wsRoot }) => {
const cli = new PublishCLICommand();
const initStub = stub(cli, "init").resolves({ error: null });
const initStub = stub(cli, "init").resolves({
data: { templateVersion: "" },
});
const buildStub = stub(cli, "build").resolves({ error: null });
const devStub = stub(cli, "dev").resolves({ error: null });
await runPublishCmd({ cli, cmd, wsRoot });
Expand Down Expand Up @@ -235,7 +330,9 @@ describe("WHEN run `dendron publish export`", () => {
fs.ensureFileSync(
path.join(wsRoot, ".next", "out", "canary-success")
);
const initStub = stub(cli, "init").resolves({ error: null });
const initStub = stub(cli, "init").resolves({
data: { templateVersion: "" },
});
const buildStub = stub(cli, "build").resolves({ error: null });
const exportStub = stub(cli, "export").resolves({} as any);
prompts.inject([true]);
Expand Down Expand Up @@ -278,7 +375,9 @@ describe("WHEN run `dendron publish export`", () => {
fs.ensureFileSync(
path.join(wsRoot, ".next", "out", "canary-success")
);
const initStub = stub(cli, "init").resolves({ error: null });
const initStub = stub(cli, "init").resolves({
data: { templateVersion: "" },
});
const buildStub = stub(cli, "build").resolves({ error: null });
const exportStub = stub(cli, "export").resolves({} as any);
prompts.inject([false]);
Expand Down
Loading