#Returning a JSON object type
1 messages · Page 1 of 1 (latest)
You can return stdout from an executed function then pipe that to where ever you need it.
dagger core container from --address=alpine/git with-exec --args=git,version stdout
✔ connect 0.2s
✔ loading type definitions 0.2s
✔ parsing command line arguments 0.0s
✔ container: Container! 0.0s
$ .from(address: "alpine/git"): Container! 0.5s CACHED
✔ .withExec(args: ["git", "version"]): Container! 0.1s
✔ .stdout: String! 0.1s
git version 2.47.2
Even if I try to type it I get a stack overflow, probably because the type is recursive?
export type JsonPrimitive = string | number | boolean | null;
export type JsonArray = Json[];
export type JsonObject = { [key: string]: Json };
export type JsonComposite = JsonArray | JsonObject;
export type Json = JsonPrimitive | JsonComposite;
type HelmReleaseConfig = {
chart: string;
version?: string;
namespace: string;
release: string;
values?: Json;
};
Error
│ ✘ inspecting module metadata 0.0s
│ ! input: failed to get schema: failed to select introspection JSON file: select: introspection query failed: input:
│ ! __schema.types[59].fields[4].type.ofType panic while resolving __Type.ofType: unknown type: Json
│ ! goroutine 10412586 [running]:
...
Unfortunately GraphQL doesn't support maps, and by extension neither does Dagger.
If you remove the map it should work.
Would you mind filing an issue to help us prioritize a solution?
Sorry!
@misty arch so what's the work around for now? Pass everything around as a string and parse it at the point of use at runtime?
It depends what your API is currently, could you share some code? What's the goal of the module?
You can get an idea from the snippet above.
Basically I have a complicated pipeline, that orchestrates the setup of an environment.
The environment is supposed to be configurable, so I'm providing the ability to specify what Helm charts to install, and what values should be provided when installing the release.
values is essentially of type JSON, as I can't know ahead of time what Helm chart they'll want to use and therefore what the valid values for the chart will be. So I just want to assume any valid JSON object is fine, and have the helm command error in the case where they've made a mistake.
I don't see a snippet anywhere. But it seems like you have an argument values and that's what causes the introspection error.
How do you expect callers will pass that argument? Will it be from reading an existing values file, or by passing explicit values in code? Or both?
Maybe a simpler example will help convey the issue better.
import { argument, File, func, object } from '@dagger.io/dagger'
import { z } from 'zod';
const HelmReleaseSchema = z.object({
chart: z.string(),
version: z.string().optional(),
namespace: z.string(),
release: z.string(),
values: z.array(z.string()).optional(), // WORKAROUND: Should be valid JSON object not a string
});
// Cannot use this because of because it causes IntrospectionError
// type HelmRelease = z.infer<typeof HelmReleaseSchema>;
type HelmRelease = {
chart: string;
version?: string;
namespace: string;
release: string;
values?: string[]; // WORKAROUND: Should be valid JSON object not a string
};
const ConfigSchema = z.object({
releases: z.array(HelmReleaseSchema),
});
// Cannot use this because of because it causes IntrospectionError
// type Config = z.infer<typeof ConfigSchema>;
type Config = {
releases: HelmRelease[];
}
@object()
export class Dagger {
config: Config;
configFile: File;
constructor(
@argument({ defaultPath: './config.json' })
configFile: File,
) {
this.configFile = configFile;
}
@func()
provision(): void {
console.debug('Provisioning with the following config...');
console.debug(JSON.stringify(this.config, null, 2));
// TODO: Implement provisioning logic
}
@func()
async setup(): Promise<Config> {
const configFileContent = await this.configFile.contents();
// Validates the config file content against the schema
this.config = ConfigSchema.parse(JSON.parse(configFileContent)) as Config;
// Stores the config for later use
this.provision();
return this.config;
}
}
thanks.
I will make the assumption that the most common way clients will pass helm values, is straight from a values.yaml file. So I recommend passing them as a dagger.File type.
The config file doesn't just include Helm values in practice it has many options about the setup of the automation, in fact most of the helm things are taken from a default config object embedded in the module with parts of it overridden at runtime.
Ah ok, so you have your own custom config file which includes helm values and also other non-helm configuration? and you want your dagger module to natively understand that config format?