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 <djen...@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