Skip to content

Commit 22963fe

Browse files
authored
Merge branch 'main' into milinda/eng-8119-connection-stats-being-enabled-break-subscriptions
2 parents 1e58fba + e1abdea commit 22963fe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+28255
-6794
lines changed

cli/src/commands/mcp/tools/subgraph-verify-schema-changes.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export const registerSubgraphVerifySchemaChangesTool = ({ server, opts }: ToolCo
4848
clientTrafficCheckSkipped: resp.clientTrafficCheckSkipped === true,
4949
hasProposalMatchError:
5050
resp.response?.code === EnumStatusCode.ERR_SCHEMA_MISMATCH_WITH_APPROVED_PROPOSAL,
51+
isLinkedTrafficCheckFailed: resp.isLinkedTrafficCheckFailed,
52+
isLinkedPruningCheckFailed: resp.isLinkedPruningCheckFailed,
5153
}),
5254
},
5355
null,
@@ -68,6 +70,8 @@ const isCheckSuccessful = ({
6870
hasGraphPruningErrors,
6971
clientTrafficCheckSkipped,
7072
hasProposalMatchError,
73+
isLinkedTrafficCheckFailed,
74+
isLinkedPruningCheckFailed,
7175
}: {
7276
isComposable: boolean;
7377
isBreaking: boolean;
@@ -76,7 +80,14 @@ const isCheckSuccessful = ({
7680
hasGraphPruningErrors: boolean;
7781
clientTrafficCheckSkipped: boolean;
7882
hasProposalMatchError: boolean;
83+
isLinkedTrafficCheckFailed?: boolean;
84+
isLinkedPruningCheckFailed?: boolean;
7985
}) => {
86+
// if a subgraph is linked to another subgraph, then the status of the check depends on the traffic and pruning check of the linked subgraph
87+
if (isLinkedTrafficCheckFailed || isLinkedPruningCheckFailed) {
88+
return false;
89+
}
90+
8091
return (
8192
isComposable &&
8293
// If no breaking changes found
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
2+
import { Command, program } from 'commander';
3+
import ora from 'ora';
4+
import pc from 'picocolors';
5+
import { getBaseHeaders } from '../../../core/config.js';
6+
import { BaseCommandOptions } from '../../../core/types/types.js';
7+
8+
export default (opts: BaseCommandOptions) => {
9+
const command = new Command('link');
10+
command.description(
11+
'Links a subgraph to another subgraph on the control plane. When performing schema checks on the source subgraph, traffic and pruning checks will also be performed on the target subgraph. This is useful for verifying the impact of the schema changes before they are propagated to the next environment.',
12+
);
13+
command.argument('<source-subgraph-name>', 'The name of the subgraph to link.');
14+
command.option('-n, --namespace <string>', 'The namespace of the source subgraph.', 'default');
15+
command.requiredOption(
16+
'-t, --target-subgraph <string>',
17+
'The name of the subgraph to link to. Format: <namespace>/<subgraph-name>',
18+
);
19+
20+
command.action(async (name, options) => {
21+
// Split on all slashes, take first as namespace, join rest as subgraph name
22+
const [targetNamespace, ...rest] = options.targetSubgraph.split('/');
23+
if (!targetNamespace || rest.length === 0) {
24+
program.error('Target subgraph must be in the format <namespace>/<subgraph-name>');
25+
}
26+
27+
const targetSubgraphName = rest.join('/');
28+
29+
// Prevent self-linking
30+
if (options.namespace === targetNamespace && name === targetSubgraphName) {
31+
program.error('The source and target subgraphs cannot be the same subgraphs.');
32+
}
33+
34+
const spinner = ora(`The subgraph "${name}" is being linked to "${targetSubgraphName}"...`).start();
35+
36+
const resp = await opts.client.platform.linkSubgraph(
37+
{
38+
sourceSubgraphName: name,
39+
sourceSubgraphNamespace: options.namespace,
40+
targetSubgraphName,
41+
targetSubgraphNamespace: targetNamespace,
42+
},
43+
{
44+
headers: getBaseHeaders(),
45+
},
46+
);
47+
48+
if (resp.response?.code === EnumStatusCode.OK) {
49+
spinner.succeed('Subgraph was linked successfully.');
50+
} else {
51+
spinner.fail('Failed to link subgraph.');
52+
if (resp.response?.details) {
53+
console.log(pc.red(pc.bold(resp.response?.details)));
54+
}
55+
process.exitCode = 1;
56+
// eslint-disable-next-line no-useless-return
57+
return;
58+
}
59+
});
60+
61+
return command;
62+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
2+
import { Command } from 'commander';
3+
import ora from 'ora';
4+
import pc from 'picocolors';
5+
import { getBaseHeaders } from '../../../core/config.js';
6+
import { BaseCommandOptions } from '../../../core/types/types.js';
7+
8+
export default (opts: BaseCommandOptions) => {
9+
const command = new Command('unlink');
10+
command.description('Unlinks a subgraph from another subgraph on the control plane.');
11+
command.argument('<source-subgraph-name>', 'The name of the subgraph to unlink.');
12+
command.option('-n, --namespace <string>', 'The namespace of the source subgraph.', 'default');
13+
14+
command.action(async (name, options) => {
15+
const spinner = ora(`The subgraph "${name}" is being unlinked...`).start();
16+
17+
const resp = await opts.client.platform.unlinkSubgraph(
18+
{
19+
sourceSubgraphName: name,
20+
sourceSubgraphNamespace: options.namespace,
21+
},
22+
{
23+
headers: getBaseHeaders(),
24+
},
25+
);
26+
27+
if (resp.response?.code === EnumStatusCode.OK) {
28+
spinner.succeed('Subgraph was unlinked successfully.');
29+
} else {
30+
spinner.fail('Failed to unlink subgraph.');
31+
if (resp.response?.details) {
32+
console.log(pc.red(pc.bold(resp.response?.details)));
33+
}
34+
process.exitCode = 1;
35+
// eslint-disable-next-line no-useless-return
36+
return;
37+
}
38+
});
39+
40+
return command;
41+
};

cli/src/commands/subgraph/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import ListSubgraphs from './commands/list.js';
1111
import IntrospectSubgraph from './commands/introspect.js';
1212
import MoveSubgraph from './commands/move.js';
1313
import FetchSubgraph from './commands/fetch.js';
14+
import LinkSubgraph from './commands/link.js';
15+
import UnlinkSubgraph from './commands/unlink.js';
1416

1517
export default (opts: BaseCommandOptions) => {
1618
const command = new Command('subgraph');
@@ -25,6 +27,8 @@ export default (opts: BaseCommandOptions) => {
2527
command.addCommand(IntrospectSubgraph(opts));
2628
command.addCommand(MoveSubgraph(opts));
2729
command.addCommand(FetchSubgraph(opts));
30+
command.addCommand(LinkSubgraph(opts));
31+
command.addCommand(UnlinkSubgraph(opts));
2832

2933
command.hook('preAction', async (thisCmd) => {
3034
await checkAuth();

cli/src/handle-check-result.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,21 @@ export const handleCheckResult = (resp: CheckSubgraphSchemaResponse) => {
228228
console.log(graphPruningIssuesTable.toString());
229229
}
230230

231+
if (resp.isLinkedTrafficCheckFailed || resp.isLinkedPruningCheckFailed) {
232+
finalStatement += success
233+
? `\n\n But this schema change has been linked to a target subgraph and the target subgraph check has failed.`
234+
: `\n\n This schema change has been linked to a target subgraph and the target subgraph check has failed.`;
235+
236+
if (resp.isLinkedTrafficCheckFailed) {
237+
finalStatement += `\n\n The target subgraph check has failed because of client traffic issues.`;
238+
}
239+
240+
if (resp.isLinkedPruningCheckFailed) {
241+
finalStatement += `\n\n The target subgraph check has failed because of graph pruning issues.`;
242+
}
243+
success = false;
244+
}
245+
231246
if (success) {
232247
console.log(
233248
'\n' +

cli/src/handle-proposal-result.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ export const handleProposalResult = (
236236
console.log(graphPruningIssuesTable.toString());
237237
}
238238

239+
if (resp.isLinkedTrafficCheckFailed || resp.isLinkedPruningCheckFailed) {
240+
finalStatement += success
241+
? `\n\n But this schema change has been linked to a target subgraph and the target subgraph check has failed.`
242+
: `\n\n This schema change has been linked to a target subgraph and the target subgraph check has failed.`;
243+
244+
if (resp.isLinkedTrafficCheckFailed) {
245+
finalStatement += `\n\n The target subgraph check has failed because of client traffic issues.`;
246+
}
247+
248+
if (resp.isLinkedPruningCheckFailed) {
249+
finalStatement += `\n\n The target subgraph check has failed because of graph pruning issues.`;
250+
}
251+
success = false;
252+
}
253+
239254
if (success) {
240255
console.log(
241256
'\n' +

0 commit comments

Comments
 (0)