mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
283 lines
7.7 KiB
TypeScript
283 lines
7.7 KiB
TypeScript
/**
|
|
* 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');
|