From 51b7d8a5bc978a75bbbdadfbb2063caa09a8e1b8 Mon Sep 17 00:00:00 2001 From: WolffRuoff Date: Fri, 13 Oct 2023 21:23:21 -0700 Subject: [PATCH 1/4] Allow absolute paths for subgraphs --- src/Subgraph.ts | 2 +- src/setup.ts | 32 +++++++++++++++++++++++++++----- src/supergraph.ts | 5 +++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/Subgraph.ts b/src/Subgraph.ts index e42c6e2..1bd2429 100644 --- a/src/Subgraph.ts +++ b/src/Subgraph.ts @@ -254,7 +254,7 @@ export class Subgraph extends vscode.TreeItem { type: 'node', request: 'launch', name: this.label, - program: '${workspaceRoot}' + `/${this.filePath}/server.js`, + program: `${this.filePath}/server.js`, skipFiles: ['/**'], // eslint-disable-next-line @typescript-eslint/naming-convention env: { NODE_ENV: 'local' }, diff --git a/src/setup.ts b/src/setup.ts index 367f6db..3b122e2 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { commands, window, workspace } from 'vscode'; import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import { isAbsolute, join } from 'path'; import axios from 'axios'; export const sampleSupergraphJson = { @@ -38,15 +39,22 @@ export const generateTemplate = (rootPath: string) => { mkdirSync(rootPath + '/.vscode'); } if (!existsSync(rootPath + '/.rover-runner/supergraph.json')) { - writeFileSync(`${rootPath}/.rover-runner/supergraph.json`, JSON.stringify(sampleSupergraphJson, null, 2), 'utf-8'); + writeFileSync( + `${rootPath}/.rover-runner/supergraph.json`, + JSON.stringify(sampleSupergraphJson, null, 2), + 'utf-8' + ); commands.executeCommand('subgraphsList.refreshEntry'); } }; export const isApolloConfigured = () => { if ( - workspace.getConfiguration().get('apolloStudioConfiguration.apolloKey', '').length > 0 && - workspace.getConfiguration().get('apolloStudioConfiguration.apolloGraphRef', '').length > 0 + workspace.getConfiguration().get('apolloStudioConfiguration.apolloKey', '') + .length > 0 && + workspace + .getConfiguration() + .get('apolloStudioConfiguration.apolloGraphRef', '').length > 0 ) { return true; } @@ -54,8 +62,12 @@ export const isApolloConfigured = () => { }; export const fetchSubgraphUrls = async () => { - let apolloKey = workspace.getConfiguration().get('apolloStudioConfiguration.apolloKey', ''); - let graphRef = workspace.getConfiguration().get('apolloStudioConfiguration.apolloGraphRef', ''); + let apolloKey = workspace + .getConfiguration() + .get('apolloStudioConfiguration.apolloKey', ''); + let graphRef = workspace + .getConfiguration() + .get('apolloStudioConfiguration.apolloGraphRef', ''); let body = { operationName: 'GetSubgraphUrls', query: @@ -91,3 +103,13 @@ export const fetchSubgraphUrls = async () => { return {}; }); }; + +export const makePathAbsolute = (filePath: string, configPath: string) => { + // If absolute or empty path, then return + if (isAbsolute(filePath) || filePath.length === 0) { + return filePath; + } + // Convert relative path to be absolute + const workspaceRoot = configPath.split('.rover-runner')[0]; + return join(workspaceRoot, filePath); +}; diff --git a/src/supergraph.ts b/src/supergraph.ts index 49b6625..045acfe 100644 --- a/src/supergraph.ts +++ b/src/supergraph.ts @@ -1,6 +1,6 @@ import { readFileSync } from 'fs'; import { setTimeout } from 'timers/promises'; -import { fetchSubgraphUrls } from './setup'; +import { fetchSubgraphUrls, makePathAbsolute } from './setup'; import { ExtensionContext, TreeItem, TreeItemCollapsibleState, window, workspace } from 'vscode'; import { SupergraphYaml, writeSupergraphYaml } from './supergraphYaml'; import { Subgraph } from './Subgraph'; @@ -35,6 +35,7 @@ export class Supergraph extends TreeItem { const current = context.workspaceState.get(subgraphName + 'currentUrl', 'devUrl'); // Can either be Stopped or Running const contextValue = context.workspaceState.get(subgraphName, 'StoppedSubgraph'); + const filePath = makePathAbsolute(subgraphConfig.path, configPath); return [ new Subgraph( subgraphName, @@ -42,7 +43,7 @@ export class Supergraph extends TreeItem { subgraphConfig.localUrl, usedDevUrl, contextValue, - subgraphConfig.path, + filePath, TreeItemCollapsibleState.None ), ]; From e5173d166d0d24bdcc45f3f280aebdd42a3ca8ef Mon Sep 17 00:00:00 2001 From: WolffRuoff Date: Tue, 17 Oct 2023 11:06:51 -0400 Subject: [PATCH 2/4] Add stricter eslint profile --- .eslintrc.json | 1 + .github/workflows/main.yml | 1 - src/Subgraph.ts | 27 +++++++++++++++------------ src/SubgraphsProvider.ts | 6 +++--- src/setup.ts | 6 +++--- src/supergraph.ts | 13 +++++++------ 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f9b22b7..11ef8bf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,6 +8,7 @@ "plugins": [ "@typescript-eslint" ], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], "rules": { "@typescript-eslint/naming-convention": "warn", "@typescript-eslint/semi": "warn", diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 45e3899..9ef48c5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,7 +64,6 @@ jobs: - name: Version Package run: | npm version $RELEASE_VERSION - git tag -a $RELEASE_VERSION -m "$RELEASE_VERSION" - name: Package Extension run: npm run package -- $RELEASE_VERSION -o "./rover-runner-$RELEASE_VERSION.vsix" - name: Publish to Visual Studio Marketplace diff --git a/src/Subgraph.ts b/src/Subgraph.ts index 1bd2429..f75cbf1 100644 --- a/src/Subgraph.ts +++ b/src/Subgraph.ts @@ -15,7 +15,7 @@ export const startup = ( subgraph: Subgraph, debug: boolean, context: vscode.ExtensionContext, - shouldRefresh: boolean = true + shouldRefresh = true ) => { const subgraphStartupFulfilled = (name: string) => { context.workspaceState.update(name, 'RunningSubgraph'); @@ -99,7 +99,7 @@ export class Subgraph extends vscode.TreeItem { // Add auth header if Bearer Token set const authHeader = vscode.workspace.getConfiguration().get('rover-runner.authorizationHeader', ''); process.env.ROV_TOK = authHeader; - let introspectionQuery = authHeader.length + const introspectionQuery = authHeader.length ? `rover subgraph introspect ${url} --header "Authorization: $ROV_TOK" --output ${this.label}.graphql` : `rover subgraph introspect ${url} --output ${this.label}.graphql`; const workspacePath = join(vscode.workspace?.workspaceFolders?.[0]?.uri?.fsPath || '', '.rover-runner/'); @@ -108,8 +108,10 @@ export class Subgraph extends vscode.TreeItem { env: process.env, }); return Promise.resolve(''); - } catch (e: any) { - console.log(e?.message); + } catch (err) { + if (err instanceof Error) { + console.log(err?.message); + } return Promise.reject(`Introspection failed at ${url}. Make sure Auth is up to date`); } } @@ -124,14 +126,14 @@ export class Subgraph extends vscode.TreeItem { return Promise.resolve('Path not provided'); } else if (debug) { this.setLaunchJson(); - let folder = vscode.workspace.workspaceFolders?.[0]; + const folder = vscode.workspace.workspaceFolders?.[0]; await vscode.debug.startDebugging(folder, this.label, { suppressDebugToolbar: false, }); this.contextValue = 'RunningSubgraph'; return Promise.resolve('Launched in debug mode'); } else { - let subgraphTerminal = + const subgraphTerminal = vscode.window.terminals.find((i) => i.name === this.label) || vscode.window.createTerminal(this.label); subgraphTerminal.show(true); subgraphTerminal.sendText( @@ -145,7 +147,7 @@ export class Subgraph extends vscode.TreeItem { public async startRunning(debug: boolean): Promise { this.contextValue = 'RunningSubgraph'; - let roverTerminal = + const roverTerminal = vscode.window.terminals.find((i) => i.name === `Rover ${this.label}`) || vscode.window.createTerminal(`Rover ${this.label}`); roverTerminal.sendText(` @@ -159,7 +161,7 @@ export class Subgraph extends vscode.TreeItem { await setTimeout(3000); roverTerminal.show(true); // Make sure the subgraph is running before trying to run rover - let port: number = parseInt(this.local.split(':')?.[2]?.split('/')?.[0]); + const port: number = parseInt(this.local.split(':')?.[2]?.split('/')?.[0]); return await detect(port).then((_port: number) => { // _port is the next available port so if equal then server isn't running if (port === _port && this.filePath) { @@ -209,9 +211,10 @@ export class Subgraph extends vscode.TreeItem { } public async stopRunning(): Promise { + // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { this.contextValue = 'StoppedSubgraph'; - let roverTerminal = vscode.window.terminals.find((i) => i.name === `Rover ${this.label}`); + const roverTerminal = vscode.window.terminals.find((i) => i.name === `Rover ${this.label}`); if (roverTerminal) { roverTerminal.sendText('\u0003'); await setTimeout(3000); @@ -219,7 +222,7 @@ export class Subgraph extends vscode.TreeItem { } if (this.current === 'localUrl') { - let subgraphTerminal = vscode.window.terminals.find((i) => i.name === this.label); + const subgraphTerminal = vscode.window.terminals.find((i) => i.name === this.label); if (subgraphTerminal) { subgraphTerminal.sendText('\u0003'); await setTimeout(3000); @@ -231,8 +234,8 @@ export class Subgraph extends vscode.TreeItem { } setLaunchJson = () => { - let fileP: string = vscode.workspace.workspaceFolders?.[0].uri.path + '/.vscode/launch.json'; - let launchFile = existsSync(fileP) ? readFileSync(fileP, 'utf-8') : undefined; + const fileP: string = vscode.workspace.workspaceFolders?.[0].uri.path + '/.vscode/launch.json'; + const launchFile = existsSync(fileP) ? readFileSync(fileP, 'utf-8') : undefined; let launchJson = launchFile ? JSON.parse(launchFile) : {}; if (!launchJson || !launchJson?.configurations) { diff --git a/src/SubgraphsProvider.ts b/src/SubgraphsProvider.ts index b84d305..3f4815e 100644 --- a/src/SubgraphsProvider.ts +++ b/src/SubgraphsProvider.ts @@ -54,7 +54,7 @@ export class SubgraphsProvider implements vscode.TreeDataProvider { + const toSupergraph = (supergraphName: string): Supergraph => { // Can either be Stopped or Running const contextValue = this.context.workspaceState.get(`${supergraphName}Supergraph`, 'StoppedSupergraph'); const newSupergraph = new Supergraph( @@ -69,11 +69,11 @@ export class SubgraphsProvider implements vscode.TreeDataProvider - toSupergraph(supergraph, configJson.supergraphs[supergraph]) + toSupergraph(supergraph) ) : [] ); diff --git a/src/setup.ts b/src/setup.ts index 3b122e2..8cd3600 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -62,13 +62,13 @@ export const isApolloConfigured = () => { }; export const fetchSubgraphUrls = async () => { - let apolloKey = workspace + const apolloKey = workspace .getConfiguration() .get('apolloStudioConfiguration.apolloKey', ''); - let graphRef = workspace + const graphRef = workspace .getConfiguration() .get('apolloStudioConfiguration.apolloGraphRef', ''); - let body = { + const body = { operationName: 'GetSubgraphUrls', query: 'query GetSubgraphUrls($ref: ID!) { variant(ref: $ref) { ... on GraphVariant { subgraphs { name url }} ... on InvalidRefFormat { message }}}', diff --git a/src/supergraph.ts b/src/supergraph.ts index 045acfe..17e9179 100644 --- a/src/supergraph.ts +++ b/src/supergraph.ts @@ -23,14 +23,14 @@ export class Supergraph extends TreeItem { async getChildren(configPath: string, context: ExtensionContext): Promise { const toSubgraph = (subgraphName: string): Subgraph[] => { - let apolloDevUrl = + const apolloDevUrl = apolloSubgraphs.data.variant?.subgraphs.find((e: any) => e['name'] === subgraphName)?.url ?? ''; - let subgraphConfig = configJson.subgraphs[subgraphName]; + const subgraphConfig = configJson.subgraphs[subgraphName]; if (!subgraphConfig) { window.showErrorMessage(`Subgraph ${subgraphName} in supergraph has no match in the subgraphs list`); return []; } - let usedDevUrl = subgraphConfig?.devUrl ?? apolloDevUrl; + const usedDevUrl = subgraphConfig?.devUrl ?? apolloDevUrl; // Can either be devUrl or localUrl const current = context.workspaceState.get(subgraphName + 'currentUrl', 'devUrl'); // Can either be Stopped or Running @@ -106,7 +106,7 @@ export class Supergraph extends TreeItem { .then(() => writeSupergraphYaml(supergraphYaml)) .then( () => { - let roverTerminal = + const roverTerminal = window.terminals.find((i) => i.name === `Rover Runner`) || window.createTerminal(`Rover Runner`); roverTerminal.show(true); roverTerminal.sendText(` @@ -124,14 +124,15 @@ export class Supergraph extends TreeItem { } public stopRunning(context: ExtensionContext): Promise { + // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { - let roverTerminal = window.terminals.find((i) => i.name === `Rover Runner`); + const roverTerminal = window.terminals.find((i) => i.name === `Rover Runner`); if (roverTerminal) { roverTerminal.sendText('\u0003'); await setTimeout(3000); roverTerminal.dispose(); } - let stopList: any[] = []; + const stopList: Promise[] = []; // Add subgraphs to a promise all this.children.forEach((subgraph) => { if (context.workspaceState.get(subgraph.label) === 'RunningSubgraph') { From 93eb633ff8f662333e23aaf9a5c62520df2a0a03 Mon Sep 17 00:00:00 2001 From: WolffRuoff Date: Tue, 17 Oct 2023 11:13:47 -0400 Subject: [PATCH 3/4] Update to fulfill eslint --- src/quickPicks.ts | 10 +++++----- src/redis.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/quickPicks.ts b/src/quickPicks.ts index 0d27912..fdc52cd 100644 --- a/src/quickPicks.ts +++ b/src/quickPicks.ts @@ -27,7 +27,7 @@ export const selectUrl = (rootPath: string, subgraph: Subgraph, context: Extensi }, ]; urlSelector.onDidChangeSelection(() => { - let label = urlSelector.selectedItems[0].label || ''; + const label = urlSelector.selectedItems[0].label || ''; if (!label) { return; } @@ -37,7 +37,7 @@ export const selectUrl = (rootPath: string, subgraph: Subgraph, context: Extensi urlSelector.dispose(); }); urlSelector.onDidTriggerItemButton((item) => { - let placeHolder = item.item.label === 'Use Local Url' ? subgraph.local : subgraph.dev; + const placeHolder = item.item.label === 'Use Local Url' ? subgraph.local : subgraph.dev; window .showInputBox({ ignoreFocusOut: true, @@ -49,12 +49,12 @@ export const selectUrl = (rootPath: string, subgraph: Subgraph, context: Extensi if (!inp) { return; } - let filePath = `${rootPath}/.rover-runner/${context.workspaceState.get( + const filePath = `${rootPath}/.rover-runner/${context.workspaceState.get( 'Supergraph Configuration Filename', 'supergraph.json' )}`; - let supergraphJson = JSON.parse(readFileSync(filePath, 'utf-8')); - let urlKey: string = item.item.label === 'Use Local Url' ? 'localUrl' : 'devUrl'; + const supergraphJson = JSON.parse(readFileSync(filePath, 'utf-8')); + const urlKey: string = item.item.label === 'Use Local Url' ? 'localUrl' : 'devUrl'; supergraphJson.subgraphs[subgraph.label][urlKey] = inp; writeFileSync(filePath, JSON.stringify(supergraphJson, null, 2), 'utf-8'); if (urlKey === 'localUrl') { diff --git a/src/redis.ts b/src/redis.ts index 671e730..997b1c1 100644 --- a/src/redis.ts +++ b/src/redis.ts @@ -5,7 +5,7 @@ export const startRedis = () => { detect(6379).then((_port: number) => { // _port is the next available port so if equal then server isn't running if (6379 === _port) { - let redisTerminal = + const redisTerminal = window.terminals.find((i: { name: string }) => i.name === `Redis`) || window.createTerminal(`Redis`); redisTerminal.sendText('redis-server'); } @@ -13,7 +13,7 @@ export const startRedis = () => { }; export const stopRedis = () => { - let redisTerminal = window.terminals.find((i: { name: string }) => i.name === `Redis`); + const redisTerminal = window.terminals.find((i: { name: string }) => i.name === `Redis`); if (redisTerminal) { redisTerminal.sendText('\u0003'); redisTerminal.dispose(); From b1fad27b59c6e429b3f8f4f55692d66fa9e51bac Mon Sep 17 00:00:00 2001 From: WolffRuoff Date: Tue, 17 Oct 2023 11:14:32 -0400 Subject: [PATCH 4/4] Update docs for absolute paths --- README.md | 4 ++-- src/setup.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5a271a..613d994 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This extension requires a `supergraph.json` file at `.rover-runner/supergraph.js { "subgraphs": { "Subgraph1": { - "path": "", + "path": "/Users/name/Desktop/repos/subgraph", "localUrl": "http://localhost:3000/graphql" }, "Subgraph2": { @@ -40,7 +40,7 @@ This extension requires a `supergraph.json` file at `.rover-runner/supergraph.js ``` Some notes about this format: - `Subgraph1`, `Subgraph2`, etc are the subgraph names and should match the names in Apollo Studio -- `path` is the relative path to the subgraph from the workspace root. If this is blank like in `Subgraph1`, then you need to run the subgraph on its own +- `path` is the path to the subgraph. It can either be a relative path from the workspace root like in `Subgraph2` or an absolute path like in `Subgraph1`. - `localUrl` is the graphQL endpoint when running the subgraph locally - `devUrl` is the graphQL endpoint for the GraphQL variant. This field is optional as the extension will grab the endpoint from Apollo Studio by default diff --git a/src/setup.ts b/src/setup.ts index 8cd3600..7712b46 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -8,7 +8,7 @@ export const sampleSupergraphJson = { subgraphs: { // eslint-disable-next-line @typescript-eslint/naming-convention Subgraph1: { - path: '', + path: '/Users/name/Desktop/repos/subgraph', localUrl: 'http://localhost:3000/graphql', }, // eslint-disable-next-line @typescript-eslint/naming-convention