nickel-lang / organist

Control all your tooling from a single console
MIT License
361 stars 20 forks source link

Netlify schema file generation example is broken #195

Closed ofalvai closed 2 months ago

ofalvai commented 2 months ago

I tried to generate a file conforming to one of the schemas in the schemastore repo, but ran into an error: contract broken by a value: value is not of type Record error.

To make sure it's not a problem with the specific schema, I also tried running the netlify.toml example in the docs. It fails with the same error, here is the full output:

       error: builder for '/nix/store/cvckrc01346hm33wnz4dvvnbs10q73m9-nickel-res.json.drv' failed with exit code 1;
       last 18 log lines:
       > error: contract broken by a value: value is not of type Record
       >    ┌─ /nix/store/x354r0px5263dh9npwnlm2hnihkrkd3w-dxima2gbfsgg6fmm2jxrm1l3w3idqsqn-source/project.ncl:34:5
       >    │
       > 34 │ ╭     std.serialize
       > 35 │ │       'Toml
       > 36 │ │       {
       > 37 │ │         build.command = "gatsby build",
       > 38 │ │         build.publish = "public/",
       > 39 │ │       }
       >    │ ╰───────^ applied to this expression
       > 40 │         | netlify_schema
       >    │           -------------- expected type
       >    │
       >    ┌─ <unknown> (generated by evaluation):1:1
       >    │
       >  1 │ "[build]\ncommand = \"gatsby build\"\npublish = \"public/\"\n"
       >    │ -------------------------------------------------------------- evaluated to this value
       >
       For full logs, run 'nix-store -l /nix/store/cvckrc01346hm33wnz4dvvnbs10q73m9-nickel-res.json.drv'.

My flake.lock file:

``` { "nodes": { "flake-compat": { "locked": { "lastModified": 1696426674, "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "owner": "edolstra", "repo": "flake-compat", "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "type": "github" }, "original": { "owner": "edolstra", "repo": "flake-compat", "type": "github" } }, "flake-utils": { "inputs": { "systems": "systems" }, "locked": { "lastModified": 1694529238, "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", "owner": "numtide", "repo": "flake-utils", "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "nickel_src": { "flake": false, "locked": { "lastModified": 1698331902, "narHash": "sha256-BEqUDYIy9YCgdz0WPg6BTf88hRzW/hq9K7iqogQBpbs=", "owner": "tweag", "repo": "nickel", "rev": "1921c316ad81bca8100c3a0c6ae2e3da974cdd51", "type": "github" }, "original": { "owner": "tweag", "repo": "nickel", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1713537308, "narHash": "sha256-XtTSSIB2DA6tOv+l0FhvfDMiyCmhoRbNB+0SeInZkbk=", "owner": "NixOS", "repo": "nixpkgs", "rev": "5c24cf2f0a12ad855f444c30b2421d044120c66f", "type": "github" }, "original": { "id": "nixpkgs", "ref": "nixos-unstable", "type": "indirect" } }, "organist": { "inputs": { "flake-compat": "flake-compat", "flake-utils": "flake-utils", "nickel_src": "nickel_src", "nixpkgs": [ "nixpkgs" ] }, "locked": { "lastModified": 1711376357, "narHash": "sha256-ZEKfiPM3Z59xp5lsQl+YdvxGUIs9QRKol+45I8k8wVc=", "owner": "nickel-lang", "repo": "organist", "rev": "d69c758780974ed8729bb32e1f8642f61891b7a9", "type": "github" }, "original": { "owner": "nickel-lang", "repo": "organist", "type": "github" } }, "root": { "inputs": { "nixpkgs": "nixpkgs", "organist": "organist" } }, "systems": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "owner": "nix-systems", "repo": "default", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default", "type": "github" } } }, "root": "root", "version": 7 } ```
yannham commented 2 months ago

Hello, thanks for the report!

I think the issue is that the netlify schema verifies the structure of a record, but std.serialize 'Toml will produce a string. Thus, it seems the example is indeed wrong, and we should apply the schema before serializing (notice the parentheses around the config and the contract application)

  files."netlify.toml".content = std.serialize 'Toml ({
    build.command = "gatsby build",
    build.publish = "public/",
  } | netlify_schema)

Or, maybe slightly more readable:

  files."netlify.toml".content = 
    let config | netlify_schema = {
      build.command = "gatsby build",
      build.publish = "public/",
    }
    in
    std.serialize 'Toml config,

If I try that, I now get a contract error missing required field backend. Which still makes the example wrong, but at least the schema check seems to trigger :upside_down_face:

ofalvai commented 2 months ago

Thank you @yannham, it's now working with my specific schema and file content! 🙂

yannham commented 2 months ago

Good :slightly_smiling_face: let's keep this issue open until we fix the documentation.

thufschmitt commented 2 months ago

Thanks for catching that. I indeed managed to write something twice wrong for two independent reasons in 6 lines of code (I guess I'm a good userbase for Nickel :smile: )

I've opened #197 to provide a better and working example