Repository: kestra-io/kestra (java)

Issue:
Store Kestra version inside the database
### Feature description

This would be needed to be able to detect incompatible update at some point.

For example, with 0.23 we add a migration script for tenantId.
We will at some point, for example in 0.26 remove that script so to migrate to 0.27 you would mandate a user to first migrate to a version pre-0.27.

Pull request:
feat(system): store version in the settings
Closes #9373


Patch:
diff --git a/core/src/main/java/io/kestra/core/models/Setting.java b/core/src/main/java/io/kestra/core/models/Setting.java
index 26ed057dc..cbf8f216e 100644
--- a/core/src/main/java/io/kestra/core/models/Setting.java
+++ b/core/src/main/java/io/kestra/core/models/Setting.java
@@ -15,6 +15,8 @@ import jakarta.validation.constraints.NotNull;
 @NoArgsConstructor
 public class Setting {
     public static final String INSTANCE_UUID = "instance.uuid";
+    public static final String INSTANCE_VERSION = "instance.version";
+
     @NotNull
     private String key;
 
diff --git a/core/src/main/java/io/kestra/core/utils/VersionProvider.java b/core/src/main/java/io/kestra/core/utils/VersionProvider.java
index 2d61a4e02..dab5932d7 100644
--- a/core/src/main/java/io/kestra/core/utils/VersionProvider.java
+++ b/core/src/main/java/io/kestra/core/utils/VersionProvider.java
@@ -1,5 +1,7 @@
 package io.kestra.core.utils;
 
+import io.kestra.core.models.Setting;
+import io.kestra.core.repositories.SettingRepositoryInterface;
 import io.micronaut.context.env.Environment;
 import io.micronaut.context.env.PropertiesPropertySourceLoader;
 import io.micronaut.context.env.PropertySource;
@@ -29,6 +31,9 @@ public class VersionProvider {
     @Inject
     private Environment environment;
 
+    @Inject
+    private Optional<SettingRepositoryInterface> settingRepository; // repositories are not always there on unit tests
+
     @PostConstruct
     public void start() {
         final Optional<PropertySource> gitProperties = new PropertiesPropertySourceLoader()
@@ -40,6 +45,18 @@ public class VersionProvider {
         this.revision = loadRevision(gitProperties);
         this.date = loadTime(gitProperties);
         this.version = loadVersion(buildProperties, gitProperties);
+
+        // check the version in the settings and update if needed, we did't use it would allow us to detect incompatible update later if needed
+        if (settingRepository.isPresent()) {
+            Optional<Setting> versionSetting = settingRepository.get().findByKey(Setting.INSTANCE_VERSION);
+            if (versionSetting.isEmpty() || !versionSetting.get().getValue().equals(this.version)) {
+                settingRepository.get().save(Setting.builder()
+                    .key(Setting.INSTANCE_VERSION)
+                    .value(this.version)
+                    .build()
+                );
+            }
+        }
     }
 
     private String loadVersion(final Optional<PropertySource> buildProperties,
diff --git a/ui/src/components/code/segments/Editor.vue b/ui/src/components/code/segments/Editor.vue
index 7e8300e91..ca534c8f2 100644
--- a/ui/src/components/code/segments/Editor.vue
+++ b/ui/src/components/code/segments/Editor.vue
@@ -90,6 +90,7 @@
     import MetadataInputs from "../../flows/MetadataInputs.vue";
     import MetadataInputsContent from "../../flows/MetadataInputsContent.vue";
     import TaskObjectField from "../../flows/tasks/TaskObjectField.vue";
+    import InitialSchema from "./flow-schema.json"
 
 
     import {
@@ -163,7 +164,7 @@
     const schema = ref<{
         definitions?: any,
         $ref?: string,
-    }>({})
+    }>(InitialSchema)
 
     const pluginStore = usePluginsStore();
 
diff --git a/ui/tests/storybook/components/flows/flow-schema.json b/ui/src/components/code/segments/flow-schema.json
similarity index 100%
rename from ui/tests/storybook/components/flows/flow-schema.json
rename to ui/src/components/code/segments/flow-schema.json
diff --git a/ui/src/stores/flow.js b/ui/src/stores/flow.js
index 91fa4b4a3..796ad8ae1 100644
--- a/ui/src/stores/flow.js
+++ b/ui/src/stores/flow.js
@@ -785,7 +785,7 @@ export default {
             } else return false;
         },
         nextRevision(_state, getters){
-            return getters.flow.revision + 1;
+            return (getters.flow?.revision ?? 0) + 1;
         },
         yamlWithNextRevision(_state, getters){
             return `revision: ${getters.nextRevision}\n${getters.flowYaml}`;


Test patch:
diff --git a/ui/tests/storybook/components/flows/FlowEditor.stories.jsx b/ui/tests/storybook/components/flows/FlowEditor.stories.jsx
index 4c3c1bebc..a274ce420 100644
--- a/ui/tests/storybook/components/flows/FlowEditor.stories.jsx
+++ b/ui/tests/storybook/components/flows/FlowEditor.stories.jsx
@@ -3,7 +3,7 @@ import {vueRouter} from "storybook-vue3-router";
 import FlowEditor from "../../../../src/components/flows/FlowEditor.vue";
 import * as YAML_UTILS from "@kestra-io/ui-libs/flow-yaml-utils";
 import allowFailureDemo from "../../../fixtures/flowgraphs/allow-failure-demo.json";
-import flowSchema from "./flow-schema.json";
+import flowSchema from "../../../../src/components/code/segments/flow-schema.json";
 
 
 export default {