Sample Actions¶
Real-world examples from the sample/ module demonstrating common workflow patterns.
PrintHelloWorldGithubAction¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/PrintHelloWorldGithubAction.kt
Key: print_helloworld
Context: IssueContext
A minimal example that prints environment variables and context data.
class PrintHelloWorldGithubAction : GithubAction<IssueContext> {
override fun run(context: IssueContext, environment: GithubEnvironment): ActionResult {
println(environment.require("CUSTOM_PARAM"))
println(environment.toMap())
println(context.sender.login)
return ActionResult.Success()
}
}
ValidateCommitsAction¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/ValidateCommitsAction.kt
Key: validate_commits
Context: PushContext
Validates that all commits follow the conventional commit format.
class ValidateCommitsAction : GithubAction<PushContext> {
private val conventionalCommitPattern =
Regex("^(feat|fix|docs|style|refactor|test|chore)(\\(.+\\))?: .+")
override fun run(context: PushContext, environment: GithubEnvironment): ActionResult {
val invalidCommits = context.commits.filter { commit ->
!conventionalCommitPattern.matches(commit.message.lines().first())
}
return if (invalidCommits.isEmpty()) {
ActionResult.Success(mapOf(
"MESSAGE" to "All commits follow conventional commit format",
"TIME" to Instant.now().toString()
))
} else {
ActionResult.Failure("Invalid commit messages found")
}
}
}
Pattern: Iterates over context.commits, validates each message against a regex, returns success with outputs or failure.
AutoLabelIssueAction¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/AutoLabelIssueAction.kt
Key: auto_label
Context: IssueContext
Automatically labels issues based on their title and body content.
class AutoLabelIssueAction : GithubAction<IssueContext> {
override fun run(context: IssueContext, environment: GithubEnvironment): ActionResult {
if (context.action !in listOf("opened", "edited")) {
return ActionResult.Success()
}
val combinedText = "${context.issue.title.lowercase()} ${context.issue.body?.lowercase() ?: ""}"
val labelsToAdd = mutableSetOf<String>()
when {
combinedText.contains("bug") || combinedText.contains("error") -> labelsToAdd.add("bug")
combinedText.contains("feature") || combinedText.contains("enhancement") -> labelsToAdd.add("enhancement")
combinedText.contains("documentation") || combinedText.contains("docs") -> labelsToAdd.add("documentation")
combinedText.contains("question") || combinedText.contains("how to") -> labelsToAdd.add("question")
}
if (combinedText.contains("urgent") || combinedText.contains("critical")) {
labelsToAdd.add("priority: high")
}
// Post labels via GitHub API using OkHttp
// ...
return ActionResult.Success()
}
}
Pattern: Filters by action type, analyzes text content, makes HTTP calls to the GitHub API.
CodeQualityCheckAction¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/CodeQualityCheckAction.kt
Key: code_quality
Context: PullRequestContext
Runs quality checks on pull requests and posts results as a comment.
class CodeQualityCheckAction : GithubAction<PullRequestContext> {
override fun run(context: PullRequestContext, environment: GithubEnvironment): ActionResult {
if (context.action !in listOf("opened", "synchronize", "reopened")) {
return ActionResult.Success()
}
val pr = context.pullRequest
val results = runQualityChecks(pr)
// Post check results as GitHub PR comment
val githubToken = environment["GITHUB_TOKEN"]
if (githubToken != null) {
postCheckResults(environment.repository!!, pr.number, results, githubToken)
}
return if (results.allPassed) {
ActionResult.Success()
} else {
ActionResult.Failure("Some quality checks failed")
}
}
}
Pattern: Runs simulated checks (lint, tests, coverage), formats a Markdown report, posts via GitHub API.
RunTestsAndNotifyWithEmail¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/RunTestsAndNotifyWithEmail.kt
Key: run_tests
Context: WorkflowDispatchContext
Runs the test suite and sends an HTML email with detailed results.
class RunTestsAndNotifyWithEmail : GithubAction<WorkflowDispatchContext> {
override fun run(
context: WorkflowDispatchContext,
environment: GithubEnvironment
): ActionResult {
val testResult = runTests(environment)
val html = buildEmailHtml(context, environment, testResult)
sendEmail(
apiUrl = environment.require("EMAIL_API_URL"),
apiKey = environment.require("EMAIL_API_KEY"),
to = environment.require("NOTIFY_EMAIL"),
subject = if (testResult.success) "Tests Passed" else "Tests Failed",
html = html
)
return if (testResult.success) {
ActionResult.Success()
} else {
ActionResult.Failure("Tests failed. Notification sent.")
}
}
}
Pattern: Executes a subprocess (./gradlew test), parses XML test reports, builds HTML email, sends via HTTP.
NotifyOnReleaseAction¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/NotifyOnReleaseAction.kt
Key: notify_release
Context: ReleaseContext
Sends an HTML email notification when a release is published.
class NotifyOnReleaseAction : GithubAction<ReleaseContext> {
override fun run(context: ReleaseContext, environment: GithubEnvironment): ActionResult {
val subject = "New release published: ${context.release.tagName}"
val html = buildEmailHtml(context)
sendEmail(
apiUrl = environment.require("EMAIL_API_URL"),
apiKey = environment.require("EMAIL_API_KEY"),
to = environment.require("NOTIFY_EMAIL"),
subject = subject,
html = html
)
return ActionResult.Success()
}
}
Pattern: Accesses release data (tagName, body, assets), builds HTML email, sends via HTTP.
NotifyOnCreateAction¶
Source: sample/src/main/kotlin/ir/amirroid/workflowkt/samples/NotifyOnCreateAction.kt
Key: notify_create
Context: CreateContext
Sends an email notification when a branch or tag is created.
class NotifyOnCreateAction : GithubAction<CreateContext> {
override fun run(context: CreateContext, environment: GithubEnvironment): ActionResult {
val subject = "New ${context.refType.name.lowercase()} created"
val html = buildEmailHtml(context)
sendEmail(
apiUrl = environment.get("EMAIL_API_URL") ?: return ActionResult.Failure("..."),
apiKey = environment.get("EMAIL_API_KEY") ?: return ActionResult.Failure("..."),
to = environment.get("NOTIFY_EMAIL") ?: return ActionResult.Failure("..."),
subject = subject,
html = html
)
return ActionResult.Success()
}
}
Pattern: Reads refType (BRANCH/TAG), builds contextual email, sends via HTTP.
Common Patterns¶
Filtering by Action Type¶
Most actions check the action property to only run on specific sub-events:
if (context.action !in listOf("opened", "synchronize", "reopened")) {
return ActionResult.Success()
}
Accessing Environment Variables¶
// Optional access (returns null if not set)
val token = environment["GITHUB_TOKEN"]
// Required access (throws if not set)
val token = environment.require("GITHUB_TOKEN")
// With default value
val retries = environment.getInt("MAX_RETRIES", default = 3)
HTTP Calls with OkHttp¶
Several sample actions use OkHttp for API calls:
private val client = OkHttpClient()
private val json = "application/json; charset=utf-8".toMediaTypeOrNull()
val body = """{"body": "$comment"}""".toRequestBody(json)
val request = Request.Builder()
.url("https://api.github.com/repos/$repo/issues/$number/comments")
.addHeader("Authorization", "Bearer $token")
.addHeader("Accept", "application/vnd.github+json")
.post(body)
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw Exception("GitHub API error: ${response.code}")
}
}