Skip to content

Commit

Permalink
Merge pull request #51 from Kortvk/add-click-up-integration
Browse files Browse the repository at this point in the history
Add task to automate ClickUp workflows
  • Loading branch information
rinekri authored May 23, 2024
2 parents 97c674a + 48d96cf commit ecc622e
Show file tree
Hide file tree
Showing 11 changed files with 396 additions and 1 deletion.
8 changes: 8 additions & 0 deletions example/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ buildPublish {
fixVersionPattern.set("fix_%2\$s_%1\$s")
}
}
clickUp {
register("default") {
apiTokenFile = File("clickup-token.txt")
fixVersionPattern = "fix_%2\$s_%1\$s"
fixVersionFieldId = "01234567qwerty"
tagName = "test_tag_name"
}
}
telegram {
register("default") {
botId.set("0000")
Expand Down
2 changes: 1 addition & 1 deletion plugin-build/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {

allprojects {
group = "ru.kode.android"
version = "1.3.0-alpha04"
version = "1.3.0-alpha05"
}

val dependsOnRecursivelyByName = { task: Task, name: String ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import ru.kode.android.build.publish.plugin.extension.BuildPublishExtension
import ru.kode.android.build.publish.plugin.extension.EXTENSION_NAME
import ru.kode.android.build.publish.plugin.extension.config.AppCenterDistributionConfig
import ru.kode.android.build.publish.plugin.extension.config.ChangelogConfig
import ru.kode.android.build.publish.plugin.extension.config.ClickUpConfig
import ru.kode.android.build.publish.plugin.extension.config.FirebaseAppDistributionConfig
import ru.kode.android.build.publish.plugin.extension.config.JiraConfig
import ru.kode.android.build.publish.plugin.extension.config.OutputConfig
Expand All @@ -39,6 +40,7 @@ import ru.kode.android.build.publish.plugin.extension.config.SlackConfig
import ru.kode.android.build.publish.plugin.extension.config.TelegramConfig
import ru.kode.android.build.publish.plugin.task.appcenter.AppCenterDistributionTask
import ru.kode.android.build.publish.plugin.task.changelog.GenerateChangelogTask
import ru.kode.android.build.publish.plugin.task.clickup.ClickUpAutomationTask
import ru.kode.android.build.publish.plugin.task.jira.JiraAutomationTask
import ru.kode.android.build.publish.plugin.task.play.PlayDistributionTask
import ru.kode.android.build.publish.plugin.task.slack.changelog.SendSlackChangelogTask
Expand All @@ -65,6 +67,7 @@ internal const val APP_CENTER_DISTRIBUTION_UPLOAD_TASK_PREFIX = "appCenterDistri
internal const val PLAY_DISTRIBUTION_UPLOAD_TASK_PREFIX = "playUpload"
internal const val SLACK_DISTRIBUTION_UPLOAD_TASK_PREFIX = "slackDistributionUpload"
internal const val JIRA_AUTOMATION_TASK = "jiraAutomation"
internal const val CLICK_UP_AUTOMATION_TASK = "clickUpAutomation"
internal const val DEFAULT_CONTAINER_NAME = "default"

internal object AgpVersions {
Expand Down Expand Up @@ -275,6 +278,20 @@ abstract class BuildPublishPlugin : Plugin<Project> {
tagBuildProvider,
)
}

val clickUpConfig =
with(buildPublishExtension.clickUp) {
findByName(buildVariant.name) ?: findByName(DEFAULT_CONTAINER_NAME)
}
if (clickUpConfig != null) {
tasks.registerClickUpTasks(
clickUpConfig,
buildVariant,
changelogConfig.issueNumberPattern,
changelogFile,
tagBuildProvider,
)
}
}
return OutputProviders(
versionName = versionNameProvider,
Expand Down Expand Up @@ -313,6 +330,41 @@ abstract class BuildPublishPlugin : Plugin<Project> {
}
}

private fun TaskContainer.registerClickUpTasks(
config: ClickUpConfig,
buildVariant: BuildVariant,
issueNumberPattern: Provider<String>,
changelogFileProvider: Provider<RegularFile>,
tagBuildProvider: Provider<RegularFile>,
) {
val fixVersionIsPresent =
config.fixVersionPattern.isPresent && config.fixVersionFieldId.isPresent
val hasMissingFixVersionProperties =
config.fixVersionPattern.isPresent || config.fixVersionFieldId.isPresent

if (!fixVersionIsPresent && hasMissingFixVersionProperties) {
throw GradleException(
"To use the fixVersion logic, the fixVersionPattern or fixVersionFieldId " +
"properties must be specified",
)
}

if (fixVersionIsPresent || config.tagName.isPresent) {
register(
"$CLICK_UP_AUTOMATION_TASK${buildVariant.capitalizedName()}",
ClickUpAutomationTask::class.java,
) {
it.tagBuildFile.set(tagBuildProvider)
it.changelogFile.set(changelogFileProvider)
it.issueNumberPattern.set(issueNumberPattern)
it.apiTokenFile.set(config.apiTokenFile)
it.fixVersionPattern.set(config.fixVersionPattern)
it.fixVersionFieldId.set(config.fixVersionFieldId)
it.taskTag.set(config.tagName)
}
}
}

@Suppress("LongParameterList") // TODO Get parameters inside
private fun TaskContainer.registerSlackTasks(
outputConfig: OutputConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.model.ObjectFactory
import ru.kode.android.build.publish.plugin.extension.config.AppCenterDistributionConfig
import ru.kode.android.build.publish.plugin.extension.config.ChangelogConfig
import ru.kode.android.build.publish.plugin.extension.config.ClickUpConfig
import ru.kode.android.build.publish.plugin.extension.config.FirebaseAppDistributionConfig
import ru.kode.android.build.publish.plugin.extension.config.JiraConfig
import ru.kode.android.build.publish.plugin.extension.config.OutputConfig
Expand All @@ -24,6 +25,8 @@ abstract class BuildPublishExtension
objectFactory.domainObjectContainer(ChangelogConfig::class.java)
val jira: NamedDomainObjectContainer<JiraConfig> =
objectFactory.domainObjectContainer(JiraConfig::class.java)
val clickUp: NamedDomainObjectContainer<ClickUpConfig> =
objectFactory.domainObjectContainer(ClickUpConfig::class.java)
val telegram: NamedDomainObjectContainer<TelegramConfig> =
objectFactory.domainObjectContainer(TelegramConfig::class.java)
val slack: NamedDomainObjectContainer<SlackConfig> =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ru.kode.android.build.publish.plugin.extension.config

import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional

interface ClickUpConfig {
val name: String

/**
* The path to the file containing the API token for the ClickUp
*/
@get:InputFile
val apiTokenFile: RegularFileProperty

/**
* Pattern to be used to format version to the ClickUp tasks
*/
@get:Input
@get:Optional
val fixVersionPattern: Property<String>

/**
* The id of the custom field to be used for the fix version in the ClickUp tasks
*/
@get:Input
@get:Optional
val fixVersionFieldId: Property<String>

/**
* The tag name to be used for the ClickUp tasks
*/
@get:Input
@get:Optional
val tagName: Property<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package ru.kode.android.build.publish.plugin.task.clickup

import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor
import ru.kode.android.build.publish.plugin.enity.Tag
import ru.kode.android.build.publish.plugin.enity.mapper.fromJson
import ru.kode.android.build.publish.plugin.task.clickup.work.AddFixVersionWork
import ru.kode.android.build.publish.plugin.task.clickup.work.AddTagToTaskWork
import javax.inject.Inject

abstract class ClickUpAutomationTask
@Inject
constructor(
private val workerExecutor: WorkerExecutor,
) : DefaultTask() {
init {
description = "Task to automate ClickUp statuses"
group = BasePlugin.BUILD_GROUP
}

@get:InputFile
@get:Option(option = "tagBuildFile", description = "Json contains info about tag build")
abstract val tagBuildFile: RegularFileProperty

@get:InputFile
@get:Option(option = "changelogFile", description = "File with saved changelog")
abstract val changelogFile: RegularFileProperty

@get:Input
@get:Option(
option = "issueNumberPattern",
description = "How task number formatted",
)
abstract val issueNumberPattern: Property<String>

@get:InputFile
@get:Option(
option = "apiTokenFile",
description = "API token for ClickUp",
)
abstract val apiTokenFile: RegularFileProperty

@get:Input
@get:Option(
option = "fixVersionPattern",
description = "How fix version should be formatted",
)
@get:Optional
abstract val fixVersionPattern: Property<String>

@get:Input
@get:Option(
option = "fixVersionFieldId",
description = "Field id for fix version in ClickUp",
)
@get:Optional
abstract val fixVersionFieldId: Property<String>

@get:Input
@get:Option(
option = "taskTag",
description = "What tag should be used for tasks",
)
@get:Optional
abstract val taskTag: Property<String>

@TaskAction
fun upload() {
val currentBuildTag = fromJson(tagBuildFile.asFile.get())
val changelog = changelogFile.asFile.get().readText()
val issues =
Regex(issueNumberPattern.get())
.findAll(changelog)
.mapTo(mutableSetOf()) { it.groupValues[0] }
if (issues.isEmpty()) {
logger.info("issues not found in the changelog, nothing will change")
} else {
val workQueue: WorkQueue = workerExecutor.noIsolation()
workQueue.submitUpdateVersionIfPresent(currentBuildTag, issues)
workQueue.submitSetTagIfPresent(issues)
}
}

private fun WorkQueue.submitUpdateVersionIfPresent(
currentBuildTag: Tag.Build,
issues: Set<String>,
) {
if (fixVersionPattern.isPresent && fixVersionFieldId.isPresent) {
val version =
fixVersionPattern.get()
.format(
currentBuildTag.buildVersion,
currentBuildTag.buildNumber,
currentBuildTag.buildVariant,
)
val fieldId = fixVersionFieldId.get()
submit(AddFixVersionWork::class.java) { parameters ->
parameters.apiToken.set(apiTokenFile.asFile.get().readText())
parameters.issues.set(issues)
parameters.version.set(version)
parameters.fieldId.set(fieldId)
}
}
}

private fun WorkQueue.submitSetTagIfPresent(issues: Set<String>) {
if (taskTag.isPresent) {
val tagName = taskTag.get()
submit(AddTagToTaskWork::class.java) { parameters ->
parameters.apiToken.set(apiTokenFile.asFile.get().readText())
parameters.issues.set(issues)
parameters.tagName.set(tagName)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ru.kode.android.build.publish.plugin.task.clickup.api

import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Path
import ru.kode.android.build.publish.plugin.task.clickup.entity.AddFieldToTaskRequest

interface ClickUpApi {
@POST("v2/task/{task_id}/tag/{tag_name}")
fun addTagToTask(
@Path("task_id") taskId: String,
@Path("tag_name") tagName: String,
): Call<Unit>

@POST("v2/task/{task_id}/field/{field_id}")
fun addFieldToTask(
@Path("task_id") taskId: String,
@Path("field_id") fieldId: String,
@Body request: AddFieldToTaskRequest,
): Call<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.kode.android.build.publish.plugin.task.clickup.entity

import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
@Suppress("ConstructorParameterNaming") // network model
data class AddFieldToTaskRequest(
val value: String,
)
Loading

0 comments on commit ecc622e

Please sign in to comment.