Skip to content
This repository has been archived by the owner on Sep 22, 2024. It is now read-only.

Commit

Permalink
wip(cli): add sync_env subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelrk committed Aug 9, 2023
1 parent 1994e09 commit c27921a
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 33 deletions.
2 changes: 1 addition & 1 deletion lib/cli/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export {
export { parse as parseArgs } from "https://deno.land/[email protected]/flags/mod.ts";
export { TextLineStream } from "https://deno.land/[email protected]/streams/text_line_stream.ts";
export { default as question } from "https://deno.land/x/[email protected]/mod.ts";
export { load } from "https://deno.land/[email protected]/dotenv/mod.ts";
export { config, load } from "https://deno.land/[email protected]/dotenv/mod.ts";

// x/semver
export {
Expand Down
48 changes: 24 additions & 24 deletions lib/cli/src/subcommands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ USAGE:
netzo deploy [OPTIONS] <entrypoint>
OPTIONS:
--api-key=<API_KEY> The API key to use (defaults to NETZO_API_KEY environment variable)
--exclude=<PATTERNS> Exclude files that match this pattern
--include=<PATTERNS> Only upload files that match this pattern
--import-map=<FILE> Use import map file
Expand All @@ -54,6 +53,7 @@ OPTIONS:
--prod Create a production deployment (default is preview deployment)
-p, --project=<PROJECT_UID> The UID of the project to deploy to
--dry-run Dry run the deployment process
--api-key=<API_KEY> The API key to use (defaults to NETZO_API_KEY environment variable)
ARGS:
<entrypoint> The file path to the entrypoint file (e.g. main.tsx)
Expand All @@ -65,11 +65,11 @@ export interface Args {
prod: boolean;
exclude?: string[];
include?: string[];
apiKey: string | null;
apiUrl?: string;
project: string | null;
importMap: string | null;
dryRun: boolean;
apiKey: string | null;
apiUrl?: string;
}

// deno-lint-ignore no-explicit-any
Expand All @@ -78,13 +78,13 @@ export default async function (rawArgs: Record<string, any>): Promise<void> {
help: !!rawArgs.help,
static: !rawArgs["no-static"], // negate the flag
prod: !!rawArgs.prod,
apiKey: rawArgs["api-key"] ? String(rawArgs["api-key"]) : null,
apiUrl: rawArgs["api-url"] ?? "https://api.netzo.io",
project: rawArgs.project ? String(rawArgs.project) : null,
importMap: rawArgs["import-map"] ? String(rawArgs["import-map"]) : null,
exclude: rawArgs.exclude?.split(","),
include: rawArgs.include?.split(","),
dryRun: !!rawArgs["dry-run"],
apiKey: rawArgs["api-key"] ? String(rawArgs["api-key"]) : null,
apiUrl: rawArgs["api-url"] ?? "https://api.netzo.io",
};
const entrypoint = typeof rawArgs._[0] === "string" ? rawArgs._[0] : null;
if (args.help) {
Expand All @@ -111,23 +111,23 @@ export default async function (rawArgs: Record<string, any>): Promise<void> {
error("Missing project UID.");
}

const opts: DeployOpts = {
entrypoint: await parseEntrypoint(entrypoint).catch((e) => error(e)),
importMapUrl: args.importMap === null
? null
: await parseEntrypoint(args.importMap, undefined, "import map")
.catch((e) => error(e)),
static: args.static,
prod: args.prod,
apiKey,
apiUrl: args.apiUrl,
project: args.project,
include: args.include?.map((pattern) => normalize(pattern)),
exclude: args.exclude?.map((pattern) => normalize(pattern)),
dryRun: args.dryRun,
};

await deploy(opts);
await deploy(
{
entrypoint: await parseEntrypoint(entrypoint).catch((e) => error(e)),
importMapUrl: args.importMap === null
? null
: await parseEntrypoint(args.importMap, undefined, "import map")
.catch((e) => error(e)),
static: args.static,
prod: args.prod,
project: args.project,
include: args.include?.map((pattern) => normalize(pattern)),
exclude: args.exclude?.map((pattern) => normalize(pattern)),
dryRun: args.dryRun,
apiKey,
apiUrl: args.apiUrl,
} satisfies DeployOpts,
);
}

interface DeployOpts {
Expand All @@ -137,10 +137,10 @@ interface DeployOpts {
prod: boolean;
exclude?: string[];
include?: string[];
apiKey: string;
apiUrl?: string;
project: string;
dryRun: boolean;
apiKey: string;
apiUrl?: string;
}

async function deploy(opts: DeployOpts): Promise<void> {
Expand Down
17 changes: 9 additions & 8 deletions lib/cli/src/subcommands/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,30 @@ USAGE:
netzo logs [OPTIONS] <project>
OPTIONS:
--api-key The API key to use (defaults to NETZO_API_KEY environment variable)
--deployment The ID of the deployment you want to stream logs for (defaults to latest deployment)
--prod Select the production deployment
-p, --project The UID of the project you want to stream logs for
--api-key The API key to use (defaults to NETZO_API_KEY environment variable)
`;

export interface Args {
help: boolean;
prod: boolean;
apiKey: string | null;
apiUrl?: string;
deployment: string | null;
project: string | null;
apiKey: string | null;
apiUrl?: string;
}

// deno-lint-ignore no-explicit-any
export default async function (rawArgs: Record<string, any>): Promise<void> {
const args: Args = {
help: !!rawArgs.help,
prod: !!rawArgs.prod,
apiKey: rawArgs["api-key"] ? String(rawArgs["api-key"]) : null,
apiUrl: rawArgs["api-url"] ?? "https://api.netzo.io",
deployment: rawArgs.deployment ? String(rawArgs.deployment) : null,
project: rawArgs.project ? String(rawArgs.project) : null,
apiKey: rawArgs["api-key"] ? String(rawArgs["api-key"]) : null,
apiUrl: rawArgs["api-url"] ?? "https://api.netzo.io",
};

if (args.help) {
Expand All @@ -67,7 +67,7 @@ export default async function (rawArgs: Record<string, any>): Promise<void> {
error("Too many positional arguments given.");
}

const opts: DeployOpts = {
const opts: LogsOpts = {
project: args.project,
deploymentId: args.deployment,
prod: args.prod,
Expand All @@ -78,15 +78,15 @@ export default async function (rawArgs: Record<string, any>): Promise<void> {
await logs(opts);
}

interface DeployOpts {
interface LogsOpts {
project: string;
deploymentId: string | null;
prod: boolean;
apiKey: string;
apiUrl?: string;
}

async function logs(opts: DeployOpts): Promise<void> {
async function logs(opts: LogsOpts): Promise<void> {
if (opts.prod && opts.deploymentId) {
error(
"You can't select a deployment and choose production flag at the same time",
Expand All @@ -98,6 +98,7 @@ async function logs(opts: DeployOpts): Promise<void> {
uid: opts.project,
$limit: 1,
});
// FIXME: get deployments from project using `api` client
const projectDeployments = await DenoAPI.getDeployments(project._id);
if (project === null) {
projectSpinner.fail("Project not found.");
Expand Down
116 changes: 116 additions & 0 deletions lib/cli/src/subcommands/sync_env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// from https://github.com/drollinger/deployctl
// see https://github.com/denoland/deployctl/issues/138

import { config, netzo, Paginated, Project, wait } from "../../deps.ts";
import { error } from "../console.ts";

const help = `netzo env
Sync environment variable with Netzo.
USAGE:
netzo env [OPTIONS] <ENV_FILE>
OPTIONS:
-h, --help Prints help information
-p, --project=NAME The project to deploy to
--api-key=<API_KEY> The API key to use (defaults to NETZO_API_KEY environment variable)
`;

export interface Args {
help: boolean;
project: string | null;
apiKey: string | null;
apiUrl?: string;
}

// deno-lint-ignore no-explicit-any
export default async function (rawArgs: Record<string, any>): Promise<void> {
const args: Args = {
help: !!rawArgs.help,
project: rawArgs.project ? String(rawArgs.project) : null,
apiKey: rawArgs["api-key"] ? String(rawArgs["api-key"]) : null,
apiUrl: rawArgs["api-url"] ?? "https://api.netzo.io",
};
const envFile: string | null = typeof rawArgs._[0] === "string"
? rawArgs._[0]
: null;
if (args.help) {
console.log(help);
Deno.exit(0);
}
const apiKey = args.apiKey ?? Deno.env.get("NETZO_API_KEY") ?? null;
if (apiKey === null) {
console.error(help);
error(
"Missing API key. Set via --api-key flag or NETZO_API_KEY environment variable to avoid passing it each time.",
);
}
if (envFile === null) {
console.error(help);
error("No environment file specifier given.");
}
if (rawArgs._.length > 1) {
console.error(help);
error("Too many positional arguments given.");
}
if (args.project === null) {
console.error(help);
error("Missing project name.");
}

await syncEnv(
{
envFile,
project: args.project,
apiKey,
apiUrl: args.apiUrl,
} satisfies SyncEnvOpts,
);
}

interface SyncEnvOpts {
envFile: string;
project: string;
apiKey: string;
apiUrl?: string;
}

async function syncEnv(opts: SyncEnvOpts): Promise<void> {
const projectSpinner = wait("Fetching project information...").start();
const { api } = netzo({ apiKey: opts.apiKey, baseURL: opts.apiUrl });
const { data: [project] } = await api.projects.get<Paginated<Project>>({
uid: opts.project,
$limit: 1,
});
if (project === null) {
projectSpinner.fail("Project not found.");
Deno.exit(1);
}
projectSpinner.succeed(`Project: ${project.name}`);

const fileSpinner = wait("Reading env file...").start();
let envVars: Record<string, string> = {};
try {
envVars = await config({ path: opts.envFile });
if (Object.keys(envVars).length === 0) {
fileSpinner.info("File did not contain any variables.");
Deno.exit(1);
}
} catch {
fileSpinner.fail(`Could not load file: ${opts.envFile}`);
Deno.exit(1);
}
fileSpinner.succeed(`File Loaded: ${opts.envFile}`);

const syncSpinner = wait("Syncing environment variables...").start();
try {
await api.projects[project._id].patch<Project>({
...project.configuration,
envVars,
});
} catch {
syncSpinner.fail("Failed to sync variables.");
Deno.exit(1);
}
syncSpinner.succeed("Environment variables synced.");
}

0 comments on commit c27921a

Please sign in to comment.