Skip to content

Commit 941cd61

Browse files
committed
Add gradle plugin for creating lambda release artifact
1 parent 20fadbe commit 941cd61

File tree

9 files changed

+102
-29
lines changed

9 files changed

+102
-29
lines changed

.github/workflows/buildLinux86_64.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ jobs:
2020
sudo apt-get install libcurl3-dev
2121
2222
- name: Run build
23-
run: ./gradlew build
23+
run: ./gradlew buildLambdaRelease
2424

2525
- name: Upload artifacts
2626
uses: actions/upload-artifact@v4
2727
with:
2828
name: kotlin-native-build
29-
path: sample/build/bin
29+
path: sample/build/bin/lambda/release

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ xcuserdata
66
!src/**/build/
77
local.properties
88
.idea
9+
.vscode
910
.DS_Store
1011
captures
1112
.externalNativeBuild

README.md

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,19 @@ To create a simple lambda function, follow the following steps:
3434
2. Include library dependency into your module-level build.gradle file
3535

3636
```kotlin
37-
//..
3837
kotlin {
39-
//..
4038
sourceSets {
4139
nativeMain.dependencies {
4240
implementation("io.github.trueangle:lambda-runtime:0.0.2")
4341
implementation("io.github.trueangle:lambda-events:0.0.2")
4442
}
4543
}
46-
//..
4744
}
48-
//..
4945
```
5046

5147
3. Specify application entry point reference and supported targets
52-
5348
```kotlin
54-
//..
5549
kotlin {
56-
//..
5750
listOf(
5851
macosArm64(),
5952
macosX64(),
@@ -66,14 +59,10 @@ kotlin {
6659
}
6760
}
6861
}
69-
//..
7062
}
71-
//..
7263
```
7364

74-
4. Choose lambda function type.
75-
76-
There are two types of lambda functions:
65+
4. Choose lambda function type. There are two types of lambda functions:
7766

7867
### Buffered
7968
Buffered Lambda function collects all the data it needs to return as a response before sending
@@ -149,23 +138,19 @@ used. Here's how to run project's sample:
149138

150139
## Build and deploy to AWS
151140

152-
1. Execute `./gradlew build`
153-
2. After successful build execute `cd YOUR_MODULE/build/bin/linuxX64/releaseExecutable/` this will
154-
locate Lambda handler's executable file, e.g. `YOUR_MODULE.kexe`. The name of the file (including
155-
the extension) will be used as `handler` name. Don't forget to specify it upon
156-
lambda-function creation.
157-
3. Execute `(echo '#!/bin/sh' > bootstrap && echo './"$_HANDLER"' >> bootstrap && chmod +x bootstrap && zip -r bootstrap.zip ./*)`
158-
4. Deploy bootstrap.zip archive to AWS. If you have never used AWS Lambda
141+
1. Apply plugin `id("io.github.trueangle.plugin.lambda") version "0.0.1"`
142+
2. Execute `./gradlew buildLambdaRelease`. The command will output the path to the archive containing lambda executable (YOUR_MODULE_NAME.kexe) located in (YOUR_MODULE_NAME/build/bin/lambda/release/YOUR_MODULE_NAME.zip)
143+
3. Deploy .zip archive to AWS. If you have never used AWS Lambda
159144
before, [learn how to deploy Lambda function as zip archive manually](https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-zip.html)
160145
or
161146
using [AWS CLI](https://docs.aws.amazon.com/codedeploy/latest/userguide/getting-started-codedeploy.html):
162147

163148
```bash
164-
$ aws lambda create-function --function-name sample \
165-
--handler sample.kexe \ # Important to specify the name of the Lambda executable
166-
--zip-file bootstrap.zip \
149+
$ aws lambda create-function --function-name LAMBDA_FUNCTION_NAME \
150+
--handler YOUR_MODULE_NAME.kexe \ # Important to specify the name of the Lambda executable.
151+
--zip-file YOUR_MODULE_NAME.zip \
167152
--runtime provided.al2023 \ # Change this to provided.al2 if you would like to use Amazon Linux 2
168-
--role arn:aws:iam::XXXXXXXXXXXXX:role/your_lambda_execution_role \
153+
--role arn:aws:iam::XXXXXXXXXXXXX:role/YOUR_LAMBDA_EXECUTION_ROLE \
169154
--environment Variables={RUST_BACKTRACE=1} \
170155
--tracing-config Mode=Active
171156
```
@@ -233,7 +218,6 @@ Log.fatal(message: T?) // Messages about serious errors that cause the applicati
233218
build command:
234219

235220
```bash
236-
237221
docker build -t sample .
238222
docker run --rm -v $(pwd):/sample -w /sample sample ./gradlew build
239223
```

gradle-plugin/build.gradle.kts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
plugins {
2+
`java-gradle-plugin`
3+
`kotlin-dsl`
4+
id("com.gradle.plugin-publish") version "1.2.1"
5+
}
6+
7+
repositories {
8+
gradlePluginPortal()
9+
}
10+
11+
kotlin {
12+
jvmToolchain(17)
13+
}
14+
15+
group = "io.github.trueangle.plugin.lambda"
16+
version = "0.0.1"
17+
18+
gradlePlugin {
19+
website.set("https://github.com/trueangle/kotlin-native-aws-lambda-runtime")
20+
vcsUrl.set("https://github.com/trueangle/kotlin-native-aws-lambda-runtime.git")
21+
22+
plugins {
23+
create("buildLambdaRelease") {
24+
id = "io.github.trueangle.plugin.lambda"
25+
implementationClass = "LambdaPlugin"
26+
displayName = "A plugin for Kotlin Native AWS Lambda"
27+
description = "A plugin to streamline the development of Kotlin Native AWS Lambda functions"
28+
tags.set(listOf("aws", "lambda", "kotlin-native"))
29+
}
30+
}
31+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import org.gradle.api.DefaultTask
2+
import org.gradle.api.Plugin
3+
import org.gradle.api.Project
4+
import org.gradle.api.tasks.TaskAction
5+
import java.io.File
6+
7+
class LambdaPlugin : Plugin<Project> {
8+
override fun apply(project: Project) {
9+
project.tasks.create("buildLambdaRelease", LambdaPackagerTask::class.java)
10+
}
11+
}
12+
13+
abstract class LambdaPackagerTask : DefaultTask() {
14+
15+
@TaskAction
16+
fun packageLambda() {
17+
project.exec {
18+
workingDir = project.rootDir
19+
commandLine("./gradlew", "build")
20+
}
21+
22+
val buildDir = project.layout.buildDirectory
23+
val executableDir = project.file(buildDir.dir("bin/linuxX64/releaseExecutable"))
24+
val executable = executableDir
25+
.listFiles()
26+
?.first { it.name.endsWith(".kexe") }
27+
?: throw IllegalStateException("No .kexe file found in $executableDir")
28+
val outputZip = project.file(buildDir.dir("lambda/release/${executable.nameWithoutExtension}.zip"))
29+
30+
outputZip.parentFile.mkdirs()
31+
outputZip.setWritable(true)
32+
33+
val bootstrapFile = File(executableDir, "bootstrap")
34+
bootstrapFile.writeText(
35+
"""
36+
#!/bin/sh
37+
./"${'$'}_HANDLER"
38+
""".trimIndent()
39+
)
40+
bootstrapFile.setExecutable(true)
41+
42+
project.exec {
43+
workingDir = executableDir
44+
commandLine("zip", "-r", outputZip.absolutePath, ".")
45+
}
46+
47+
logger.lifecycle(
48+
"\u001B[0;32mLambda package created at ${outputZip.absolutePath}. " +
49+
"Provide the \u001B[1m${executable.name}\u001B[0;32m as a value of " +
50+
"\u001B[1m--handler\u001B[0;32m argument while configuring the lambda function on AWS\u001B[0m\n"
51+
)
52+
}
53+
}

gradle/libs.versions.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ksp = "2.0.10-1.0.24"
1111
allopen = "2.0.20"
1212
mokkery = "2.3.0"
1313
kotlinx-resources = "0.9.0"
14+
gradle-publish = "1.2.0"
1415

1516
[libraries]
1617
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
@@ -37,4 +38,5 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi
3738
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
3839
allopen = { id = "org.jetbrains.kotlin.plugin.allopen", version.ref = "allopen" }
3940
mokkery = { id = "dev.mokkery", version.ref = "mokkery" }
40-
kotlinx-resources = { id = "com.goncalossilva.resources", version.ref = "kotlinx-resources" }
41+
kotlinx-resources = { id = "com.goncalossilva.resources", version.ref = "kotlinx-resources" }
42+
gradle-publish = { id = "com.gradle.plugin-publish", version.ref = "gradle-publish" }

lambda-runtime/src/commonMain/kotlin/io/github/trueangle/knative/lambda/runtime/LambdaRuntime.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import io.github.trueangle.knative.lambda.runtime.log.debug
1414
import io.github.trueangle.knative.lambda.runtime.log.error
1515
import io.github.trueangle.knative.lambda.runtime.log.fatal
1616
import io.github.trueangle.knative.lambda.runtime.log.info
17-
import io.github.trueangle.knative.lambda.runtime.log.trace
1817
import io.github.trueangle.knative.lambda.runtime.log.warn
1918
import io.ktor.client.HttpClient
2019
import io.ktor.client.engine.HttpClientEngine
@@ -35,9 +34,10 @@ import kotlinx.serialization.json.Json
3534
object LambdaRuntime {
3635
@OptIn(ExperimentalSerializationApi::class)
3736
internal val json = Json { explicitNulls = false }
37+
@PublishedApi
38+
internal val curlHttpClient = createHttpClient(Curl.create())
3839

3940
inline fun <reified I, reified O> run(crossinline initHandler: () -> LambdaHandler<I, O>) = runBlocking {
40-
val curlHttpClient = createHttpClient(Curl.create())
4141
val lambdaClient = LambdaClientImpl(curlHttpClient)
4242

4343
Runner(client = lambdaClient, log = Log).run(false, initHandler)

sample/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
alias(libs.plugins.kotlin.multiplatform)
33
alias(libs.plugins.kotlin.serialization)
4+
id("io.github.trueangle.plugin.lambda")
45
}
56

67
kotlin {

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencyResolutionManagement {
2828
}
2929
}
3030
includeBuild("convention-plugins")
31+
includeBuild("gradle-plugin")
3132
include(":lambda-runtime")
3233
include(":sample")
3334
include(":lambda-events")

0 commit comments

Comments
 (0)