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

[2/] Improvement: Introduce new command structure #16

Merged
merged 26 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 22 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
2 changes: 2 additions & 0 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import auth from "./commands/auth/index.js";
import site from "./commands/site/index.js";
import typescript from "./commands/typescript/index.js";
import { ExitProcessError } from "./ExitProcessError.js";
import { logConfigFileMiddleware } from "./yargs/logConfigFileMiddleware.js";
import { logVersionMiddleware } from "./yargs/logVersionMiddleware.js";

export async function cli(args: string[] = process.argv) {
Expand All @@ -39,6 +40,7 @@ export async function cli(args: string[] = process.argv) {
)
.demandCommand()
.middleware(logVersionMiddleware, true)
.middleware(logConfigFileMiddleware)
.strict()
.command({
command: "unstable",
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/commands/site/CommonSiteArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import type { CliCommonArgs } from "../../CliCommonArgs.js";
import type { ThirdPartyAppRid } from "../../net/ThirdPartyAppRid.js";

export interface CommonSiteArgs extends CliCommonArgs {
appRid: ThirdPartyAppRid;
baseUrl: string;
application: ThirdPartyAppRid;
foundryUrl: string;
token?: string;
tokenFile?: string;
}
7 changes: 5 additions & 2 deletions packages/cli/src/commands/site/deploy/SiteDeployArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import type { CommonSiteArgs } from "../CommonSiteArgs.js";

export interface SiteDeployArgs extends CommonSiteArgs {
siteVersion?: string;
clearVersion?: boolean;
version?: string;
directory: string;
uploadOnly: boolean;
autoVersion?: string;
gitTagPrefix?: string;
}
120 changes: 94 additions & 26 deletions packages/cli/src/commands/site/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
* limitations under the License.
*/

import { consola } from "consola";
import type { CommandModule } from "yargs";
import type { LoadedFoundryConfig, SiteConfig } from "../../../util/config.js";
import configLoader from "../../../util/configLoader.js";
import type { CommonSiteArgs } from "../CommonSiteArgs.js";
import type { SiteDeployArgs } from "./SiteDeployArgs.js";

Expand All @@ -24,42 +27,107 @@ export const command: CommandModule<
> = {
command: "deploy",
describe: "Deploy an uploaded version",
builder: (argv) => {
builder: async (argv) => {
const config: LoadedFoundryConfig | undefined = await configLoader();
const siteConfig: SiteConfig | undefined = config?.foundryConfig.site;
const directory = siteConfig?.directory;
const autoVersion = siteConfig?.autoVersion;
const gitTagPrefix = autoVersion?.tagPrefix;

return argv
.options({
"siteVersion": {
directory: {
type: "string",
conflicts: "clearVersion",
// group: "Deploy Version",
// implies: { "clearVersion": "false" },
description: "Directory to deploy",
...directory
? { default: directory }
: { demandOption: true },
},
undeploy: {
alias: "clearVersion",
description: "Causes the site to no longer be deployed",
uploadOnly: {
type: "boolean",
conflicts: "siteVersion",
// group: "Deploy Version",
// implies: { "siteVersion": "" },
description: "Upload the directory but do not deploy it",
default: false,
},
version: {
type: "string",
description: "Version to deploy",
...autoVersion == null
? { conflicts: "autoVersion" }
: {},
},
autoVersion: {
type: "string",
description:
"Enables autoversioning. Can be set to 'git-describe' to use git describe to determine the version.",
...(autoVersion != null)
? { default: autoVersion.type }
: { conflicts: "version" },
},
gitTagPrefix: {
type: "string",
description:
"Prefix to match git tags against when --autoVersion=git-describe is used. If not provided, a default prefix 'v' is used.",
...gitTagPrefix
? { default: gitTagPrefix }
: {},
},
}).group(
["siteVersion", "clearVersion"],
"Version To Deploy (requires one of)",
);
["autoVersion", "gitTagPrefix"],
"Autoversion Arguments",
)
.group(
["version", "directory", "uploadOnly"],
"Common Arguments",
)
.check((argv) => {
// This is required because we can't use demandOption with conflicts. conflicts protects us against the case where both are provided.
// So this case is for when nothing is provided.
if (
autoVersion == null && argv.autoVersion == null
&& argv.version == null
) {
throw new Error(
"One of --version or --autoVersion must be specified",
);
}

if (
(autoVersion?.type != "git-describe"
|| argv.autoVersion != "git-describe")
zeyadkhaled marked this conversation as resolved.
Show resolved Hide resolved
&& argv.gitTagPrefix != null
) {
throw new Error(
`--gitTagPrefix is only supported when --autoVersion=git-describe`,
);
}

if (autoVersion != null && argv.autoVersion !== autoVersion.type) {
consola.debug(
`Overriding "autoVersion" from config file with ${argv.autoVersion}`,
);
if (argv.autoVersion != "git-describe") {
zeyadkhaled marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(
zeyadkhaled marked this conversation as resolved.
Show resolved Hide resolved
`Only 'git-describe' is supported for autoVersion`,
);
}
}

if (directory != null && argv.directory !== directory) {
consola.debug(
`Overriding "directory" from config file with ${argv.directory}`,
);
}

// .check((args) => {
// if (
// (args.siteVersion && args.clearVersion)
// || (!args.siteVersion && args.clearVersion == undefined)
// ) {
// // consola.error("Only one of --siteVersion or --clearVersion may be provided");
// throw new Error(
// "Only one of --siteVersion or --clearVersion may be provided",
// );
// }
// });
if (gitTagPrefix != null && argv.gitTagPrefix !== gitTagPrefix) {
consola.debug(
`Overriding "gitTagPrefix" from config file with ${argv.gitTagPrefix}`,
);
}
return true;
});
},
handler: async (args) => {
const command = await import("./handleSiteDeploy.mjs");
const command = await import("./siteDeployCommand.mjs");
await command.default(args);
},
};
Expand Down
94 changes: 94 additions & 0 deletions packages/cli/src/commands/site/deploy/siteDeployCommand.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2023 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { consola } from "consola";

import {
artifacts,
ArtifactsSitesAdminV2Service,
createConjureContext,
thirdPartyApplicationService,
} from "#net";
import archiver from "archiver";
import * as fs from "node:fs";
import { Readable } from "node:stream";
import { ExitProcessError } from "../../../ExitProcessError.js";
import { autoVersion as findAutoVersion } from "../../../util/autoVersion.js";
import type { SiteDeployArgs } from "./SiteDeployArgs.js";

export default async function siteDeployCommand(
{
version,
application,
foundryUrl,
autoVersion,
gitTagPrefix,
uploadOnly,
directory,
}: SiteDeployArgs,
) {
if (!version && !autoVersion) {
throw new ExitProcessError(
2,
"Either version or autoVersion must be specified",
);
}

const siteVersion = !version ? await findAutoVersion(gitTagPrefix) : version;
if (autoVersion) {
consola.info(
`Auto version inferred next version to be: ${siteVersion}`,
);
}

const stat = await fs.promises.stat(directory);
if (!stat.isDirectory()) {
consola.error("Specified path is not a directory");
throw new ExitProcessError(2);
}

consola.start("Zippping site files");

const archive = archiver("zip").directory(directory, false);

await Promise.all([
artifacts.SiteAssetArtifactsService.uploadZippedSiteAsset(
foundryUrl,
application,
siteVersion,
Readable.toWeb(archive) as ReadableStream<any>, // This cast is because the dom fetch doesnt align type wise with streams
),
archive.finalize(),
]);

consola.success("Upload complete");

if (!uploadOnly) {
const repositoryRid = await thirdPartyApplicationService
.fetchWebsiteRepositoryRid(foundryUrl, application);

const ctx = createConjureContext(foundryUrl, "/artifacts/api");
await ArtifactsSitesAdminV2Service.updateDeployedVersion(
ctx,
repositoryRid,
{ siteVersion: { version: siteVersion } },
);

consola.success(`Deployed ${siteVersion} successfully`);
} else {
consola.debug("Upload only mode enabled, skipping deployment");
}
}
81 changes: 62 additions & 19 deletions packages/cli/src/commands/site/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,83 @@
* limitations under the License.
*/

import type * as yargs from "yargs";
import { consola } from "consola";
import type { CommandModule } from "yargs";
import type { CliCommonArgs } from "../../CliCommonArgs.js";
import type { ThirdPartyAppRid } from "../../net/ThirdPartyAppRid.js";
import type { LoadedFoundryConfig } from "../../util/config.js";
import configLoader from "../../util/configLoader.js";
import type { CommonSiteArgs } from "./CommonSiteArgs.js";
import siteDelete from "./delete/index.js";
import siteDeploy from "./deploy/index.js";
import upload from "./upload/index.js";
import versions from "./versions/index.js";
import deploy from "./deploy/index.js";
import version from "./version/index.js";

const site: yargs.CommandModule<CliCommonArgs, CommonSiteArgs> = {
export const command: CommandModule<CliCommonArgs, CommonSiteArgs> = {
zeyadkhaled marked this conversation as resolved.
Show resolved Hide resolved
command: "site",
describe: "Manage your site",
builder: (argv) => {
builder: async (argv) => {
const config: LoadedFoundryConfig | undefined = await configLoader();
const application = config?.foundryConfig.site.application;
const foundryUrl = config?.foundryConfig.foundryUrl;
return argv
.options({
appRid: {
application: {
type: "string",
demandOption: true,
coerce: (a) => a as ThirdPartyAppRid,
...application
? { default: application }
: { demandOption: true },
description: "Application RID",
},
baseUrl: {
foundryUrl: {
type: "string",
demandOption: true,
...foundryUrl
? { default: foundryUrl }
: { demandOption: true },
description:
"Foundry Stack URL with Protocol (e.g. https://example.palantirfoundry.com)",
},
token: {
type: "string",
conflicts: "tokenFile",
description: "Foundry API Token",
},
tokenFile: {
type: "string",
conflicts: "token",
description: "Path to a file containing your Foundry API Token",
},
})
.group(["appRid", "baseUrl"], "Common Arguments")
.command(versions)
.command(upload)
.command(siteDelete)
.command(siteDeploy)
.group(
["application", "foundryUrl", "token", "tokenFile"],
"Common Arguments",
)
.command(version)
.command(deploy)
.check((argv) => {
if (application != null && argv.application !== application) {
consola.debug(
`Overriding "application" from config file with ${argv.application}`,
);
}

if (foundryUrl != null && argv.foundryUrl !== foundryUrl) {
consola.debug(
`Overriding "foundryUrl" from config file with ${argv.foundryUrl}`,
);
}

if (!argv.foundryUrl.startsWith("https://")) {
throw new Error(
"foundryUrl must start with https://",
);
}

argv.foundryUrl = argv.foundryUrl.replace(/\/$/, "");
return true;
})
.demandCommand();
},
handler: async (args) => {
},
handler: async (args) => {},
};

export default site;
export default command;
Loading
Loading