├── .github
├── CODEOWNERS
└── actions
│ └── test-action
│ └── action.yml
├── version.txt
├── test-action
├── webpack.config.d
│ └── github.action.config.js
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradle.properties
├── README.md
├── settings.gradle.kts
├── build.gradle.kts
├── src
│ └── main
│ │ └── kotlin
│ │ └── Main.kt
└── gradlew.bat
├── kotlin-js-action
├── kotlin-js-action
│ ├── gradle.properties
│ ├── src
│ │ ├── main
│ │ │ └── kotlin
│ │ │ │ ├── internal
│ │ │ │ ├── core
│ │ │ │ │ ├── Typealiases.kt
│ │ │ │ │ ├── summary.module_@actions_core.kt
│ │ │ │ │ └── core.module_@actions_core.kt
│ │ │ │ ├── httpclient
│ │ │ │ │ ├── Typealiases.kt
│ │ │ │ │ ├── interfaces.module_@actions_http-client.kt
│ │ │ │ │ └── index.module_@actions_http-client.kt
│ │ │ │ ├── Typealiases.kt
│ │ │ │ ├── glob
│ │ │ │ │ ├── internal-hash-file-options.module_@actions_glob.kt
│ │ │ │ │ ├── internal-globber.module_@actions_glob.kt
│ │ │ │ │ ├── glob.module_@actions_glob.kt
│ │ │ │ │ └── internal-glob-options.module_@actions_glob.kt
│ │ │ │ ├── github
│ │ │ │ │ ├── github.module_@actions_github.kt
│ │ │ │ │ ├── Typealiases.kt
│ │ │ │ │ ├── context.module_@actions_github.kt
│ │ │ │ │ ├── RequestRequestOptions.module_@octokit_types.kt
│ │ │ │ │ ├── types.module_@octokit_core.kt
│ │ │ │ │ ├── index.module_@octokit_core.kt
│ │ │ │ │ └── interfaces.module_@actions_github.kt
│ │ │ │ ├── artifact
│ │ │ │ │ ├── download-options.module_@actions_artifact.kt
│ │ │ │ │ ├── upload-options.module_@actions_artifact.kt
│ │ │ │ │ └── artifact-client.module_@actions_artifact.kt
│ │ │ │ ├── exec
│ │ │ │ │ ├── exec.module_@actions_exec.kt
│ │ │ │ │ └── interfaces.module_@actions_exec.kt
│ │ │ │ ├── cache
│ │ │ │ │ ├── cache.module_@actions_cache.kt
│ │ │ │ │ └── options.module_@actions_cache.kt
│ │ │ │ ├── lib.es2018.asyncgenerator.module_dukat.kt
│ │ │ │ ├── index.module_before-after-hook.kt
│ │ │ │ ├── lib.es2018.asynciterable.module_dukat.kt
│ │ │ │ ├── io
│ │ │ │ │ └── io.module_@actions_io.kt
│ │ │ │ └── toolcache
│ │ │ │ │ └── toolcache.kt
│ │ │ │ └── com
│ │ │ │ └── rnett
│ │ │ │ └── action
│ │ │ │ ├── core
│ │ │ │ ├── PATH.kt
│ │ │ │ ├── SummaryTableItem.kt
│ │ │ │ ├── outputs.kt
│ │ │ │ ├── AnnotationProperties.kt
│ │ │ │ ├── inputs.kt
│ │ │ │ ├── state.kt
│ │ │ │ ├── TopLevel.kt
│ │ │ │ ├── logger.kt
│ │ │ │ └── Env.kt
│ │ │ │ ├── exec
│ │ │ │ ├── ExecResult.kt
│ │ │ │ └── Shell.kt
│ │ │ │ ├── httpclient
│ │ │ │ ├── Auth.kt
│ │ │ │ ├── HttpResponse.kt
│ │ │ │ ├── RequestHandler.kt
│ │ │ │ └── Headers.kt
│ │ │ │ ├── github
│ │ │ │ └── context.kt
│ │ │ │ ├── artifact
│ │ │ │ ├── Responses.kt
│ │ │ │ └── artifact.kt
│ │ │ │ ├── OperatingSystem.kt
│ │ │ │ ├── Utils.kt
│ │ │ │ └── io
│ │ │ │ └── io.kt
│ │ └── test
│ │ │ ├── resources
│ │ │ └── archives
│ │ │ │ ├── test.7z
│ │ │ │ ├── test.zip
│ │ │ │ ├── test.tar.bz2
│ │ │ │ ├── test.tar.gz
│ │ │ │ └── test.tar
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── rnett
│ │ │ └── action
│ │ │ ├── TestOS.kt
│ │ │ ├── TestEnv.kt
│ │ │ ├── TestStreamUtils.kt
│ │ │ ├── TestWithDir.kt
│ │ │ ├── TestExec.kt
│ │ │ ├── TestToolCache.kt
│ │ │ └── TestGlob.kt
│ ├── README.md
│ ├── packages.md
│ └── build.gradle.kts
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradle.properties
├── build-logic
│ ├── common-module
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ └── kjs-action.common-module.gradle.kts
│ ├── js-module
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ └── kjs-action.js-module.gradle.kts
│ ├── publishing
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ └── kjs-action.publishing.gradle.kts
│ ├── metadata
│ │ ├── src
│ │ │ └── main
│ │ │ │ └── kotlin
│ │ │ │ └── com
│ │ │ │ └── rnett
│ │ │ │ └── action
│ │ │ │ ├── MetadataExtension.kt
│ │ │ │ └── MetadataPlugin.kt
│ │ └── build.gradle.kts
│ ├── docs
│ │ ├── src
│ │ │ └── main
│ │ │ │ └── kotlin
│ │ │ │ └── com
│ │ │ │ └── rnett
│ │ │ │ └── action
│ │ │ │ ├── LeafDocsExtension.kt
│ │ │ │ ├── RootDocsExtension.kt
│ │ │ │ ├── DocsRootPlugin.kt
│ │ │ │ └── DocsLeafPlugin.kt
│ │ └── build.gradle.kts
│ └── settings.gradle.kts
├── serialization
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── test
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── rnett
│ │ │ └── action
│ │ │ └── serialization
│ │ │ ├── TestSerialization.kt
│ │ │ └── TestJsonHttpClient.kt
│ │ └── main
│ │ └── kotlin
│ │ └── com
│ │ └── rnett
│ │ └── action
│ │ └── serialization
│ │ ├── HttpClient.kt
│ │ └── ReadOnlyDelegates.kt
├── kotlin-js-action-plugin
│ ├── README.md
│ ├── src
│ │ └── main
│ │ │ └── kotlin
│ │ │ └── com
│ │ │ └── rnett
│ │ │ └── action
│ │ │ ├── Constants.kt
│ │ │ ├── GithubActionPlugin.kt
│ │ │ ├── KotlinAction.kt
│ │ │ └── AutoBuildWorkflow.kt
│ └── build.gradle.kts
├── DOCS.md
├── build.gradle.kts
├── settings.gradle.kts
└── gradlew.bat
├── .idea
├── vcs.xml
├── kotlinc.xml
├── misc.xml
├── artifacts
│ ├── test_action_1_3_0_SNAPSHOT.xml
│ ├── serialization_1_5_1_SNAPSHOT.xml
│ ├── kotlin_js_action_1_5_1_SNAPSHOT.xml
│ ├── serialization_1_6_0_SNAPSHOT.xml
│ └── kotlin_js_action_1_6_0_SNAPSHOT.xml
├── kotlin-js-action.iml
├── modules
│ ├── 31940085
│ │ └── kotlin-js-action.build-logic.docs.iml
│ ├── 904965605
│ │ └── com.github.rnett.ktjs-github-action.kotlin-js-action-parent.iml
│ ├── 1473984502
│ │ └── kotlin-js-action.build-logic.js-module.iml
│ ├── 1664358933
│ │ └── kotlin-js-action.build-logic.iml
│ ├── 1757210950
│ │ └── com.github.rnett.ktjs-github-action.kotlin-js-action-parent.serialization.iml
│ ├── test-action.iml
│ ├── -1802679831
│ │ └── kotlin-js-action.build-logic.metadata.iml
│ ├── -921324371
│ │ └── kotlin-js-action.build-logic.publishing.iml
│ ├── -868266476
│ │ └── kotlin-js-action.build-logic.common-module.iml
│ ├── -224497576
│ │ └── com.github.rnett.ktjs-github-action.kotlin-js-action-parent.kotlin-js-action.iml
│ └── -898967992
│ │ └── com.github.rnett.ktjs-github-action.kotlin-js-action-parent.kotlin-js-action-plugin.iml
├── jarRepositories.xml
└── compiler.xml
├── libs.versions.toml
├── .gitignore
├── CONTRIBUTING.md
├── CHANGELOG.md
└── README.md
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @rnett
2 |
--------------------------------------------------------------------------------
/version.txt:
--------------------------------------------------------------------------------
1 | 1.6.1-SNAPSHOT
2 |
--------------------------------------------------------------------------------
/test-action/webpack.config.d/github.action.config.js:
--------------------------------------------------------------------------------
1 | config.target = 'node';
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.js.generate.executable.default=false
2 | kotlin.js.generate.externals=false
--------------------------------------------------------------------------------
/test-action/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rnett/kotlin-js-action/HEAD/test-action/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/kotlin-js-action/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rnett/kotlin-js-action/HEAD/kotlin-js-action/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/core/Typealiases.kt:
--------------------------------------------------------------------------------
1 | package internal.core
2 |
3 | internal typealias SummaryTableRow = Array
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.7z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rnett/kotlin-js-action/HEAD/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.7z
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rnett/kotlin-js-action/HEAD/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.zip
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.tar.bz2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rnett/kotlin-js-action/HEAD/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.tar.bz2
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rnett/kotlin-js-action/HEAD/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.tar.gz
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/httpclient/Typealiases.kt:
--------------------------------------------------------------------------------
1 | package internal.httpclient
2 |
3 | internal typealias HttpClientError = Error
4 |
5 | internal typealias HttpError = Error
--------------------------------------------------------------------------------
/test-action/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.caching=true
2 | org.gradle.parallel=false
3 | kotlin.code.style=official
4 | kotlin.js.generate.executable.default=false
5 | kotlin.js.generate.externals=false
6 | sourceLinkBranch=main
--------------------------------------------------------------------------------
/test-action/README.md:
--------------------------------------------------------------------------------
1 | # test-action
2 |
3 | A test action for integration tests. See [test-action/action.yml](../.github/actions/test-action/action.yml) for the
4 | action definition and [the CI](../.github/workflows/ci.yml#L70) for usage.
--------------------------------------------------------------------------------
/test-action/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/kotlin-js-action/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/kotlin-js-action/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.caching=true
2 | org.gradle.parallel=false
3 | kotlin.code.style=official
4 | kotlin.js.generate.executable.default=false
5 | kotlin.js.generate.externals=false
6 | org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=1024m
7 | sourceLinkBranch=main
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/common-module/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | gradlePluginPortal()
8 | }
9 |
10 | dependencies {
11 | api(project(":docs"))
12 | api(project(":publishing"))
13 | }
14 |
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/js-module/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | gradlePluginPortal()
8 | }
9 |
10 | dependencies {
11 | api(project(":common-module"))
12 | api(libs.build.kotlin.js)
13 | }
14 |
--------------------------------------------------------------------------------
/kotlin-js-action/serialization/README.md:
--------------------------------------------------------------------------------
1 | # Module Kotlin JS GitHub Action SDK Serialization support
2 |
3 | Adds support for Kotlinx serialization, by adding delegate transformers.
4 |
5 | Example:
6 |
7 | ```kotlin
8 | val json = Json{}
9 | var testState: MyData by state.deserialized(json)
10 | ```
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action-plugin/README.md:
--------------------------------------------------------------------------------
1 | # Module Kotlin JS GitHub Action Gradle Plugin
2 |
3 | A gradle plugin (`com.github.rnett.ktjs-github-action`) that provides functions to configure Kotlin/JS for GitHub
4 | actions, and to auto-generate a GitHub Actions workflow to update action distributables on push.
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/publishing/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | gradlePluginPortal()
8 | }
9 |
10 | dependencies {
11 | api(project(":metadata"))
12 | implementation(project(":docs"))
13 | implementation(libs.build.publish)
14 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action-plugin/src/main/kotlin/com/rnett/action/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | internal object Constants {
4 | val taskGroup = "kotlin js github action"
5 | val createWebpackTaskName = "createGithubActionWebpackConfig"
6 | val generateWorkflowTaskName = "generateBuildWorkflow"
7 |
8 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestOS.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | class TestOS {
7 | @Test
8 | fun current() {
9 | assertEquals(TestEnv.os.lowercase(), OperatingSystem.current.name.lowercase())
10 | }
11 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action-plugin/src/main/kotlin/com/rnett/action/GithubActionPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 |
6 | /**
7 | * Does nothing, just a placeholder.
8 | */
9 | class GithubActionPlugin : Plugin {
10 | override fun apply(target: Project) {
11 |
12 | }
13 | }
--------------------------------------------------------------------------------
/kotlin-js-action/DOCS.md:
--------------------------------------------------------------------------------
1 | # Kotlin JS GitHub Action SDK
2 |
3 | See [the README](https://github.com/rnett/kotlin-js-action#readme) for an overview.
4 |
5 | Artifacts:
6 |
7 | * `kotlin-js-action` - the GitHub Actions SDK.
8 | * `kotlin-js-action-plugin` - the Gradle plugin to help with build setup.
9 | * `serialization` - [Kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) helpers for the SDK.
--------------------------------------------------------------------------------
/.idea/artifacts/test_action_1_3_0_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/test-action/build/libs
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/kotlin-js-action/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kjs-action.docs-root")
3 | alias(libs.plugins.kotlin.js) apply false
4 | alias(libs.plugins.publish) apply false
5 | }
6 |
7 | repositories {
8 | mavenCentral()
9 | gradlePluginPortal()
10 | }
11 |
12 | metadata {
13 | title.set("Kotlin/JS GitHub Actions SDK")
14 | }
15 |
16 | docs {
17 | readmeHeader.set("Kotlin JS GitHub Action SDK")
18 | }
--------------------------------------------------------------------------------
/.idea/artifacts/serialization_1_5_1_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/kotlin-js-action/serialization/build/libs
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/artifacts/kotlin_js_action_1_5_1_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/kotlin-js-action/kotlin-js-action/build/libs
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/artifacts/serialization_1_6_0_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/kotlin-js-action/serialization/build/libs
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/artifacts/kotlin_js_action_1_6_0_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/kotlin-js-action/kotlin-js-action/build/libs
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/Typealiases.kt:
--------------------------------------------------------------------------------
1 | package internal
2 |
3 |
4 |
5 | internal typealias HookMethod = (options: O) -> dynamic
6 |
7 | internal typealias BeforeHook = (options: O) -> Unit
8 |
9 | internal typealias ErrorHook = (error: E, options: O) -> Unit
10 |
11 | internal typealias AfterHook = (result: R, options: O) -> Unit
12 |
13 | internal typealias WrapHook = (hookMethod: HookMethod, options: O) -> dynamic
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/glob/internal-hash-file-options.module_@actions_glob.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 |
8 | package internal.glob
9 |
10 | internal external interface HashFileOptions {
11 | var followSymbolicLinks: Boolean?
12 | get() = definedExternally
13 | set(value) = definedExternally
14 | }
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/metadata/src/main/kotlin/com/rnett/action/MetadataExtension.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Project
4 | import org.gradle.api.provider.Property
5 | import org.gradle.api.provider.Provider
6 | import javax.inject.Inject
7 |
8 | abstract class MetadataExtension @Inject constructor(project: Project) {
9 | abstract val title: Property
10 |
11 | val description: Provider = project.provider { project.description }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/metadata/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | gradlePluginPortal()
8 | }
9 |
10 | tasks.processResources {
11 | from(rootDir.parentFile.parentFile.resolve("version.txt"))
12 | }
13 |
14 | gradlePlugin {
15 | plugins {
16 | create("kjs-metadata") {
17 | id = "kjs-action.metadata"
18 | implementationClass = "com.rnett.action.MetadataPlugin"
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/github.module_@actions_github.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/github")
3 | @file:JsNonModule
4 |
5 | package internal.github
6 |
7 | import kotlin.js.*
8 |
9 | internal external var context: Context
10 |
11 | internal external fun getOctokit(token: String, options: OctokitOptions = definedExternally): InstanceType
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/artifact/download-options.module_@actions_artifact.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/artifact")
3 | @file:JsNonModule
4 |
5 | package internal.artifact
6 |
7 | import kotlin.js.*
8 |
9 | internal external interface DownloadOptions {
10 | var createArtifactFolder: Boolean?
11 | get() = definedExternally
12 | set(value) = definedExternally
13 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/README.md:
--------------------------------------------------------------------------------
1 | # Module Kotlin JS GitHub Action SDK
2 |
3 | Kotlin JS utilities for writing GitHub Actions, including wrappers
4 | for [actions/toolkit](https://github.com/actions/toolkit) packages, except for `@actions/github`
5 | and `@actions/tool-cache`. `@actions/tool-cache` will be added once blocking `dukat` bugs are fixes.
6 |
7 | In addition to the `@actions` bindings, a utility `Path` class modeled after Python's `pathlib` is included, as are some
8 | miscellaneous utilities (like `JsObject` and an OS enum and detector).
9 |
--------------------------------------------------------------------------------
/kotlin-js-action/serialization/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kjs-action.js-module")
3 | alias(libs.plugins.kotlinx.serialization)
4 | }
5 |
6 | description = "Support for Kotlinx serialization use with GitHub APIs"
7 | metadata{
8 | title.set("Kotlin JS GitHub Action SDK Serialization support")
9 | }
10 |
11 | dependencies {
12 | testImplementation(kotlin("test"))
13 | testImplementation(libs.kotlinx.coroutines.test)
14 |
15 | api(libs.kotlinx.serialization.json)
16 | implementation(project(":kotlin-js-action"))
17 | }
18 |
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/docs/src/main/kotlin/com/rnett/action/LeafDocsExtension.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.provider.Property
4 | import org.gradle.api.provider.Provider
5 | import org.gradle.api.Project
6 | import org.jetbrains.dokka.Platform
7 | import javax.inject.Inject
8 |
9 | abstract class LeafDocsExtension @Inject constructor(val project: Project) {
10 | abstract val platform: Property
11 |
12 | val title: Provider get() = project.extensions.getByType(MetadataExtension::class.java).title
13 | }
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/docs/src/main/kotlin/com/rnett/action/RootDocsExtension.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.provider.Property
4 | import org.gradle.api.provider.Provider
5 | import org.gradle.api.Project
6 | import org.jetbrains.dokka.Platform
7 | import javax.inject.Inject
8 |
9 | abstract class RootDocsExtension @Inject constructor(val project: Project) {
10 | abstract val readmeHeader: Property
11 |
12 | val title: Provider get() = project.extensions.getByType(MetadataExtension::class.java).title
13 | }
--------------------------------------------------------------------------------
/.github/actions/test-action/action.yml:
--------------------------------------------------------------------------------
1 | name: "Test action"
2 | description: "Action to test Kotlin JS SDK"
3 | inputs:
4 | required-input:
5 | description: "A required input"
6 | required: true
7 | optional-no-default:
8 | description: "Optional input"
9 | required: false
10 | with-default:
11 | description: "Input with default"
12 | required: false
13 | default: "Test"
14 | multiline:
15 | description: "Multiline input"
16 | required: true
17 | runs:
18 | using: 'node16'
19 | main: '../../../test-action/build/dist/index.js'
20 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/PATH.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import com.rnett.action.Path
4 |
5 | /**
6 | * A setter for the path.
7 | */
8 | public object PATH {
9 | /**
10 | * Add a new path [inputPath] to PATH.
11 | */
12 | public operator fun plusAssign(inputPath: String) {
13 | core.addPath(inputPath)
14 | }
15 |
16 | /**
17 | * Add a new path [inputPath] to PATH.
18 | */
19 | public operator fun plusAssign(inputPath: Path): Unit = plusAssign(inputPath.path)
20 | }
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/common-module/src/main/kotlin/kjs-action.common-module.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.gradle.api.tasks.testing.AbstractTestTask
2 |
3 | plugins {
4 | id("kjs-action.docs-leaf")
5 | id("kjs-action.publishing")
6 | }
7 |
8 | tasks.withType(AbstractTestTask::class.java).configureEach {
9 | testLogging {
10 | showExceptions = true // It is true by default. Set it just for explicitness.
11 | exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
12 | }
13 | }
14 |
15 | repositories {
16 | mavenCentral()
17 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/glob/internal-globber.module_@actions_glob.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/glob")
3 | @file:JsNonModule
4 |
5 | package internal.glob
6 |
7 | import internal.AsyncGenerator__2
8 | import kotlin.js.*
9 |
10 | internal external interface Globber {
11 | fun getSearchPaths(): Array
12 | fun glob(): Promise>
13 | fun globGenerator(): AsyncGenerator__2
14 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/Typealiases.kt:
--------------------------------------------------------------------------------
1 | package internal.github
2 |
3 |
4 |
5 | internal typealias Constructor = Any
6 |
7 | internal typealias ReturnTypeOf = Any
8 |
9 | internal typealias UnionToIntersection = Any
10 |
11 | internal typealias AnyFunction = (args: Any) -> Any
12 |
13 | internal typealias OctokitPlugin = (octokit: Octokit, options: OctokitOptions) -> dynamic
14 | internal typealias Signal = Any
15 |
16 | internal typealias ReturnType = Any
17 |
18 | internal typealias InstanceType = Any
19 |
20 | internal typealias Fetch = Any
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestEnv.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import kotlinx.js.get
4 | import kotlin.reflect.KProperty
5 |
6 | object TestEnv {
7 | private operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
8 | val key = "TEST_ENV_${property.name}"
9 | return currentProcess.env[key] ?: error("Test environment variable $key not set")
10 | }
11 |
12 | val os by this
13 | val projectDirPath by this
14 | val tempDir by this
15 | val userHome by this
16 | val projectDir get() = Path(projectDirPath)
17 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/exec/ExecResult.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.exec
2 |
3 | public data class ExecFailureException(val command: String, val returnCode: Int, val stderr: String): RuntimeException("Command failed with return code $returnCode and stderr: $stderr")
4 |
5 | public data class ExecResult(private val command: String, val returnCode: Int, val stdout: String, val stderr: String){
6 | public fun throwIfFailure(): ExecResult = apply {
7 | if(returnCode != 0)
8 | throw ExecFailureException(command, returnCode, stderr)
9 | }
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/test-action/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("VERSION_CATALOGS")
2 |
3 | pluginManagement {
4 | repositories {
5 | mavenCentral()
6 | gradlePluginPortal()
7 | maven("https://oss.sonatype.org/content/repositories/snapshots") {
8 | mavenContent { snapshotsOnly() }
9 | }
10 | }
11 | }
12 |
13 | dependencyResolutionManagement {
14 | versionCatalogs {
15 | create(defaultLibrariesExtensionName.get()) {
16 | from(files("../libs.versions.toml"))
17 | }
18 | }
19 | }
20 |
21 | rootProject.name = "test-action"
22 |
23 | includeBuild("../kotlin-js-action")
24 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/artifact/upload-options.module_@actions_artifact.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/artifact")
3 | @file:JsNonModule
4 |
5 | package internal.artifact
6 |
7 | import kotlin.js.*
8 |
9 | internal external interface UploadOptions {
10 | var continueOnError: Boolean?
11 | get() = definedExternally
12 | set(value) = definedExternally
13 | var retentionDays: Number?
14 | get() = definedExternally
15 | set(value) = definedExternally
16 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/glob/glob.module_@actions_glob.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/glob")
8 | @file:JsNonModule
9 |
10 | package internal.glob
11 |
12 | import kotlin.js.Promise
13 |
14 | internal external fun create(patterns: String, options: GlobOptions = definedExternally): Promise
15 |
16 | internal external fun hashFiles(patterns: String, options: HashFileOptions = definedExternally, verbose: Boolean = definedExternally): Promise
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/metadata/src/main/kotlin/com/rnett/action/MetadataPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.kotlin.dsl.create
6 |
7 | class MetadataPlugin : Plugin {
8 | override fun apply(project: Project): Unit = with(project) {
9 | val extension = project.extensions.create("metadata", MetadataExtension::class)
10 | group = "com.github.rnett.ktjs-github-action"
11 | version = MetadataPlugin::class.java.getResource("/version.txt")?.readText()?.trim() ?: throw IllegalStateException("version.txt not found")
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test-action/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.rnett.action.githubAction
2 |
3 | plugins {
4 | alias(libs.plugins.kotlin.js)
5 | id("com.github.rnett.ktjs-github-action")
6 | }
7 |
8 | group = "com.github.rnett.ktjs-github-action.test"
9 | version = "1.3.0-SNAPSHOT"
10 |
11 | repositories {
12 | mavenCentral()
13 | }
14 |
15 | dependencies {
16 | implementation("com.github.rnett.ktjs-github-action:kotlin-js-action")
17 | implementation("com.github.rnett.ktjs-github-action:serialization")
18 | implementation(kotlin("test"))
19 | }
20 |
21 | kotlin {
22 | js(IR) {
23 | githubAction(layout.buildDirectory.dir("dist").get())
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/docs/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | gradlePluginPortal()
8 | }
9 |
10 | dependencies {
11 | api(project(":metadata"))
12 | api(libs.build.dokka)
13 | api(libs.build.dokka.versioning)
14 | }
15 |
16 | gradlePlugin {
17 | plugins {
18 | create("kjs-docs-leaf") {
19 | id = "kjs-action.docs-leaf"
20 | implementationClass = "com.rnett.action.DocsLeafPlugin"
21 | }
22 | create("kjs-docs-root") {
23 | id = "kjs-action.docs-root"
24 | implementationClass = "com.rnett.action.DocsRootPlugin"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("VERSION_CATALOGS")
2 |
3 | pluginManagement {
4 | repositories {
5 | mavenCentral()
6 | gradlePluginPortal()
7 | maven("https://oss.sonatype.org/content/repositories/snapshots") {
8 | mavenContent { snapshotsOnly() }
9 | }
10 | }
11 | }
12 |
13 | dependencyResolutionManagement {
14 | versionCatalogs {
15 | create(defaultLibrariesExtensionName.get()) {
16 | from(files("../../libs.versions.toml"))
17 | }
18 | }
19 | }
20 |
21 | include(
22 | "metadata",
23 | "docs",
24 | "common-module",
25 | "js-module",
26 | "publishing"
27 | )
28 |
--------------------------------------------------------------------------------
/kotlin-js-action/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("VERSION_CATALOGS")
2 |
3 | pluginManagement {
4 | includeBuild("build-logic")
5 | repositories {
6 | mavenCentral()
7 | gradlePluginPortal()
8 | maven("https://oss.sonatype.org/content/repositories/snapshots") {
9 | mavenContent { snapshotsOnly() }
10 | }
11 | }
12 | }
13 |
14 | dependencyResolutionManagement {
15 | versionCatalogs {
16 | create(defaultLibrariesExtensionName.get()) {
17 | from(files("../libs.versions.toml"))
18 | }
19 | }
20 | }
21 |
22 | rootProject.name = "kotlin-js-action-parent"
23 |
24 | include("kotlin-js-action", "serialization", "kotlin-js-action-plugin")
25 |
--------------------------------------------------------------------------------
/.idea/kotlin-js-action.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/exec/exec.module_@actions_exec.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/exec")
8 | @file:JsNonModule
9 |
10 | package internal.exec
11 |
12 | import kotlin.js.Promise
13 |
14 | internal external fun exec(
15 | commandLine: String,
16 | args: Array = definedExternally,
17 | options: ExecOptions = definedExternally
18 | ): Promise
19 |
20 | internal external fun getExecOutput(
21 | commandLine: String,
22 | args: Array = definedExternally,
23 | options: ExecOptions = definedExternally
24 | ): Promise
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/cache/cache.module_@actions_cache.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/cache")
3 | @file:JsNonModule
4 |
5 | package internal.cache
6 |
7 | import kotlin.js.*
8 |
9 |
10 | internal external fun restoreCache(
11 | paths: Array,
12 | primaryKey: String,
13 | restoreKeys: Array = definedExternally,
14 | options: DownloadOptions = definedExternally
15 | ): Promise
16 |
17 | internal external fun saveCache(paths: Array, key: String, options: UploadOptions = definedExternally): Promise
18 |
19 | internal external fun isFeatureAvailable(): Boolean
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/context.module_@actions_github.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/github")
8 | @file:JsNonModule
9 |
10 | package internal.github
11 |
12 | internal external open class Context {
13 | open var payload: WebhookPayload
14 | open var eventName: String
15 | open var sha: String
16 | open var ref: String
17 | open var workflow: String
18 | open var action: String
19 | open var actor: String
20 | open var job: String
21 | open var runNumber: Number
22 | open var runId: Number
23 | open var apiUrl: String
24 | open var serverUrl: String
25 | open var graphqlUrl: String
26 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/SummaryTableItem.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | public sealed interface SummaryTableItem
4 |
5 | /**
6 | * A raw text cell.
7 | */
8 | public value class SummaryTableTextCell(public val text: String) : SummaryTableItem
9 |
10 | /**
11 | * A table cell element.
12 | * Corresponds to a `| `, or a ` | ` is [header] is `true`.
13 | *
14 | * [colspan] and [rowspan] correspond to their respective HTML attributes.
15 | */
16 | public data class SummaryTableCell(val data: String, val header: Boolean = false, val colspan: String = "1", val rowspan: String = "1") :
17 | SummaryTableItem {
18 | public constructor(data: String, header: Boolean = false, colspan: Int, rowspan: Int = 1) : this(
19 | data,
20 | header,
21 | colspan.toString(),
22 | rowspan.toString()
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/glob/internal-glob-options.module_@actions_glob.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/glob")
8 | @file:JsNonModule
9 |
10 | package internal.glob
11 |
12 | internal external interface GlobOptions {
13 | var followSymbolicLinks: Boolean?
14 | get() = definedExternally
15 | set(value) = definedExternally
16 | var implicitDescendants: Boolean?
17 | get() = definedExternally
18 | set(value) = definedExternally
19 | var matchDirectories: Boolean?
20 | get() = definedExternally
21 | set(value) = definedExternally
22 | var omitBrokenSymbolicLinks: Boolean?
23 | get() = definedExternally
24 | set(value) = definedExternally
25 | }
--------------------------------------------------------------------------------
/.idea/modules/test-action.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/1664358933/kotlin-js-action.build-logic.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/904965605/com.github.rnett.ktjs-github-action.kotlin-js-action-parent.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/artifact/artifact-client.module_@actions_artifact.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/artifact")
3 | @file:JsNonModule
4 |
5 | package internal.artifact
6 |
7 | import com.rnett.action.artifact.DownloadResponse
8 | import com.rnett.action.artifact.UploadResponse
9 | import kotlin.js.Promise
10 |
11 | internal external interface ArtifactClient {
12 | fun uploadArtifact(name: String, files: Array, rootDirectory: String, options: UploadOptions = definedExternally): Promise
13 | fun downloadArtifact(name: String, path: String = definedExternally, options: DownloadOptions = definedExternally): Promise
14 | fun downloadAllArtifacts(path: String = definedExternally): Promise>
15 | }
16 |
17 | internal external fun create(): ArtifactClient
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/js-module/src/main/kotlin/kjs-action.js-module.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("org.jetbrains.kotlin.js")
3 | id("kjs-action.common-module")
4 | }
5 |
6 | kotlin {
7 | js(IR) {
8 | useCommonJs()
9 | nodejs {
10 | binaries.library()
11 | testTask {
12 | useMocha {
13 | timeout = "20s"
14 | }
15 | }
16 | }
17 | }
18 | explicitApi()
19 | sourceSets.configureEach {
20 | languageSettings {
21 | optIn("kotlin.contracts.ExperimentalContracts")
22 | optIn("kotlin.RequiresOptIn")
23 | }
24 | }
25 | }
26 | plugins.withType {
27 | configure {
28 | nodeVersion = "16.18.0"
29 | }
30 | }
31 |
32 | docs {
33 | platform.set(org.jetbrains.dokka.Platform.js)
34 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/lib.es2018.asyncgenerator.module_dukat.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 |
3 | package internal
4 |
5 | import kotlin.js.Promise
6 |
7 | internal external interface AsyncGenerator : AsyncIterator {
8 | override fun next(vararg args: Any /* JsTuple<> | JsTuple */): Promise | IteratorReturnResult */>
9 | fun `return`(value: TReturn): Promise | IteratorReturnResult */>
10 | fun `return`(value: Promise): Promise | IteratorReturnResult */>
11 | override var `throw`: (e: Any) -> Promise | IteratorReturnResult */>
12 | }
13 |
14 | internal external interface AsyncGenerator__2 : AsyncGenerator
--------------------------------------------------------------------------------
/.idea/modules/31940085/kotlin-js-action.build-logic.docs.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/RequestRequestOptions.module_@octokit_types.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@octokit/types")
3 | @file:JsNonModule
4 |
5 | package internal.github
6 |
7 | import node.http.Agent
8 | import kotlin.js.*
9 |
10 | internal external interface RequestRequestOptions {
11 | var agent: Agent?
12 | get() = definedExternally
13 | set(value) = definedExternally
14 | var fetch: Fetch?
15 | get() = definedExternally
16 | set(value) = definedExternally
17 | var signal: Signal?
18 | get() = definedExternally
19 | set(value) = definedExternally
20 | var timeout: Number?
21 | get() = definedExternally
22 | set(value) = definedExternally
23 | @nativeGetter
24 | operator fun get(option: String): Any?
25 | @nativeSetter
26 | operator fun set(option: String, value: Any)
27 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/httpclient/Auth.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.httpclient
2 |
3 | import com.rnett.action.encodeBase64
4 |
5 | /**
6 | * Request handler for basic auth.
7 | */
8 | public data class BasicAuthHandler(val username: String, val password: String) : HeaderProvider {
9 | override fun MutableHeaders.headers() {
10 | this["Authorization"] = "Basic ${"$username:$password".encodeBase64()}"
11 | }
12 | }
13 |
14 | /**
15 | * Request handler for bearer auth.
16 | */
17 | public data class BearerAuthHandler(val token: String) : HeaderProvider {
18 | override fun MutableHeaders.headers() {
19 | this["Authorization"] = "Bearer $token"
20 | }
21 | }
22 |
23 | /**
24 | * Request handler for personal access token auth.
25 | */
26 | public data class PersonalAccessTokenAuthHandler(val token: String) : HeaderProvider {
27 | override fun MutableHeaders.headers() {
28 | this["Authorization"] = "Basic ${"PAT:$token".encodeBase64()}"
29 | }
30 | }
--------------------------------------------------------------------------------
/.idea/modules/-1802679831/kotlin-js-action.build-logic.metadata.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/1473984502/kotlin-js-action.build-logic.js-module.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/-921324371/kotlin-js-action.build-logic.publishing.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/-868266476/kotlin-js-action.build-logic.common-module.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/1757210950/com.github.rnett.ktjs-github-action.kotlin-js-action-parent.serialization.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/github/context.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.github
2 |
3 | import com.rnett.action.Path
4 | import com.rnett.action.core.env
5 |
6 | public object github {
7 | public object context {
8 | public val eventName: String get() = internal.github.context.eventName
9 | public val sha: String get() = internal.github.context.sha
10 | public val ref: String get() = internal.github.context.ref
11 | public val workflow: String get() = internal.github.context.workflow
12 | public val action: String get() = internal.github.context.action
13 | public val actor: String get() = internal.github.context.actor
14 | public val job: String get() = internal.github.context.job
15 | public val runId: Int get() = internal.github.context.runId.toInt()
16 | public val runNumber: Int get() = internal.github.context.runNumber.toInt()
17 | public val workspace: String by env.required("GITHUB_WORKSPACE")
18 | public val workspacePath: Path get() = Path(workspace)
19 | }
20 | }
--------------------------------------------------------------------------------
/.idea/modules/-224497576/com.github.rnett.ktjs-github-action.kotlin-js-action-parent.kotlin-js-action.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules/-898967992/com.github.rnett.ktjs-github-action.kotlin-js-action-parent.kotlin-js-action-plugin.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/cache/options.module_@actions_cache.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/cache")
3 | @file:JsNonModule
4 |
5 | package internal.cache
6 |
7 | import kotlin.js.*
8 |
9 | internal external interface UploadOptions {
10 | var uploadConcurrency: Number?
11 | get() = definedExternally
12 | set(value) = definedExternally
13 | var uploadChunkSize: Number?
14 | get() = definedExternally
15 | set(value) = definedExternally
16 | }
17 |
18 | internal external interface DownloadOptions {
19 | var useAzureSdk: Boolean?
20 | get() = definedExternally
21 | set(value) = definedExternally
22 | var downloadConcurrency: Number?
23 | get() = definedExternally
24 | set(value) = definedExternally
25 | var timeoutInMs: Number?
26 | get() = definedExternally
27 | set(value) = definedExternally
28 | var segmentTimeoutInMs: Number?
29 | get() = definedExternally
30 | set(value) = definedExternally
31 | }
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/exec/Shell.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.exec
2 |
3 | /**
4 | * Represents a shell used to run commands.
5 | */
6 | public abstract class Shell(public val escapeWindows: Boolean = true) {
7 | public abstract fun shellCommand(command: String): String
8 | public abstract fun args(command: String): Array
9 |
10 | public object bash : ConstantShell("bash") {
11 | override fun args(command: String): Array = arrayOf("-c", command)
12 | }
13 |
14 | public object cmd : ConstantShell("cmd") {
15 | override fun args(command: String): Array = arrayOf("/c", command)
16 | }
17 |
18 | /**
19 | * **Note that output redirects with > will be written in utf16-le with a BOM**
20 | */
21 | public object powershell : ConstantShell("powershell") {
22 | override fun args(command: String): Array = arrayOf("-c", command)
23 | }
24 |
25 | }
26 |
27 | /**
28 | * A shell where the shell command is constant.
29 | */
30 | public abstract class ConstantShell(public val shellCommand: String, escapeWindows: Boolean = true) :
31 | Shell(escapeWindows) {
32 | override fun shellCommand(command: String): String = shellCommand
33 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action-plugin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kjs-action.common-module")
3 | `kotlin-dsl`
4 | }
5 |
6 | description = "A Gradle plugin to easily configure GitHub action packing"
7 | metadata {
8 | title.set("Kotlin JS GitHub Action Gradle Plugin")
9 | }
10 |
11 | kotlin {
12 | target {
13 | attributes {
14 | attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8)
15 | }
16 | }
17 | }
18 |
19 | tasks.compileJava {
20 | sourceCompatibility = "1.8"
21 | targetCompatibility = "1.8"
22 | }
23 |
24 | tasks.compileKotlin {
25 | kotlinOptions {
26 | jvmTarget = "1.8"
27 | }
28 | }
29 |
30 | docs {
31 | platform.set(org.jetbrains.dokka.Platform.jvm)
32 | }
33 |
34 | dependencies {
35 | compileOnly(kotlin("gradle-plugin"))
36 | implementation(kotlin("gradle-plugin-api"))
37 | }
38 |
39 | gradlePlugin {
40 | plugins {
41 | create("kotlinJsGithubActionPlugin") {
42 | id = "com.github.rnett.ktjs-github-action"
43 | displayName = "Kotlin JS GitHub Action Gradle Plugin"
44 | description = "Kotlin JS GitHub Action Gradle Plugin"
45 | implementationClass = "com.rnett.action.GithubActionPlugin"
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/kotlin-js-action/serialization/src/test/kotlin/com/rnett/action/serialization/TestSerialization.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.serialization
2 |
3 | import com.rnett.action.core.env
4 | import kotlinx.serialization.ExperimentalSerializationApi
5 | import kotlinx.serialization.Serializable
6 | import kotlinx.serialization.encodeToString
7 | import kotlinx.serialization.json.Json
8 | import kotlin.properties.ReadOnlyProperty
9 | import kotlin.test.Test
10 | import kotlin.test.assertEquals
11 | import kotlin.test.assertNull
12 |
13 | @Serializable
14 | data class TestData(val i: Int, val s: String)
15 |
16 | private val original = TestData(2, "test")
17 |
18 | @OptIn(ExperimentalSerializationApi::class)
19 | internal class BasicTest {
20 |
21 | @Test
22 | fun testBasics() {
23 | val json = Json { }
24 | val delegate = ReadOnlyProperty { _, _ -> json.encodeToString(original) }
25 | val typedDelegate: TestData by delegate.deserialize(json)
26 |
27 | assertEquals(original, typedDelegate)
28 | }
29 |
30 | @Test
31 | fun testEnv() {
32 | val json = Json { }
33 | var envData: TestData? by env.deserializeNotNull(json)
34 | envData = null
35 | assertNull(envData)
36 | envData = original
37 | assertEquals(original, envData)
38 | }
39 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/index.module_before-after-hook.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("before-after-hook")
3 | @file:JsNonModule
4 |
5 | package internal
6 |
7 | import kotlin.js.*
8 |
9 | internal external interface HookCollection {
10 | @nativeInvoke
11 | operator fun invoke(name: String, hookMethod: HookMethod, options: Any = definedExternally): Promise
12 | @nativeInvoke
13 | operator fun invoke(name: String, hookMethod: HookMethod): Promise
14 | @nativeInvoke
15 | operator fun invoke(name: Array, hookMethod: HookMethod, options: Any = definedExternally): Promise
16 | @nativeInvoke
17 | operator fun invoke(name: Array, hookMethod: HookMethod): Promise
18 | fun before(name: String, beforeHook: BeforeHook)
19 | fun error(name: String, errorHook: ErrorHook)
20 | fun after(name: String, afterHook: AfterHook)
21 | fun wrap(name: String, wrapHook: WrapHook)
22 | fun remove(name: String, hook: BeforeHook)
23 | fun remove(name: String, hook: ErrorHook)
24 | fun remove(name: String, hook: WrapHook)
25 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/packages.md:
--------------------------------------------------------------------------------
1 | # Package com.rnett.action
2 |
3 | `Path`, OS, and utilities.
4 |
5 | # Package com.rnett.action.artifact
6 |
7 | Wrappers for [@actions/artifact](https://github.com/actions/toolkit/blob/main/packages/artifact).
8 |
9 | # Package com.rnett.action.cache
10 |
11 | Wrappers for [@actions/cache](https://github.com/actions/toolkit/blob/main/packages/cache).
12 |
13 | # Package com.rnett.action.core
14 |
15 | Wrappers for [@actions/core](https://github.com/actions/toolkit/blob/main/packages/core).
16 |
17 | # Package com.rnett.action.exec
18 |
19 | Wrappers for [@actions/exec](https://github.com/actions/toolkit/blob/main/packages/exec).
20 |
21 | # Package com.rnett.action.glob
22 |
23 | Wrappers for [@actions/glob](https://github.com/actions/toolkit/blob/main/packages/glob).
24 |
25 | # Package com.rnett.action.io
26 |
27 | Wrappers for [@actions/io](https://github.com/actions/toolkit/blob/main/packages/io).
28 |
29 | # Package com.rnett.action.tool-cache
30 |
31 | Wrappers for [@actions/tool-cache](https://github.com/actions/toolkit/blob/main/packages/tool-cache).
32 |
33 | # Package com.rnett.action.httpclient
34 |
35 | Wrappers for [@actions/http-client](https://github.com/actions/http-client).
36 |
37 | # Package com.rnett.action.delegates
38 |
39 | Delegation base classes, utilities, and transforms.
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/lib.es2018.asynciterable.module_dukat.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 |
3 | package internal
4 |
5 | import kotlin.js.Promise
6 |
7 | internal external interface `L$0` {
8 | @nativeInvoke
9 | operator fun invoke(value: TReturn = definedExternally): Promise | IteratorReturnResult */>
10 |
11 | @nativeInvoke
12 | operator fun invoke(): Promise | IteratorReturnResult */>
13 |
14 | @nativeInvoke
15 | operator fun invoke(value: Promise = definedExternally): Promise | IteratorReturnResult */>
16 | }
17 |
18 | internal external interface AsyncIterator {
19 | fun next(vararg args: Any /* JsTuple<> | JsTuple */): Promise | IteratorReturnResult */>
20 | val `return`: `L$0`?
21 | get() = definedExternally
22 | val `throw`: ((e: Any) -> Promise | IteratorReturnResult */>)?
23 | }
24 |
25 | internal external interface AsyncIterator__1 : AsyncIterator
26 |
27 | internal external interface AsyncIterable
28 |
29 | internal external interface AsyncIterableIterator : AsyncIterator__1
--------------------------------------------------------------------------------
/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | kotlin = "1.7.21"
3 | kotlinx-serialization = "1.4.1"
4 | kotlinx-coroutines = "1.6.4"
5 | kotlin-wrappers-node = "18.11.5-pre.414"
6 |
7 | publish = "0.22.0"
8 | dokka = "1.7.20"
9 |
10 | [libraries]
11 |
12 | kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
13 | kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
14 |
15 | kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
16 |
17 | kotlin-wrappers-node = { module = "org.jetbrains.kotlin-wrappers:kotlin-node", version.ref = "kotlin-wrappers-node" }
18 |
19 | build-publish = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "publish" }
20 | build-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
21 | build-dokka-versioning = { module = "org.jetbrains.dokka:versioning-plugin", version.ref = "dokka" }
22 |
23 | build-kotlin-js = { module = "org.jetbrains.kotlin.js:org.jetbrains.kotlin.js.gradle.plugin", version.ref = "kotlin" }
24 |
25 | [plugins]
26 | kotlin-js = { id = "org.jetbrains.kotlin.js", version.ref = "kotlin" }
27 |
28 | kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
29 |
30 | publish = { id = "com.vanniktech.maven.publish", version.ref = "publish" }
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/publishing/src/main/kotlin/kjs-action.publishing.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.rnett.action.MetadataExtension
2 | import com.vanniktech.maven.publish.SonatypeHost
3 |
4 | plugins {
5 | id("com.vanniktech.maven.publish")
6 | }
7 |
8 | mavenPublishing {
9 | publishToMavenCentral(SonatypeHost.DEFAULT)
10 |
11 | signAllPublications()
12 |
13 | pom {
14 | name.set(project.providers.provider { project.extensions.getByType() }.flatMap { it.title })
15 | description.set(project.providers.provider { project.description })
16 | inceptionYear.set("2021")
17 | url.set("https://github.com/rnett/kotlin-js-action/")
18 |
19 | licenses {
20 | license {
21 | name.set("The Apache Software License, Version 2.0")
22 | url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
23 | distribution.set("repo")
24 | }
25 | }
26 |
27 | scm {
28 | url.set("https://github.com/rnett/kotlin-js-action.git")
29 | connection.set("scm:git:git://github.com/rnett/kotlin-js-action.git")
30 | developerConnection.set("scm:git:ssh://git@github.com/rnett/kotlin-js-action.git")
31 | }
32 |
33 | developers {
34 | developer {
35 | id.set("rnett")
36 | name.set("Ryan Nett")
37 | url.set("https://github.com/rnett/")
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/io/io.module_@actions_io.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/io")
8 | @file:JsNonModule
9 |
10 | package internal.io
11 |
12 | import kotlin.js.Promise
13 |
14 | internal external interface CopyOptions {
15 | var recursive: Boolean?
16 | get() = definedExternally
17 | set(value) = definedExternally
18 | var force: Boolean?
19 | get() = definedExternally
20 | set(value) = definedExternally
21 | var copySourceDirectory: Boolean?
22 | get() = definedExternally
23 | set(value) = definedExternally
24 | }
25 |
26 | internal external interface MoveOptions {
27 | var force: Boolean?
28 | get() = definedExternally
29 | set(value) = definedExternally
30 | }
31 |
32 | internal external fun cp(source: String, dest: String, options: CopyOptions = definedExternally): Promise
33 |
34 | internal external fun mv(source: String, dest: String, options: MoveOptions = definedExternally): Promise
35 |
36 | internal external fun rmRF(inputPath: String): Promise
37 |
38 | internal external fun mkdirP(fsPath: String): Promise
39 |
40 | internal external fun which(tool: String, check: Boolean = definedExternally): Promise
41 |
42 | internal external fun findInPath(tool: String): Promise>
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/artifact/Responses.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/artifact")
8 | @file:JsNonModule
9 |
10 | package com.rnett.action.artifact
11 |
12 | /**
13 | * The response to an artifact upload.
14 | */
15 | public external interface UploadResponse {
16 | /**
17 | * The name of the artifact that was uploaded
18 | */
19 | public val artifactName: String
20 |
21 | /**
22 | * A list of all items that are meant to be uploaded as part of the artifact
23 | */
24 | public val artifactItems: Array
25 |
26 | /**
27 | * Total size of the artifact in bytes that was uploaded
28 | */
29 | public val size: Number
30 |
31 | /**
32 | * A list of items that were not uploaded as part of the artifact (includes queued items that were not uploaded if
33 | * continueOnError is set to false). This is a subset of artifactItems.
34 | */
35 | public val failedItems: Array
36 | }
37 |
38 | /**
39 | * The response of an artifact download.
40 | */
41 | public external interface DownloadResponse {
42 | /**
43 | * The name of the artifact that was downloaded
44 | */
45 | public val artifactName: String
46 |
47 | /**
48 | * The full Path to where the artifact was downloaded
49 | */
50 | public val downloadPath: String
51 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/types.module_@octokit_core.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@octokit/core")
3 | @file:JsNonModule
4 |
5 | package internal.github
6 |
7 | import kotlin.js.*
8 |
9 | internal external interface `T$11` {
10 | var debug: (message: String) -> Any
11 | var info: (message: String) -> Any
12 | var warn: (message: String) -> Any
13 | var error: (message: String) -> Any
14 | }
15 |
16 | internal external interface OctokitOptions {
17 | var authStrategy: Any?
18 | get() = definedExternally
19 | set(value) = definedExternally
20 | var auth: Any?
21 | get() = definedExternally
22 | set(value) = definedExternally
23 | var userAgent: String?
24 | get() = definedExternally
25 | set(value) = definedExternally
26 | var previews: Array?
27 | get() = definedExternally
28 | set(value) = definedExternally
29 | var baseUrl: String?
30 | get() = definedExternally
31 | set(value) = definedExternally
32 | var log: `T$11`?
33 | get() = definedExternally
34 | set(value) = definedExternally
35 | var request: RequestRequestOptions?
36 | get() = definedExternally
37 | set(value) = definedExternally
38 | var timeZone: String?
39 | get() = definedExternally
40 | set(value) = definedExternally
41 | @nativeGetter
42 | operator fun get(option: String): Any?
43 | @nativeSetter
44 | operator fun set(option: String, value: Any)
45 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/outputs.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import com.rnett.action.camelToSnakeCase
4 | import kotlin.properties.ReadWriteProperty
5 | import kotlin.reflect.KProperty
6 |
7 | internal class OutputDelegate(val name: String?) : ReadWriteProperty {
8 | private var value: String? = null
9 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
10 | this.value = value
11 | outputs.set(name ?: property.name.camelToSnakeCase(), value)
12 | }
13 |
14 | override fun getValue(thisRef: Any?, property: KProperty<*>): String {
15 | return value ?: ""
16 | }
17 | }
18 |
19 | /**
20 | * A setter to set outputs.
21 | *
22 | * Can be delegated from. Property names will be converted to snake-case unless name is specified.
23 | * Delegates return `""` if the delegate hasn't been set, or the value set by that delegate if it has been used.
24 | */
25 | public object outputs : ReadWriteProperty by OutputDelegate(null) {
26 |
27 | /**
28 | * Get a delegate for [name].
29 | *
30 | * Delegates return `""` if the delegate hasn't been set, or the value set by that delegate if it has been used.
31 | */
32 | public operator fun invoke(name: String): ReadWriteProperty = OutputDelegate(name)
33 |
34 | /**
35 | * Set an output [name] to [value].
36 | */
37 | public operator fun set(name: String, value: String) {
38 | core.setOutput(name, value)
39 | }
40 |
41 | /**
42 | * Set all outputs from [outputs].
43 | */
44 | public fun setAll(outputs: Map) {
45 | outputs.forEach { (k, v) -> set(k, v) }
46 | }
47 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/index.module_@octokit_core.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@octokit/core")
3 | @file:JsNonModule
4 |
5 | package internal.github
6 |
7 | import internal.HookCollection
8 | import kotlin.js.*
9 |
10 | internal external interface `T$9` {
11 | var plugins: Array
12 | }
13 |
14 | internal external interface `T$10` {
15 | var debug: (message: String, additionalInfo: Any?) -> Any
16 | var info: (message: String, additionalInfo: Any?) -> Any
17 | var warn: (message: String, additionalInfo: Any?) -> Any
18 | var error: (message: String, additionalInfo: Any?) -> Any
19 | @nativeGetter
20 | operator fun get(key: String): Any?
21 | @nativeSetter
22 | operator fun set(key: String, value: Any)
23 | }
24 |
25 | internal external open class Octokit(options: OctokitOptions = definedExternally) {
26 | open var request: Any
27 | open var graphql: Any
28 | open var log: `T$10`
29 | open var hook: HookCollection
30 | open var auth: (args: Any) -> Promise
31 | @nativeGetter
32 | open operator fun get(key: String): Any?
33 | @nativeSetter
34 | open operator fun set(key: String, value: Any)
35 |
36 | companion object {
37 | var VERSION: String
38 | fun > defaults(self: S, defaults: OctokitOptions): Any /* Any & S */
39 | fun > defaults(self: S, defaults: Function<*>): Any /* Any & S */
40 | var plugins: Array
41 | fun , T : Array> plugin(self: S, vararg newPlugins: T): `T$9` /* `T$9` & S & Constructor>> */
42 | }
43 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/httpclient/HttpResponse.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.httpclient
2 |
3 | import internal.httpclient.HttpClientResponse
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.await
6 | import kotlinx.coroutines.promise
7 | import node.http.IncomingMessage
8 | import kotlin.js.Promise
9 |
10 |
11 | /**
12 | * The response from a HTTP request.
13 | */
14 | public interface HttpResponse {
15 | public suspend fun readBody(): String
16 |
17 | public val message: IncomingMessage
18 | public val headers: Headers
19 | public val statusCode: Int
20 | public val statusMessage: String
21 | public fun isSuccess(): Boolean
22 | }
23 |
24 | internal fun HttpResponse.toInternal(): HttpClientResponse =
25 | if (this is HttpResponseImpl)
26 | this.internal
27 | else
28 | object : HttpClientResponse(this@toInternal.message) {
29 | override var message: IncomingMessage = this@toInternal.message
30 |
31 | override fun readBody(): Promise = GlobalScope.promise {
32 | this@toInternal.readBody()
33 | }
34 | }
35 |
36 |
37 | /**
38 | * The response from a HTTP request.
39 | */
40 | internal class HttpResponseImpl internal constructor(internal val internal: HttpClientResponse) : HttpResponse {
41 | override suspend fun readBody(): String = internal.readBody().await()
42 |
43 | override val message: IncomingMessage get() = internal.message
44 |
45 | override val headers: Headers = message.rawHeaders.asSequence().chunked(2) {
46 | it[0].lowercase() to it[1]
47 | }.toMap().let { MapHeaders(it) }
48 |
49 | override val statusCode: Int = message.statusCode!!.toInt()
50 | override val statusMessage: String get() = message.statusMessage!!
51 | override fun isSuccess(): Boolean = statusCode in 200..299
52 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestStreamUtils.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import kotlinx.coroutines.ExperimentalCoroutinesApi
4 | import kotlinx.coroutines.flow.flowOf
5 | import kotlinx.coroutines.flow.toList
6 | import kotlinx.coroutines.test.runTest
7 | import node.events.Event
8 | import node.stream.Transform
9 | import kotlin.test.Test
10 | import kotlin.test.assertEquals
11 |
12 | @OptIn(ExperimentalCoroutinesApi::class)
13 | class TestStreamUtils {
14 |
15 | @Test
16 | fun testStreamToFlow() = runTest {
17 | val stream = Transform(JsObject {
18 | this.writableObjectMode = true
19 | this.readableObjectMode = true
20 |
21 | transform = { chunk, encoding, callback ->
22 | callback(null, chunk)
23 | }
24 | })
25 |
26 | stream.write(listOf(1, 2, 3))
27 | val flow = stream.toFlow>()
28 |
29 | stream.write(listOf(3, 4, 5))
30 | stream.end()
31 |
32 | val lists = flow.toList()
33 |
34 | assertEquals(
35 | listOf(
36 | listOf(1, 2, 3),
37 | listOf(3, 4, 5)
38 | ), lists
39 | )
40 | }
41 |
42 | @Test
43 | fun testObjectStream() = runTest {
44 | val flow = flowOf(listOf(1, 2, 3), listOf(3, 4, 5))
45 | val stream = flow.toObjectStream(this)
46 | var i = 0
47 | stream.on(Event.DATA) { it ->
48 | if (i == 0)
49 | assertEquals(listOf(1, 2, 3), it)
50 | else
51 | assertEquals(listOf(3, 4, 5), it)
52 | i++
53 | }
54 | stream.resume()
55 | }
56 |
57 | @Test
58 | fun canCreateBuffersFromEncodedData() {
59 | assertEquals(
60 | "test",
61 | "test".encodeBase64().decodeBase64()
62 | )
63 | }
64 | }
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/docs/src/main/kotlin/com/rnett/action/DocsRootPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.api.tasks.Copy
6 | import org.gradle.kotlin.dsl.create
7 | import org.gradle.kotlin.dsl.withType
8 |
9 | class DocsRootPlugin : Plugin {
10 | override fun apply(project: Project): Unit = with(project) {
11 | project.plugins.apply(MetadataPlugin::class.java)
12 | project.plugins.apply("org.jetbrains.dokka")
13 |
14 | val extension = project.extensions.create("docs", RootDocsExtension::class.java)
15 |
16 | val oldVersionsDir = providers.gradleProperty("oldVersionsDir")
17 |
18 | tasks.withType().configureEach {
19 | this.fileLayout.set(org.jetbrains.dokka.gradle.DokkaMultiModuleFileLayout.CompactInParent)
20 | this.includes.from("DOCS.md")
21 | this.moduleName.set(extension.title)
22 | this.moduleVersion.set(version.toString())
23 | if (oldVersionsDir.isPresent && "snapshot" !in project.version.toString().toLowerCase()) {
24 | val resolved = rootDir.resolve(oldVersionsDir.get())
25 | println("Using older versions from $resolved")
26 | pluginConfiguration {
27 | version = project.version.toString()
28 | olderVersionsDir = resolved
29 | }
30 | }
31 | }
32 |
33 | tasks.create("generateReadme") {
34 | from(rootDir.resolve("../README.md"))
35 | into(buildDir.resolve("readme"))
36 | filter {
37 | val header = extension.readmeHeader.get()
38 | it.replace(
39 | "# $header",
40 | "# [$header](https://github.com/rnett/kotlin-js-action)"
41 | )
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/OperatingSystem.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import node.path.path
4 | import node.process.Platform
5 |
6 | /**
7 | * Operating system Enum. Limited to GitHub action runners (Windows, Mac, and Linux).
8 | */
9 | public enum class OperatingSystem {
10 | Windows, Mac, Linux;
11 |
12 | public companion object {
13 |
14 | /**
15 | * The current operating system.
16 | */
17 | public val current: OperatingSystem by lazy {
18 | when (node.os.platform()) {
19 | Platform.win32 -> Windows
20 | Platform.darwin -> Mac
21 | else -> Linux
22 | }
23 | }
24 |
25 | /**
26 | * Whether the current OS is Windows
27 | */
28 | public inline val isWindows: Boolean get() = current == Windows
29 |
30 | /**
31 | * Whether the current OS is Max
32 | */
33 | public inline val isMac: Boolean get() = current == Mac
34 |
35 | /**
36 | * Whether the current OS is Linux
37 | */
38 | public inline val isLinux: Boolean get() = current == Linux
39 |
40 | /**
41 | * Whether the current OS is POSIX compliant, i.e. Linux or Mac
42 | */
43 | public inline val isPosix: Boolean get() = !isWindows
44 |
45 | /**
46 | * The line separator of the current operating system
47 | */
48 | public inline val lineSeparator: String
49 | get() = when (current) {
50 | Windows -> "\r\n"
51 | Mac -> "\r"
52 | Linux -> "\n"
53 | }
54 |
55 | /**
56 | * Get the current OS's path seperator
57 | */
58 | public inline val pathSeperator: String get() = path.sep
59 |
60 | /**
61 | * Get [os.arch].
62 | */
63 | public inline val arch: String get() = node.os.arch()
64 |
65 | /**
66 | * Get [os.platform]
67 | */
68 | public inline val platform: String get() = node.os.platform().name
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestWithDir.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import kotlinx.coroutines.ExperimentalCoroutinesApi
4 | import kotlinx.coroutines.delay
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.test.TestResult
7 | import kotlinx.coroutines.test.TestScope
8 | import kotlinx.coroutines.test.advanceUntilIdle
9 | import kotlin.random.Random
10 | import kotlin.test.AfterTest
11 | import kotlin.test.BeforeTest
12 | import kotlin.time.Duration.Companion.milliseconds
13 |
14 | val globalTestDir by lazy { Path(TestEnv.tempDir.trimEnd('/') + "/testdir") }
15 |
16 | @OptIn(ExperimentalCoroutinesApi::class)
17 | abstract class TestWithDir {
18 |
19 | private var _testDir: Path? = null
20 |
21 | val testDir: Path
22 | get() = _testDir ?: error("Test dir not set yet")
23 |
24 | fun runTest(block: suspend TestScope.() -> Unit): TestResult {
25 | return kotlinx.coroutines.test.runTest {
26 | doInit()
27 | block()
28 | }
29 | }
30 |
31 | @BeforeTest
32 | fun before() = kotlinx.coroutines.test.runTest {
33 | doInit()
34 | }
35 |
36 | private suspend fun doInit() {
37 | if (_testDir != null) {
38 | return
39 | }
40 |
41 | val name = Random.nextLong().toString(20) + Random.nextLong().toString(20)
42 | val dir = globalTestDir / "test-$name"
43 |
44 | if (dir.exists) {
45 | node.fs.rmdirSync(dir.path, JsObject {
46 | this.recursive = true
47 | })
48 | }
49 |
50 | dir.mkdir()
51 | dir.initDir()
52 | if (_testDir == null) {
53 | _testDir = dir
54 | Path.cd(dir)
55 | }
56 | }
57 |
58 | open suspend fun Path.initDir() {
59 |
60 | }
61 |
62 | @AfterTest
63 | internal fun after() = kotlinx.coroutines.test.runTest {
64 | backgroundScope.launch {
65 | delay(500.milliseconds)
66 | node.fs.rmdirSync(testDir.resolve().path, JsObject {
67 | this.recursive = true
68 | })
69 | }
70 | advanceUntilIdle()
71 | }
72 | }
--------------------------------------------------------------------------------
/kotlin-js-action/serialization/src/test/kotlin/com/rnett/action/serialization/TestJsonHttpClient.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.serialization
2 |
3 | import com.rnett.action.httpclient.use
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.flow.flowOf
6 | import kotlinx.coroutines.test.runTest
7 | import kotlinx.serialization.Serializable
8 | import kotlinx.serialization.json.Json
9 | import kotlin.test.Test
10 | import kotlin.test.assertEquals
11 |
12 | @Serializable
13 | data class TestResponse(val slideshow: Slideshow)
14 |
15 | @Serializable
16 | data class Slideshow(val title: String, val author: String, val date: String, val slides: List)
17 |
18 | @Serializable
19 | data class Slide(val title: String, val type: String, val items: List = emptyList())
20 |
21 | @Serializable
22 | data class TestPostResponse(val json: T)
23 |
24 | @OptIn(ExperimentalCoroutinesApi::class)
25 | class HttpClientTest {
26 | @Test
27 | fun testGet() = runTest {
28 | JsonHttpClient().use { client ->
29 | val response = client.get("https://httpbin.org/json")
30 | assertEquals(200, response.statusCode)
31 | val data = response.readJsonBody()
32 | assertEquals("Yours Truly", data.slideshow.author)
33 | }
34 | }
35 |
36 | @Test
37 | fun testPost() = runTest {
38 | JsonHttpClient(Json {
39 | this.ignoreUnknownKeys = true
40 | }).use { client ->
41 | val slide = Slide("Nothing", "all")
42 | val response = client.postJson("https://httpbin.org/post", slide)
43 | assertEquals(200, response.statusCode)
44 | val data = response.readJsonBody>().json
45 | assertEquals(slide, data)
46 | }
47 | }
48 |
49 | @Test
50 | fun testPostStreaming() = runTest {
51 | JsonHttpClient(Json {
52 | this.ignoreUnknownKeys = true
53 | }).use { client ->
54 | val slide = Slide("Nothing", "all")
55 | val slides = flowOf(slide)
56 | val response = client.postJson("https://httpbin.org/post", slides)
57 | assertEquals(200, response.statusCode)
58 | val data = response.readJsonBody>().json
59 | assertEquals(slide, data)
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | /.gradle/
3 | /build/
4 | /testdir/
5 | /docs/
6 |
7 | log
8 | **/build
9 |
10 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
11 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
12 |
13 | # User-specific stuff
14 | .idea/**/workspace.xml
15 | .idea/**/tasks.xml
16 | .idea/**/usage.statistics.xml
17 | .idea/**/dictionaries
18 | .idea/**/shelf
19 |
20 | # Generated files
21 | .idea/**/contentModel.xml
22 |
23 | # Sensitive or high-churn files
24 | .idea/**/dataSources/
25 | .idea/**/dataSources.ids
26 | .idea/**/dataSources.local.xml
27 | .idea/**/sqlDataSources.xml
28 | .idea/**/dynamic.xml
29 | .idea/**/uiDesigner.xml
30 | .idea/**/dbnavigator.xml
31 |
32 | # Gradle
33 | .idea/**/gradle.xml
34 | .idea/**/libraries
35 |
36 | # Gradle and Maven with auto-import
37 | # When using Gradle or Maven with auto-import, you should exclude module files,
38 | # since they will be recreated, and may cause churn. Uncomment if using
39 | # auto-import.
40 | # .idea/artifacts
41 | # .idea/compiler.xml
42 | # .idea/modules.xml
43 | # .idea/*.iml
44 | # .idea/modules
45 | # *.iml
46 | # *.ipr
47 |
48 | # CMake
49 | cmake-build-*/
50 |
51 | # Mongo Explorer plugin
52 | .idea/**/mongoSettings.xml
53 |
54 | # File-based project format
55 | *.iws
56 |
57 | # IntelliJ
58 | out/
59 |
60 | # mpeltonen/sbt-idea plugin
61 | .idea_modules/
62 |
63 | # JIRA plugin
64 | atlassian-ide-plugin.xml
65 |
66 | # Cursive Clojure plugin
67 | .idea/replstate.xml
68 |
69 | # Crashlytics plugin (for Android Studio and IntelliJ)
70 | com_crashlytics_export_strings.xml
71 | crashlytics.properties
72 | crashlytics-build.properties
73 | fabric.properties
74 |
75 | # Editor-based Rest Client
76 | .idea/httpRequests
77 |
78 | # Android studio 3.1+ serialized cache file
79 | .idea/caches/build_file_checksums.ser
80 |
81 | .gradle
82 | /build/
83 |
84 | # Ignore Gradle GUI config
85 | gradle-app.setting
86 |
87 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
88 | !gradle-wrapper.jar
89 |
90 | # Cache of project
91 | .gradletasknamecache
92 |
93 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
94 | # gradle/wrapper/gradle-wrapper.properties
95 | /.idea/google-java-format.xml
96 | /.idea/GitLink.xml
97 | /.idea/checkstyle-idea.xml
98 | /.idea/git_toolbox_prj.xml
99 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/AnnotationProperties.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import com.rnett.action.JsObject
4 | import com.rnett.action.Path
5 |
6 | /**
7 | * Properties for GitHub actions state annotations. Can be used with some logging methods to show UI indications.
8 | *
9 | * See [the docs](https://github.com/actions/toolkit/tree/main/packages/core#annotations).
10 | */
11 | public data class AnnotationProperties internal constructor(
12 | val title: String,
13 | val file: Path?,
14 | val startLine: Int?,
15 | val endLine: Int?,
16 | val startColumn: Int?,
17 | val endColumn: Int?
18 | ) {
19 | /**
20 | * Create an annotation with no location information.
21 | */
22 | public constructor(title: String) : this(title, null, null, null, null, null)
23 |
24 | internal fun toJsObject() = JsObject {
25 | this.title = this@AnnotationProperties.title
26 | this.startLine = this@AnnotationProperties.startLine
27 | this.endLine = this@AnnotationProperties.endLine
28 | this.startColumn = this@AnnotationProperties.startColumn
29 | this.endColumn = this@AnnotationProperties.endColumn
30 | this.file = this@AnnotationProperties.file?.path
31 | }
32 |
33 | public companion object {
34 |
35 | /**
36 | * Create an annotation with a single line location, optionally with start and end columns.
37 | */
38 | public fun singleLine(
39 | title: String,
40 | file: Path,
41 | line: Int,
42 | startColumn: Int? = null,
43 | endColumn: Int? = startColumn
44 | ): AnnotationProperties = AnnotationProperties(title, file, line, line, startColumn, endColumn)
45 |
46 | /**
47 | * Create an annotation with a multi-line location.
48 | */
49 | public fun multiLine(
50 | title: String,
51 | file: Path,
52 | startLine: Int,
53 | endLine: Int,
54 | ): AnnotationProperties = AnnotationProperties(title, file, startLine, endLine, null, null)
55 |
56 | /**
57 | * Create an annotation with no location information.
58 | */
59 | public fun noLine(title: String, file: Path? = null): AnnotationProperties = AnnotationProperties(title, file, null, null, null, null)
60 | }
61 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/httpclient/interfaces.module_@actions_http-client.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/http-client")
8 | @file:JsNonModule
9 |
10 | package internal.httpclient
11 |
12 | import node.http.IncomingHttpHeaders
13 | import node.http.OutgoingHttpHeaders
14 | import org.w3c.dom.url.URL
15 | import kotlin.js.Promise
16 |
17 | internal external interface RequestOptions {
18 | var headers: OutgoingHttpHeaders?
19 | get() = definedExternally
20 | set(value) = definedExternally
21 | var socketTimeout: Number?
22 | get() = definedExternally
23 | set(value) = definedExternally
24 | var ignoreSslError: Boolean?
25 | get() = definedExternally
26 | set(value) = definedExternally
27 | var allowRedirects: Boolean?
28 | get() = definedExternally
29 | set(value) = definedExternally
30 | var allowRedirectDowngrade: Boolean?
31 | get() = definedExternally
32 | set(value) = definedExternally
33 | var maxRedirects: Number?
34 | get() = definedExternally
35 | set(value) = definedExternally
36 | var maxSockets: Number?
37 | get() = definedExternally
38 | set(value) = definedExternally
39 | var keepAlive: Boolean?
40 | get() = definedExternally
41 | set(value) = definedExternally
42 | var deserializeDates: Boolean?
43 | get() = definedExternally
44 | set(value) = definedExternally
45 | var allowRetries: Boolean?
46 | get() = definedExternally
47 | set(value) = definedExternally
48 | var maxRetries: Number?
49 | get() = definedExternally
50 | set(value) = definedExternally
51 | }
52 |
53 | internal external interface RequestHandler {
54 | fun prepareRequest(options: node.http.RequestOptions)
55 | fun canHandleAuthentication(response: HttpClientResponse): Boolean
56 | fun handleAuthentication(httpClient: HttpClient, requestInfo: RequestInfo, data: Any?): Promise
57 | }
58 |
59 | internal external interface RequestInfo {
60 | var options: node.http.RequestOptions
61 | var parsedUrl: URL
62 | var httpModule: Any
63 | }
64 |
65 | internal external interface TypedResponse {
66 | var statusCode: Number
67 | var result: T?
68 | var headers: IncomingHttpHeaders
69 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/resources/archives/test.tar:
--------------------------------------------------------------------------------
1 | test/ 0040777 0000000 0000000 00000000000 14072432207 006774 5 ustar 00 test/file.txt 0100777 0000000 0000000 00000000011 14072432213 010441 0 ustar 00 Test file
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action-plugin/src/main/kotlin/com/rnett/action/KotlinAction.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Project
4 | import org.gradle.api.Task
5 | import org.gradle.api.file.Directory
6 | import org.gradle.api.tasks.TaskProvider
7 | import org.gradle.kotlin.dsl.the
8 | import org.gradle.kotlin.dsl.withType
9 | import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
10 | import java.io.File
11 |
12 | /**
13 | * Add a task to create the custom webpack config necessary for packing GitHub actions. Done automatically in [githubAction].
14 | */
15 | fun Project.addWebpackGenTask(): TaskProvider = tasks.register(Constants.createWebpackTaskName) {
16 | group = Constants.taskGroup
17 | val directory = File("$projectDir/webpack.config.d/")
18 | val outputFile = File("$directory/github.action.config.js")
19 | doLast {
20 | if (!directory.exists())
21 | directory.mkdir()
22 |
23 | outputFile.writeText("config.target = 'node';")
24 | }
25 | outputs.file(outputFile)
26 | .withPropertyName("outputFile")
27 | }
28 |
29 | /**
30 | * Adds a JS target for GitHub actions (browser commonJs w/ node libraries) that run using `node12` and configures necessary tasks for packing.
31 | *
32 | * Running the production webpack task will generate the compiled GitHub task in [outputDir]/[outFileName], which by default is `dist/index.js`.
33 | */
34 | fun KotlinJsTargetDsl.githubAction(
35 | outputDir: Directory = project.layout.projectDirectory.dir("dist"),
36 | outFileName: String = "index.js",
37 | nodeVersion: String = "16.18.0"
38 | ) {
39 |
40 | useCommonJs()
41 |
42 | val webpackGenTask = project.addWebpackGenTask()
43 | binaries.executable()
44 |
45 | browser {
46 | distribution {
47 | this.directory = outputDir.asFile
48 | this.name = outFileName
49 | }
50 | webpackTask {
51 | if (mode == org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode.PRODUCTION) {
52 | output.globalObject = "this" // NodeJS mode
53 | sourceMaps = false
54 | this.outputFileName = outFileName
55 |
56 | dependsOn(webpackGenTask)
57 | }
58 | }
59 | }
60 |
61 | project.rootProject.plugins.withType {
62 | project.rootProject.the().nodeVersion = nodeVersion
63 | }
64 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/inputs.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import com.rnett.action.delegates.Delegatable
4 | import com.rnett.action.delegates.ifNull
5 | import kotlin.properties.ReadOnlyProperty
6 | import kotlin.reflect.KProperty
7 |
8 | /**
9 | * Accessors for input variables.
10 | *
11 | * Can be delegated from. Property names will be converted to snake-case unless name is specified.
12 | * Delegating from [inputs] treats the input as required.
13 | */
14 | public object inputs : Delegatable(true), ReadOnlyProperty {
15 |
16 | /**
17 | * Get the input passed for [name], or throws an error if it was not passed.
18 | */
19 | public override fun getRequired(name: String): String = core.getRequiredInput(name)
20 |
21 | /**
22 | * Get the input passed for [name], or throws an error if it was not passed.
23 | */
24 | public override fun getOptional(name: String): String? = core.getOptionalInput(name)
25 |
26 | /**
27 | * Get the input passed for [name]. Treats it as optional, see [getOptional].
28 | */
29 | public operator fun get(name: String): String? = getOptional(name)
30 |
31 | /**
32 | * A delegate based on the property name converted to snake case, for a required input.
33 | */
34 | override fun getValue(thisRef: Any?, property: KProperty<*>): String {
35 | return getRequired(property.name.delegateName())
36 | }
37 |
38 | /**
39 | * Get a delegate for [name].
40 | */
41 | public operator fun invoke(name: String): ReadOnlyProperty = delegate(name)
42 |
43 | /**
44 | * Get an optional delegate. Property names will be converted to snake-case unless name is specified.
45 | */
46 | public val optional: ReadOnlyProperty by lazy { optionalDelegate(null) }
47 |
48 | /**
49 | * Get an optional delegate for [name].
50 | */
51 | public fun optional(name: String): ReadOnlyProperty = optionalDelegate(name)
52 |
53 | /**
54 | * Get an optional delegate with a default value. Property names will be converted to snake-case unless name is specified.
55 | */
56 | public fun optionalWithDefault(default: () -> String): ReadOnlyProperty = optional.ifNull(default)
57 |
58 | /**
59 | * Get an optional delegate with a default value for [name].
60 | */
61 | public fun optionalWithDefault(name: String, default: () -> String): ReadOnlyProperty =
62 | optional(name).ifNull(default)
63 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestExec.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import com.rnett.action.exec.exec
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.test.runTest
6 | import node.buffer.Buffer
7 | import node.buffer.BufferEncoding
8 | import kotlin.test.Test
9 | import kotlin.test.assertEquals
10 | import kotlin.test.assertTrue
11 |
12 | @OptIn(ExperimentalCoroutinesApi::class)
13 | class TestExec : TestWithDir() {
14 | override suspend fun Path.initDir() {
15 | descendant("testFile3").touch().write("Testing file")
16 | }
17 |
18 | val diff = if (OperatingSystem.isWindows) "\r\n" else ""
19 |
20 | @Test
21 | fun testExec() = runTest {
22 | exec.execCommand("javac", "--version")
23 | }
24 |
25 | @Test
26 | fun testExecAndCapture() = runTest {
27 | assertTrue(exec.execCommandAndCapture("javac", "--version").stdout.startsWith("javac"))
28 | }
29 |
30 | @Test
31 | fun testExecShell() = runTest {
32 | exec.execShell("cp testFile3 testOut1", cwd = testDir)
33 | val file = (testDir / "testOut1")
34 | assertEquals("Testing file", file.readText())
35 | }
36 |
37 | @Test
38 | fun testExecAndCaptureShell() = runTest {
39 | assertEquals("Testing file$diff", exec.execShellAndCapture("cat testFile3 | cat", cwd = testDir).stdout)
40 | }
41 |
42 | @Test
43 | fun testInputRedirect() = runTest {
44 | if (!OperatingSystem.isWindows) {
45 | val output = exec.execShellAndCapture("cat", input = Buffer.from("Test"))
46 | assertEquals("Test", output.throwIfFailure().stdout)
47 | }
48 | }
49 |
50 | @Test
51 | fun testOutputRedirect() = runTest {
52 | val outputFile = (testDir / "testOut3")
53 | val stream = outputFile.writeStream()
54 | exec.execShell("echo \"Test\"", outStream = stream)
55 | stream.close()
56 | assertEquals("Test", outputFile.readText().lines()[1])
57 | }
58 |
59 | @Test
60 | fun testOutputInShellRedirect() = runTest {
61 | val shellDiff = if (OperatingSystem.isWindows) "\r\n" else "\n"
62 |
63 | val outputFile = (testDir / "testOut2")
64 | exec.execShell("echo \"Test\" > \"$outputFile\"")
65 | assertEquals("Test$shellDiff", outputFile.readText(if (OperatingSystem.isWindows) BufferEncoding.ucs2 else BufferEncoding.utf8).let {
66 | if (OperatingSystem.isWindows)
67 | it.substring(1)
68 | else
69 | it
70 | })
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/kotlin-js-action/build-logic/docs/src/main/kotlin/com/rnett/action/DocsLeafPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import org.gradle.kotlin.dsl.create
6 | import org.gradle.kotlin.dsl.withType
7 | import java.net.URL
8 |
9 | class DocsLeafPlugin : Plugin {
10 | override fun apply(project: Project): Unit = with(project) {
11 | project.plugins.apply(MetadataPlugin::class.java)
12 | project.plugins.apply("org.jetbrains.dokka")
13 | val extension = project.extensions.create("docs", LeafDocsExtension::class)
14 |
15 | tasks.withType() {
16 | moduleName.set(extension.title)
17 | moduleVersion.set(version.toString())
18 |
19 | dokkaSourceSets.configureEach {
20 | includes.from(listOf(file("module.md"), file("packages.md"), file("README.md")).filter { it.exists() })
21 | includeNonPublic.set(false)
22 | suppressObviousFunctions.set(true)
23 | suppressInheritedMembers.set(false)
24 | skipDeprecated.set(false)
25 | skipEmptyPackages.set(true)
26 | jdkVersion.set(8)
27 |
28 | val sourceSet = this.sourceSetID.sourceSetName
29 |
30 | sourceLink {
31 | localDirectory.set(file("src/$sourceSet/kotlin"))
32 |
33 | remoteUrl.set(project.providers.gradleProperty("sourceLinkBranch").map { sourceLinkBranch ->
34 |
35 | val githubRoot = buildString {
36 | append("https://github.com/rnett/kotlin-js-action/blob/")
37 | append(sourceLinkBranch)
38 | append("/kotlin-js-action/")
39 |
40 | val dir = project.projectDir.relativeTo(rootProject.projectDir).path.trim('/')
41 |
42 | append("/$dir")
43 | }
44 |
45 | java.net.URL("$githubRoot/src/$sourceSet/kotlin")
46 | })
47 | remoteLineSuffix.set("#L")
48 | }
49 |
50 | platform.set(extension.platform)
51 |
52 | externalDocumentationLink {
53 | url.set(URL("https://kotlin.github.io/kotlinx.coroutines/"))
54 | }
55 |
56 | externalDocumentationLink {
57 | url.set(URL("https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/"))
58 | }
59 | }
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestToolCache.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import com.rnett.action.core.isActionRunner
4 | import com.rnett.action.toolcache.toolcache
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlin.test.Test
7 | import kotlin.test.assertEquals
8 | import kotlin.test.assertNotNull
9 |
10 | @OptIn(ExperimentalCoroutinesApi::class)
11 | class TestToolCache : TestWithDir() {
12 |
13 | val licenseUrl = "https://raw.githubusercontent.com/rnett/kotlin-js-action/main/LICENSE"
14 | suspend fun localLicense() = (Path(TestEnv.projectDirPath) / "LICENSE").readText().replace("\r\n", "\n")
15 |
16 | @Test
17 | fun testDownload() = runTest {
18 | val resultFile = testDir / "testLicense"
19 | val result = toolcache.downloadTool(licenseUrl, resultFile)
20 | assertEquals(result, resultFile)
21 | assertEquals(localLicense(), resultFile.readText())
22 |
23 | if (isActionRunner) {
24 | val tempResult = toolcache.downloadTool(licenseUrl)
25 | assertEquals(localLicense(), tempResult.readText().replace("\r\n", "\n"))
26 | }
27 | }
28 |
29 | @Test
30 | fun testExtract() = runTest {
31 | val archivesDir = Path(TestEnv.projectDirPath) / "kotlin-js-action/kotlin-js-action/src/test/resources/archives"
32 | val extractedDir = testDir / "testExtract"
33 | archivesDir.children().forEach {
34 |
35 | if (it.name.endsWith(".7z") && !OperatingSystem.isWindows)
36 | return@forEach
37 |
38 | val extracted = toolcache.extract(it, extractedDir)
39 | assertEquals("Test file", (extracted / "test/file.txt").readText())
40 | extractedDir.delete(true)
41 | }
42 | }
43 |
44 | @Test
45 | fun testCacheDir() = runTest {
46 | if (!isActionRunner) return@runTest
47 |
48 | val dir = testDir / "cacheDir"
49 | toolcache.downloadTool(licenseUrl, dir / "test")
50 |
51 | toolcache.cacheDir(dir, "testTool", "1.0.1")
52 | toolcache.cacheDir(dir, "testTool", "1.0.2")
53 |
54 | val found = toolcache.find("testTool", "1.x.x")
55 | assertNotNull(found)
56 |
57 | assertEquals(listOf("1.0.1", "1.0.2"), toolcache.findAllVersions("testTool").sorted())
58 | }
59 |
60 | @Test
61 | fun testCacheFile() = runTest {
62 | if (!isActionRunner) return@runTest
63 |
64 | toolcache.downloadTool(licenseUrl, testDir / "test")
65 |
66 | toolcache.cacheFile(testDir / "test", "testFileTool", "1.0.1")
67 |
68 | val found = toolcache.find("testFileTool", "1.x.x")
69 | assertNotNull(found)
70 | }
71 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/test/kotlin/com/rnett/action/TestGlob.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import com.rnett.action.glob.glob
4 | import com.rnett.action.glob.globFlow
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.toList
7 | import kotlin.test.Test
8 | import kotlin.test.assertEquals
9 |
10 | @OptIn(ExperimentalCoroutinesApi::class)
11 | class TestGlob : TestWithDir() {
12 | override suspend fun Path.initDir() {
13 | descendant("testDir1/innerDir1/file1").touch()
14 | descendant("testDir1/innerDir1/file2").touch()
15 | descendant("testDir1/innerDir1/file3").touch()
16 | descendant("testDir1/innerDir2/file1").touch()
17 | descendant("testDir1/innerDir2/file2").touch()
18 | descendant("testDir2/innerDir1/file1").touch()
19 | descendant("testDir2/innerDir1/file2").touch()
20 | descendant("testDir2/innerDir1/file3").touch()
21 | descendant("testDir2/innerDir2/file1").touch()
22 | }
23 |
24 | private suspend fun tryGlob(
25 | vararg patterns: String,
26 | followSymbolicLinks: Boolean = true,
27 | implicitDescendants: Boolean = true,
28 | omitBrokenSymbolicLinks: Boolean = true,
29 | matchDirectories: Boolean = true
30 | ): List {
31 | val glob = glob(
32 | *patterns,
33 | followSymbolicLinks = followSymbolicLinks,
34 | implicitDescendants = implicitDescendants,
35 | omitBrokenSymbolicLinks = omitBrokenSymbolicLinks,
36 | matchDirectories = matchDirectories
37 | )
38 | val globFlow = globFlow(
39 | *patterns,
40 | followSymbolicLinks = followSymbolicLinks,
41 | implicitDescendants = implicitDescendants,
42 | omitBrokenSymbolicLinks = omitBrokenSymbolicLinks,
43 | matchDirectories = matchDirectories
44 | ).toList()
45 | assertEquals(glob.toSet(), globFlow.toSet(), "Glob and Glob flow did not match")
46 | return glob
47 | }
48 |
49 | @Test
50 | fun getFiles() = runTest {
51 | val files = tryGlob("./**/file*")
52 | assertEquals(9, files.size)
53 | }
54 |
55 | @Test
56 | fun byDir() = runTest {
57 | val files = tryGlob("./**/innerDir*")
58 | assertEquals(13, files.size)
59 | }
60 |
61 | @Test
62 | fun byDirNoDirs() = runTest {
63 | val files = tryGlob("./**/innerDir*", matchDirectories = false)
64 | assertEquals(9, files.size)
65 | }
66 |
67 | @Test
68 | fun getDirs() = runTest {
69 | val files = tryGlob("./**/innerDir*", implicitDescendants = false)
70 | assertEquals(4, files.size)
71 | }
72 |
73 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/httpclient/RequestHandler.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.httpclient
2 |
3 | import com.rnett.action.JsObject
4 | import internal.httpclient.HttpClientResponse
5 | import internal.httpclient.RequestInfo
6 | import kotlinx.coroutines.DelicateCoroutinesApi
7 | import kotlinx.coroutines.GlobalScope
8 | import kotlinx.coroutines.promise
9 | import kotlinx.js.set
10 | import node.ReadableStream
11 | import node.http.ClientRequestArgs
12 | import node.http.OutgoingHttpHeaders
13 | import node.http.RequestOptions
14 | import org.w3c.dom.url.URL
15 | import kotlin.js.Promise
16 |
17 |
18 | /**
19 | * A handler that modifies outgoing requests and optionally handles authentication on 401s.
20 | */
21 | public fun interface RequestHandler {
22 |
23 | /**
24 | * Modify an outgoing request.
25 | */
26 | public fun ClientRequestArgs.prepareRequest(headers: MutableHeaders)
27 |
28 | /**
29 | * If this returns `true`, [handleAuthentication] must be implemented.
30 | */
31 | public fun canHandleAuthentication(response: HttpResponse): Boolean {
32 | return false
33 | }
34 |
35 | /**
36 | * Will not be called unless [canHandleAuthentication] is `true`.
37 | *
38 | * [data] will be [ReadableStream] or [String].
39 | */
40 | public suspend fun handleAuthentication(
41 | client: HttpClient,
42 | url: URL,
43 | data: Any?,
44 | options: ClientRequestArgs
45 | ): HttpResponse {
46 | error("Can not handle authentication")
47 | }
48 | }
49 |
50 | @OptIn(DelicateCoroutinesApi::class)
51 | internal fun RequestHandler.toInternal() = object : internal.httpclient.RequestHandler {
52 | override fun prepareRequest(options: RequestOptions) {
53 | options.prepareRequest(WrappedClientRequestArgs(options))
54 | }
55 |
56 | override fun canHandleAuthentication(response: HttpClientResponse): Boolean {
57 | return this@toInternal.canHandleAuthentication(HttpResponseImpl(response))
58 | }
59 |
60 | override fun handleAuthentication(
61 | httpClient: internal.httpclient.HttpClient,
62 | requestInfo: RequestInfo,
63 | data: Any?
64 | ): Promise {
65 | return GlobalScope.promise {
66 | this@toInternal.handleAuthentication(
67 | WrappedClient(httpClient),
68 | requestInfo.parsedUrl,
69 | data,
70 | requestInfo.options
71 | ).toInternal()
72 | }
73 | }
74 |
75 | }
76 |
77 | internal fun Map.toIHeaders(): OutgoingHttpHeaders = JsObject {
78 | this@toIHeaders.forEach {
79 | this[it.key] = it.value
80 | }
81 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/exec/interfaces.module_@actions_exec.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/exec")
8 | @file:JsNonModule
9 |
10 | package internal.exec
11 |
12 | import node.buffer.Buffer
13 | import node.stream.Writable
14 |
15 |
16 | internal external interface EnvBuilder {
17 | @nativeGetter
18 | operator fun get(key: String): String?
19 |
20 | @nativeSetter
21 | operator fun set(key: String, value: String)
22 | }
23 |
24 | internal external interface ExecListeners {
25 | var stdout: ((data: Buffer) -> Unit)?
26 | get() = definedExternally
27 | set(value) = definedExternally
28 | var stderr: ((data: Buffer) -> Unit)?
29 | get() = definedExternally
30 | set(value) = definedExternally
31 | var stdline: ((data: String) -> Unit)?
32 | get() = definedExternally
33 | set(value) = definedExternally
34 | var errline: ((data: String) -> Unit)?
35 | get() = definedExternally
36 | set(value) = definedExternally
37 | var debug: ((data: String) -> Unit)?
38 | get() = definedExternally
39 | set(value) = definedExternally
40 | }
41 |
42 | internal external interface ExecOptions {
43 | var cwd: String?
44 | get() = definedExternally
45 | set(value) = definedExternally
46 | var env: EnvBuilder?
47 | get() = definedExternally
48 | set(value) = definedExternally
49 | var silent: Boolean?
50 | get() = definedExternally
51 | set(value) = definedExternally
52 | var outStream: Writable?
53 | get() = definedExternally
54 | set(value) = definedExternally
55 | var errStream: Writable?
56 | get() = definedExternally
57 | set(value) = definedExternally
58 | var windowsVerbatimArguments: Boolean?
59 | get() = definedExternally
60 | set(value) = definedExternally
61 | var failOnStdErr: Boolean?
62 | get() = definedExternally
63 | set(value) = definedExternally
64 | var ignoreReturnCode: Boolean?
65 | get() = definedExternally
66 | set(value) = definedExternally
67 | var delay: Number?
68 | get() = definedExternally
69 | set(value) = definedExternally
70 | var input: Buffer?
71 | get() = definedExternally
72 | set(value) = definedExternally
73 | var listeners: ExecListeners?
74 | get() = definedExternally
75 | set(value) = definedExternally
76 | }
77 |
78 | internal external interface ExecOutput {
79 | var exitCode: Number
80 | var stdout: String
81 | var stderr: String
82 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/state.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import com.rnett.action.delegates.MutableDelegatable
4 | import com.rnett.action.delegates.ifNull
5 | import kotlin.properties.ReadOnlyProperty
6 | import kotlin.properties.ReadWriteProperty
7 | import kotlin.reflect.KProperty
8 |
9 | /**
10 | * Accessors for state. State is action-specific, and only useful when set in one phase and read in another (i.e. post).
11 | * Delegating from [state] treats the input as required.
12 | */
13 | public object state : MutableDelegatable(), ReadWriteProperty {
14 | /**
15 | * Get state [name], returning `null` if it is not set.
16 | */
17 | public operator fun get(name: String): String? = getOptional(name)
18 |
19 | /**
20 | * Get state [name], throwing if it is not set.
21 | */
22 | public override fun getRequired(name: String): String = core.getRequiredState(name)
23 |
24 | /**
25 | * Get state [name], returning `null` if it is not set.
26 | */
27 | override fun getOptional(name: String): String? = core.getState(name)
28 |
29 | /**
30 | * Set state [name] to [value].
31 | */
32 | public override operator fun set(name: String, value: String): Unit = core.saveState(name, value)
33 |
34 | /**
35 | * A delegate based on the property name, for a required state.
36 | */
37 | override fun getValue(thisRef: Any?, property: KProperty<*>): String {
38 | return getRequired(property.name.delegateName())
39 | }
40 |
41 | /**
42 | * A delegate based on the property name, for a required state.
43 | */
44 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
45 | set(property.name.delegateName(), value)
46 | }
47 |
48 | /**
49 | * Get a delegate for [name].
50 | */
51 | public operator fun invoke(name: String): ReadOnlyProperty = delegate(name)
52 |
53 | /**
54 | * Get an optional delegate.
55 | */
56 | public val optional: ReadOnlyProperty by lazy { optionalDelegate(null) }
57 |
58 | /**
59 | * Get an optional delegate for [name].
60 | */
61 | public fun optional(name: String): ReadOnlyProperty = optionalDelegate(name)
62 |
63 | /**
64 | * Get an optional delegate with a default value.
65 | */
66 | public fun optionalWithDefault(default: () -> String): ReadOnlyProperty =
67 | inputs.optional.ifNull(default)
68 |
69 | /**
70 | * Get an optional delegate with a default value for [name].
71 | */
72 | public fun optionalWithDefault(name: String, default: () -> String): ReadOnlyProperty =
73 | inputs.optional(
74 | name
75 | ).ifNull(default)
76 | }
--------------------------------------------------------------------------------
/test-action/src/main/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import com.rnett.action.core.SummaryTableCell
2 | import com.rnett.action.core.env
3 | import com.rnett.action.core.inputs
4 | import com.rnett.action.core.runAction
5 | import com.rnett.action.core.summary
6 | import com.rnett.action.delegates.lines
7 | import kotlin.test.assertEquals
8 | import kotlin.test.assertFails
9 | import kotlin.test.assertNull
10 |
11 | const val requiredInputKey = "required-input"
12 | const val requiredInputValue = "required-test"
13 |
14 | const val optionalNoDefaultKey = "optional-no-default"
15 |
16 | const val withDefaultKey = "with-default"
17 | const val withDefaultValue = "Test"
18 |
19 | const val multilineKey = "multiline"
20 | val multilineValue = listOf("test1", "test2")
21 |
22 | const val testEnvKey = "test-env"
23 | const val testEnvValue = "test2"
24 |
25 | const val noEnvKey = "no-env"
26 |
27 | suspend fun main() = runAction {
28 | assertEquals(requiredInputValue, inputs[requiredInputKey])
29 | assertEquals(requiredInputValue, inputs.getRequired(requiredInputKey))
30 | assertEquals(requiredInputValue, inputs.getOptional(requiredInputKey))
31 | val requiredInput by inputs
32 | assertEquals(requiredInputValue, requiredInput)
33 |
34 | assertFails { inputs.getRequired(optionalNoDefaultKey) }
35 | assertNull(inputs.getOptional(optionalNoDefaultKey))
36 | val optionalNoDefault by inputs.optional
37 | assertNull(optionalNoDefault)
38 |
39 | assertEquals(withDefaultValue, inputs[withDefaultKey])
40 | assertEquals(withDefaultValue, inputs.getRequired(withDefaultKey))
41 | assertEquals(withDefaultValue, inputs.getOptional(withDefaultKey))
42 | val withDefault by inputs
43 | assertEquals(withDefaultValue, withDefault)
44 |
45 | assertEquals(multilineValue, inputs[multilineKey]?.split("\n"))
46 | assertEquals(multilineValue, inputs.getRequired(multilineKey).split("\n"))
47 | assertEquals(multilineValue, inputs.getOptional(multilineKey)?.split("\n"))
48 | val multiline by inputs.lines()
49 | assertEquals(multilineValue, multiline)
50 |
51 | assertEquals(testEnvValue, env[testEnvKey])
52 | assertEquals(testEnvValue, env.getRequired(testEnvKey))
53 | val testEnv by env(testEnvKey)
54 | assertEquals(testEnvValue, testEnv)
55 |
56 | assertNull(env[noEnvKey])
57 | assertFails { env.getRequired(noEnvKey) }
58 | var noEnv by env(noEnvKey)
59 | assertNull(noEnv)
60 | noEnv = "test"
61 | assertEquals("test", noEnv)
62 | assertEquals("test", env.getRequired(noEnvKey))
63 |
64 | summary.append {
65 | h2("Test")
66 | hr()
67 | addTable(
68 | listOf(SummaryTableCell("Test", true), SummaryTableCell("Test2", true)),
69 | listOf(SummaryTableCell("1"), SummaryTableCell("2"))
70 | )
71 | }
72 |
73 | println("Tests done!")
74 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/TopLevel.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import com.rnett.action.currentProcess
4 | import com.rnett.action.delegates.ifNull
5 | import com.rnett.action.delegates.isTrue
6 | import kotlin.contracts.InvocationKind
7 | import kotlin.contracts.contract
8 |
9 | /**
10 | * Mask [this] in log output.
11 | */
12 | public fun String.maskSecret(): Unit = maskSecret(this)
13 |
14 | /**
15 | * Mask [secret] in log output.
16 | */
17 | public fun maskSecret(secret: String): Unit = core.setSecret(secret)
18 |
19 |
20 | /**
21 | * Fail with [message], logging [message] as an error and killing the process.
22 | */
23 | @Suppress("UNREACHABLE_CODE")
24 | public fun fail(message: String): Nothing {
25 | core.setFailed(message)
26 | currentProcess.exit(1)
27 | return error("")
28 | }
29 |
30 | /**
31 | * Fail with [exception], logging [exception] as an error and killing the process.
32 | */
33 | @Suppress("UNREACHABLE_CODE")
34 | public fun fail(exception: Throwable): Nothing {
35 | core.setFailed(exception)
36 | exception.printStackTrace()
37 | currentProcess.exit(1)
38 | return error("")
39 | }
40 |
41 | /**
42 | * Runs [block], [fail]-ing if an exception is thrown and not caught within [block].
43 | *
44 | * Runs [finally] in the try-catch's `finally` block. If [flush] is `true`, prints a newline in the finally block.
45 | */
46 | public inline fun runOrFail(finally: () -> Unit = {}, flush: Boolean = true, block: () -> R): R {
47 | contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
48 | try {
49 | return block()
50 | } catch (e: Throwable) {
51 | fail(e)
52 | } finally {
53 | finally()
54 | if (flush)
55 | println()
56 | }
57 | }
58 |
59 | /**
60 | * Runs [block], failing the action if exceptions are thrown
61 | */
62 | public inline fun runAction(flush: Boolean = true, block: () -> Unit) {
63 | contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
64 | runOrFail(flush = flush, block = block)
65 | }
66 |
67 | /**
68 | * Runs [block], logging (as [logger.error]) any exceptions that are not caught within [block].
69 | *
70 | * Runs [finally] in the try-catch's `finally` block. If [flush] is `true`, prints a newline in the finally block.
71 | */
72 | public inline fun runOrLogException(finally: () -> Unit = {}, flush: Boolean = true, block: () -> R): Result {
73 | contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
74 | return try {
75 | Result.success(block())
76 | } catch (e: Throwable) {
77 | logger.error(e)
78 | Result.failure(e)
79 | } finally {
80 | finally()
81 | if (flush)
82 | println()
83 | }
84 | }
85 |
86 | /**
87 | * `true` if the current environment is a GitHub actions runner.
88 | */
89 | public val isActionRunner: Boolean by env("GITHUB_ACTIONS").isTrue().ifNull { false }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/github/interfaces.module_@actions_github.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/github")
3 | @file:JsNonModule
4 |
5 | package internal.github
6 |
7 | import kotlin.js.*
8 |
9 | internal external interface `T$13` {
10 | @nativeGetter
11 | operator fun get(key: String): Any?
12 | @nativeSetter
13 | operator fun set(key: String, value: Any)
14 | var login: String
15 | var name: String?
16 | get() = definedExternally
17 | set(value) = definedExternally
18 | }
19 |
20 | internal external interface PayloadRepository {
21 | @nativeGetter
22 | operator fun get(key: String): Any?
23 | @nativeSetter
24 | operator fun set(key: String, value: Any)
25 | var full_name: String?
26 | get() = definedExternally
27 | set(value) = definedExternally
28 | var name: String
29 | var owner: `T$13`
30 | var html_url: String?
31 | get() = definedExternally
32 | set(value) = definedExternally
33 | }
34 |
35 | internal external interface `T$14` {
36 | @nativeGetter
37 | operator fun get(key: String): Any?
38 | @nativeSetter
39 | operator fun set(key: String, value: Any)
40 | var number: Number
41 | var html_url: String?
42 | get() = definedExternally
43 | set(value) = definedExternally
44 | var body: String?
45 | get() = definedExternally
46 | set(value) = definedExternally
47 | }
48 |
49 | internal external interface `T$15` {
50 | @nativeGetter
51 | operator fun get(key: String): Any?
52 | @nativeSetter
53 | operator fun set(key: String, value: Any)
54 | var type: String
55 | }
56 |
57 | internal external interface `T$16` {
58 | var id: Number
59 | @nativeGetter
60 | operator fun get(key: String): Any?
61 | @nativeSetter
62 | operator fun set(key: String, value: Any)
63 | }
64 |
65 | internal external interface WebhookPayload {
66 | @nativeGetter
67 | operator fun get(key: String): Any?
68 | @nativeSetter
69 | operator fun set(key: String, value: Any)
70 | var repository: PayloadRepository?
71 | get() = definedExternally
72 | set(value) = definedExternally
73 | var issue: `T$14`?
74 | get() = definedExternally
75 | set(value) = definedExternally
76 | var pull_request: `T$14`?
77 | get() = definedExternally
78 | set(value) = definedExternally
79 | var sender: `T$15`?
80 | get() = definedExternally
81 | set(value) = definedExternally
82 | var action: String?
83 | get() = definedExternally
84 | set(value) = definedExternally
85 | var installation: `T$16`?
86 | get() = definedExternally
87 | set(value) = definedExternally
88 | var comment: `T$16`?
89 | get() = definedExternally
90 | set(value) = definedExternally
91 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import node.WritableStream
4 | import node.buffer.Buffer
5 | import node.process.Process
6 | import node.stream.Duplex
7 | import org.khronos.webgl.ArrayBuffer
8 | import org.khronos.webgl.Int8Array
9 | import org.khronos.webgl.Uint8Array
10 | import kotlin.contracts.InvocationKind
11 | import kotlin.contracts.contract
12 |
13 | /**
14 | * Convert a camelCase string to snake-case.
15 | */
16 | public fun String.camelToSnakeCase(): String = replace(Regex("[^A-Z][A-Z]")) {
17 | it.value[0] + "-" + it.value[1].lowercaseChar()
18 | }
19 |
20 | /**
21 | * Convert a snake-case string to camelCase.
22 | */
23 | public fun String.snakeToCamelCase(): String = replace(Regex("-[a-z]")) { it.value[1].uppercaseChar().toString() }
24 |
25 |
26 | /**
27 | * Create a JavaScript object for the given interface.
28 | */
29 | public inline fun JsObject(block: T.() -> Unit = {}): T {
30 | contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
31 | node.os.arch()
32 | val value = js("{}") as T
33 | value.block()
34 | return value
35 | }
36 |
37 | /**
38 | * Get the entries of a JS object, using `Object.entries`.
39 | */
40 | @Suppress("NOTHING_TO_INLINE")
41 | public inline fun jsEntries(jsObject: dynamic): Map = js("Object")
42 | .entries(jsObject)
43 | .unsafeCast>>()
44 | .map {
45 | it[0].unsafeCast() to it[1]
46 | }.toMap()
47 |
48 | /**
49 | * Get the current process. Alias for [process] that doesn't have name conflicts.
50 | */
51 | public val currentProcess: Process get() = node.process.process
52 |
53 | /**
54 | * Write a line to [this], using the OS's line seperator.
55 | */
56 | public fun WritableStream.writeLine(buffer: String): Boolean = write(buffer + OperatingSystem.lineSeparator)
57 |
58 | /**
59 | * Write a line to [this], using the OS's line seperator.
60 | */
61 | public fun Duplex.writeLine(buffer: String): Boolean = write(buffer + OperatingSystem.lineSeparator)
62 |
63 | /**
64 | * Non-copying conversion to a Kotlin [ByteArray].
65 | */
66 | public fun ArrayBuffer.asByteArray(byteOffset: Int = 0, length: Int = this.byteLength): ByteArray =
67 | Int8Array(this, byteOffset, length).asByteArray()
68 |
69 | /**
70 | * Non-copying conversion to a Kotlin [ByteArray].
71 | */
72 | public fun Int8Array.asByteArray(): ByteArray = this.unsafeCast()
73 |
74 | /**
75 | * Non-copying conversion to a Kotlin [ByteArray].
76 | */
77 | public fun Uint8Array.asByteArray(): ByteArray = Int8Array(buffer, byteOffset, length).asByteArray()
78 |
79 | /**
80 | * Non-copying conversion to a [Int8Array].
81 | */
82 | public fun ByteArray.asInt8Array(): Int8Array = this.unsafeCast()
83 |
84 | /**
85 | * Non-copying conversion to a [Buffer].
86 | */
87 | public fun ByteArray.asBuffer(): Buffer = this.asInt8Array().let {
88 | Buffer(Uint8Array(it.buffer, it.byteOffset, it.length))
89 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/core/summary.module_@actions_core.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
2 | @file:JsModule("@actions/core")
3 | @file:JsNonModule
4 |
5 | package internal.core
6 |
7 | import org.khronos.webgl.*
8 | import org.w3c.dom.*
9 | import org.w3c.dom.events.*
10 | import org.w3c.dom.parsing.*
11 | import org.w3c.dom.svg.*
12 | import org.w3c.dom.url.*
13 | import org.w3c.fetch.*
14 | import org.w3c.files.*
15 | import org.w3c.notifications.*
16 | import org.w3c.performance.*
17 | import org.w3c.workers.*
18 | import org.w3c.xhr.*
19 | import kotlin.js.*
20 |
21 | internal external val summary: Summary
22 |
23 | internal external interface SummaryTableCell {
24 | var data: String
25 | var header: Boolean?
26 | get() = definedExternally
27 | set(value) = definedExternally
28 | var colspan: String?
29 | get() = definedExternally
30 | set(value) = definedExternally
31 | var rowspan: String?
32 | get() = definedExternally
33 | set(value) = definedExternally
34 | }
35 |
36 | internal external interface SummaryImageOptions {
37 | var width: String?
38 | get() = definedExternally
39 | set(value) = definedExternally
40 | var height: String?
41 | get() = definedExternally
42 | set(value) = definedExternally
43 | }
44 |
45 | internal external interface SummaryWriteOptions {
46 | var overwrite: Boolean?
47 | get() = definedExternally
48 | set(value) = definedExternally
49 | }
50 |
51 | internal external open class Summary {
52 | open var _buffer: Any
53 | open var _filePath: Any
54 | open var filePath: Any
55 | open var wrap: Any
56 | open fun write(options: SummaryWriteOptions = definedExternally): Promise
57 | open fun clear(): Promise
58 | open fun stringify(): String
59 | open fun isEmptyBuffer(): Boolean
60 | open fun emptyBuffer(): Summary
61 | open fun addRaw(text: String, addEOL: Boolean = definedExternally): Summary
62 | open fun addEOL(): Summary
63 | open fun addCodeBlock(code: String, lang: String = definedExternally): Summary
64 | open fun addList(items: Array, ordered: Boolean = definedExternally): Summary
65 | open fun addTable(rows: Array): Summary
66 | open fun addDetails(label: String, content: String): Summary
67 | open fun addImage(src: String, alt: String, options: SummaryImageOptions = definedExternally): Summary
68 | open fun addHeading(text: String, level: Number = definedExternally): Summary
69 | open fun addHeading(text: String): Summary
70 | open fun addHeading(text: String, level: String = definedExternally): Summary
71 | open fun addSeparator(): Summary
72 | open fun addBreak(): Summary
73 | open fun addQuote(text: String, cite: String = definedExternally): Summary
74 | open fun addLink(text: String, href: String): Summary
75 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/toolcache/toolcache.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/tool-cache")
8 | @file:JsNonModule
9 |
10 | package internal.toolcache
11 |
12 | import node.http.OutgoingHttpHeaders
13 | import kotlin.js.Promise
14 |
15 | internal external fun downloadTool(
16 | url: String,
17 | dest: String? = definedExternally,
18 | auth: String? = definedExternally,
19 | headers: OutgoingHttpHeaders? = definedExternally
20 | ): Promise
21 |
22 | internal external fun extract7z(
23 | file: String,
24 | dest: String? = definedExternally,
25 | _7zPath: String? = definedExternally,
26 | ): Promise
27 |
28 | internal external fun extractTar(
29 | file: String,
30 | dest: String? = definedExternally,
31 | flags: Array = definedExternally,
32 | ): Promise
33 |
34 | internal external fun extractXar(
35 | file: String,
36 | dest: String? = definedExternally,
37 | flags: Array = definedExternally,
38 | ): Promise
39 |
40 | internal external fun extractZip(
41 | file: String,
42 | dest: String? = definedExternally,
43 | ): Promise
44 |
45 | internal external fun cacheDir(sourceDir: String, tool: String, version: String, arch: String? = definedExternally): Promise
46 |
47 | internal external fun cacheFile(
48 | sourceFile: String,
49 | targetFile: String,
50 | tool: String,
51 | version: String,
52 | arch: String? = definedExternally
53 | ): Promise
54 |
55 | internal external fun find(toolName: String, versionSpec: String, arch: String? = definedExternally): String
56 |
57 | internal external fun findAllVersions(toolName: String, arch: String? = definedExternally): Array
58 |
59 | public external interface IToolRelease {
60 | public val version: String
61 | public val stable: Boolean
62 |
63 | @JsName("release_url")
64 | public val releaseUrl: String
65 | public val files: Array
66 | }
67 |
68 | public external interface IToolReleaseFile {
69 | public val filename: String
70 | public val platform: String
71 |
72 | @JsName("platform_version")
73 | public val platformVersion: String?
74 | public val arch: String
75 |
76 | @JsName("download_url")
77 | public val downloadUrl: String
78 | }
79 |
80 | internal external fun getManifestFromRepo(
81 | owner: String,
82 | repo: String,
83 | auth: String? = definedExternally,
84 | branch: String = definedExternally
85 | ): Promise>
86 |
87 | internal external fun findFromManifest(
88 | versionSpec: String,
89 | stable: Boolean,
90 | manifest: Array,
91 | archFilter: String = definedExternally
92 | ): Promise
93 |
94 | internal external fun isExplicitVersion(versionSpec: String): Boolean
95 |
96 |
97 | internal external fun evaluateVersions(versions: Array, versionSpec: String): String
--------------------------------------------------------------------------------
/test-action/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if %ERRORLEVEL% equ 0 goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if %ERRORLEVEL% equ 0 goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | set EXIT_CODE=%ERRORLEVEL%
84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
86 | exit /b %EXIT_CODE%
87 |
88 | :mainEnd
89 | if "%OS%"=="Windows_NT" endlocal
90 |
91 | :omega
92 |
--------------------------------------------------------------------------------
/kotlin-js-action/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if %ERRORLEVEL% equ 0 goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if %ERRORLEVEL% equ 0 goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | set EXIT_CODE=%ERRORLEVEL%
84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
86 | exit /b %EXIT_CODE%
87 |
88 | :mainEnd
89 | if "%OS%"=="Windows_NT" endlocal
90 |
91 | :omega
92 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.apache.commons.lang3.SystemUtils
2 | import org.jetbrains.kotlin.cli.common.toBooleanLenient
3 | import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
4 | import java.net.URL
5 |
6 | plugins {
7 | alias(libs.plugins.kotlin.js)
8 | id("kjs-action.js-module")
9 | }
10 |
11 | description = "Utilities for writing Kotlin JS GitHub actions, including wrappers around @actions/toolkit"
12 | metadata {
13 | title.set("Kotlin JS GitHub Action SDK")
14 | }
15 |
16 | val generateExternals = false
17 |
18 | private val latestVersionRegex = Regex("\"dist-tags\":\\{\"latest\":\"([^\"]+)\"")
19 |
20 | fun DependencyHandlerScope.latestNpm(
21 | name: String,
22 | version: String,
23 | generate: Boolean = generateExternals
24 | ): NpmDependency {
25 | val url = "https://registry.npmjs.org/$name/"
26 | val latest = latestVersionRegex.find(URL(url).readText())?.groupValues?.get(1) ?: error("Version not found in $url")
27 |
28 | if (latest != version) {
29 | val message = "Using old version of npm library $name: Using $version, but latest was $latest"
30 | if ((findProperty("enforceLatest")?.toString()?.toLowerCase() ?: "false") != "false")
31 | error(message)
32 | logger.warn(message)
33 | }
34 | return npm(name, version, generate)
35 | }
36 |
37 | dependencies {
38 | testImplementation(kotlin("test"))
39 | testImplementation(libs.kotlinx.coroutines.test)
40 | testImplementation(libs.kotlinx.serialization.json)
41 |
42 | api(libs.kotlinx.coroutines.core)
43 | api(libs.kotlin.wrappers.node)
44 |
45 | implementation(latestNpm("@actions/core", "1.10.0"))
46 | implementation(latestNpm("@actions/exec", "1.1.1"))
47 | implementation(latestNpm("@actions/glob", "0.3.0"))
48 | implementation(latestNpm("@actions/io", "1.1.2"))
49 | //TODO breaks dukat
50 | implementation(latestNpm("@actions/tool-cache", "2.0.1", false))
51 | implementation(latestNpm("@actions/github", "5.1.1"))
52 | implementation(latestNpm("@actions/artifact", "1.1.0"))
53 | implementation(latestNpm("@actions/cache", "3.0.6"))
54 | implementation(latestNpm("@actions/http-client", "2.0.1"))
55 | }
56 |
57 |
58 |
59 | kotlin {
60 | js(IR) {
61 | nodejs {
62 | testTask {
63 | val dir = layout.buildDirectory.dir("testdir").get().asFile
64 | doFirst {
65 | dir.deleteRecursively()
66 | dir.mkdirs()
67 | }
68 | doLast {
69 | dir.deleteRecursively()
70 | }
71 | environment("TEST_ENV_tempDir", dir.absolutePath)
72 |
73 | if (System.getenv("CI").toBooleanLenient() != true) {
74 | environment("TEST_ENV_projectDirPath", rootProject.layout.projectDirectory.asFile.parentFile.absolutePath)
75 | environment(
76 | "TEST_ENV_os", when {
77 | SystemUtils.IS_OS_MAC -> "mac"
78 | SystemUtils.IS_OS_LINUX -> "linux"
79 | SystemUtils.IS_OS_WINDOWS -> "windows"
80 | else -> error("Unsupported operating system")
81 | }
82 | )
83 | environment(
84 | "TEST_ENV_userHome",
85 | File(System.getProperty("user.home")).canonicalFile.absolutePath
86 | )
87 | }
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/internal/core/core.module_@actions_core.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "INTERFACE_WITH_SUPERCLASS",
3 | "OVERRIDING_FINAL_MEMBER",
4 | "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
5 | "CONFLICTING_OVERLOADS"
6 | )
7 | @file:JsModule("@actions/core")
8 | @file:JsNonModule
9 |
10 | package internal.core
11 |
12 | import kotlin.js.Promise
13 |
14 | internal external interface InputOptions {
15 | var required: Boolean?
16 | get() = definedExternally
17 | set(value) = definedExternally
18 | var trimWhitespace: Boolean?
19 | get() = definedExternally
20 | set(value) = definedExternally
21 | }
22 |
23 | internal external enum class ExitCode {
24 | Success /* = 0 */,
25 | Failure /* = 1 */
26 | }
27 |
28 | internal external interface AnnotationProperties {
29 | var title: String?
30 | get() = definedExternally
31 | set(value) = definedExternally
32 | var startLine: Number?
33 | get() = definedExternally
34 | set(value) = definedExternally
35 | var endLine: Number?
36 | get() = definedExternally
37 | set(value) = definedExternally
38 | var startColumn: Number?
39 | get() = definedExternally
40 | set(value) = definedExternally
41 | var endColumn: Number?
42 | get() = definedExternally
43 | set(value) = definedExternally
44 | var file: String?
45 | get() = definedExternally
46 | set(value) = definedExternally
47 | }
48 |
49 | internal external fun exportVariable(name: String, param_val: Any)
50 |
51 | internal external fun setSecret(secret: String)
52 |
53 | internal external fun addPath(inputPath: String)
54 |
55 | internal external fun getInput(name: String, options: InputOptions = definedExternally): String
56 |
57 | internal external fun getMultilineInput(name: String, options: InputOptions = definedExternally): Array
58 |
59 | internal external fun getBooleanInput(name: String, options: InputOptions = definedExternally): Boolean
60 |
61 | internal external fun setOutput(name: String, value: Any)
62 |
63 | internal external fun setCommandEcho(enabled: Boolean)
64 |
65 | internal external fun setFailed(message: String)
66 |
67 | internal external fun setFailed(message: Throwable)
68 |
69 | internal external fun isDebug(): Boolean
70 |
71 | internal external fun debug(message: String)
72 |
73 | internal external fun error(message: String, properties: AnnotationProperties = definedExternally)
74 |
75 | internal external fun error(message: String)
76 |
77 | internal external fun error(message: Throwable, properties: AnnotationProperties = definedExternally)
78 |
79 | internal external fun error(message: Throwable)
80 |
81 | internal external fun warning(message: String, properties: AnnotationProperties = definedExternally)
82 |
83 | internal external fun warning(message: String)
84 |
85 | internal external fun warning(message: Throwable, properties: AnnotationProperties = definedExternally)
86 |
87 | internal external fun warning(message: Throwable)
88 |
89 | internal external fun notice(message: String, properties: AnnotationProperties = definedExternally)
90 |
91 | internal external fun notice(message: String)
92 |
93 | internal external fun notice(message: Throwable, properties: AnnotationProperties = definedExternally)
94 |
95 | internal external fun notice(message: Throwable)
96 |
97 | internal external fun info(message: String)
98 |
99 | internal external fun startGroup(name: String)
100 |
101 | internal external fun endGroup()
102 |
103 | internal external fun group(name: String, fn: () -> Promise): Promise
104 |
105 | internal external fun saveState(name: String, value: Any)
106 |
107 | internal external fun getState(name: String): String
108 |
109 | internal external fun getIDToken(aud: String?): Promise
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/io/io.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.io
2 |
3 | import com.rnett.action.JsObject
4 | import com.rnett.action.Path
5 | import kotlinx.coroutines.await
6 |
7 | /**
8 | * Wrappers for [`@actions/io`](https://github.com/actions/toolkit/tree/main/packages/io).
9 | */
10 | public object io {
11 |
12 | /**
13 | * Copy files.
14 | */
15 | public suspend fun cp(
16 | source: String,
17 | dest: String,
18 | recursive: Boolean = false,
19 | force: Boolean = true,
20 | copySourceDirectory: Boolean = true
21 | ) {
22 | internal.io.cp(source, dest, JsObject {
23 | this.recursive = recursive
24 | this.force = force
25 | this.copySourceDirectory = copySourceDirectory
26 | }).await()
27 | }
28 |
29 | /**
30 | * Move files.
31 | */
32 | public suspend fun mv(source: String, dest: String, force: Boolean = true) {
33 | internal.io.mv(source, dest, JsObject {
34 | this.force = force
35 | }).await()
36 | }
37 |
38 | /**
39 | * Remove files recursively (`rm -rf`).
40 | */
41 | public suspend fun rmRF(inputPath: String) {
42 | internal.io.rmRF(inputPath).await()
43 | }
44 |
45 | /**
46 | * Create a directory and any parents that don't exist.
47 | */
48 | public suspend fun mkdirP(path: String) {
49 | internal.io.mkdirP(path).await()
50 | }
51 |
52 | /**
53 | * Get the location of a tool, or `null` if it can't be found.
54 | */
55 | public suspend fun which(tool: String): String? {
56 | return try {
57 | internal.io.which(tool, check = true).await()
58 | } catch (error: Throwable) {
59 | if (error.message != null && "Unable to locate executable file" in error.message!!)
60 | null
61 | else
62 | throw error
63 | }
64 | }
65 |
66 | /**
67 | * Copy files.
68 | */
69 |
70 | public suspend fun cp(
71 | source: Path, dest: Path, recursive: Boolean = false, force: Boolean = true,
72 | copySourceDirectory: Boolean = true
73 | ): Unit =
74 | cp(source.path, dest.path, recursive, force, copySourceDirectory)
75 |
76 | /**
77 | * Move files.
78 | */
79 | public suspend fun mv(source: Path, dest: Path, force: Boolean = true): Unit = mv(source.path, dest.path, force)
80 |
81 | /**
82 | * Copy files.
83 | */
84 | public suspend fun cp(
85 | source: Path, dest: String, recursive: Boolean = false, force: Boolean = true,
86 | copySourceDirectory: Boolean = true
87 | ): Unit =
88 | cp(source.path, dest, recursive, force, copySourceDirectory)
89 |
90 | /**
91 | * Move files.
92 | */
93 | public suspend fun mv(source: Path, dest: String, force: Boolean = true): Unit = mv(source.path, dest, force)
94 |
95 | /**
96 | * Copy files.
97 | */
98 | public suspend fun cp(
99 | source: String, dest: Path, recursive: Boolean = false, force: Boolean = true,
100 | copySourceDirectory: Boolean = true
101 | ): Unit =
102 | cp(source, dest.path, recursive, force, copySourceDirectory)
103 |
104 | /**
105 | * Move files.
106 | */
107 | public suspend fun mv(source: String, dest: Path, force: Boolean = true): Unit = mv(source, dest.path, force)
108 |
109 | /**
110 | * Remove files recursively (`rm -rf`).
111 | */
112 | public suspend fun rmRF(inputPath: Path): Unit = rmRF(inputPath.path)
113 |
114 | /**
115 | * Create a directory and any parents that don't exist.
116 | */
117 | public suspend fun mkdirP(path: Path): Unit = mkdirP(path.path)
118 |
119 | /**
120 | * Get the location of a tool, or `null` if it can't be found.
121 | */
122 | public suspend fun which(tool: Path): Path? = which(tool.path)?.let { Path(it) }
123 | }
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action-plugin/src/main/kotlin/com/rnett/action/AutoBuildWorkflow.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action
2 |
3 | import org.gradle.api.Project
4 | import org.gradle.api.Task
5 | import java.io.File
6 |
7 | /**
8 | * Create a task that calls [generateAutoBuildWorkflow].
9 | *
10 | * @param add the arguments to `git add`. `dist` by default.
11 | * @param message the commit message.
12 | * @param javaVersion the java version to use in the workflow (necessary for gradle).
13 | * @param gradleTasks the gradle command line. Called like `./gradlew $gradleTasks`.
14 | * @param runner the github actions runner to use.
15 | * @param dir the directory to create `.github/workflows/auto_build_action.yml` in. `rootDir` by default.
16 | */
17 | fun Project.autoBuildWorkflowTask(
18 | add: String = "dist",
19 | message: String = "Commit new $add",
20 | gradleTasks: String = "build",
21 | javaVersion: String = "15",
22 | runner: String = "ubuntu-latest",
23 | dir: File = rootDir,
24 | configure: Task.() -> Unit = {}
25 | ) = tasks.register("generateAutoBuildWorkflow") {
26 | doLast {
27 | generateAutoBuildWorkflow(dir, add, message, gradleTasks, javaVersion, runner)
28 | }
29 | configure()
30 | }
31 |
32 | /**
33 | * Generate sa GitHub action workflow to build (with `gradlew assemble`) and commit `dist/` on each push, if the updates one wasn't build locally.
34 | *
35 | * Generates the workflow file in `$rootDir/.github/workflows/` by default.
36 | *
37 | * @param add the arguments to `git add`. `dist` by default.
38 | * @param message the commit message.
39 | * @param javaVersion the java version to use in the workflow (necessary for gradle).
40 | * @param gradleTasks the gradle command line. Called like `./gradlew $gradleTasks`.
41 | * @param runner the github actions runner to use.
42 | * @param dir the directory to create `.github/workflows/auto_build_action.yml` in. `rootDir` by default.
43 | */
44 | fun Project.generateAutoBuildWorkflow(
45 | add: String = "dist",
46 | message: String = "Commit new $add",
47 | gradleTasks: String = "build",
48 | javaVersion: String = "15",
49 | runner: String = "ubuntu-latest",
50 | dir: File = rootDir
51 | ) {
52 | generateAutoBuildWorkflow(dir, add, message, gradleTasks, javaVersion, runner)
53 | }
54 |
55 | /**
56 | * Generate a GitHub action workflow to build (with `gradlew assemble`) and commit `dist/` on each push, if the updates one wasn't build locally.
57 | *
58 | * @param dir the directory to create `.github/workflows/auto_build_action.yml` in.
59 | * @param add the arguments to `git add`. `dist` by default.
60 | * @param message the commit message.
61 | * @param javaVersion the java version to use in the workflow (necessary for gradle).
62 | * @param gradleTasks the gradle command line. Called like `./gradlew $gradleTasks`.
63 | * @param runner the github actions runner to use.
64 | */
65 | fun generateAutoBuildWorkflow(
66 | dir: File,
67 | add: String = "dist",
68 | message: String = "Commit new $add",
69 | gradleTasks: String = "build",
70 | javaVersion: String = "15",
71 | runner: String = "ubuntu-latest"
72 | ) {
73 | val file = File("$dir/.github/workflows/auto_build_action.yml")
74 | file.parentFile.apply {
75 | if (!exists())
76 | mkdirs()
77 | }
78 |
79 | file.writeText(
80 | // language=yml
81 | """
82 | name: Auto-update dist
83 |
84 | on:
85 | push:
86 | branches: [ main, master ]
87 | pull_request:
88 | branches: [ main, master ]
89 |
90 | jobs:
91 | build:
92 | name: Update dist
93 | runs-on: $runner
94 |
95 | steps:
96 | - uses: actions/checkout@v2
97 |
98 | - name: Set up JDK
99 | uses: actions/setup-java@v1
100 | with:
101 | java-version: $javaVersion
102 |
103 | - name: Grant execute permission for gradlew
104 | run: chmod +x gradlew
105 |
106 | - name: Build
107 | run: ./gradlew $gradleTasks
108 |
109 | - name: Commit dist
110 | uses: EndBug/add-and-commit@v7
111 | with:
112 | add: '$add'
113 | message: '$message'
114 | """.trimIndent()
115 | )
116 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | PRs are welcome! Issues are also welcome.
4 |
5 | If you're making an issue, linking to your action and a failing run will vastly speed up support.
6 |
7 | I'll make a decent effort to keep things up to date, but it's not a priority for me.
8 |
9 | ## Contributing tips
10 |
11 | ### IDE experience
12 |
13 | The IDE experience is not great at the moment.
14 | IntelliJ and Kotlin's support of Gradle composite builds is somewhat lacking, which results in the configuration import for both
15 | `kotlin-js-action` and `test-action` running at the same time and conflicting.
16 | To avoid this, import them one at a time from the Gradle tool window.
17 |
18 | Source set settings (`explicitApi` mode, module-wide `@OptIn`s) sometimes aren't picked up.
19 | The Gradle tasks are your source of truth, not necessary the IDE.
20 |
21 | ### Testing
22 |
23 | While it never hurts to test locally, the GitHub actions CI that runs for each pull request is good enough to rely on.
24 | The e2e tests are only possible there.
25 | If you need permissions to run it, feel free to @ me.
26 |
27 | If you want to run the tests locally, run `test` in `kotlin-js-action` (make sure it's in `kotlin-js-action`, IntelliJ's Gradle command runner
28 | will often use `test-action`, which will run no tests).
29 |
30 | ### Project structure
31 |
32 | ```
33 | kotlin-js-action/ A parent for the library elements. A Gradle root project.
34 | kotlin-js-action/ The core JS library.
35 | serialization/ Extensions for kotlin-js-action that use Kotlinx.serialization.
36 | kotlin-js-action-plugin/ A Gradle plugin to make configuring your Kotlin/JS build to produce a GitHub action executable easy.
37 |
38 | test-action/ A GitHub action that uses this library, for e2e testing. A Gradle root project.
39 | ```
40 |
41 | `test-action` consumes `kotlin-js-action` (the parent) as an included build.
42 |
43 | The core of this library is `kotlin-js-action`.
44 | It is primarily wrappers around GitHub's `@actions/toolkit` JS packages.
45 |
46 | There are also some utilities for working with NodeJS types using idiomatic Kotlin (focused around `Path`s and streams for now).
47 | Additional utilities are always welcome, and a good way to get started.
48 |
49 | ### Updating `@actions/toolkit` libraries
50 |
51 | The process for updating `@actions/toolkit` is surprisingly painless, mostly because they are fairly stable.
52 |
53 | 1. In `./kotlin-js-action`, run `./gradlew help`. You will see output like:
54 |
55 | ```
56 | Using old version of npm library @actions/core: Using 1.6.0, but latest was 1.10.0
57 | Using old version of npm library @actions/exec: Using 1.1.0, but latest was 1.1.1
58 | Using old version of npm library @actions/glob: Using 0.2.0, but latest was 0.3.0
59 | Using old version of npm library @actions/io: Using 1.1.1, but latest was 1.1.2
60 | Using old version of npm library @actions/tool-cache: Using 1.7.1, but latest was 2.0.1
61 | Using old version of npm library @actions/github: Using 5.0.0, but latest was 5.1.1
62 | Using old version of npm library @actions/artifact: Using 0.6.1, but latest was 1.1.0
63 | Using old version of npm library @actions/cache: Using 1.0.8, but latest was 3.0.6
64 | Using old version of npm library @actions/http-client: Using 1.0.11, but latest was 2.0.1
65 | ```
66 |
67 | 2. Go to the [`@actions/toolkit`](https://github.com/actions/toolkit) page for each of the out of date library.
68 | Check the changelog (the `RELEASES.md` for each library, some are in reverse order).
69 | 3. For each library that looks like it has breaking changes, update the version in `kotlin-js-action/kotlin-js-action/build.gradle.kts`,
70 | comment out the `implementation(latestNpm("@actions/tool-cache", "1.7.1", false))` line with the `//TODO breaks dukat` comment, and run
71 | `generateExternals` (in `kotlin-js-action`).
72 | 4. This will generate a bunch of external JS definitions in `kotlin-js-action/kotlin-js-action/externals`.
73 | Look for any with your newly updated library's name in the filename.
74 | Either add them to the appropriate package in `kotlin-js-action/kotlin-js-action/src/main/kotlin/internal` (if they are new)
75 | or diff them with the existing definitions and update as necessary.
76 | You will need to add `internal` to all of the `external` definitions.
77 | 5. Then update the nice wrapper definitions in `com.rnett.action`.
78 |
--------------------------------------------------------------------------------
/kotlin-js-action/kotlin-js-action/src/main/kotlin/com/rnett/action/core/logger.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.core
2 |
3 | import kotlin.contracts.InvocationKind
4 | import kotlin.contracts.contract
5 |
6 |
7 | /**
8 | * Methods to log to the GitHub action log.
9 | *
10 | * Coloring output is supported via [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code).
11 | * 3/4 bit, 8 bit and 24 bit colors are all supported.
12 | *
13 | * See [https://github.com/actions/toolkit/tree/main/packages/core#styling-output](https://github.com/actions/toolkit/tree/main/packages/core#styling-output)
14 | */
15 | public object logger {
16 |
17 | /**
18 | * Get whether the action is running in debug mode.
19 | */
20 | public val isDebug: Boolean get() = core.isDebug
21 |
22 | /**
23 | * Setter to set whether commands are echoed to the log.
24 | *
25 | * Getter always returns `null`.
26 | */
27 | public var echoCommands: Boolean? by core::echoCommands
28 |
29 | /**
30 | * Log a debug message.
31 | */
32 | public fun debug(message: String): Unit = core.debug(message)
33 |
34 | /**
35 | * Log an info message.
36 | */
37 | public fun info(message: String): Unit = core.info(message)
38 |
39 | /**
40 | * Log a notice message.
41 | */
42 | public fun notice(message: String): Unit = core.notice(message)
43 |
44 | /**
45 | * Log [exception] as a notice message.
46 | */
47 | public fun notice(exception: Throwable): Unit = core.notice(exception)
48 |
49 | /**
50 | * Log a notice message.
51 | */
52 | public fun notice(message: String, annotationProperties: AnnotationProperties): Unit =
53 | core.notice(message, annotationProperties)
54 |
55 | /**
56 | * Log [exception] as a notice message.
57 | */
58 | public fun notice(exception: Throwable, annotationProperties: AnnotationProperties): Unit =
59 | core.notice(exception, annotationProperties)
60 |
61 | /**
62 | * Log a warning message.
63 | */
64 | public fun warning(message: String): Unit = core.warning(message)
65 |
66 | /**
67 | * Log [exception] as a warning message.
68 | */
69 | public fun warning(exception: Throwable): Unit = core.warning(exception)
70 |
71 | /**
72 | * Log a warning message.
73 | */
74 | public fun warning(message: String, annotationProperties: AnnotationProperties): Unit =
75 | core.warning(message, annotationProperties)
76 |
77 | /**
78 | * Log [exception] as a warning message.
79 | */
80 | public fun warning(exception: Throwable, annotationProperties: AnnotationProperties): Unit =
81 | core.warning(exception, annotationProperties)
82 |
83 | /**
84 | * Log an error message.
85 | */
86 | public fun error(message: String): Unit = core.error(message)
87 |
88 | /**
89 | * Log [exception] as an error message.
90 | */
91 | public fun error(exception: Throwable): Unit = core.error(exception)
92 |
93 | /**
94 | * Log an error message.
95 | */
96 | public fun error(message: String, annotationProperties: AnnotationProperties): Unit =
97 | core.error(message, annotationProperties)
98 |
99 | /**
100 | * Log [exception] as an error message.
101 | */
102 | public fun error(exception: Throwable, annotationProperties: AnnotationProperties): Unit =
103 | core.error(exception, annotationProperties)
104 |
105 | /**
106 | * Log a fatal message. This logs the message as an error and then sets failure.
107 | *
108 | * Does not exit the process, for that use [fail].
109 | */
110 | public fun fatal(message: String): Unit = core.setFailed(message)
111 |
112 |
113 | /**
114 | * Log [exception] as a fatal message. This logs the message as an error and then sets failure.
115 | *
116 | * Does not exit the process, for that use [fail].
117 | */
118 | public fun fatal(exception: Throwable): Unit = core.setFailed(exception)
119 |
120 | /**
121 | * Executes [block] within a fordable output group of [name].
122 | */
123 | public inline fun withGroup(name: String, block: () -> R): R {
124 | contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
125 | return core.withGroup(name, block)
126 | }
127 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## Next
4 |
5 | ### Breaking
6 |
7 | ### Non-breaking
8 |
9 | ## 1.6.0
10 |
11 | ### Breaking
12 |
13 | * Update to Node 16.18.0
14 | * Switch from the obsolete `kotlinx-nodejs`
15 | to [`kotlin-wrappers/node`](https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-node/README.md).
16 | **This is a massively breaking change!**.
17 | * Numerous APIs have changed as a result of this, and many NodeJS types have changed.
18 | * This includes `Path`, which has changed significantly. There are no more non-`suspend` methods, and many properties became `suspend` methods.
19 | * It also gets rid of the `jcenter()` requirement :tada:
20 | * Update Kotlin to 1.7.21
21 | * Update Kotlinx.serialization to 1.4.1
22 | * Update Kotlinx.coroutines to 1.6.4
23 | * Update `@actions/http-client` to `2.0.1`
24 |
25 | ### Non-breaking
26 |
27 | Note: Many of these supposedly non-breaking updates have had breaking changes in the same areas, due to the NodeJS wrapper change.
28 |
29 | * Update `@actions/core` to `1.10.0`. This adds summary creation, accessible via the `summary` object.
30 | * Update `@actions/exec` to `1.1.1`.
31 | * Update `@actions/glob` to `0.3.0`.
32 | * Update `@actions/io` to `1.1.2`.
33 | * Update `@actions/tool-cache` to `2.0.1`.
34 | * Update `@actions/github` to `5.1.1`.
35 | * Update `@actions/artifact` to `1.1.0`.
36 | * Update `@actions/cache` to `3.0.6`.
37 | * Update `@actions/http-client` to `2.0.1`.
38 |
39 | ## 1.5.0
40 |
41 | ### Breaking
42 |
43 | * Update Kotlin to 1.6.10
44 | * Update Kotlinx coroutines to 1.6.0
45 | * Update Kotlinx serialization to 1.3.2
46 |
47 | ### Non-breaking
48 |
49 | * Update `@actions/artifact` to 0.6.1
50 |
51 | ## 1.4.3
52 |
53 | ### Non-breaking
54 |
55 | * Update `@actions/core` to 1.5.0.
56 | * Add `notice` logging methods.
57 | * Add `AnnotationProperties` and annotation producing overloads for `notice`, `warning`, and `error`.
58 |
59 | ## 1.4.2
60 |
61 | ### Non-breaking
62 |
63 | * Update Kotlin to 1.5.30.
64 |
65 | ## 1.4.1
66 |
67 | ### Non-breaking
68 |
69 | * Update serialization to `1.2.2` and coroutines to `1.5.1`.
70 | * Add wrappers for `@actions/tool-cache`
71 | * Add `Path.deleteRecursively()`.
72 | * Add `PATH += Path`.
73 |
74 | ## 1.4.0
75 |
76 | ### Slightly breaking
77 |
78 | * Restructure HttpClient types. Some classes were replaced by interfaces or typealiases, but breakage should be pretty
79 | small unless you used the Json client or the legacy json request methods.
80 | * Make the auto-build workflow use the `build` task, by default.
81 |
82 | ### Non-breaking
83 |
84 | * Add a plugin method to add a task to generate the auto-build workflow.
85 | * Builtin withDefault delegate methods
86 |
87 | ## 1.3.0
88 |
89 | Many breaking changes, mostly around `env`, `Path`, `inputs`, and `state`. The whole library has been cleaned up and
90 | tested.
91 |
92 | ### Breaking
93 |
94 | * **Made `execCapture` methods error on a command error return by default**.
95 | * Cache client is properly marked as experimental
96 | * `core.getInput` is removed in favor of explicit `getRequiredInput` or `getOptionalInput`.
97 | * `inputs`, `env`/`exportEnv`, and `state` had their delegation reworked. Should be compatible for basic use cases
98 | except `env`, where the delegates became optional by default.
99 | * Lots of type conversion methods were added for the reworked delegates
100 | * `log` was renamed to `logger`.
101 | * Updated underlying `exec` bindings, used new capture method.
102 | * Fixed `execShell` shell escaping.
103 | * Removed `hashFiles` from `github.context`, added a wrapper for the underlying method to the `glob` package.
104 | * Updated the underlying `glob` package, added `matchDirectories` option and `hashFiles`.
105 | * Removed `currentOS` and `lineSeperator` in favor of `OperatingSystem.current`/`.lineSeperator`, added and moved other
106 | properties to `OperatingSystem` companion.
107 | * Made `Path.cwd` settable (it calls `cd`).
108 | * Make `Path` read, write, and append methods `suspend` by default, added non-suspending versions.
109 | * Move `Path.seperator` to `OperatingSystem.pathSeperator`.
110 | * Reworked the `Path.copy` and `Path.move` methods, seperate out `*Into` and `*ChildrenInto`.
111 | * Replace `Path.read` with `Path.readText`, add `Path.readBytes`.
112 |
113 | ### Non-breaking
114 |
115 | * Add stream utils
116 | * Add Buffer <-> ByteArray conversions
117 | * Add tests
118 | * Added wrappers for `@actions/http-client`. Used via `HttpClient` or `JsonHttpClient` in the `serialization` artifact.
119 | * Add serialization artifact for Kotlinx serialization support
120 | * Added `runAction`, like `runOrFail` but returns `Unit`.
121 | * Add `Buffer` and `ByteArray` `Path` write methods.
122 |
--------------------------------------------------------------------------------
/kotlin-js-action/serialization/src/main/kotlin/com/rnett/action/serialization/HttpClient.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.serialization
2 |
3 | import com.rnett.action.httpclient.BaseHttpClient
4 | import com.rnett.action.httpclient.HeaderProvider
5 | import com.rnett.action.httpclient.HttpClient
6 | import com.rnett.action.httpclient.HttpClientBuilder
7 | import com.rnett.action.httpclient.HttpResponse
8 | import kotlinx.coroutines.coroutineScope
9 | import kotlinx.coroutines.flow.Flow
10 | import kotlinx.coroutines.flow.map
11 | import kotlinx.serialization.decodeFromString
12 | import kotlinx.serialization.encodeToString
13 | import kotlinx.serialization.json.Json
14 | import node.ReadableStream
15 | import kotlin.contracts.InvocationKind
16 | import kotlin.contracts.contract
17 |
18 | /**
19 | * A HTTP response that you can get JSON deserialized responses from.
20 | */
21 | public class JsonHttpResponse(response: HttpResponse, @PublishedApi internal val json: Json) :
22 | HttpResponse by response {
23 | public suspend inline fun readJsonBody(): T = json.decodeFromString(readBody())
24 | }
25 |
26 | /**
27 | * Get a Http client with json support wrapping this client.
28 | *
29 | * Closing the returned client will not close the wrapped client.
30 | */
31 | public fun HttpClient.json(json: Json = Json): JsonHttpClient = if (this is JsonHttpClient && this.json == json)
32 | this
33 | else
34 | JsonHttpClient(json, this, false)
35 |
36 | /**
37 | * A [`@actions/http-client`](https://github.com/actions/http-client) based Http client that uses
38 | * kotlinx serialization Json parsing and adds `Accept` (always) and `Content-Type` (*Json methods) headers.
39 | */
40 | public inline fun JsonHttpClient(json: Json = Json, builder: HttpClientBuilder.() -> Unit = {}): JsonHttpClient {
41 | contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) }
42 | return JsonHttpClient(
43 | json,
44 | HttpClient {
45 | builder()
46 | addHeader("accept", "application/json")
47 | }
48 | )
49 | }
50 |
51 | /**
52 | * A [`@actions/http-client`](https://github.com/actions/http-client) based Http client that uses
53 | * kotlinx serialization Json parsing and adds `Accept` (always) and `Content-Type` (*Json methods) headers.
54 | */
55 | public class JsonHttpClient @PublishedApi internal constructor(
56 | @PublishedApi internal val json: Json,
57 | private val client: HttpClient,
58 | private val closeClient: Boolean = true
59 | ) :
60 | BaseHttpClient {
61 |
62 | override suspend fun request(verb: String, url: String, data: String, headers: HeaderProvider): JsonHttpResponse =
63 | JsonHttpResponse(client.request(verb, url, data, headers), json)
64 |
65 | override suspend fun request(
66 | verb: String,
67 | url: String,
68 | data: ReadableStream,
69 | headers: HeaderProvider
70 | ): JsonHttpResponse = JsonHttpResponse(client.request(verb, url, data, headers), json)
71 |
72 | public suspend inline fun postJson(
73 | url: String,
74 | data: T,
75 | headers: HeaderProvider = HeaderProvider { }
76 | ): JsonHttpResponse =
77 | requestJson("post", url, data, headers = headers)
78 |
79 | public suspend inline fun postJson(
80 | url: String,
81 | data: Flow,
82 | headers: HeaderProvider = HeaderProvider { }
83 | ): JsonHttpResponse =
84 | requestJson("post", url, data, headers = headers)
85 |
86 | public suspend inline fun putJson(
87 | url: String,
88 | data: T,
89 | headers: HeaderProvider = HeaderProvider { }
90 | ): JsonHttpResponse =
91 | requestJson("put", url, data, headers = headers)
92 |
93 | public suspend inline fun putJson(
94 | url: String,
95 | data: Flow,
96 | headers: HeaderProvider = HeaderProvider { }
97 | ): JsonHttpResponse =
98 | requestJson("put", url, data, headers = headers)
99 |
100 | public suspend inline fun patchJson(
101 | url: String,
102 | data: T,
103 | headers: HeaderProvider = HeaderProvider { }
104 | ): JsonHttpResponse =
105 | requestJson("patch", url, data, headers = headers)
106 |
107 | public suspend inline fun patchJson(
108 | url: String,
109 | data: Flow,
110 | headers: HeaderProvider = HeaderProvider { }
111 | ): JsonHttpResponse =
112 | requestJson("patch", url, data, headers = headers)
113 |
114 | public suspend inline fun requestJson(
115 | verb: String,
116 | url: String,
117 | data: T,
118 | headers: HeaderProvider = HeaderProvider {}
119 | ): JsonHttpResponse {
120 | val response =
121 | request(verb, url, json.encodeToString(data), headers + { add("content-type", "application/json") })
122 | return JsonHttpResponse(response, json)
123 | }
124 |
125 | public suspend inline fun requestJson(
126 | verb: String,
127 | url: String,
128 | data: Flow,
129 | headers: HeaderProvider = HeaderProvider {}
130 | ): JsonHttpResponse = coroutineScope {
131 | val response = request(
132 | verb,
133 | url,
134 | data.map { json.encodeToString(it) },
135 | headers + { add("content-type", "application/json") })
136 | JsonHttpResponse(response, json)
137 | }
138 |
139 | override fun close() {
140 | if (closeClient)
141 | client.close()
142 | }
143 | }
--------------------------------------------------------------------------------
/kotlin-js-action/serialization/src/main/kotlin/com/rnett/action/serialization/ReadOnlyDelegates.kt:
--------------------------------------------------------------------------------
1 | package com.rnett.action.serialization
2 |
3 | import com.rnett.action.delegates.map
4 | import com.rnett.action.delegates.mapNonNull
5 | import kotlinx.serialization.BinaryFormat
6 | import kotlinx.serialization.DeserializationStrategy
7 | import kotlinx.serialization.ExperimentalSerializationApi
8 | import kotlinx.serialization.SerializationStrategy
9 | import kotlinx.serialization.StringFormat
10 | import kotlinx.serialization.decodeFromByteArray
11 | import kotlinx.serialization.decodeFromString
12 | import kotlinx.serialization.encodeToByteArray
13 | import kotlinx.serialization.encodeToString
14 | import kotlin.properties.ReadOnlyProperty
15 |
16 | /**
17 | * Deserialize the read string.
18 | */
19 | @ExperimentalSerializationApi
20 | public fun ReadOnlyProperty.deserialize(
21 | format: StringFormat,
22 | serializer: DeserializationStrategy
23 | ): ReadOnlyProperty = map { format.decodeFromString(serializer, it) }
24 |
25 | /**
26 | * Deserialize the read string if it is non-null.
27 | */
28 | @ExperimentalSerializationApi
29 | public fun ReadOnlyProperty.deserializeNotNull(
30 | format: StringFormat,
31 | serializer: DeserializationStrategy
32 | ): ReadOnlyProperty = mapNonNull { format.decodeFromString(serializer, it) }
33 |
34 | /**
35 | * Serialize the read value.
36 | */
37 | @ExperimentalSerializationApi
38 | public fun ReadOnlyProperty.serialize(
39 | format: StringFormat,
40 | serializer: SerializationStrategy
41 | ): ReadOnlyProperty = map { format.encodeToString(serializer, it) }
42 |
43 | /**
44 | * Serialize the read value, if it is non-null.
45 | */
46 | @ExperimentalSerializationApi
47 | public fun ReadOnlyProperty.serializeNonNull(
48 | format: StringFormat,
49 | serializer: SerializationStrategy
50 | ): ReadOnlyProperty = mapNonNull { format.encodeToString(serializer, it) }
51 |
52 | /**
53 | * Deserialize the read string.
54 | */
55 | @ExperimentalSerializationApi
56 | public fun ReadOnlyProperty.deserialize(
57 | format: BinaryFormat,
58 | serializer: DeserializationStrategy
59 | ): ReadOnlyProperty = map { format.decodeFromByteArray(serializer, it) }
60 |
61 | /**
62 | * Deserialize the read string if it is non-null.
63 | */
64 | @ExperimentalSerializationApi
65 | public fun ReadOnlyProperty.deserializeNotNull(
66 | format: BinaryFormat,
67 | serializer: DeserializationStrategy
68 | ): ReadOnlyProperty = mapNonNull { format.decodeFromByteArray(serializer, it) }
69 |
70 | /**
71 | * Serialize the read value.
72 | */
73 | @ExperimentalSerializationApi
74 | public fun ReadOnlyProperty.serialize(
75 | format: BinaryFormat,
76 | serializer: SerializationStrategy
77 | ): ReadOnlyProperty = map { format.encodeToByteArray(serializer, it) }
78 |
79 | /**
80 | * Serialize the read value, if it is non-null.
81 | */
82 | @ExperimentalSerializationApi
83 | public fun ReadOnlyProperty.serializeNonNull(
84 | format: BinaryFormat,
85 | serializer: SerializationStrategy
86 | ): ReadOnlyProperty = mapNonNull { format.encodeToByteArray(serializer, it) }
87 |
88 | /**
89 | * Deserialize the read string.
90 | */
91 | @ExperimentalSerializationApi
92 | public inline fun ReadOnlyProperty.deserialize(
93 | format: StringFormat
94 | ): ReadOnlyProperty = map { format.decodeFromString(it) }
95 |
96 | /**
97 | * Deserialize the read string if it is non-null.
98 | */
99 | @ExperimentalSerializationApi
100 | public inline fun ReadOnlyProperty.deserializeNotNull(
101 | format: StringFormat
102 | ): ReadOnlyProperty = mapNonNull { format.decodeFromString(it) }
103 |
104 | /**
105 | * Serialize the read value.
106 | */
107 | @ExperimentalSerializationApi
108 | public inline fun ReadOnlyProperty.serialize(
109 | format: StringFormat
110 | ): ReadOnlyProperty = map { format.encodeToString(it) }
111 |
112 | /**
113 | * Serialize the read value, if it is non-null.
114 | */
115 | @ExperimentalSerializationApi
116 | public inline fun ReadOnlyProperty.serializeNonNull(
117 | format: StringFormat
118 | ): ReadOnlyProperty = mapNonNull { format.encodeToString(it) }
119 |
120 | /**
121 | * Deserialize the read string.
122 | */
123 | @ExperimentalSerializationApi
124 | public inline fun ReadOnlyProperty.deserialize(
125 | format: BinaryFormat
126 | ): ReadOnlyProperty = map { format.decodeFromByteArray(it) }
127 |
128 | /**
129 | * Deserialize the read string if it is non-null.
130 | */
131 | @ExperimentalSerializationApi
132 | public inline fun ReadOnlyProperty.deserializeNotNull(
133 | format: BinaryFormat
134 | ): ReadOnlyProperty = mapNonNull { format.decodeFromByteArray(it) }
135 |
136 | /**
137 | * Serialize the read value.
138 | */
139 | @ExperimentalSerializationApi
140 | public inline fun ReadOnlyProperty.serialize(
141 | format: BinaryFormat
142 | ): ReadOnlyProperty |