= Quarkus - Codestarts

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

== Description

"Codestarts" is the name we gave to our Quarkus quickstart code generation system. 
Codestarts provide a personalized Quarkus getting started experience and really show the Quarkus breadth.
A Quarkus extension are 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.

== 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)
* example: 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

*NOTE* The `codestart.yml` file and the directory structure follow the same principle, it can optionally contain a base and/or some language overrides.

=== Project generation

When generating a Quarkus project:

. Codestarts to use are resolved depending on the input
. The Codestarts' `shared-data` (defined in the different codestart.yml) is merge together and made available to all codestarts
. The relevant files are processed:
** Only the files that are related to the selected language are processed
** The files are processed differently based on a naming convention.
** The data is used to render Qute templates
** We always process in this order: 

. language
. project
. buildtool
. config
. tooling
. example


The data used to generate a specific codestart is a merge of:

. The data of the codestart to generate
. All codestarts "shared" data
. The user input
. Some specific post processing (e.g. adding dependencies)

*NOTE* The data (shared or not) can also be specific to a language.

=== 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
* `./[languageName]` contains all the files that will be processed if the specified language has been selected (overriding base)

=== codestart.yml

codestart.yml:
[source,yaml]
----
name: the unique name - REQUIRED
ref: the reference name (not unique) to use for extension matching (else the name is used)
type: the type [example (default), project, buildtool, language, config] or any custom type
fallback: flag to indicate that it should be selected as fallback when no codestart has been selected with type - Only for base types
preselected: flag to indicate that it should be pre-selected - Only for extra types.
spec:
  [base or language name]: the specification (base, java, ...)
    data: a map of data to use only for this codestart
    shared-data: a map of data to use accross all codestarts
    dependencies: a list of dependencies to add when this is selected
    test-dependencies: a list of test dependencies to add when this is selected
----

=== Naming Convention for files

* `.tpl.qute` will be processed with Qute (`.tpl.qute` will be removed from the output file name).
* `.include.qute` is used as a Qute template for inclusion (only available to the codestart, not listed in the generated project ).

  Example: When using `{#include [name]}` in a template, it will look for `[name].include.qute` in the language dir, then in the base dir or the codestart.

* an output strategy can be defined for specific files, it defines some specific logic on how to deal with those files.

 Example: in the Quarkus project `codestart.yml`:
[source,yaml]
----
output-strategy:
  "pom.xml": smart-pom-merge # smartly merge pom.xml contents together
  "README.md": append # they are appended together
  "readme.md": forbidden # it will fail if found in any codestart
  "README.adoc": forbidden
  "readme.adoc": forbidden
  ".gitignore": append
  "src/main/resources/application.yml": smart-config-merge # smartly merge config together and automatically converted to the selected config type (yaml or properties)
  "src/main/resources/application.yaml": forbidden # should use yml instead
  "src/main/resources/application.properties": forbidden # should use yml instead
  "*": fail-on-duplicate # it will fail if a duplicate is found for all other files
----

* other files are just copied as is.


=== Writing Example Code for an Extension

Let's imagine we are writing the example codestart for my "foo" extension. As we discussed before, the base of the project is already provided so we can focus on the example code.

1. Create your `codestart.yml`:

codestart.yml:
[source,yaml]
----
---
name: foo-example
ref: foo
type: example
spec:
  base:
    data:
      # Some data for my templates which gives could be overridden by the user input
      some:
        data:
          here: bar
          there: foo
    dependencies:
      # the dependencies needed for my codestart (note that the extension dependency is auto-added if missing)
      - io.quarkus:quarkus-foo
      - io.quarkus:quarkus-resteasy
      # ... you can also provide a version (when it's not part of the platform bom)
      - group:artifact:version
    test-dependencies:
      # test dependencies
      - io.rest-assured:rest-assured
----

*NOTE* You don't need to add `pom.xml` or `build.gradle`, it is going to be auto generated. It will include the dependencies provided in the `codestart.yml`.

2. Add you example code in java, kotlin or scala

* java/src/main/java/org/acme/foo/Foo.java:
[source,java]
----
package org.acme.foo

import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.core.MediaType

@Path("foo")
class ExampleResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    fun hello() = "Hello foo"
}
----

* kotlin/src/main/kotlin/org/acme/foo/Foo.kt
* scala/src/main/scala/org/acme/foo/Foo.kt

*NOTE* Just add `.tpl.qute` if you want it to be rendered with qute and use some data and simple logic

*NOTE* You can use a `base` directory to add files to process for all languages: readme, configs, ...


2. Add some configuration (if needed)

The `base/src/main/resources/application.yml` file is going to be merged with the other codestarts config and automatically converted to the selected config type (yaml or properties).

Note: if it's specific to a language, you can put the config in each languages folders

* base/src/main/resources/application.yml (using quarkus yaml config convention):
[source,yaml]
----
quarkus:
  http:
    port: 8081
----

3. Create a readme section (if needed)

This will be appended to all different selected examples.

* base/README.md
[source,markdown]
----
# FOO Example

The Foo Example shows...
----

=== Tips for writing extension example code

- Your example must/should be independent from buildtool and dockerfiles
- Use the package `org.acme.[unique-name]` for your sources.
- Use the path `/unique-name/...` for your REST paths
- Write tests for your examples
- Examples in different codestarts must be independent, only the config and the build file are merged.
- 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 add languages independently

== Problems to solve

- How to test that (in combinations)?
- Dependencies conflicts?
- Config conflicts?
- Versioning?
- Dynamic paths for dynamic package names (should or should not do)?
    - `/{project.package-name}` or auto-replace `org.acme`
- We could add `foo.data.qute` processed and made available in data `foo` as a collection to other templates
