mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
add app deployments seed script (#7521)
This commit is contained in:
parent
ccd5056834
commit
617d48a63a
2 changed files with 284 additions and 0 deletions
|
|
@ -44,6 +44,7 @@
|
|||
"release": "pnpm build:libraries && changeset publish",
|
||||
"release:docs:update-version": "tsx scripts/sync-docker-image-tag-docs.ts",
|
||||
"release:version": "changeset version && pnpm --filter hive-apollo-router-plugin sync-cargo-file && pnpm build:libraries && pnpm --filter @graphql-hive/cli oclif:readme && pnpm run release:docs:update-version",
|
||||
"seed:app-deployments": "tsx scripts/seed-app-deployments.mts",
|
||||
"seed:org": "tsx scripts/seed-organization.mts",
|
||||
"seed:schemas": "tsx scripts/seed-schemas.ts",
|
||||
"seed:usage": "tsx scripts/seed-usage.ts",
|
||||
|
|
|
|||
283
scripts/seed-app-deployments.mts
Normal file
283
scripts/seed-app-deployments.mts
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
/**
|
||||
* Script for seeding app deployments into an existing target.
|
||||
*
|
||||
* Requirements:
|
||||
* - Docker Compose is started (pnpm start)
|
||||
* - FEATURE_FLAGS_APP_DEPLOYMENTS_ENABLED=1 in server .env
|
||||
* - A published schema in the target
|
||||
*
|
||||
* Example:
|
||||
* `TOKEN=<access_token> pnpm seed:app-deployments`
|
||||
*
|
||||
* Where <access_token> is a Target Access Token from the target's Settings page.
|
||||
*/
|
||||
|
||||
const token = process.env.TOKEN || process.env.HIVE_TOKEN;
|
||||
|
||||
if (!token) {
|
||||
console.error('Missing "TOKEN" environment variable.');
|
||||
console.error('Usage: TOKEN=<access_token> pnpm seed:app-deployments');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const graphqlEndpoint = 'http://localhost:3001/graphql';
|
||||
|
||||
async function executeGraphQL<T>(query: string, variables: Record<string, unknown>): Promise<T> {
|
||||
const response = await fetch(graphqlEndpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ query, variables }),
|
||||
});
|
||||
|
||||
const result = (await response.json()) as { data?: T; errors?: Array<{ message: string }> };
|
||||
|
||||
if (result.errors?.length) {
|
||||
throw new Error(`GraphQL Error: ${result.errors.map(e => e.message).join(', ')}`);
|
||||
}
|
||||
|
||||
return result.data as T;
|
||||
}
|
||||
|
||||
const CreateAppDeployment = /* GraphQL */ `
|
||||
mutation CreateAppDeployment($input: CreateAppDeploymentInput!) {
|
||||
createAppDeployment(input: $input) {
|
||||
error {
|
||||
message
|
||||
}
|
||||
ok {
|
||||
createdAppDeployment {
|
||||
id
|
||||
name
|
||||
version
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const AddDocumentsToAppDeployment = /* GraphQL */ `
|
||||
mutation AddDocumentsToAppDeployment($input: AddDocumentsToAppDeploymentInput!) {
|
||||
addDocumentsToAppDeployment(input: $input) {
|
||||
error {
|
||||
message
|
||||
}
|
||||
ok {
|
||||
appDeployment {
|
||||
id
|
||||
name
|
||||
version
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ActivateAppDeployment = /* GraphQL */ `
|
||||
mutation ActivateAppDeployment($input: ActivateAppDeploymentInput!) {
|
||||
activateAppDeployment(input: $input) {
|
||||
error {
|
||||
message
|
||||
}
|
||||
ok {
|
||||
activatedAppDeployment {
|
||||
id
|
||||
name
|
||||
version
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const RetireAppDeployment = /* GraphQL */ `
|
||||
mutation RetireAppDeployment($input: RetireAppDeploymentInput!) {
|
||||
retireAppDeployment(input: $input) {
|
||||
error {
|
||||
message
|
||||
}
|
||||
ok {
|
||||
retiredAppDeployment {
|
||||
id
|
||||
name
|
||||
version
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// Sample GraphQL documents for app deployments
|
||||
const sampleDocuments = [
|
||||
{ hash: 'get-user-query', body: 'query GetUser($id: ID!) { user(id: $id) { id name email } }' },
|
||||
{
|
||||
hash: 'list-users-query',
|
||||
body: 'query ListUsers($limit: Int) { users(limit: $limit) { id name } }',
|
||||
},
|
||||
{
|
||||
hash: 'create-user-mutation',
|
||||
body: 'mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { id name } }',
|
||||
},
|
||||
{
|
||||
hash: 'update-user-mutation',
|
||||
body: 'mutation UpdateUser($id: ID!, $input: UpdateUserInput!) { updateUser(id: $id, input: $input) { id name } }',
|
||||
},
|
||||
{ hash: 'delete-user-mutation', body: 'mutation DeleteUser($id: ID!) { deleteUser(id: $id) }' },
|
||||
{
|
||||
hash: 'get-products-query',
|
||||
body: 'query GetProducts($category: String) { products(category: $category) { id name price } }',
|
||||
},
|
||||
{
|
||||
hash: 'get-product-query',
|
||||
body: 'query GetProduct($id: ID!) { product(id: $id) { id name price description } }',
|
||||
},
|
||||
{
|
||||
hash: 'search-query',
|
||||
body: 'query Search($term: String!) { search(term: $term) { __typename ... on User { id name } ... on Product { id name } } }',
|
||||
},
|
||||
];
|
||||
|
||||
// App deployment configurations to create
|
||||
const appDeployments = [
|
||||
{ name: 'web-app', versions: ['1.0.0', '1.1.0', '1.2.0', '2.0.0'] },
|
||||
{ name: 'mobile-app', versions: ['3.0.0', '3.1.0', '3.2.0'] },
|
||||
{ name: 'admin-dashboard', versions: ['1.0.0', '1.0.1'] },
|
||||
{ name: 'cli-tool', versions: ['0.1.0', '0.2.0', '1.0.0'] },
|
||||
];
|
||||
|
||||
async function createAppDeploymentWithDocuments(
|
||||
appName: string,
|
||||
appVersion: string,
|
||||
documents: Array<{ hash: string; body: string }>,
|
||||
shouldActivate: boolean,
|
||||
shouldRetire: boolean = false,
|
||||
) {
|
||||
// Create the app deployment
|
||||
const createResult = await executeGraphQL<{
|
||||
createAppDeployment: {
|
||||
error: { message: string } | null;
|
||||
ok: {
|
||||
createdAppDeployment: { id: string; name: string; version: string; status: string };
|
||||
} | null;
|
||||
};
|
||||
}>(CreateAppDeployment, { input: { appName, appVersion } });
|
||||
|
||||
if (createResult.createAppDeployment.error) {
|
||||
console.error(
|
||||
` Failed to create ${appName}@${appVersion}:`,
|
||||
createResult.createAppDeployment.error.message,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(` Created ${appName}@${appVersion} (pending)`);
|
||||
|
||||
// Add documents
|
||||
const addDocsResult = await executeGraphQL<{
|
||||
addDocumentsToAppDeployment: {
|
||||
error: { message: string } | null;
|
||||
ok: { appDeployment: { id: string } } | null;
|
||||
};
|
||||
}>(AddDocumentsToAppDeployment, { input: { appName, appVersion, documents } });
|
||||
|
||||
if (addDocsResult.addDocumentsToAppDeployment.error) {
|
||||
console.error(
|
||||
` Failed to add documents to ${appName}@${appVersion}:`,
|
||||
addDocsResult.addDocumentsToAppDeployment.error.message,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(` Added ${documents.length} documents to ${appName}@${appVersion}`);
|
||||
|
||||
if (shouldActivate) {
|
||||
const activateResult = await executeGraphQL<{
|
||||
activateAppDeployment: {
|
||||
error: { message: string } | null;
|
||||
ok: { activatedAppDeployment: { id: string } } | null;
|
||||
};
|
||||
}>(ActivateAppDeployment, { input: { appName, appVersion } });
|
||||
|
||||
if (activateResult.activateAppDeployment.error) {
|
||||
console.error(
|
||||
` Failed to activate ${appName}@${appVersion}:`,
|
||||
activateResult.activateAppDeployment.error.message,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(` Activated ${appName}@${appVersion}`);
|
||||
|
||||
if (shouldRetire) {
|
||||
const retireResult = await executeGraphQL<{
|
||||
retireAppDeployment: {
|
||||
error: { message: string } | null;
|
||||
ok: { retiredAppDeployment: { id: string } } | null;
|
||||
};
|
||||
}>(RetireAppDeployment, { input: { appName, appVersion } });
|
||||
|
||||
if (retireResult.retireAppDeployment.error) {
|
||||
console.error(
|
||||
` Failed to retire ${appName}@${appVersion}:`,
|
||||
retireResult.retireAppDeployment.error.message,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(` Retired ${appName}@${appVersion}`);
|
||||
}
|
||||
}
|
||||
|
||||
return createResult.createAppDeployment.ok?.createdAppDeployment;
|
||||
}
|
||||
|
||||
console.log(`
|
||||
GraphQL endpoint: ${graphqlEndpoint}
|
||||
`);
|
||||
|
||||
console.log('Creating app deployments...\n');
|
||||
|
||||
for (const app of appDeployments) {
|
||||
console.log(`Creating deployments for ${app.name}:`);
|
||||
|
||||
for (let i = 0; i < app.versions.length; i++) {
|
||||
const version = app.versions[i];
|
||||
const isLatest = i === app.versions.length - 1;
|
||||
const isOldest = i === 0;
|
||||
|
||||
// Select a subset of documents for variety
|
||||
const docsToUse = sampleDocuments.slice(0, 3 + (i % 5));
|
||||
|
||||
// Activate all versions, retire old ones (except the latest)
|
||||
const shouldActivate = true;
|
||||
const shouldRetire = !isLatest && isOldest;
|
||||
|
||||
await createAppDeploymentWithDocuments(
|
||||
app.name,
|
||||
version,
|
||||
docsToUse,
|
||||
shouldActivate,
|
||||
shouldRetire,
|
||||
);
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Create one pending deployment (not activated)
|
||||
console.log('Creating a pending deployment:');
|
||||
await createAppDeploymentWithDocuments(
|
||||
'beta-app',
|
||||
'0.0.1-beta',
|
||||
sampleDocuments.slice(0, 2),
|
||||
false, // Don't activate
|
||||
);
|
||||
|
||||
console.log('\n========================================');
|
||||
console.log('App deployments seeded successfully!');
|
||||
console.log('========================================\n');
|
||||
Loading…
Reference in a new issue