From 867bc859db796bc19b6c44ebd1717d38c949456a Mon Sep 17 00:00:00 2001 From: Daniel M Date: Sat, 28 Oct 2023 14:50:14 -0400 Subject: [PATCH] feat:filter by workflow type (#100) Fix #98 --- .github/workflows/build.yml | 2 +- CHANGELOG.md | 6 ++++- gradle.properties | 8 +++--- .../com/dsoftware/ghmanager/api/GithubApi.kt | 25 +++++++++++++------ .../dsoftware/ghmanager/api/model/RunModel.kt | 19 ++++++++++++-- .../ghmanager/data/WorkflowRunListLoader.kt | 25 +++++++++++++++++++ .../ui/panels/filters/WfRunsFiltersFactory.kt | 9 +++++++ .../panels/filters/WfRunsListSearchValue.kt | 6 ++--- .../filters/WfRunsSearchPanelViewModel.kt | 7 +++--- 9 files changed, 85 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3846508f..281afd20 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: # Validate wrapper - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.0.4 + uses: gradle/wrapper-validation-action@v1.1.0 # Setup Java 17 environment for the next steps - name: Setup Java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f9645bf..2b8f2bb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ ## [Unreleased] -## [1.13.6] +## [1.14.0] + +### 🚀 Features + +- Filter by workflow type #98 ### Maintenance diff --git a/gradle.properties b/gradle.properties index 4ea0e717..8ce4116e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,16 +3,16 @@ pluginGroup=com.dsoftware.ghmanager pluginName=github-actions-manager # SemVer format -> https://semver.org -pluginVersion=1.13.6 +pluginVersion=1.14.0 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild=231.8109.175 -pluginUntilBuild=233.* +pluginUntilBuild=234.* # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType=IC -platformVersion=LATEST-EAP-SNAPSHOT -#platformVersion=2023.3.3 +#platformVersion=LATEST-EAP-SNAPSHOT +platformVersion=2023.2.4 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 diff --git a/src/main/kotlin/com/dsoftware/ghmanager/api/GithubApi.kt b/src/main/kotlin/com/dsoftware/ghmanager/api/GithubApi.kt index f0de816d..9c50b1aa 100644 --- a/src/main/kotlin/com/dsoftware/ghmanager/api/GithubApi.kt +++ b/src/main/kotlin/com/dsoftware/ghmanager/api/GithubApi.kt @@ -2,13 +2,12 @@ package com.dsoftware.ghmanager.api import com.dsoftware.ghmanager.api.model.WorkflowRunJobsList import com.dsoftware.ghmanager.api.model.WorkflowRuns +import com.dsoftware.ghmanager.api.model.WorkflowTypes import com.dsoftware.ghmanager.data.RepositoryCoordinates import com.intellij.openapi.diagnostic.logger import org.jetbrains.plugins.github.api.GithubApiRequest import org.jetbrains.plugins.github.api.GithubApiRequest.Get.Companion.json import org.jetbrains.plugins.github.api.GithubApiRequests -import org.jetbrains.plugins.github.api.data.GithubBranch -import org.jetbrains.plugins.github.api.data.GithubResponsePage import org.jetbrains.plugins.github.api.data.request.GithubRequestPagination import org.jetbrains.plugins.github.api.util.GithubApiUrlQueryBuilder @@ -17,6 +16,7 @@ data class WorkflowRunFilter( val status: String? = null, val actor: String? = null, val event: String? = null, + val workflowId: Long? = null, ) typealias GitHubLog = Map> @@ -29,23 +29,31 @@ object GithubApi : GithubApiRequests.Entity("/repos") { GithubApiRequest.Post.Json(url, Object(), Object::class.java, null) .withOperationName("Rerun workflow") - fun getBranches(coordinates: RepositoryCoordinates): GithubApiRequest> = - GithubApiRequests.Repos.Branches.get( + fun getWorkflowTypes( + coordinates: RepositoryCoordinates, + pagination: GithubRequestPagination? = null + ): GithubApiRequest { + val url = GithubApiRequests.getUrl( coordinates.serverPath, - coordinates.repositoryPath.owner, - coordinates.repositoryPath.repository, + urlSuffix, + "/${coordinates.repositoryPath}", + "/actions", + "/workflows" ) + return get(url, "Get workflow types", pagination) + } fun getWorkflowRuns( coordinates: RepositoryCoordinates, filter: WorkflowRunFilter, pagination: GithubRequestPagination? = null ): GithubApiRequest { + val specificWorkflow = if (filter.workflowId == null) "" else "/workflows/${filter.workflowId}" val url = GithubApiRequests.getUrl( coordinates.serverPath, urlSuffix, "/${coordinates.repositoryPath}", - "/actions", + "/actions${specificWorkflow}", "/runs", GithubApiUrlQueryBuilder.urlQuery { param("event", filter.event) @@ -54,9 +62,10 @@ object GithubApi : GithubApiRequests.Entity("/repos") { param("branch", filter.branch) param(pagination) }) - return get(url, "search workflow runs", pagination) + return get(url, "Get workflow runs", pagination) } + fun getWorkflowRunJobs(url: String) = get( url, "Get workflow-run jobs", pagination = GithubRequestPagination(1) ) diff --git a/src/main/kotlin/com/dsoftware/ghmanager/api/model/RunModel.kt b/src/main/kotlin/com/dsoftware/ghmanager/api/model/RunModel.kt index 5f33e97b..fcf9fcad 100644 --- a/src/main/kotlin/com/dsoftware/ghmanager/api/model/RunModel.kt +++ b/src/main/kotlin/com/dsoftware/ghmanager/api/model/RunModel.kt @@ -1,12 +1,21 @@ package com.dsoftware.ghmanager.api.model import com.fasterxml.jackson.annotation.JsonFormat +import kotlinx.serialization.Serializable import java.util.Date -data class WorkflowRuns( +data class WorkflowTypes( val total_count: Int, - val workflow_runs: List = emptyList() + val workflows: List = emptyList() +) + +@Serializable +data class WorkflowType( + val id: Long, + val name: String, + val path: String, + val state: String, ) data class PullRequest( @@ -15,6 +24,11 @@ data class PullRequest( val url: String, ) +data class WorkflowRuns( + val total_count: Int, + val workflow_runs: List = emptyList() +) + data class WorkflowRun( val id: Long, val path: String?, @@ -37,6 +51,7 @@ data class WorkflowRun( val artifacts_url: String, val cancel_url: String, val rerun_url: String, + val workflow_id: Long, val workflow_url: String, val name: String, val head_commit: GitHubHeadCommit, diff --git a/src/main/kotlin/com/dsoftware/ghmanager/data/WorkflowRunListLoader.kt b/src/main/kotlin/com/dsoftware/ghmanager/data/WorkflowRunListLoader.kt index 2899b126..09b795bd 100644 --- a/src/main/kotlin/com/dsoftware/ghmanager/data/WorkflowRunListLoader.kt +++ b/src/main/kotlin/com/dsoftware/ghmanager/data/WorkflowRunListLoader.kt @@ -3,6 +3,7 @@ package com.dsoftware.ghmanager.data import com.dsoftware.ghmanager.api.GithubApi import com.dsoftware.ghmanager.api.WorkflowRunFilter import com.dsoftware.ghmanager.api.model.WorkflowRun +import com.dsoftware.ghmanager.api.model.WorkflowType import com.dsoftware.ghmanager.ui.settings.GhActionsSettingsService import com.intellij.collaboration.async.CompletableFutureUtil import com.intellij.collaboration.async.CompletableFutureUtil.handleOnEdt @@ -36,6 +37,7 @@ class WorkflowRunListLoader( val listModel = CollectionListModel() val repoCollaborators = ArrayList() val repoBranches = ArrayList() + val workflowTypes = ArrayList() private val progressManager = ProgressManager.getInstance() private var lastFuture = CompletableFuture.completedFuture(emptyList()) private val loadingStateChangeEventDispatcher = EventDispatcher.create(SimpleEventListener::class.java) @@ -92,6 +94,11 @@ class WorkflowRunListLoader( updateBranches(it) } } + if (workflowTypes.isEmpty()) { + progressManager.submitIOTask(NonReusableEmptyProgressIndicator()) { + updateWorkflowTypes(it) + } + } lastFuture = lastFuture.thenCompose { progressManager.submitIOTask(indicator) { @@ -149,6 +156,23 @@ class WorkflowRunListLoader( repoBranches.addAll(branchSet) } + private fun updateWorkflowTypes(indicator: ProgressIndicator) { + val workflowTypesSet = HashSet() + var nextPage: Int = 0 + do { + nextPage += 1 + val request = GithubApi.getWorkflowTypes( + repositoryCoordinates, + GithubRequestPagination(pageNumber = nextPage, pageSize = 100) + ) + LOG.info("Calling ${request.url}") + val response = requestExecutor.execute(indicator, request) + workflowTypesSet.addAll(response.workflows) + } while (nextPage * 100 < response.total_count) + workflowTypes.clear() + workflowTypes.addAll(workflowTypesSet) + } + override fun dispose() { progressIndicator.cancel() task.cancel(true) @@ -166,6 +190,7 @@ class WorkflowRunListLoader( listModel.removeAll() repoCollaborators.clear() repoBranches.clear() + workflowTypes.clear() } private fun canLoadMore() = !loading && (page * settingsService.state.pageSize < totalCount) diff --git a/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsFiltersFactory.kt b/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsFiltersFactory.kt index df0e920b..749d16ad 100644 --- a/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsFiltersFactory.kt +++ b/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsFiltersFactory.kt @@ -47,6 +47,15 @@ internal class WfRunsFiltersFactory(vm: WfRunsSearchPanelViewModel) : AsyncImageIconsProvider(viewScope, AvatarLoader(vm.context.requestExecutor)) ) return listOf( + DropDownComponentFactory(vm.workflowType) + .create(viewScope, + filterName = "Workflow", + items = vm.workflowTypes, + onSelect = {}, + valuePresenter = { it.name }, + popupItemPresenter = { + ChooserPopupUtil.PopupItemPresentation.Simple(it.name.toString()) + }), DropDownComponentFactory(vm.userFilterState) .create(viewScope, filterName = "Actor", diff --git a/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsListSearchValue.kt b/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsListSearchValue.kt index d4fb174f..87179c92 100644 --- a/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsListSearchValue.kt +++ b/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsListSearchValue.kt @@ -1,6 +1,7 @@ package com.dsoftware.ghmanager.ui.panels.filters import com.dsoftware.ghmanager.api.WorkflowRunFilter +import com.dsoftware.ghmanager.api.model.WorkflowType import com.intellij.collaboration.ui.codereview.list.search.ReviewListSearchValue import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @@ -13,9 +14,8 @@ data class WfRunsListSearchValue( val branch: String? = null, val status: Status? = null, val event: Event? = null, + val workflowType: WorkflowType? = null, ) : ReviewListSearchValue { - val actorName - get() = actor?.shortName fun getShortText(): String { @Suppress("HardCodedStringLiteral") @@ -32,7 +32,7 @@ data class WfRunsListSearchValue( } fun toWorkflowRunFilter(): WorkflowRunFilter { - return WorkflowRunFilter(branch, status?.toString()?.lowercase(), actor?.shortName, "") + return WorkflowRunFilter(branch, status?.toString()?.lowercase(), actor?.shortName, "", workflowType?.id) } enum class Status { diff --git a/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsSearchPanelViewModel.kt b/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsSearchPanelViewModel.kt index 95804d25..ccf3d04e 100644 --- a/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsSearchPanelViewModel.kt +++ b/src/main/kotlin/com/dsoftware/ghmanager/ui/panels/filters/WfRunsSearchPanelViewModel.kt @@ -22,7 +22,8 @@ internal class WfRunsSearchPanelViewModel( get() = context.runsListLoader.repoBranches val collaborators get() = context.runsListLoader.repoCollaborators - + val workflowTypes + get() = context.runsListLoader.workflowTypes override fun WfRunsListSearchValue.withQuery(query: String?) = copy(searchQuery = query) override val quickFilters: List = listOf( @@ -33,12 +34,12 @@ internal class WfRunsSearchPanelViewModel( val eventFilterState = searchState.partialState(WfRunsListSearchValue::event) { copy(event = it) } val userFilterState = searchState.partialState(WfRunsListSearchValue::actor) { copy(actor = it) } val statusState = searchState.partialState(WfRunsListSearchValue::status) { copy(status = it) } - + val workflowType = searchState.partialState(WfRunsListSearchValue::workflowType) { copy(workflowType = it) } } sealed class WorkflowRunListQuickFilter(val title: String) : ReviewListQuickFilter { - class All : WorkflowRunListQuickFilter("All workflows") { + class All : WorkflowRunListQuickFilter("All workflow runs") { override val filter = WfRunsListSearchValue() } } \ No newline at end of file