Skip to content

Commit

Permalink
feat: team access
Browse files Browse the repository at this point in the history
  • Loading branch information
mo4islona committed May 30, 2023
1 parent d90c61d commit 5b7bf44
Show file tree
Hide file tree
Showing 20 changed files with 307 additions and 104 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@subsquid/cli",
"description": "squid cli tool",
"version": "2.3.1",
"version": "2.4.0-beta.2",
"license": "GPL-3.0-or-later",
"repository": "git@github.com:subsquid/squid-cli.git",
"publishConfig": {
Expand Down
8 changes: 6 additions & 2 deletions src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';

import chalk from 'chalk';
import { pickBy } from 'lodash';
import fetch from 'node-fetch';
import qs from 'query-string';

Expand Down Expand Up @@ -41,7 +42,7 @@ export async function api<T = any>({
method,
path,
data,
query,
query = {},
auth,
responseType = 'json',
abortController,
Expand All @@ -56,7 +57,10 @@ export async function api<T = any>({
}): Promise<{ body: T }> {
const config = auth || getConfig();

const url = `${config.apiUrl}${path}${query ? `?${qs.stringify(query)}` : ''}`;
const sanitizedQuery = pickBy(query, (v) => v);
const queryString = Object.keys(sanitizedQuery).length ? `?${qs.stringify(sanitizedQuery)}` : '';

const url = `${config.apiUrl}${path}${queryString}`;

const headers = {
'Content-Type': 'application/json',
Expand Down
18 changes: 0 additions & 18 deletions src/api/me.ts

This file was deleted.

42 changes: 42 additions & 0 deletions src/api/profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { api, ApiError } from './api';
import { HttpResponse } from './types';

export type Profile = {
username?: string;
email: string;
projects?: {
code: string;
name: string;
}[];
};

export async function profile({
withProjects,
auth,
}: {
auth?: { apiUrl: string; credentials: string };
withProjects?: boolean;
} = {}): Promise<Profile> {
const { body } = await api<HttpResponse<Profile>>({
method: 'get',
auth,
path: `/profile`,
query: withProjects
? {
withProjects,
}
: undefined,
});

if (!body.payload) {
throw new ApiError(401, { error: 'username is missing' });
}

return body.payload;
}

export async function listProjects() {
const { projects, ...rest } = await profile({ withProjects: true });

return projects || [];
}
42 changes: 34 additions & 8 deletions src/api/secrets.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,53 @@
import { api } from './api';
import { HttpResponse, SecretsListResponse } from './types';

export async function listSecrets(): Promise<SecretsListResponse> {
export async function listSecrets({ projectCode }: { projectCode?: string }): Promise<SecretsListResponse> {
const { body } = await api<HttpResponse<SecretsListResponse>>({
method: 'get',
path: '/secrets',
query: {
projectCode,
},
path: `/secrets`,
});
return body.payload;
}

export async function removeSecret(name: string): Promise<SecretsListResponse> {
export async function removeSecret({
name,
projectCode,
}: {
name: string;
projectCode?: string;
}): Promise<SecretsListResponse> {
const { body } = await api<HttpResponse<SecretsListResponse>>({
method: 'delete',
path: `/secrets/${name}`,
method: 'put',
path: `/secrets`,
data: {
projectCode,
secrets: [{ action: 'DELETE', name }],
},
});

return body.payload;
}

export async function setSecret(secrets: Record<string, string>): Promise<SecretsListResponse> {
export async function setSecret({
name,
value,
projectCode,
}: {
name: string;
value: string;
projectCode?: string;
}): Promise<SecretsListResponse> {
const { body } = await api<HttpResponse<SecretsListResponse>>({
method: 'patch',
method: 'put',
path: `/secrets`,
data: { secrets: secrets },
data: {
projectCode,
secrets: [{ action: 'UPDATE', name, value }],
},
});

return body.payload;
}
15 changes: 12 additions & 3 deletions src/api/squids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@ export async function squidCreate(
return body;
}

export async function squidList(): Promise<SquidResponse[]> {
export async function squidList({ projectCode }: { projectCode?: string } = {}): Promise<SquidResponse[]> {
const { body } = await api<HttpResponse<SquidResponse[]>>({
method: 'get',
path: '/squids',
query: {
projectCode,
},
});

return body.payload;
Expand Down Expand Up @@ -199,6 +202,7 @@ export async function deploySquid(data: {
hardReset: boolean;
artifactUrl: string;
manifestPath: string;
project?: string;
}): Promise<DeployResponse> {
const { body } = await api<HttpResponse<DeployResponse>>({
method: 'post',
Expand All @@ -209,10 +213,15 @@ export async function deploySquid(data: {
return body.payload;
}

export async function isVersionExists(squid: string, version: string) {
export async function fetchVersion({ squidName, versionName }: { squidName: string; versionName: string }) {
const squids = await squidList();

return squids.find((s) => s.name === squid)?.versions?.find((v) => v.name === version);
const squid = squids.find((s) => s.name === squidName);
if (!squid) return null;

squid.versions = squid.versions.filter((v) => v.name === versionName);

return squid;
}

export async function getUploadUrl(): Promise<UploadUrlResponse> {
Expand Down
1 change: 1 addition & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export type SquidResponse = {
isPublic: boolean;
deploy?: DeployResponse;
createdAt: Date;
project?: { id: string; code: string };
};

export type SquidNameIsAvailableResponse = {
Expand Down
10 changes: 6 additions & 4 deletions src/commands/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Flags } from '@oclif/core';

import { me } from '../api/me';
import { profile } from '../api/profile';
import { CliCommand } from '../command';
import { DEFAULT_API_URL, setConfig } from '../config';

Expand All @@ -26,9 +26,11 @@ export default class Auth extends CliCommand {
flags: { key, host },
} = await this.parse(Auth);

const { username, email } = await me({
apiUrl: host,
credentials: key,
const { username, email } = await profile({
auth: {
apiUrl: host,
credentials: key,
},
});

setConfig(key, host);
Expand Down
3 changes: 1 addition & 2 deletions src/commands/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ export default class DefaultCommand extends Command {

const squidCmdConfig = await getSquidCommands();
if (squidCmdConfig?.commands?.[id]) {
await squidCommandRun(squidCmdConfig, id, this.argv.slice(1));
return;
process.exit(await squidCommandRun(squidCmdConfig, id, this.argv.slice(1)));
}

const squidCommands = await help.getVisibleSquidCommands();
Expand Down
54 changes: 42 additions & 12 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import inquirer from 'inquirer';
import yaml from 'js-yaml';
import targz from 'targz';

import { deploySquid, isVersionExists, uploadFile } from '../api';
import { deploySquid, fetchVersion, uploadFile } from '../api';
import { DeployCommand } from '../deploy-command';
import { Manifest } from '../manifest';

import { chooseProjectIfRequired } from './projects';

const compressAsync = promisify(targz.compress);

const SQUID_PATH_DESC = [
Expand Down Expand Up @@ -98,16 +100,23 @@ export default class Deploy extends DeployCommand {
required: false,
default: false,
}),
project: Flags.string({
char: 'p',
description: 'Project',
required: false,
}),
};

async run(): Promise<void> {
const {
args: { source },
flags: { manifest, 'hard-reset': hardReset, update, 'no-stream-logs': disableStreamLogs },
flags: { manifest, 'hard-reset': hardReset, update, 'no-stream-logs': disableStreamLogs, project },
} = await this.parse(Deploy);

const isUrl = source.startsWith('http://') || source.startsWith('https://');
let deploy;
let projectCode = await chooseProjectIfRequired(project);

if (!isUrl) {
const res = resolveManifest(source, manifest);
if ('error' in res) return this.error(res.error);
Expand All @@ -121,16 +130,35 @@ export default class Deploy extends DeployCommand {
this.log(chalk.dim(`Build directory: ${buildDir}`));
this.log(chalk.dim(`Manifest: ${manifest}`));

const foundVersion = await isVersionExists(manifestValue.name, `v${manifestValue.version}`);
if (foundVersion && !update) {
const { confirm } = await inquirer.prompt([
{
name: 'confirm',
type: 'confirm',
message: `Version "v${manifestValue.version}" of Squid "${manifestValue.name}" will be updated. Are you sure?`,
},
]);
if (!confirm) return;
const foundSquid = await fetchVersion({
squidName: manifestValue.name,
versionName: `v${manifestValue.version}`,
});

if (foundSquid) {
if (projectCode && projectCode !== foundSquid.project?.code) {
const { confirm } = await inquirer.prompt([
{
name: 'confirm',
type: 'confirm',
message: `Version "v${manifestValue.version}" of Squid "${manifestValue.name}" belongs to "${foundSquid.project?.code}". Update a squid in "${foundSquid.project?.code}" project?`,
},
]);
if (!confirm) return;

projectCode = foundSquid.project?.code;
}

if (foundSquid.versions.length && !update) {
const { confirm } = await inquirer.prompt([
{
name: 'confirm',
type: 'confirm',
message: `Version "v${manifestValue.version}" of Squid "${manifestValue.name}" will be updated. Are you sure?`,
},
]);
if (!confirm) return;
}
}

CliUx.ux.action.start(`◷ Compressing the squid to ${archiveName} `);
Expand Down Expand Up @@ -181,6 +209,7 @@ export default class Deploy extends DeployCommand {
hardReset,
artifactUrl,
manifestPath: manifest,
project,
});
} else {
this.log(`🦑 Releasing the squid`);
Expand All @@ -189,6 +218,7 @@ export default class Deploy extends DeployCommand {
hardReset,
artifactUrl: source,
manifestPath: manifest,
project,
});
}

Expand Down
19 changes: 16 additions & 3 deletions src/commands/explorer.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import { Command } from '@oclif/core';
import { Command, Flags } from '@oclif/core';
import blessed from 'reblessed';

import { Loader } from '../ui/components/Loader';
import { VersionManager } from '../ui/components/VersionManager';

import { chooseProjectIfRequired } from './projects';

export default class Explorer extends Command {
static description = 'Squid explorer';
// static hidden = true;
static flags = {
project: Flags.string({
char: 'p',
description: 'Project',
required: false,
hidden: false,
}),
};

async run(): Promise<void> {
await this.parse(Explorer);
const {
flags: { project },
} = await this.parse(Explorer);

const projectCode = await chooseProjectIfRequired(project);
const screen = blessed.screen({
smartCSR: true,
fastCSR: true,
Expand All @@ -20,7 +33,7 @@ export default class Explorer extends Command {
fullUnicode: true,
});

const manager = new VersionManager({
const manager = new VersionManager(projectCode, {
top: '0',
left: '0',
width: '100%',
Expand Down
Loading

0 comments on commit 5b7bf44

Please sign in to comment.