From 6be096c55ea97f9b9bebcb4e2800cbabd0637fa8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miles=20St=C3=B6tzner?= <miles@stoetzner.de>
Date: Tue, 26 Nov 2024 00:05:31 +0100
Subject: [PATCH] technology plugin uses (#444)

---
 .github/workflows/night.yaml                  |  2 +-
 .../variability4tosca/specification/index.md  |  1 +
 src/enricher/elements.ts                      |  4 ++--
 src/graph/populator.ts                        |  4 +---
 src/resolver/solver.ts                        | 13 ++++++------
 src/technologies/plugins/rules/index.ts       | 21 ++++++++++++++++++-
 src/technologies/types.ts                     |  6 ++++++
 .../plugins/technology/terraform/index.js     |  1 +
 .../plugin/index.js                           |  1 +
 9 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/night.yaml b/.github/workflows/night.yaml
index 74139aabe1..24444653a3 100644
--- a/.github/workflows/night.yaml
+++ b/.github/workflows/night.yaml
@@ -108,7 +108,7 @@ jobs:
             - name: (DOCKER) Ensure Vintner can be executed
               run: docker exec vintner vintner --version
 
-            - name: (DOCKER) Ensure Vintner can be executed
+            - name: (DOCKER) Ensure Vintner version in Docker container and binary match
               run: |
                   DOCKER_VERSION=$(docker exec vintner vintner --version)
                   echo "Docker version: $DOCKER_VERSION}"
diff --git a/docs/docs/variability4tosca/specification/index.md b/docs/docs/variability4tosca/specification/index.md
index 9854d126df..fe821cf9ae 100644
--- a/docs/docs/variability4tosca/specification/index.md
+++ b/docs/docs/variability4tosca/specification/index.md
@@ -1112,6 +1112,7 @@ export type TechnologyPluginBuilder = {
 export type TechnologyPlugin = {
     assign: (node: Node) => {[technology: string]: TechnologyTemplate}[]
     implement: (name: string, type: NodeType) => NodeTypeMap
+    uses: (artifact: Artifact) => Technology[]
 }
 ```
 
diff --git a/src/enricher/elements.ts b/src/enricher/elements.ts
index b24e35a44e..bbecca8e32 100644
--- a/src/enricher/elements.ts
+++ b/src/enricher/elements.ts
@@ -26,7 +26,7 @@ export class ElementEnricher {
 
     private getTechnologyCandidates(node: Node) {
         const candidates: TechnologyTemplateMap[] = []
-        for (const plugin of this.graph.plugins.technology) {
+        for (const plugin of this.graph.plugins.technology.filter(it => it.backwards())) {
             candidates.push(...plugin.assign(node))
         }
         return candidates
@@ -39,7 +39,7 @@ export class ElementEnricher {
      */
     private enrichImplementations() {
         // for backwards compatibility and testing purposed, continue if, e.g., no rules at all exists
-        if (utils.isEmpty(this.graph.plugins.technology)) return
+        if (utils.isEmpty(this.graph.plugins.technology.filter(it => it.backwards()))) return
 
         for (const node of this.graph.nodes.filter(it => it.managed).filter(it => utils.isPopulated(it.technologies))) {
             // Do not override manual assigned technologies but enrich them with an implementation
diff --git a/src/graph/populator.ts b/src/graph/populator.ts
index d803baa66b..0e3e7b1671 100644
--- a/src/graph/populator.ts
+++ b/src/graph/populator.ts
@@ -92,9 +92,7 @@ export class Populator {
          * Technology Rule Plugin
          */
         const technologyRulePlugin = new TechnologyRulePluginBuilder().build(this.graph)
-        if (technologyRulePlugin.hasRules()) {
-            this.graph.plugins.technology.push(technologyRulePlugin)
-        }
+        this.graph.plugins.technology.push(technologyRulePlugin)
 
         /**
          * Imported plugins
diff --git a/src/resolver/solver.ts b/src/resolver/solver.ts
index 9911938c92..17a1f0bb24 100644
--- a/src/resolver/solver.ts
+++ b/src/resolver/solver.ts
@@ -3,12 +3,12 @@ import * as check from '#check'
 import Element from '#graph/element'
 import Graph from '#graph/graph'
 import Property from '#graph/property'
+import Technology from '#graph/technology'
 import {andify} from '#graph/utils'
 import Optimizer from '#resolver/optimizer'
 import {Result, ResultMap} from '#resolver/result'
 import {InputAssignmentMap, InputAssignmentValue} from '#spec/topology-template'
 import {LogicExpression, ValueExpression, VariabilityDefinition, VariabilityExpression} from '#spec/variability'
-import {destructImplementationName} from '#technologies/utils'
 import * as utils from '#utils'
 import day from '#utils/day'
 import {UnexpectedError} from '#utils/error'
@@ -629,11 +629,12 @@ export default class Solver {
          */
         if (check.isDefined(expression.is_managed)) {
             const artifact = this.graph.getArtifact(expression.is_managed, {element, cached})
-            const technologies = artifact.container.technologies.filter(it => {
-                const deconstructed = destructImplementationName(it.assign)
-                if (check.isUndefined(deconstructed.artifact)) return false
-                return artifact.getType().isA(deconstructed.artifact)
-            })
+
+            const technologies: Technology[] = []
+            for (const plugin of this.graph.plugins.technology) {
+                technologies.push(...plugin.uses(artifact))
+            }
+
             return MiniSat.or(technologies.map(it => it.id))
         }
 
diff --git a/src/technologies/plugins/rules/index.ts b/src/technologies/plugins/rules/index.ts
index 577436ee73..cb8a140d2a 100644
--- a/src/technologies/plugins/rules/index.ts
+++ b/src/technologies/plugins/rules/index.ts
@@ -1,7 +1,9 @@
 import * as assert from '#assert'
 import * as check from '#check'
+import Artifact from '#graph/artifact'
 import Graph from '#graph/graph'
 import Node from '#graph/node'
+import Technology from '#graph/technology'
 import {NodeType, NodeTypeMap} from '#spec/node-type'
 import {TechnologyTemplateMap} from '#spec/technology-template'
 import {LogicExpression} from '#spec/variability'
@@ -9,7 +11,12 @@ import std from '#std'
 import Registry from '#technologies/plugins/rules/registry'
 import {ASTERISK, METADATA} from '#technologies/plugins/rules/types'
 import {TechnologyPlugin, TechnologyPluginBuilder} from '#technologies/types'
-import {constructImplementationName, constructRuleName, isGenerated} from '#technologies/utils'
+import {
+    constructImplementationName,
+    constructRuleName,
+    destructImplementationName,
+    isGenerated,
+} from '#technologies/utils'
 import * as utils from '#utils'
 
 export class TechnologyRulePluginBuilder implements TechnologyPluginBuilder {
@@ -32,10 +39,22 @@ export class TechnologyRulePlugin implements TechnologyPlugin {
         return rules
     }
 
+    backwards() {
+        return this.hasRules()
+    }
+
     hasRules() {
         return utils.isPopulated(this.getRules())
     }
 
+    uses(artifact: Artifact): Technology[] {
+        return artifact.container.technologies.filter(it => {
+            const deconstructed = destructImplementationName(it.assign)
+            if (check.isUndefined(deconstructed.artifact)) return false
+            return artifact.getType().isA(deconstructed.artifact)
+        })
+    }
+
     implement(name: string, type: NodeType): NodeTypeMap {
         const rules = this.getRules()
         if (utils.isEmpty(rules)) return {}
diff --git a/src/technologies/types.ts b/src/technologies/types.ts
index 91e3d7dcd8..a4625b2b8e 100644
--- a/src/technologies/types.ts
+++ b/src/technologies/types.ts
@@ -1,5 +1,7 @@
+import Artifact from '#graph/artifact'
 import Graph from '#graph/graph'
 import Node from '#graph/node'
+import Technology from '#graph/technology'
 import {NodeType, NodeTypeMap} from '#spec/node-type'
 import {TechnologyTemplateMap} from '#spec/technology-template'
 
@@ -8,7 +10,11 @@ export type TechnologyPluginBuilder = {
 }
 
 export type TechnologyPlugin = {
+    // for backwards compatibility and testing purposed, continue if, e.g., no rules at all exists
+    backwards: () => Boolean
+
     // TODO: must assign technology.assign!
     assign: (node: Node) => TechnologyTemplateMap[]
     implement: (name: string, type: NodeType) => NodeTypeMap
+    uses: (artifact: Artifact) => Technology[]
 }
diff --git a/tests/enricher/technology-plugin-loader-default/plugins/technology/terraform/index.js b/tests/enricher/technology-plugin-loader-default/plugins/technology/terraform/index.js
index af9cab67b1..35ee3972cc 100644
--- a/tests/enricher/technology-plugin-loader-default/plugins/technology/terraform/index.js
+++ b/tests/enricher/technology-plugin-loader-default/plugins/technology/terraform/index.js
@@ -5,6 +5,7 @@ const technology = require("technology");
 module.exports = {
     build: (graph) => {
         return {
+            backwards: () => true,
             assign: (node) => {
                 return [{ [technology.name()]: { assign: "this-is-assigned" } }];
             }
diff --git a/tests/enricher/technology-plugin-loader-file/plugin/index.js b/tests/enricher/technology-plugin-loader-file/plugin/index.js
index af9cab67b1..35ee3972cc 100644
--- a/tests/enricher/technology-plugin-loader-file/plugin/index.js
+++ b/tests/enricher/technology-plugin-loader-file/plugin/index.js
@@ -5,6 +5,7 @@ const technology = require("technology");
 module.exports = {
     build: (graph) => {
         return {
+            backwards: () => true,
             assign: (node) => {
                 return [{ [technology.name()]: { assign: "this-is-assigned" } }];
             }