# v0.40

[Release notes](https://github.com/grafana/grafana-app-sdk/releases/tag/v0.40.0)

*Upgrading from*: v0.39.*

## What Changed from v0.39.*

The format of kinds and the manifest in the CUE used for code generation has undergone a significant refactor, 
changing from the manifest containing a list of kinds, each of which contain one or more versions, 
to the manifest having a set of versions, each of which contain one or more kinds (which are version-specific).

In practical terms, this means that a simple manifest like:
```cue
manifest: {
    appName: "example"
    kinds: [{
        kind: "Foo"
        versions: {
            "v1": {
                schema: {
                    spec: {
                        field: string
                    }
                }
            }
            "v2": {
                schema: {
                    spec: {
                        breakingChange: string
                    }
                }
            }
        }
    }]
}
```
would now look like:
```cue
manifest: {
    appName: "example"
    versions: {
        "v1": {
            kinds: [{
                kind: "Foo"
                schema: {
                    spec: {
                        field: string
                    }
                }
            }]
        }
        "v2": {
            kinds: [{
                kind: "Foo"
                schema: {
                    spec: {
                        breakingChange: string
                    }
                }
            }]
        }
    }
}
```

For a more complex example, where kinds are defined separately from the manifest, there is a pattern which can be adopted to avoid duplicating data for each version of the kind:
```cue
manifest: {
    appName: "example"
    kinds: [foo, bar]
}

foo: {
    kind: "Foo"
    plural: "multifoo"
    conversion: true
    validation: operations: ["CREATE","UPDATE"]
    versions: {
        "v1": {
            schema: {
                spec: {
                    foo: string
                }
            }
        }
        "v2": {
            schema: {
                spec: {
                    bar: string
                }
            }
        }
    }
}

bar: {
    kind: "Bar"
    versions: {
        "v1": {
            schema: {
                spec: {
                    foz: int
                }
            }
        }
        "v2": {
            validation: operations: ["CREATE","UPDATE"]
            schema: {
                spec: {
                    baz: int
                }
            }
        }
    }
}
```
would be converted to:
```cue
manifest: {
    appName: "example"
    versions: {
        "v1": {
            kinds: [foov1, barv1]
        }
        "v2": {
            kinds: [foov2, barv2]
        }
    }
}

fooKind: {
    kind: "Foo"
    plural: "multifoo"
    conversion: true
    validation: operations: ["CREATE","UPDATE"]
}

foov1: fooKind & { // join the kind data into this new object which contains the schema for the version
    schema: {
        spec: {
            foo: string
        }
    }
}

foov2: fooKind & { // join the kind data into this new object which contains the schema for the version
    schema: {
        spec: {
            bar: string
        }
    }
}

barKind: {
    kind: "Bar"
}

barv1: barKind & { // join the kind data into this new object which contains the schema for the version
    schema: {
        spec: {
            foz: int
        }
    }
}

barv2: barKind & { // join the kind data into this new object which contains the schema and the validation for this version
    validation: operations: ["CREATE","UPDATE]
    schema: {
        spec: {
            baz: int
        }
    }
}
```

the `kinds` list in the version object for the manifest is now a combination of the kind data and a _specific_ version, rather than the prior treatment of `kinds` being the kind data and an arbitrary set of versions (with version-specific data). 

## Migration Steps

If you do not yet wish to migrate your CUE, you can use the flag `--useoldmanifestkinds` in your `generate` command, 
but this will be removed in a future release.

The process for converting an arbitrary `kind` from the old format to the new is:

1. change your kind object field from something like `foo` to `fooKind` (optional, this is just to make sure if any old references are still around, they will break so you find them)
2. for each version in your kind's `versions` map, create a new root-level field called `<kind><version>` (or similar), such as `foov1`. Make this equal to your kind `&` a new object (ex. `foov1: fooKind & {}`)
3. in this new object, copy the data in the object for that version in the old `versions` map
4. remove the `versions` from your kind

Then, to update your manifest:
1. create a new `versions` field in your manifest CUE
2. add a key for each version you support (based on the version objects of your converted kinds)
3. in that key's object, add `kinds: [<foov1>,<barv1>,<etc>]`, containing the list of version-specific kinds for that version
4. remove the `kinds` key from your manifest
5. if you had a `current` field in your kind(s) which was not the latest version, add `preferredVersion: <current>` to your manifest

Following through these steps on this example:
```cue
manifest: {
    appName: "example"
    kinds: [foo]
}

foo: {
    kind: "Foo"
    scope: "Namespaced"
    conversion: true
    current: "v1"
    versions: {
        "v1": {
            schema: {
                spec: {
                    foo: string
                }
            }
        }
        "v2alpha1": {
            validation: operations: ["CREATE","UPDATE]
            schema: {
                spec: {
                    foo: string
                    bar: int
                }
            }
        }
    }
}
```
kind conversion steps:

1.
    ```cue
    // excluded manifest

    fooKind: {
        // everything still the same
    }
    ```
2. 
    ```cue
    // excluded manifest

    fooKind: {
        // everything still the same
    }

    foov1: fooKind & {}

    foov2alpha1: fooKind & {}
    ```
3. 
    ```cue
    // excluded manifest

    fooKind: {
        // everything still the same
    }

    foov1: fooKind & {
        schema: {
            spec: {
                foo: string
            }
        }
    }

    foov2alpha1: fooKind & {
        validation: operations: ["CREATE","UPDATE]
        schema: {
            spec: {
                foo: string
                bar: int
            }
        }
    }
    ```
4. 
    ```cue
    // excluded manifest

    fooKind: {
        kind: "Foo"
        scope: "Namespaced"
        conversion: true
    }

    foov1: fooKind & {
        schema: {
            spec: {
                foo: string
            }
        }
    }

    foov2alpha1: fooKind & {
        validation: operations: ["CREATE","UPDATE]
        schema: {
            spec: {
                foo: string
                bar: int
            }
        }
    }
    ```

And then the manifest:

1. 
    ```cue
    manifest: {
        appName: "example"
        kinds: [foo]
        versions: {}
    }

    // excluded kinds
    ```
2. 
    ```cue
    manifest: {
        appName: "example"
        kinds: [foo]
        versions: {
            "v1": {}
            "v2alpha1": {}
        }
    }

    // excluded kinds
    ```
3. 
    ```cue
    manifest: {
        appName: "example"
        kinds: [foo]
        versions: {
            "v1": {
                kinds: [foov1]
            }
            "v2alpha1": {
                kinds: [foov2alpha1]
            }
        }
    }

    // excluded kinds
    ```
4. 
    ```cue
    manifest: {
        appName: "example"
        versions: {
            "v1": {
                kinds: [foov1]
            }
            "v2alpha1": {
                kinds: [foov2alpha1]
            }
        }
    }

    // excluded kinds
    ```
5. 
    ```cue
    manifest: {
        appName: "example"
        preferredVersion: "v1"
        versions: {
            "v1": {
                kinds: [foov1]
            }
            "v2alpha1": {
                kinds: [foov2alpha1]
            }
        }
    }

    // excluded kinds
    ```