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 29, 2023
1 parent d90c61d commit e83b764
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 65 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.1",
"license": "GPL-3.0-or-later",
"repository": "[email protected]: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
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: 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
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
48 changes: 36 additions & 12 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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';

Expand Down Expand Up @@ -98,16 +98,24 @@ export default class Deploy extends DeployCommand {
required: false,
default: false,
}),
projectCode: Flags.string({
char: 'p',
description: 'Project',
required: false,
hidden: true,
}),
};

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, projectCode },
} = await this.parse(Deploy);

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

if (!isUrl) {
const res = resolveManifest(source, manifest);
if ('error' in res) return this.error(res.error);
Expand All @@ -121,16 +129,30 @@ 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(manifestValue.name, `v${manifestValue.version}`);

if (foundSquid && !update) {
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;

project = foundSquid.project?.code;
} else {
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 +203,7 @@ export default class Deploy extends DeployCommand {
hardReset,
artifactUrl,
manifestPath: manifest,
project,
});
} else {
this.log(`🦑 Releasing the squid`);
Expand All @@ -189,6 +212,7 @@ export default class Deploy extends DeployCommand {
hardReset,
artifactUrl: source,
manifestPath: manifest,
project,
});
}

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

import { Loader } from '../ui/components/Loader';
Expand All @@ -7,9 +7,19 @@ import { VersionManager } from '../ui/components/VersionManager';
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 screen = blessed.screen({
smartCSR: true,
Expand All @@ -20,7 +30,7 @@ export default class Explorer extends Command {
fullUnicode: true,
});

const manager = new VersionManager({
const manager = new VersionManager(project, {
top: '0',
left: '0',
width: '100%',
Expand Down
48 changes: 32 additions & 16 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import fs from 'fs';
import { promises as asyncFs } from 'fs';
import path from 'path';

import { CliUx, Flags } from '@oclif/core';
Expand All @@ -23,11 +23,11 @@ const TEMPLATE_ALIASES: Record<string, { url: string; description: string }> = {
},
abi: {
url: 'https://github.com/subsquid/squid-abi-template',
description: `A template to auto-generate a squid indexing events and txs from a contract ABI`
description: `A template to auto-generate a squid indexing events and txs from a contract ABI`,
},
'ink-abi': {
url: 'https://github.com/subsquid-labs/squid-ink-abi-template',
description: `A template to auto-generate a squid from an ink! contract ABI`
description: `A template to auto-generate a squid from an ink! contract ABI`,
},
gravatar: {
url: 'https://github.com/subsquid/gravatar-squid',
Expand Down Expand Up @@ -56,6 +56,18 @@ const git = simpleGit({
binary: 'git',
});

async function directoryIsEmpty(path: string) {
try {
const directory = await asyncFs.opendir(path);
const entry = await directory.read();
await directory.close();

return entry === null;
} catch (error) {
return false;
}
}

const SQUID_TEMPLATE_DESC = [
`A template for the squid. Accepts: `,
`- a ${chalk.bold('github repository URL')} containing a valid ${chalk.italic(
Expand Down Expand Up @@ -100,6 +112,18 @@ export default class Init extends CliCommand {
flags: { template, dir, remove },
} = await this.parse(Init);

const localDir = path.resolve(dir || name);
const isEmptyDir = await directoryIsEmpty(localDir);
if (!isEmptyDir) {
if (!remove) {
return this.error(
`The folder "${localDir}" already exists. Use the "-r" flag to init the squid at the existing path (will clean the folder first).`,
);
}

await asyncFs.rm(localDir, { recursive: true });
}

let resolvedTemplate = template || '';
if (!template) {
const { alias } = await inquirer.prompt({
Expand All @@ -121,7 +145,6 @@ export default class Init extends CliCommand {
const githubRepository = TEMPLATE_ALIASES[resolvedTemplate]
? TEMPLATE_ALIASES[resolvedTemplate].url
: resolvedTemplate;
const localDir = path.resolve(dir || name);

if (!(await squidNameIsAvailable(name))) {
const uniqueNameSuggestion = uniqueNamesGenerator({
Expand All @@ -135,16 +158,6 @@ export default class Init extends CliCommand {
);
}

if (fs.existsSync(localDir)) {
if (remove) {
fs.rmSync(localDir, { recursive: true });
} else {
return this.error(
`The folder ${localDir} already exists. Use the "-r" flag to init the squid at the existing path (will clean the folder first).`,
);
}
}

CliUx.ux.action.start(`◷ Downloading the template: ${githubRepository}... `);
try {
// TODO: support branches?
Expand All @@ -154,9 +167,12 @@ export default class Init extends CliCommand {
}
CliUx.ux.action.stop(`✔`);

fs.rmSync(path.resolve(localDir, '.git'), { recursive: true });
/** Clean up template **/
await asyncFs.rm(path.resolve(localDir, '.git'), { recursive: true });

/** Remove deprecated files from repositories **/
try {
fs.rmSync(path.resolve(localDir, 'Dockerfile'));
await asyncFs.rm(path.resolve(localDir, 'Dockerfile'));
} catch (e) {}

const manifestPath = path.resolve(localDir, 'squid.yaml');
Expand Down
Loading

0 comments on commit e83b764

Please sign in to comment.