Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ seed/**/.pytest_cache/
seed/**/.mypy_cache/
seed/**/.ruff_cache/
seed/**/*.egg-info/
seed/**/.golangci.yml

# Seed remote-local test outputs, except for seed.yml files
seed-remote-local/*
Expand All @@ -119,5 +120,9 @@ seed-remote-local/*
# Test logs from test-remote-local.sh
test-remote-local-logs-*/

# macOS system dirs leaked by local Poetry/Python execution
seed/**/Library/Application Support/
seed/**/Library/Caches/

# Devbox gradle properties
/gradle.properties
12 changes: 9 additions & 3 deletions devbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
"poetry@1.8",
"jdk@17",
"gradle@8.5",
"ruby@3.3",
"ruby@3.4",
"rubocop@latest",
"php@8.4",
"php84Packages.composer@2.7",
"rustup@latest",
"ruff@0.15",
"buf@1.50.0",
Expand All @@ -28,10 +27,17 @@
"printf '\\033]0;%s\\007' 'fern (devbox)'",
"unset GOROOT # Unset GOROOT from parent shell to avoid conflicts with devbox's Go",
"export PATH=\"$(go env GOPATH)/bin:$PATH\"",
"command -v golangci-lint &>/dev/null || { echo 'Installing golangci-lint...'; go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1 2>/dev/null || true; }",
"mkdir -p \"$HOME/.local/bin\"",
"if [ ! -f \"$HOME/.local/bin/composer\" ]; then echo 'Installing composer...'; curl -sSL https://getcomposer.org/download/latest-2.x/composer.phar -o \"$HOME/.local/bin/composer\" && chmod +x \"$HOME/.local/bin/composer\"; fi",
"if [ ! -f \"$HOME/.local/bin/php-cs-fixer\" ]; then echo 'Installing php-cs-fixer...'; curl -sSL https://cs.symfony.com/download/php-cs-fixer-v3.phar -o \"$HOME/.local/bin/php-cs-fixer\" && chmod +x \"$HOME/.local/bin/php-cs-fixer\"; fi",
"export PATH=\"$HOME/.local/bin:$PATH\"",
"if [ -f /usr/bin/xcrun ]; then mkdir -p \"$HOME/.local/bin\" && ln -sf /usr/bin/xcrun \"$HOME/.local/bin/xcrun\"; fi # Use system xcrun instead of nix xcbuild",
"rustup default stable 2>/dev/null || true",
"rustup component add rustfmt 2>/dev/null || true",
"bash scripts/setup-dotnet.sh 2>/dev/null || true",
"export PATH=\"$HOME/.dotnet:$PATH\"",
"export DOTNET_ROOT=\"$HOME/.dotnet\"",
"export PATH=\"$HOME/.dotnet:$HOME/.dotnet/tools:$PATH\"",
"echo 'Node.js:' $(node --version)",
"echo 'pnpm:' $(pnpm --version 2>/dev/null || echo 'not available')",
"echo 'Go:' $(go version)",
Expand Down
80 changes: 16 additions & 64 deletions devbox.lock
Original file line number Diff line number Diff line change
Expand Up @@ -483,54 +483,6 @@
}
}
},
"php84Packages.composer@2.7": {
"last_modified": "2024-10-02T21:32:52Z",
"resolved": "github:NixOS/nixpkgs/fd698a4ab779fb7fb95425f1b56974ba9c2fa16c#php84Packages.composer",
"source": "devbox-search",
"version": "2.7.9",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/nh3pqv4bsgivzvmc919sqvv8km265c77-composer-2.7.9",
"default": true
}
],
"store_path": "/nix/store/nh3pqv4bsgivzvmc919sqvv8km265c77-composer-2.7.9"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/iardqmy3i0cy4l9r045p7g5qb9dca8p9-composer-2.7.9",
"default": true
}
],
"store_path": "/nix/store/iardqmy3i0cy4l9r045p7g5qb9dca8p9-composer-2.7.9"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/x6z4hy24dn5l9inqcs4a5wm5layiil67-composer-2.7.9",
"default": true
}
],
"store_path": "/nix/store/x6z4hy24dn5l9inqcs4a5wm5layiil67-composer-2.7.9"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/9ajnzd7i6ywxv7mav92032iryrc4jm0g-composer-2.7.9",
"default": true
}
],
"store_path": "/nix/store/9ajnzd7i6ywxv7mav92032iryrc4jm0g-composer-2.7.9"
}
}
},
"php@8.4": {
"last_modified": "2026-03-21T07:29:51Z",
"plugin_version": "0.0.3",
Expand Down Expand Up @@ -750,68 +702,68 @@
}
}
},
"ruby@3.3": {
"last_modified": "2026-01-23T17:20:52Z",
"ruby@3.4": {
"last_modified": "2026-03-21T07:29:51Z",
"plugin_version": "0.0.2",
"resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#ruby",
"resolved": "github:NixOS/nixpkgs/09061f748ee21f68a089cd5d91ec1859cd93d0be#ruby",
"source": "devbox-search",
"version": "3.3.10",
"version": "3.4.8",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/d9wal8y7w1zpvyas3x1q4ykz880mmklk-ruby-3.3.10",
"path": "/nix/store/88sazm3fj9kabg4pxmnjc53cx0syp8fk-ruby-3.4.8",
"default": true
},
{
"name": "devdoc",
"path": "/nix/store/1rfqp0848j3gnm222ls3bipk1azcrrq3-ruby-3.3.10-devdoc"
"path": "/nix/store/mk7a50jsk138apqrnlzc077cik8cr47m-ruby-3.4.8-devdoc"
}
],
"store_path": "/nix/store/d9wal8y7w1zpvyas3x1q4ykz880mmklk-ruby-3.3.10"
"store_path": "/nix/store/88sazm3fj9kabg4pxmnjc53cx0syp8fk-ruby-3.4.8"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/1hlahw0ijkxx1aqy3x41k3gxpgv34g7d-ruby-3.3.10",
"path": "/nix/store/rpcpk0lxd8iliza4nl9apsgrpsb2yk4d-ruby-3.4.8",
"default": true
},
{
"name": "devdoc",
"path": "/nix/store/arvi0gqvw07ngbi2ci20dn5ka2jz5irv-ruby-3.3.10-devdoc"
"path": "/nix/store/9wnq7dd2yw2lbjs69y19lm08ranqa930-ruby-3.4.8-devdoc"
}
],
"store_path": "/nix/store/1hlahw0ijkxx1aqy3x41k3gxpgv34g7d-ruby-3.3.10"
"store_path": "/nix/store/rpcpk0lxd8iliza4nl9apsgrpsb2yk4d-ruby-3.4.8"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/as6xdshxpansvkag8zqr602ajkn9079z-ruby-3.3.10",
"path": "/nix/store/gq0vdqfz16vf64ip8p749rmygxd7n3x1-ruby-3.4.8",
"default": true
},
{
"name": "devdoc",
"path": "/nix/store/wix1487x3br4gxa0il4q6llz5xyqxspl-ruby-3.3.10-devdoc"
"path": "/nix/store/k3yn26wvgk4mfrd5nw4a23wnijd9hz6c-ruby-3.4.8-devdoc"
}
],
"store_path": "/nix/store/as6xdshxpansvkag8zqr602ajkn9079z-ruby-3.3.10"
"store_path": "/nix/store/gq0vdqfz16vf64ip8p749rmygxd7n3x1-ruby-3.4.8"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/6jz2pgmsh06z9a83qi33f6lp9w2q6mzm-ruby-3.3.10",
"path": "/nix/store/s57rf37r1i38kpm3nlv4h8f8z2w2n80d-ruby-3.4.8",
"default": true
},
{
"name": "devdoc",
"path": "/nix/store/kah8xsbcd10iakxqmlw558iarhsrd5vi-ruby-3.3.10-devdoc"
"path": "/nix/store/4k6c15chplw6cicc6f3lgzmi7i4792j6-ruby-3.4.8-devdoc"
}
],
"store_path": "/nix/store/6jz2pgmsh06z9a83qi33f6lp9w2q6mzm-ruby-3.3.10"
"store_path": "/nix/store/s57rf37r1i38kpm3nlv4h8f8z2w2n80d-ruby-3.4.8"
}
}
},
Expand Down
1 change: 1 addition & 0 deletions generators/base/src/AbstractGeneratorAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ReferenceConfigBuilder } from "./reference/index.js";
import { RawGithubConfig, resolveGitHubConfig } from "./utils/index.js";

const FEATURES_CONFIG_PATHS = [
...(process.env.FERN_FEATURES_YML_PATH != null ? [process.env.FERN_FEATURES_YML_PATH] : []),
"/assets/features.yml",
path.join(__dirname, "./features.yml"),
path.join(__dirname, "./assets/features.yml"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,29 @@ export class WrappedEndpointRequest extends EndpointRequest {
fileProperty: FernIr.FileProperty;
}): void {
switch (fileProperty.type) {
case "file":
case "file": {
const fileRef = this.getRequestPropertyReference({
fieldName: fileProperty.key.name,
isFile: true
});
if (fileProperty.isOptional) {
writer.writeNewLineIfLastLineNot();
writer.writeLine(`if ${fileRef} != nil {`);
writer.indent();
}
this.writeFileUploadField({
writer,
key: fileProperty.key.wireValue,
value: go.codeblock(
this.getRequestPropertyReference({ fieldName: fileProperty.key.name, isFile: true })
),
value: go.codeblock(fileRef),
contentType: fileProperty.contentType,
format: "file"
});
if (fileProperty.isOptional) {
writer.dedent();
writer.writeLine("}");
}
break;
}
case "fileArray":
writer.writeLine(
`for _, f := range ${this.getRequestPropertyReference({ fieldName: fileProperty.key.name, isFile: true })} {`
Expand Down
12 changes: 12 additions & 0 deletions generators/go/sdk/versions.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
- version: 1.33.3
changelogEntry:
- summary: |
Fix nil pointer dereference panic when optional file fields are not
provided in multipart form-data requests. The generated code now wraps
`WriteFile` calls for optional binary fields in a nil guard, matching
the existing behavior for optional non-file body properties. Required
file fields remain unconditional.
type: fix
createdAt: "2026-04-07"
irVersion: 61

- version: 1.33.2
changelogEntry:
- summary: |
Expand Down
20 changes: 14 additions & 6 deletions generators/php/dynamic-snippets/src/EndpointSnippetGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,16 +321,24 @@ export class EndpointSnippetGenerator {
auth: FernIr.dynamic.BasicAuth;
values: FernIr.dynamic.BasicAuthValues;
}): NamedArgument[] {
return [
{
// usernameOmit/passwordOmit may exist in newer IR versions
const authRecord = auth as unknown as Record<string, unknown>;
const usernameOmitted = !!authRecord.usernameOmit;
const passwordOmitted = !!authRecord.passwordOmit;
const args: NamedArgument[] = [];
if (!usernameOmitted) {
args.push({
name: this.context.getPropertyName(auth.username),
assignment: php.TypeLiteral.string(values.username)
},
{
});
}
if (!passwordOmitted) {
args.push({
name: this.context.getPropertyName(auth.password),
assignment: php.TypeLiteral.string(values.password)
}
];
});
}
return args;
}

private getConstructorEnvironmentArg({
Expand Down
Loading
Loading