Skip to content

fix: add [missing plugin tutorials](https://github.com/go-vela/docs-o… #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/usage/plugins/tutorials/bash.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
title: "Bash"
sidebar_position: 1
---

:::warning
Expand Down
145 changes: 145 additions & 0 deletions docs/usage/plugins/tutorials/go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
title: "Go"
---

:::warning
We recommend reviewing [Docker's best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) before attempting to create a custom plugin.

We recommend that all plugins be placed inside a [scratch image](https://hub.docker.com/_/scratch).
:::

## Overview

From [Go documentation](https://golang.org/):

> Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.

## Code

To create a plugin using Go, we'll need to first decide what task we want this plugin to accomplish.

For this example, we're going to create a program that makes an HTTP request from the provided input:

```go
package main

import (
"fmt"
"net/http"
"os"
"strings"
)

func main() {
// import method parameter from environment
method := os.Getenv("PARAMETER_METHOD")
// import body parameter from environment
body := os.Getenv("PARAMETER_BODY")
// import url parameter from environment
url := os.Getenv("PARAMETER_URL")

// create payload from body
payload := strings.NewReader(body)

// create new HTTP request from provided input
request, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

// send HTTP request and capture response
response, err := http.DefaultClient.Do(request)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

// output the response
fmt.Println(response)
}
```

:::info
An example of this code is provided in the [go section](https://github.com/go-vela/vela-tutorials/tree/main/plugins/go) of the [go-vela/vela-tutorials](https://github.com/go-vela/vela-tutorials/tree/main/plugins) repository.
:::

## Executable

Now that we have the program to accomplish our plugin's task, we need to compile the code to produce an executable binary for the target platform:

```sh
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o vela-sample
```

:::warning
Please ensure the program is compiled for the right target platform.

If it's not, the plugin may fail to properly run and produce unclear error messages.
:::

## Image

Once we have the executable needed to accomplish our plugin's task, we need to create a Dockerfile to produce an image.

This image should contain the binary and be setup to run that binary when the plugin is executed:

```docker
FROM golang:alpine

RUN apk add --update --no-cache ca-certificates

COPY vela-sample /bin/vela-sample

ENTRYPOINT ["/bin/vela-sample"]
```

:::info
An example of this image is provided in the [target/vela-sample](https://hub.docker.com/r/target/vela-sample) Docker repository.
:::

## Publishing

In order to run the plugin in a pipeline, we'll need to make sure we build and publish it to a Docker registry:

```sh
# build the image
docker build -t target/vela-sample:go .

# publish the image
docker push target/vela-sample:go
```

:::info
This has the added benefit of enabling others in the community to consume your plugin!
:::

## Troubleshooting

To verify that the plugin performs the desired task, it can be executed locally via the command line:

```sh
docker run --rm \
-e PARAMETER_BODY="This is a sample Vela plugin written with Go" \
-e PARAMETER_METHOD="POST" \
-e PARAMETER_URL="http://vela.localhost.com" \
target/vela-sample:go
```

## Usage

After publishing the image to a Docker registry, it can be referenced in a pipeline:

```yaml
version: "1"

steps:
- name: sample go plugin
image: target/vela-sample:go
pull: always
parameters:
url: http://vela.localhost.com
method: POST
body: |
This is a sample Vela plugin written with Go
```
174 changes: 174 additions & 0 deletions docs/usage/plugins/tutorials/kotlin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
---
title: "Kotlin"
---

:::warning
We recommend reviewing [Docker's best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) before attempting to create a custom plugin.

We recommend that all plugins be placed inside a [scratch image](https://hub.docker.com/_/scratch).
:::

## Overview

From [Kotlin documentation](https://www.kotlinlang.org/):

> Kotlin is...
>
> A modern, concise and safe programming language that is easy to pick up, so you can create powerful applications immediately

## Code

To create a plugin using Kotlin, we'll need to first decide what task we want this plugin to accomplish.

For this example, we're going to create a program that makes an HTTP request from the provided input:

```kotlinlang
import org.http4k.client.ApacheClient
import org.http4k.core.*
import org.http4k.format.Jackson.auto
import yellowstone.cr.VCRException

fun main() {
// get the vela parameters from env variables
val method = when ("METHOD".parameter.envOrDefault("GET").trim().lowercase()) {
"get" -> Method.GET
"put" -> Method.PUT
"post" -> Method.POST
"delete" -> Method.DELETE
else -> throw Exception("Method not supported")
}
val body = "BODY".parameter.env
val url = "URL".parameter.env

// set up the clientId
val client: HttpHandler = ApacheClient()

// make the request and print the result
println(Request(method, url).addBody(body).okOrDie(client).toObject<String>())
}

// Helper functions
val String.env get() = System.getenv(this) ?: throw VCRException("The environment variable $this is required but missing!")
fun String.envOrDefault(default: String) = System.getenv(this) ?: default
val String.parameter get() = "PARAMETER_$this"
fun Request.okOrDie(client: HttpHandler) = client(this).let { response ->
response.takeIf { it.status.successful }
?: throw Exception("Got unexpected ${response.status.code} from request ${method.name} $uri! ${response.bodyString()}")
}

inline fun <reified T : Any> Response.toObject() = Body.auto<T>().toLens()(this)
inline fun <reified T : Any> Request.addBody(t: T) = Body.auto<T>().toLens()(t, this)
```

## Jar

In order to make this code a runnable executable, you must first turn it into a jar file. Below is an example `build.gradle.kts`

```kotlinlang
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
application
kotlin("jvm") version "1.5.10"
}

repositories {
mavenCentral()
}

application {
group = "mygroup"
mainClass.set("mygroup.MainKt")
}

dependencies {
fun deps(format: String, vararg arr: String) = with(format) { arr.forEach { implementation(format(it)) } }

implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
deps("org.http4k:http4k-%s:4.9.9.0", "client-apache", "format-jackson")
}

tasks {
jar {
enabled = true
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = JavaVersion.VERSION_11.majorVersion
}
withType<Test> {
useJUnitPlatform()
}
}
```

To build the jar, run `./gradlew clean build distTar`

## Image

Once we have the jar needed to accomplish our plugin's task, we need to create a Dockerfile to produce an image.

This image should contain the jar and be setup to run that jar when the plugin is executed

```docker
FROM alpine:latest

# Install Java 11
ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk
ENV PATH $PATH:/usr/lib/jvm/java-11-openjdk/jre/bin:/usr/lib/jvm/java-11-openjdk

RUN apk update && \
apk upgrade && \
apk --no-cache add openjdk11 --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community

# copy the executable
ADD build/distributions/vela-sample.tar /

CMD ["/vela-sample/bin/vela-sample"]
```

## Publishing

In order to run the plugin in a pipeline, we'll need to make sure we build and publish it to a Docker registry:

```sh
# build the image
docker build -t target/vela-sample:kotlin .

# publish the image
docker push target/vela-sample:kotlin
```

:::info
This has the added benefit of enabling others in the community to consume your plugin!
:::

## Troubleshooting

To verify that the plugin performs the desired task, it can be executed locally via the command line:

```sh
docker run --rm \
-e PARAMETER_BODY="This is a sample Vela plugin written with Kotlin" \
-e PARAMETER_METHOD="POST" \
-e PARAMETER_URL="http://vela.localhost.com" \
target/vela-sample:kotlin
```

## Usage

After publishing the image to a Docker registry, it can be referenced in a pipeline:

```yaml
version: "1"

steps:
- name: sample kotlin plugin
image: target/vela-sample:kotlin
pull: always
parameters:
url: http://vela.localhost.com
method: POST
body: |
This is a sample Vela plugin written with Kotlin
```
Loading