You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by dj...@apache.org on 2021/12/24 17:09:36 UTC

[camel-kamelets] 06/07: Templates for kamelet adoc generation

This is an automated email from the ASF dual-hosted git repository.

djencks pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kamelets.git

commit eb0b675762f6080cabe481a19b57848502ad5111
Author: David Jencks <dj...@apache.org>
AuthorDate: Sun Nov 14 12:14:42 2021 -0800

    Templates for kamelet adoc generation
---
 docs/antora.yml                                    |   5 +-
 docs/indexPages.yml                                |  33 +++++
 docs/modules/ROOT/examples/js/kamelets.js          | 160 +++++++++++++++++++++
 .../ROOT/examples/template/kamelet-icon.svg        |   1 +
 .../ROOT/examples/template/kamelet-options.adoc    | 131 +++++++++++++++++
 5 files changed, 329 insertions(+), 1 deletion(-)

diff --git a/docs/antora.yml b/docs/antora.yml
index 763c601..c14f4b4 100644
--- a/docs/antora.yml
+++ b/docs/antora.yml
@@ -24,7 +24,10 @@ display-version: Next (Pre-release)
 nav:
 - modules/ROOT/nav.adoc
 
-# Update to appropriate released camel-k version on release
 asciidoc:
   attributes:
+    requires: "'util=camel-website-util,kamelets=xref:js/kamelets.js'"
+    # Update to appropriate released camel-k version on release
     camel-k-version: next
+    jsonpath-trace: true
+    jsonpath-debug: true
diff --git a/docs/indexPages.yml b/docs/indexPages.yml
new file mode 100644
index 0000000..178106d
--- /dev/null
+++ b/docs/indexPages.yml
@@ -0,0 +1,33 @@
+indexPages:
+  - query:
+      module: ROOT
+      family: example
+      relative: yaml/*
+    requires: 'kamelets=xref:js/kamelets.js'
+    content-as: json
+    template-id:
+      family: example
+      relative: template/kamelet-options.adoc
+    extract:
+      - path: 'src.relative'
+        match: 'yaml/(?<basename>*).kamelet.yaml'
+    target:
+      match: 'yaml/(?<basename>*).kamelet.yaml'
+      format: '`${basename}.adoc`'
+
+  - query:
+      module: ROOT
+      family: example
+      relative: yaml/*
+    requires: 'kamelets=xref:js/kamelets.js'
+    content-as: json
+    template-id:
+      family: example
+      relative: template/kamelet-icon.svg
+    extract:
+      - path: 'src.relative'
+        match: 'yaml/(?<basename>*).kamelet.yaml'
+    target:
+      family: image
+      match: 'yaml/(?<basename>*).kamelet.yaml'
+      format: '`kamelets/${basename}.svg`'
diff --git a/docs/modules/ROOT/examples/js/kamelets.js b/docs/modules/ROOT/examples/js/kamelets.js
new file mode 100644
index 0000000..549983c
--- /dev/null
+++ b/docs/modules/ROOT/examples/js/kamelets.js
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const util = require('camel-website-util')
+
+const QUOTED_CHARS = /[$`"\\]/g
+
+const QUOTE_REPLACEMENTS = {
+  '$': '\\$',
+  '\`': '\\\`',
+  '"': '\\"',
+  '\\': '\\\\',
+}
+
+const svgb64Prefix = 'data:image/svg+xml;base64,'
+
+module.exports = {
+  binding: (binding, apiVersion, kind, metadata_, spec_, refKind, refApiVersion, refName) => {
+      const name = metadata_.name
+      const metadata = {name: `${name}-binding`}
+      const kamelet = {
+        ref: {
+          kind,
+          apiVersion,
+          name,
+        },
+        properties: kameletPropertyList(spec_.definition)
+      }
+      const platform = {
+        ref: {
+          kind: refKind,
+          apiVersion: refApiVersion,
+          name: refName,
+        },
+      }
+      const base = {
+        apiVersion,
+        kind: 'KameletBinding',
+        metadata,
+      }
+      const fn = kameletBindings[binding] || (() => `unrecognized binding ${binding}`)
+      return fn(base, kamelet, platform)
+  },
+
+  bindingCommand: (binding, name, definition, topic) => {
+    const namePrefix = { action: 'step-0', sink: 'sink', source: 'source' }[binding]
+    const quote = (string) => (typeof string === 'String')
+      ? string.replace(QUOTED_CHARS, (m) => QUOTE_REPLACEMENTS[m])
+      : string
+    const properties = Object.entries(kameletPropertyList(definition) || {})
+      .map(([name, value]) => `-p "${namePrefix}.${name}=${quote(value)}"`)
+      .join(' ')
+    return `kamel bind ${name} ${properties} ${topic}`
+  },
+
+  sort: function (list) {
+    function alphaSort (list) {
+      return list.sort((a, b) => a.name < b.name ?  -1: a.name > b.name ? 1: 0)
+    }
+    const requiredNames = this.data.spec.definition.required || []
+    const { required, optional } = list.reduce((accum, item) => {
+      const name = item.path[4]
+      if (requiredNames.includes(name)) {
+        accum.required.push({name, value: Object.assign({ required: true }, item.value)} )
+      } else {
+        accum.optional.push({ name, value: item.value })
+      }
+      return accum
+    }, { required: [], optional: []})
+    return [...alphaSort(required), ...alphaSort(optional)]
+  },
+
+  icon: ($) => {
+    const b64 = $.metadata.annotations['camel.apache.org/kamelet.icon']
+    try {
+      if (b64.startsWith(svgb64Prefix)) {
+        data = b64.slice(svgb64Prefix.length)
+        return Buffer.from(data, 'base64').toString()
+      }
+    } catch (e) {
+      console.log(`icon problem ${b64}`, e)
+    }
+    return 'generic svg!'
+  },
+
+  templateHeader: (basename, $) => {
+    const title = $.spec.definition.title
+    const name = $.metadata.name
+    const provider = $.metadata.annotations["camel.apache.org/provider"]
+    const supportLevel = $.metadata.annotations["camel.apache.org/kamelet.support.level"]
+    const type = $.metadata.labels["camel.apache.org/kamelet.type"]
+    const propertyCount = Object.keys(($.spec.definition.properties || {})).length
+    return `= image:kamelets/${basename}.svg[] ${title}
+:name: ${name}
+:provider: ${provider}
+:support-level: ${supportLevel}
+:type: ${type}
+:propertycount: ${propertyCount}
+`
+  }
+}
+
+function kameletPropertyList (definition) {
+  return definition.required && definition.properties && Object.fromEntries(
+    Object.entries(definition.properties)
+      .filter(([name, value]) => definition.required.includes(name))
+      .sort(([name1, value1], [name2, value2]) => name1.localeCompare(name2))
+      .map(([name, value]) => [name, value.example ? value.example : `The ${value.title}`])
+  )
+}
+
+const kameletBindings = {
+  action: (base, kamelet, platform) => Object.assign(base, {
+      spec: {
+        source: {
+          ref: {
+            kind: 'Kamelet',
+            apiVersion: 'camel.apache.org/v1alpha1',
+            name: 'timer-source',
+            properties: {
+              message: 'Hello',
+            },
+          },
+        },
+        steps: [
+          kamelet,
+        ],
+        sink: platform,
+      },
+    }),
+
+  sink: (base, kamelet, platform) => Object.assign(base, {
+      spec: {
+        source: platform,
+        sink: kamelet,
+      },
+    }),
+
+  source: (base, kamelet, platform) => Object.assign(base, {
+      spec: {
+        source: kamelet,
+        sink: platform,
+      },
+    }),
+}
+
diff --git a/docs/modules/ROOT/examples/template/kamelet-icon.svg b/docs/modules/ROOT/examples/template/kamelet-icon.svg
new file mode 100644
index 0000000..533d8b4
--- /dev/null
+++ b/docs/modules/ROOT/examples/template/kamelet-icon.svg
@@ -0,0 +1 @@
+${kamelets.icon($)}
\ No newline at end of file
diff --git a/docs/modules/ROOT/examples/template/kamelet-options.adoc b/docs/modules/ROOT/examples/template/kamelet-options.adoc
new file mode 100644
index 0000000..150adf6
--- /dev/null
+++ b/docs/modules/ROOT/examples/template/kamelet-options.adoc
@@ -0,0 +1,131 @@
+${kamelets.templateHeader(basename, $)}
+
+*Provided by: "{provider}"*
+
+*Support Level for this Kamelet is: "{support-level}"*
+
+jsonpathExpression::example$yaml/${basename}.kamelet.yaml[query='$.spec.definition', format='description']
+
+== Configuration Options
+
+ifeval::[{propertycount} == 0]
+The \`{name}\` Kamelet does not specify any configuration options.
+endif::[]
+
+ifeval::[{propertycount} != 0]
+The following table summarizes the configuration options available for the \`{name}\` Kamelet:
+
+[width="100%",cols="2,^2,3,^2,^2,^3",options="header"]
+|===
+| Property| Name| Description| Type| Default| Example
+|===
+
+jsonpathTable::example$yaml/${basename}.kamelet.yaml[query='nodes$.spec.definition.properties.*',cellformats='util.boldLink(name)|value.title|util.description(value)|util.valueAsString(value.type)|util.valueAsString(value.default)|util.valueAsString(value.example)',{requires},transform=kamelets.sort]
+
+endif::[]
+
+== Dependencies
+
+At runtime, the \`{name}\` Kamelet relies upon the presence of the following dependencies:
+
+jsonpathList::example$yaml/${basename}.kamelet.yaml[query='nodes$.spec.dependencies.*',format='value']
+
+== Usage
+
+This section describes how you can use the \`{name}\`.
+
+=== Knative {type}
+
+ifeval::['{type}' == 'action']
+You can use the \`{name}\` Kamelet as an intermediate step in a Knative binding.
+endif::[]
+ifeval::['{type}' != 'action']
+You can use the \`{name}\` Kamelet as a Knative {type} by binding it to a Knative object.
+endif::[]
+
+:ref-api-version: messaging.knative.dev/v1
+:ref-kind: Channel
+:ref-name: mychannel
+
+.{name}-binding.yaml
+[source,yaml,subs='+attributes,macros']
+----
+jsonpathExpression::example$yaml/${basename}.kamelet.yaml[query='$', format='kamelets.binding("{type}", apiVersion, kind, metadata, spec, "{ref-kind}", "{ref-api-version}", "{ref-name}")', outputFormat=yml, requires={requires}]
+----
+
+==== *Prerequisite*
+
+You have xref:{camel-k-version}@camel-k::installation/installation.adoc[Camel K installed] on the cluster.
+
+==== *Procedure for using the cluster CLI*
+
+. Save the \`{name}-binding.yaml\` file to your local drive, and then edit it as needed for your configuration.
+
+. Run the {type} by using the following command:
++
+[source,shell,subs=+attributes]
+----
+kubectl apply -f {name}-binding.yaml
+----
+
+==== *Procedure for using the Kamel CLI*
+
+Configure and run the {type} by using the following command:
+
+[source,shell,subs='+attributes,macros']
+----
+jsonpathExpression:example$yaml/${basename}.kamelet.yaml[query='$.spec', format='kamelets.bindingCommand("{type}", "{name}", definition, "channel:mychannel")', requires={requires}]
+----
+
+This command creates the KameletBinding in the current namespace on the cluster.
+
+=== Kafka {type}
+
+ifeval::['{type}' == 'action']
+You can use the \`{name}\` Kamelet as an intermediate step in a Kafka binding.
+endif::[]
+ifeval::['{type}' != 'action']
+You can use the \`{name}\` Kamelet as a Kafka {type} by binding it to a Kafka topic.
+endif::[]
+
+:ref-api-version: kafka.strimzi.io/v1beta1
+:ref-kind: KafkaTopic
+:ref-name: my-topic
+
+.{name}-binding.yaml
+[source,yaml,subs='+attributes,macros']
+----
+jsonpathExpression::example$yaml/${basename}.kamelet.yaml[query='$', format='kamelets.binding("{type}", apiVersion, kind, metadata, spec, "{ref-kind}", "{ref-api-version}", "{ref-name}")', outputFormat=yml, requires={requires}]
+----
+
+==== *Prerequisites*
+
+* You've installed https://strimzi.io/[Strimzi].
+* You've created a topic named \`my-topic\` in the current namespace.
+* You have xref:{camel-k-version}@camel-k::installation/installation.adoc[Camel K installed] on the cluster.
+
+==== *Procedure for using the cluster CLI*
+
+. Save the \`{name}-binding.yaml\` file to your local drive, and then edit it as needed for your configuration.
+
+. Run the {type} by using the following command:
++
+[source,shell,subs=+attributes]
+----
+kubectl apply -f {name}-binding.yaml
+----
+
+==== *Procedure for using the Kamel CLI*
+
+Configure and run the {type} by using the following command:
+
+[source,shell,subs='+attributes,macros']
+----
+jsonpathExpression::example$yaml/${basename}.kamelet.yaml[query='$.spec', format='kamelets.bindingCommand("{type}", "{name}", definition, "kafka.strimzi.io/v1beta1:KafkaTopic:my-topic")', requires={requires}]
+----
+
+This command creates the KameletBinding in the current namespace on the cluster.
+
+== Kamelet source file
+
+https://github.com/apache/camel-kamelets/blob/main/{name}.kamelet.yaml