Skip to content
Merged
Show file tree
Hide file tree
Changes from 98 commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
29bb604
feat: cli updates
SkArchon Oct 21, 2025
e1c3dbd
fix: updates
SkArchon Oct 21, 2025
cc08a5b
feat: cli updates
SkArchon Oct 22, 2025
5e68f51
feat: cli updates
SkArchon Oct 22, 2025
c2f32f7
fix: cli
SkArchon Oct 22, 2025
be23381
fix: updates
SkArchon Oct 22, 2025
9053591
fix: updates
SkArchon Oct 22, 2025
7abe72f
fix: updates
SkArchon Oct 23, 2025
009ea52
fix: add health check service and move go router plugin
SkArchon Oct 23, 2025
f962e9d
fix: updates
SkArchon Oct 23, 2025
809ae2e
fix: router plugin
SkArchon Oct 27, 2025
1c480c5
fix: updates
SkArchon Oct 27, 2025
d41a606
fix: updates
SkArchon Oct 27, 2025
f6f7b61
fix: updates
SkArchon Oct 27, 2025
6ea8136
fix: updates
SkArchon Oct 27, 2025
2f4a1cc
fix: updates
SkArchon Oct 27, 2025
81d8e08
fix: updates
SkArchon Oct 27, 2025
1eb5db5
fix: updates
SkArchon Oct 27, 2025
52adc57
fix: updates
SkArchon Oct 27, 2025
11347a8
fix: updates
SkArchon Oct 28, 2025
f423a92
fix: updates
SkArchon Oct 28, 2025
6ab77e9
fix: cleanup
SkArchon Oct 28, 2025
19e1f19
fix: revert
SkArchon Oct 28, 2025
a06c05c
fix: cleanup
SkArchon Oct 28, 2025
a6a1255
fix: cleanup
SkArchon Oct 28, 2025
5cda4dc
fix: cleanup
SkArchon Oct 28, 2025
e0025be
fix: updates
SkArchon Oct 28, 2025
df8c076
fix: templates
SkArchon Oct 28, 2025
6eace15
fix: templates
SkArchon Oct 28, 2025
10be6cb
fix: updates
SkArchon Oct 28, 2025
6c1de9f
fix: lint changes
SkArchon Oct 28, 2025
4897a0f
fix: linting
SkArchon Oct 28, 2025
2a0292e
fix: updates
SkArchon Oct 28, 2025
69c434f
fix: updates
SkArchon Oct 29, 2025
a94f90f
fix: changes
SkArchon Oct 29, 2025
773d616
fix: temp
SkArchon Oct 29, 2025
df92322
fix: updates
SkArchon Oct 29, 2025
f8b2145
fix: updates
SkArchon Oct 29, 2025
c94513f
fix: updates
SkArchon Oct 29, 2025
40a3d48
fix: updates
SkArchon Oct 29, 2025
dc15d41
fix: refactoring
SkArchon Oct 29, 2025
c7229ae
fix: refactoring
SkArchon Oct 29, 2025
5340a19
fix: updates
SkArchon Oct 29, 2025
48831fd
fix: ci changes
SkArchon Oct 29, 2025
5feb446
fix: refactoring
SkArchon Oct 29, 2025
30f48e6
fix: ci updates
SkArchon Oct 29, 2025
7f4d714
fix: ci updates
SkArchon Oct 29, 2025
0f9c289
fix: updates
SkArchon Oct 29, 2025
2dddf0c
fix: refactoring`
SkArchon Oct 29, 2025
4bb7b10
fix: revert
SkArchon Oct 29, 2025
4bb5dd2
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Oct 29, 2025
56f4e28
fix: review comments
SkArchon Oct 29, 2025
f5a7089
fix: updates
SkArchon Oct 29, 2025
ee9307a
fix: recompile templates
SkArchon Oct 29, 2025
a00ed32
fix: cleanup
SkArchon Oct 29, 2025
4e25bd4
fix: cleanup
SkArchon Oct 29, 2025
f20ff83
fix: updates
SkArchon Oct 29, 2025
db1d2f0
fix: refactoring
SkArchon Oct 29, 2025
489b50a
fix: linting
SkArchon Oct 29, 2025
760d277
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Oct 29, 2025
747854a
fix: refactoring
SkArchon Oct 29, 2025
10125cc
fix: templates
SkArchon Oct 29, 2025
fc4bf7f
fix: platform updates
SkArchon Oct 30, 2025
c1580f2
fix: linting
SkArchon Oct 30, 2025
c9340e2
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Oct 30, 2025
c2d0b81
fix: tests
SkArchon Oct 30, 2025
4dce726
fix: templates
SkArchon Oct 30, 2025
a91f3dd
fix: tests
SkArchon Oct 30, 2025
8a5bda0
fix: revert
SkArchon Oct 30, 2025
d4c8b78
fix: formatting
SkArchon Oct 30, 2025
1672582
fix: update imports`
SkArchon Oct 30, 2025
7883122
fix: demonstration
SkArchon Oct 30, 2025
6fbd524
fix: update configuration
SkArchon Oct 30, 2025
e553b06
fix: diff testing
SkArchon Oct 30, 2025
1991bf0
fix: diff updates
SkArchon Oct 30, 2025
349e5b1
fix: project updates
SkArchon Oct 30, 2025
10594aa
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Nov 5, 2025
4a9234b
fix: patch the grpc health check node modules
SkArchon Nov 10, 2025
1291745
fix: template compilation
SkArchon Nov 10, 2025
22f7c5b
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Nov 10, 2025
d27a5f3
fix: local builds
SkArchon Nov 11, 2025
3e523e8
fix: spinner updating
SkArchon Nov 11, 2025
a80cf59
fix: ts tests
SkArchon Nov 15, 2025
770c4ba
fix: tests
SkArchon Nov 15, 2025
49812b6
Merge remote-tracking branch 'origin/main' into milinda/eng-7174-supp…
SkArchon Nov 15, 2025
04b622b
fix: linting
SkArchon Nov 15, 2025
42273e1
fix: update makefile
SkArchon Nov 15, 2025
10ba33e
fix: plugin build
SkArchon Nov 15, 2025
3a08009
fix: workflows
SkArchon Nov 15, 2025
1238bb2
fix: ci updates
SkArchon Nov 15, 2025
9d291a2
fix: courses updates
SkArchon Nov 15, 2025
07437fc
fix: go module
SkArchon Nov 15, 2025
a95f179
fix: enable debugging
SkArchon Nov 15, 2025
acb1628
fix: linting
SkArchon Nov 15, 2025
2b4e469
fix: package updating
SkArchon Nov 15, 2025
6344161
fix: protographic changes
SkArchon Nov 17, 2025
7b53b98
fix: protographic
SkArchon Nov 17, 2025
80c71dd
fix: mutation dirty data
SkArchon Nov 17, 2025
b6242ec
fix: review comments
SkArchon Nov 17, 2025
c757d2e
fix: inquire patch
SkArchon Nov 18, 2025
fe4fe83
fix: tool installation
SkArchon Nov 18, 2025
febcbcc
fix: hash update
SkArchon Nov 18, 2025
66fce76
fix: errors compilation
SkArchon Nov 18, 2025
ba8f5c8
fix: linting
SkArchon Nov 18, 2025
8b77e0b
fix: linting
SkArchon Nov 18, 2025
14702fb
fix: add node for protoc libraries
SkArchon Nov 18, 2025
c0c95fb
fix: new flags
SkArchon Nov 18, 2025
0c4c3ac
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Nov 18, 2025
49f53d4
Merge branch 'main' into milinda/eng-7174-support-grpc-plugins-with-b…
SkArchon Nov 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/cli-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ jobs:
- name: Generate code
run: pnpm buf generate --template buf.ts.gen.yaml

- name: Generate router templates
run: pnpm --filter ./cli compile-templates

- name: Check if git is not dirty after generating files
run: git diff --no-ext-diff --exit-code

Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/router-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ jobs:
- name: Install tools
run: make setup-build-tools

- name: Install Bun For Plugin Building
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.15

- name: Generate code
run: make generate-go

Expand Down Expand Up @@ -127,6 +132,11 @@ jobs:
- name: Install tools
run: make setup-build-tools

- name: Install Bun For Plugin Building
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.15

- name: Generate code
run: make generate-go

Expand Down Expand Up @@ -299,6 +309,12 @@ jobs:
router-tests/go.sum
- name: Install tools
run: make setup-build-tools

- name: Install Bun For Plugin Building
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.15

- name: Install dependencies
working-directory: ./router-tests
run: go mod download
Expand Down
3 changes: 3 additions & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"url": "https://github.com/wundergraph/cosmo"
},
"scripts": {
"compile-templates": "tsx scripts/compile-templates.ts && prettier --write src/commands/router/commands/plugin/templates/*.ts",
"prebuild": "npm run compile-templates",
"prebuild:bun": "bun run compile-templates",
"build": "rm -rf dist && tsc",
"build:bun": "bun build --compile --production --outfile wgc src/index.ts",
"wgc": "tsx --env-file .env src/index.ts",
Expand Down
103 changes: 103 additions & 0 deletions cli/scripts/compile-templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { readFileSync, writeFileSync, readdirSync } from 'node:fs';
import { join, basename } from 'node:path';

interface TemplateMap {
[key: string]: string;
}

// Convert file names to camelCase property names
function fileNameToPropertyName(fileName: string): string {
// Remove .template extension
let name = fileName.replace('.template', '');

// Handle special cases for dotfiles
if (name.startsWith('.')) {
name = name.slice(1); // Remove the dot
}

// Convert to camelCase
// Split by dots, dashes, underscores, and spaces
const parts = name.split(/[ ._-]/);

return parts
.map((part, index) => {
// Normalize all-caps words (like README -> Readme)
if (part === part.toUpperCase() && part.length > 1) {
part = part.charAt(0) + part.slice(1).toLowerCase();
}

if (index === 0) {
// First part: lowercase first char, preserve rest
return part.charAt(0).toLowerCase() + part.slice(1);
}
// Subsequent parts: uppercase first char, preserve rest
return part.charAt(0).toUpperCase() + part.slice(1);
})
.join('');
}

function compileTemplates(dir: string, outputFile: string, comment?: string) {
const files = readdirSync(dir).filter((f) => f.endsWith('.template'));

if (files.length === 0) {
console.log(`No templates found in ${dir}`);
return;
}

const templates: TemplateMap = {};

for (const file of files) {
const filePath = join(dir, file);
const content = readFileSync(filePath, 'utf8');

// Convert file name to property name
const key = fileNameToPropertyName(file);
templates[key] = content;
}

// Generate TypeScript file
const lines: string[] = [];

if (comment) {
lines.push(`// ${comment}`);
}
lines.push('// This file is auto-generated. Do not edit manually.');
lines.push('/* eslint-disable no-template-curly-in-string */');
lines.push('');

// Create const declarations
for (const [key, content] of Object.entries(templates)) {
lines.push(`const ${key} = ${JSON.stringify(content)};`);
lines.push('');
}

// Export default object
lines.push('export default {');
for (const key of Object.keys(templates)) {
lines.push(` ${key},`);
}
lines.push('};');
lines.push('');

writeFileSync(outputFile, lines.join('\n'), 'utf8');
console.log(`Generated ${outputFile} with ${files.length} templates`);
}

// Compile all template subdirectories, generating <templates>/<folder>.ts in the templates root
const templatesDir = 'src/commands/router/commands/plugin/templates';

const entries = readdirSync(templatesDir, { withFileTypes: true });
const subdirs = entries.filter((e: any) => e.isDirectory());

if (subdirs.length === 0) {
console.log(`No template subdirectories found in ${templatesDir}`);
} else {
for (const dirent of subdirs) {
const dirName = dirent.name;
const dirPath = join(templatesDir, dirName);
const outFile = join(templatesDir, `${dirName}.ts`);
const comment = `Templates for ${dirName} (templating is done by pupa)`;
compileTemplates(dirPath, outFile, comment);
}
console.log('All templates compiled successfully');
}
10 changes: 9 additions & 1 deletion cli/src/commands/grpc-service/commands/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
compileGraphQLToMapping,
compileGraphQLToProto,
ProtoLock,
ProtoOption,
validateGraphQLSDL,
} from '@wundergraph/protographic';
import { Command, program } from 'commander';
Expand All @@ -11,6 +12,7 @@ import Spinner, { type Ora } from 'ora';
import { resolve } from 'pathe';
import { BaseCommandOptions } from '../../../core/types/types.js';
import { renderResultTree, renderValidationResults } from '../../router/commands/plugin/helper.js';
import { getGoModulePathProtoOption } from '../../router/commands/plugin/toolchain.js';

type CLIOptions = {
input: string;
Expand Down Expand Up @@ -135,11 +137,17 @@ async function generateProtoAndMapping({
// Continue with generation if validation passed (no errors)
spinner.text = 'Generating mapping and proto files...';
const mapping = compileGraphQLToMapping(schema, serviceName);

const protoOptions: ProtoOption[] = [];
if (goPackage) {
protoOptions.push(getGoModulePathProtoOption(goPackage!));
}

const proto = compileGraphQLToProto(schema, {
serviceName,
packageName,
goPackage,
lockData,
protoOptions,
});

return {
Expand Down
85 changes: 59 additions & 26 deletions cli/src/commands/router/commands/plugin/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import os from 'node:os';
import { Command, program } from 'commander';
import { resolve } from 'pathe';
import Spinner from 'ora';
import { ProtoOption } from '@wundergraph/protographic';
import { BaseCommandOptions } from '../../../../../core/types/types.js';
import { renderResultTree } from '../helper.js';
import {
buildBinaries,
buildGoBinaries,
checkAndInstallTools,
generateGRPCCode,
generateProtoAndMapping,
HOST_PLATFORM,
getLanguage,
installGoDependencies,
installTsDependencies,
typeCheckTs,
buildTsBinaries,
normalizePlatforms,
validateAndGetGoModulePath,
getGoModulePathProtoOption,
} from '../toolchain.js';

export default (opts: BaseCommandOptions) => {
Expand All @@ -21,28 +27,35 @@ export default (opts: BaseCommandOptions) => {
command.argument('[directory]', 'Directory of the plugin', '.');
command.option('--generate-only', 'Generate only the proto and mapping files, do not compile the plugin');
command.option('--debug', 'Build the binary with debug information', false);
command.option('--platform [platforms...]', 'Platform-architecture combinations (e.g., darwin-arm64 linux-amd64)', [
HOST_PLATFORM,
]);
command.option(
'--platform [platforms...]',
'Platform-architecture combinations (e.g., darwin-arm64 linux-amd64)',
[],
);
command.option('--all-platforms', 'Build for all supported platforms', false);
command.option('--skip-tools-installation', 'Skip tool installation', false);
command.option(
'--force-tools-installation',
'Force tools installation regardless of version check or confirmation',
false,
);
command.option(
'--go-module-path <path>',
'Go module path to use for the plugin',
'github.com/wundergraph/cosmo/plugin',
);
command.option('--go-module-path <path>', 'Go module path to use for the plugin');

command.action(async (directory, options) => {
const startTime = performance.now();
const pluginDir = resolve(directory);
const spinner = Spinner();
const pluginName = path.basename(pluginDir);
const goModulePath = options.goModulePath;

const language = getLanguage(pluginDir);
if (!language) {
renderResultTree(spinner, 'Plugin language detection failed!', false, pluginName, {
output: pluginDir,
});
program.error('');
}

const protoOptions: ProtoOption[] = [];
let platforms: string[] = [];

try {
Expand All @@ -51,24 +64,44 @@ export default (opts: BaseCommandOptions) => {
await checkAndInstallTools(options.forceToolsInstallation);
}

// Normalize platform list
platforms = normalizePlatforms(options.platform, options.allPlatforms);

// Start the main build process
spinner.start('Building plugin...');

const goModulePath = validateAndGetGoModulePath(language, options.goModulePath);

switch (language) {
case 'ts': {
await installTsDependencies(pluginDir, spinner);
break;
}
case 'go': {
protoOptions.push(getGoModulePathProtoOption(goModulePath!));
break;
}
}

// Normalize platform list
platforms = normalizePlatforms(options.platform, options.allPlatforms, language);

// Generate proto and mapping files
await generateProtoAndMapping(pluginDir, goModulePath, spinner);
await generateProtoAndMapping(pluginDir, protoOptions, spinner);

// Generate gRPC code
await generateGRPCCode(pluginDir, spinner);
await generateGRPCCode(pluginDir, spinner, language);

if (!options.generateOnly) {
// Install Go dependencies
await installGoDependencies(pluginDir, spinner);

// Build binaries for all platforms
await buildBinaries(pluginDir, platforms, options.debug, spinner);
switch (language) {
case 'go': {
await installGoDependencies(pluginDir, spinner);
await buildGoBinaries(pluginDir, platforms, options.debug, spinner);
break;
}
case 'ts': {
await typeCheckTs(pluginDir, spinner);
await buildTsBinaries(pluginDir, platforms, options.debug, spinner);
break;
}
}
}

// Calculate and format elapsed time
Expand All @@ -79,24 +112,24 @@ export default (opts: BaseCommandOptions) => {

renderResultTree(spinner, 'Plugin built successfully!', true, pluginName, {
output: pluginDir,
'go module': goModulePath,
platforms: platforms.join(', '),
env: `${os.platform()} ${os.arch()}`,
build: options.debug ? 'debug' : 'release',
type: options.generateOnly ? 'generate-only' : 'full',
time: formattedTime,
protoOptions: protoOptions.join(','),
});
} catch (error: any) {
renderResultTree(spinner, 'Plugin build failed!', false, pluginName, {
const details: Record<string, any> = {
output: pluginDir,
'go module': goModulePath,
platforms: platforms.join(', '),
env: `${os.platform()} ${os.arch()}`,
build: options.debug ? 'debug' : 'release',
type: options.generateOnly ? 'generate-only' : 'full',
error: error.message,
});

protoOptions: protoOptions.join(','),
};
renderResultTree(spinner, 'Plugin build failed!', false, pluginName, details);
program.error('');
}
});
Expand Down
Loading
Loading