Quarkus - Extension Codestarts
====================
:toc: preamble
:toclevels: 3
:showtitle:

This guide explains how to create and configure a Quarkus Codestart for an extension.

== Description

"Extension Codestarts" is the name we gave to our Quarkus extension quickstart code generation system. It aims to provide a personalized getting started experience with Quarkus.
A Quarkus extension is able to provide one or more well defined codestarts which will contain the necessary resources and code examples required to get started using that particular extension.

You can play with the extension codestarts in the Quarkus tooling:

* The https://code.quarkus.io web app
* The Quarkus Maven plugin:
+
[source,bash]
----
mvn io.quarkus:quarkus-maven-plugin:create
----

* The experimental Quarkus CLI (using JBang until it gets a proper installer):
+
[source,bash]
----
jbang cli@quarkusio create
----

We decided that:

* "Codestart(s)" is the tool (the code generator system).
* A "codestart" is a directory following a specific struture containing a `codestart.yml` and templates. It is used by the tool in combinations with other codestarts to generate a project.
* An "Extension codestart" is a specific codestart providing example code for a Quarkus extension.

== How it works

There are two kinds of codestarts contributing to the generation of a project, the kind where we want to have only one for a project (called Base) and the rest (called Extra).

Base:

* project: The project skeleton (e.g. a Quarkus project)
* buildtool: The build tool (e.g. Maven, Gradle, Gradle with Kotlin DSL)
* language: The coding language (e.g. Java, Kotlin, Scala)
* config: The config type (e.g. yaml, properties)

Extra:

* tooling: Anything that can be added to improve the project (e.g. dockerfiles)
* code: Any Quarkus extension can provide example code. The user can decide to activate it or not.

Each codestart consists of:

. A codestart unique name, ie `my-codestart`
. A directory for the codestart files, ie `my-codestart/`
. A `codestart.yml` file
. Optionally some templates which following a common structure and naming conventions

== Where are the Quarkus Extension Codestarts located

* Quarkus core codestarts dir: https://github.com/quarkusio/quarkus/tree/master/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/core
* Extension codestarts directory: https://github.com/quarkusio/quarkus/tree/master/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples

== Writing an Extension Codestart

As we discussed before, the base project files (pom.xml, dockerfiles, ...) are already generated by some existing codestarts. Thanks to this, we can only focus on the important, the example code for the extension.

Here is the flow I am using to develop a new extension codestart:

. duplicate the example (e.g. link:./examples/quarkus/my-example[./examples/quarkus/my-example])
. update the codestart.yml (1 & 2 will be replaced by https://github.com/quarkusio/quarkus/issues/13614)
. use the `qcd@quarkusio` jbang script to generate the project using your new extension codestart named `my-example` located in `./examples/quarkus` in java and kotlin:
+
[source,bash]
----
jbang qcd@quarkusio -l java,kotlin -c ./examples/quarkus my-example
----

. Make sure the generated project(s) are as expected. You can use `-t` option to automatically build and test the generated project(s).
. You can either edit the codestart files and start again from 3 or also, open the generated project(s) using you IDE and edit the files. You need to manually copy the changes back to your codestart files (and iterate again from 3)

*NOTE 1* You can start with java and add kotlin later in another PR

*NOTE 2* The build file will automatically include the dependencies provided in the `codestart.yml`.

=== When done (to bind the extension codestart to the actual extension):

. put the working extension codestart in `devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples` and submit a PR.
. Add the `ref` value of the codestart to the extension metadata. This is how it is activated when the extension is selected (e.g )

    Example: https://github.com/quarkusio/quarkus/blob/master/extensions/resteasy/runtime/src/main/resources/META-INF/quarkus-extension.yaml#L14

*NOTE* This is temporary, extension codestarts will soon live alongside the extension.

=== Tests

* We already have tests making sure we can create and build apps with all extension codestarts together with each build tools and languages:
+
https://github.com/quarkusio/quarkus/blob/master/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartRunIT.java#L74-L90
* We have specific tests making sure the generation is working as expected (we will split it soon, you may create another class for your codestart):
+
https://github.com/quarkusio/quarkus/blob/master/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java

=== Writing tips

* Your extension codestart must/should be independent of buildtool and dockerfiles
* Extension codestarts should be able to work alongside each other without interference
* Make sure your class names are unique accross all extension codestarts.
* Use `org.acme` as package name, and `org.acme.[something]` if it has more than one class.
* Use the path `/[unique-name]-...` for your REST paths
* If they are not adding learning value, don't provide tests
* Write the config in `src/main/resources/application.yml`.
+
It is going to be merged with the other codestarts config and automatically converted to the selected config type (yaml or properties).
* You can start with java and add kotlin later in another PR
* If the extension codestart is a bad citizen and may have some compatibility issues, make it a `singleton-example`
* Ping me @ia3andy on https://quarkusio.zulipchat.com/

=== Directory Structure

*NOTE* `codestart.yml` is the only required file.

* `codestart.yml` must be at the root of the codestart
* `./base` contains all the files that will be processed
* `./[java/kotlin/scala]` contains all the files that will be processed if the specified language has been selected (overriding base)

=== codestart.yml

codestart.yml:
[source,yaml]
----
name: resteasy-example // the codestart unique name
ref: resteasy // the codestart reference (the name is used if not set)
type: code // the type of codestart (other types are used for other project files)
tags: example // indicate that this is optional example code
language:
  base: //  most of the time, only base is needed (we may also define java, kotlin, scala overrides)
    data:
      title: RESTEasy JAX-RS
      description: |
        <p>A Hello World RESTEasy resource</p>
      guide: https://quarkus.io/guides/rest-json
    dependencies:
      - io.quarkus:quarkus-resteasy // You need to specify the dependencies to add (even if it's the one attached)
    test-dependencies:
      - io.rest-assured:rest-assured // And maybe test dependencies?
----

== Advanced topics

=== Naming Convention for files

* `.tpl.qute` will be processed with Qute and can use data (`.tpl.qute` will be removed from the output file name).
* some files have a specific processing (`readme.md`, `src/test/resources/application.yml`, `src/main/resources/META-INF/resources/index.html`)
* other files are copied.

=== Templates (Qute)

Codestarts may use Qute templates `MyClass.tpl.qute.java` for dynamic rendering.

Those templates are able to use data which contains:

* The `data` of the codestart to generate (specified in the `codestart.yml`)
* A merge of the `shared-data` from the all the codestarts used to generate the project
* The user input
* Some dynamically generated data (e.g. `dependencies` and `test-dependencies`)

=== README.md

You may add a `README.md` or `README.tpl.qute.md` in the `base` directory, it will be appended to the others.
So just add the info relative to your extension codestart.

=== application.properties

As a convention, you should always provide the Quarkus configuration as a yaml file (`src/test/resources/application.yml`).

It is going to be:

* merged with the other extension codestarts configs
* automatically converted to the selected config type (yaml or properties) at generation time depending on the selected extensions

=== index.html and Cloud Extension codestarts

Extension codestarts may provide a snippet for the generated index.html by adding this file:

base/src/main/resources/META-INF/resources/index.tpl.qute.html:
[source,html]
----
<div class="example">
    <div class="example-header">
        <h4>{title}</h4>
        <a href="{guide}" target="_blank" class="guide-link">Guide</a>
    </div>
    <div class="example-description">
        {description}
    </div>
    <div class="example-paths">
        {#for item in paths}
        <a href="{item.path}" class="path-link" target="_blank">{item.method} {item.path}</a>
        {/for}
    </div>
</div>
----

You also need to add this data to the `codestart.yml`:

codestart.yml:
[source,yaml]
----
...
language:
  base:
    data:
      title: My example
      description: |
        <p>My example description.</p>
        <p><b>A Quarkus catch phrase!</b></p>
      paths:
        - method: GET
          path: /the-rest-path-of-my-example
      guide: https://quarkus.io/guides/my-example
...
----

=== Singleton example

If the extension codestart is a bad citizen and may have some compatibility issues, make it a `singleton-example`.

This is a big constraint and should be done as a last resort:

* The extension can't be selected with another singleton extension if examples are activated
* When selected, it will automatically disable all other examples

To make it a singleton:

* Put it in this directory: https://github.com/quarkusio/quarkus/tree/master/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/singleton-examples
* Add `singleton-example` in the tags:
+
codestart.yml
[source,yaml]
----
...
tags:
  - example
  - singleton-example
...
----

== The generator sources

* Codestart generator: https://github.com/quarkusio/quarkus/tree/master/independent-projects/tools/codestarts
* Quarkus implementation of the Codestart generator: https://github.com/quarkusio/quarkus/tree/master/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/quarkus

== Issues and Feature requests

https://github.com/quarkusio/quarkus/labels/area%2Fcodestarts
