diff --git a/.grit/workflows/stainless-gritql-generator/config/.terraform.lock.hcl b/.grit/workflows/stainless-gritql-generator/config/.terraform.lock.hcl deleted file mode 100644 index f635a6ded34..00000000000 --- a/.grit/workflows/stainless-gritql-generator/config/.terraform.lock.hcl +++ /dev/null @@ -1,25 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/cloudflare/cloudflare" { - version = "4.36.0" - constraints = "~> 4.0" - hashes = [ - "h1:zjzavjIdLDGRYsWd3v0HJz6ul12Cewj9RW/cqAQ4DxI=", - "zh:02665712b3893307596b3caab99cf1f2502d5caca18e22d4b37bb535e628e102", - "zh:1514b0d3ef62934484ac471113ee68cddec0c21e56b4f710922741fe9b6e6fdf", - "zh:1fab4dfcecbcea13267b42e5ff05ba0692aa2dcb247b8e633fea0daf49feb156", - "zh:24d8367295fe1f1b2be37802aecb96edf32f743364663ffe781d1bb92438395d", - "zh:34e84e7940c99dcf65663cfd25afac22bf5c8a5ff2cd21900c67180d3a072be9", - "zh:3d71d63204a329acf1d1de8638f2c725243cb94cf444d2d7acde54b3d1ac1696", - "zh:57831ba88e779a762bcfa224ba9eac8bc22ef9cd70cd541d848b351e0ba6a75c", - "zh:6407560f2e548afcb4852c91efc664627a9ee565c31a9c81fc9ea1806fca0567", - "zh:738ddbc664d75f4859aa09444a27809bc398795a8ea8f5be8531040690287712", - "zh:841ca2b2d78b6f8d33ec3435bc090c5e04a3a7d85c80df11227a7ea00d36f6b1", - "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", - "zh:8b3d3d63354032ab9b2403c50728e9aa4e83c7367eaad2d18794221addeafc0f", - "zh:9e293443fe3127e488f540229983c1b9688268185f87567bb3d18e794697acd2", - "zh:b3a22439156e46461213db183e2e89569cd2e8d7cbcfc4b9f90469090e105807", - "zh:f430feb5d51891e84028459e57039045dea4f1f5fcf671161d8ac2d8f28763f3", - ] -} diff --git a/.grit/workflows/stainless-gritql-generator/.gitignore b/.grit/workflows/stainless/.gitignore similarity index 100% rename from .grit/workflows/stainless-gritql-generator/.gitignore rename to .grit/workflows/stainless/.gitignore diff --git a/.grit/workflows/stainless-gritql-generator/__fixtures__/basic.after/main.tf b/.grit/workflows/stainless/__fixtures__/basic.after/main.tf similarity index 100% rename from .grit/workflows/stainless-gritql-generator/__fixtures__/basic.after/main.tf rename to .grit/workflows/stainless/__fixtures__/basic.after/main.tf diff --git a/.grit/workflows/stainless-gritql-generator/__fixtures__/basic.before/main.tf b/.grit/workflows/stainless/__fixtures__/basic.before/main.tf similarity index 100% rename from .grit/workflows/stainless-gritql-generator/__fixtures__/basic.before/main.tf rename to .grit/workflows/stainless/__fixtures__/basic.before/main.tf diff --git a/.grit/workflows/stainless-gritql-generator/config/main.tf b/.grit/workflows/stainless/config/main.tf similarity index 100% rename from .grit/workflows/stainless-gritql-generator/config/main.tf rename to .grit/workflows/stainless/config/main.tf diff --git a/.grit/workflows/stainless-gritql-generator/new.json b/.grit/workflows/stainless/new.json similarity index 100% rename from .grit/workflows/stainless-gritql-generator/new.json rename to .grit/workflows/stainless/new.json diff --git a/.grit/workflows/stainless-gritql-generator/old.json b/.grit/workflows/stainless/old.json similarity index 100% rename from .grit/workflows/stainless-gritql-generator/old.json rename to .grit/workflows/stainless/old.json diff --git a/.grit/workflows/stainless/workflow.js b/.grit/workflows/stainless/workflow.js new file mode 100644 index 00000000000..2f3922b83ab --- /dev/null +++ b/.grit/workflows/stainless/workflow.js @@ -0,0 +1,107 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var sdk = require("@getgrit/workflows-sdk"); +var grit = require("@getgrit/api"); +var fs_1 = require("fs"); +var zod_1 = require("zod"); +var BlockTypeSchema = zod_1.z.object({ + nesting_mode: zod_1.z.string(), +}); +var ResourceSchema = zod_1.z.object({ + block: zod_1.z.object({ + block_types: zod_1.z.record(BlockTypeSchema).optional(), + }) +}); +var CloudflareSchema = zod_1.z.object({ + format_version: zod_1.z.string(), + provider_schemas: zod_1.z.record(zod_1.z.object({ + resource_schemas: zod_1.z.record(ResourceSchema), + })), +}); +function findListNestingModeBlockTypes(schema) { + var results = []; + var cloudflareSchema = schema.provider_schemas["registry.terraform.io/cloudflare/cloudflare"]; + var resourceSchemas = cloudflareSchema.resource_schemas; + for (var _i = 0, _a = Object.entries(resourceSchemas); _i < _a.length; _i++) { + var _b = _a[_i], resourceName = _b[0], resourceSchema = _b[1]; + if (resourceSchema.block_types) { + for (var _c = 0, _d = Object.entries(resourceSchema.block_types); _c < _d.length; _c++) { + var _e = _d[_c], attributeName = _e[0], blockType = _e[1]; + if (blockType.nesting_mode === "list") { + results.push({ resource: resourceName, attribute: attributeName }); + } + } + } + } + return results; +} +var schema = { + $schema: 'https://json-schema.org/draft/2020-12/schema', + type: 'object', + properties: { + old_schema_path: { type: 'string' }, + }, + required: ['query'], +}; +exports.default = await sdk.defineWorkflow({ + name: 'workflow', + options: schema, + run: function (options) { return __awaiter(void 0, void 0, void 0, function () { + var oldSchemaPath, oldSchemaData, oldSchema, results; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log('Running workflow'); + grit.logging.info('Generating a GritQL migration for the provided Terraform schema'); + oldSchemaPath = options.old_schema_path; + return [4 /*yield*/, fs_1.default.promises.readFile(oldSchemaPath, 'utf-8')]; + case 1: + oldSchemaData = _a.sent(); + oldSchema = CloudflareSchema.parse(JSON.parse(oldSchemaData)); + grit.logging.info("Successfully loaded and validated the old schema at ".concat(JSON.stringify(oldSchema))); + console.log(oldSchema); + results = findListNestingModeBlockTypes(oldSchema); + grit.logging.info("Found ".concat(results.length, " resources with list nesting mode block types")); + return [2 /*return*/, { + success: true + }]; + } + }); + }); }, +}); diff --git a/.grit/workflows/stainless-gritql-generator/workflow.md b/.grit/workflows/stainless/workflow.md similarity index 87% rename from .grit/workflows/stainless-gritql-generator/workflow.md rename to .grit/workflows/stainless/workflow.md index 40fc1f06792..0c7f82cb1ac 100644 --- a/.grit/workflows/stainless-gritql-generator/workflow.md +++ b/.grit/workflows/stainless/workflow.md @@ -39,9 +39,5 @@ Here is an example for the above attribute: ```grit language hcl -`resource "cloudflare_access_application" $_ { $attr }` where { - $attr <: contains bubble or { - `cors_headers { $block }` => `cors_headers = { $block }` - } -} +`cors_headers { $block }` => `cors_headers = { $block }` where { $block <: within `resource "cloudflare_access_application" $_ { $_ }` } ``` diff --git a/.grit/workflows/stainless/workflow.ts b/.grit/workflows/stainless/workflow.ts new file mode 100644 index 00000000000..f96cf552ede --- /dev/null +++ b/.grit/workflows/stainless/workflow.ts @@ -0,0 +1,96 @@ + +import * as sdk from '@getgrit/workflows-sdk'; +import type { JSONSchema7 } from 'json-schema'; +import * as grit from '@getgrit/api'; + +import fs from 'fs'; + +import { z } from "zod"; + +const BlockTypeSchema = z.object({ + nesting_mode: z.string(), +}); + +const ResourceSchema = z.object({ + block: z.object({ + block_types: z.record(BlockTypeSchema).optional(), + }) +}); + +const CloudflareSchema = z.object({ + format_version: z.string(), + provider_schemas: z.record(z.object({ + resource_schemas: z.record(ResourceSchema), + })), +}); + +interface Result { + resource: string; + attribute: string; +} + +function findListNestingModeBlockTypes(schema: z.infer): Result[] { + const results: Result[] = []; + + const cloudflareSchema = schema.provider_schemas["registry.terraform.io/cloudflare/cloudflare"]; + const resourceSchemas = cloudflareSchema.resource_schemas; + + for (const [resourceName, resourceSchema] of Object.entries(resourceSchemas)) { + const blockTypes = resourceSchema.block.block_types; + if (blockTypes) { + for (const [attributeName, blockType] of Object.entries(blockTypes)) { + if (blockType.nesting_mode === "list") { + results.push({ resource: resourceName, attribute: attributeName }); + } + } + } + } + + return results; +} + +const schema = { + $schema: 'https://json-schema.org/draft/2020-12/schema', + type: 'object' as const, + properties: { + old_schema_path: { type: 'string' }, + }, + required: ['query'], +} satisfies JSONSchema7; + +export default await sdk.defineWorkflow({ + name: 'workflow', + options: schema, + + run: async (options) => { + console.log('Running workflow'); + grit.logging.info('Generating a GritQL migration for the provided Terraform schema'); + + const oldSchemaPath = options.old_schema_path; + const oldSchemaData = await fs.promises.readFile(oldSchemaPath, 'utf-8'); + const oldSchema = CloudflareSchema.parse(JSON.parse(oldSchemaData)); + + const results = findListNestingModeBlockTypes(oldSchema); + + grit.logging.info(`Found ${results.length} resources with list nesting mode block types`); + + const subqueries = results.map(({ resource, attribute }) => + ` \`${attribute} { $block }\` => \`${attribute} = { $block }\` where { $block <: within \`resource "${resource}" $_ { $_ }\` }` + ).join(',\n'); + + const query = ` + language hcl + + or { + ${subqueries} + }`; + + console.log(query); + + + return { + success: true, + subqueries, + }; + } +}); \ No newline at end of file