Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
vinsg committed Sep 7, 2022
1 parent 73ea27a commit 9cc494e
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 17 deletions.
6 changes: 4 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
}

group = "ca.vinsg"
version = "1.0-SNAPSHOT"
version = "0.1.0-SNAPSHOT"

repositories {
mavenCentral()
Expand Down Expand Up @@ -91,7 +91,9 @@ kotlin {
* Credits to Andrew:
* https://github.com/DrewCarlson/ktpack/blob/main/ktpack/build.gradle.kts
*/

/**
* Create the release task used to produce the final release binary for a specific platform.
*/
fun createPackageReleaseTask(target: String) {
val extension = if (hostOs.isWindows) ".exe" else ".kexe"
tasks.create("packageRelease${target.capitalized()}") {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion example.csv
Original file line number Diff line number Diff line change
@@ -1 +1 @@
vinsg/onboard-cli,vinsg/onboardTest,vinsg/onboard-cli,vinsg/test-onboard
vinsg/onboard-cli,vinsg/test,vinsg/test2
45 changes: 39 additions & 6 deletions src/commonMain/kotlin/GithubService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ import model.getRepoName
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

/**
* Contains main GitHub API functionalities.
*/
class GithubService : KoinComponent {

// DI injecting httpClient
private val ghClient: HttpClient by inject()

@Serializable
Expand All @@ -32,6 +36,9 @@ class GithubService : KoinComponent {
@Serializable
data class ObjectSha(val sha: String)

/**
* Serves as auth validation and gets the GitHub username associated with the token.
*/
suspend fun getUsername(): String {
@Serializable
data class User(val url: String)
Expand All @@ -47,6 +54,17 @@ class GithubService : KoinComponent {
return response.url.substringAfterLast("/")
}

sealed class CodeOwnersResult {
data class Success(val codeOwnersFile: CodeownerFile) : CodeOwnersResult()
data class FileMissing(val message: String, val cause: Exception? = null) : CodeOwnersResult()
data class Error(val message: String?, val cause: Exception? = null) : CodeOwnersResult()
}

/**
* Get a repository object using username.
* @param username
* @param repoName in the <org>/<name> format
*/
suspend fun getRepo(username: String, repoName: String): Repository =
when (val result = getCodeOwnersFile(repoName)) {
is CodeOwnersResult.Success -> {
Expand Down Expand Up @@ -87,12 +105,9 @@ class GithubService : KoinComponent {
}
}

sealed class CodeOwnersResult {
data class Success(val codeOwnersFile: CodeownerFile) : CodeOwnersResult()
data class FileMissing(val message: String, val cause: Exception? = null) : CodeOwnersResult()
data class Error(val message: String?, val cause: Exception? = null) : CodeOwnersResult()
}

/**
* Decode Base64 file content.
*/
object Base64ContentSerializer : KSerializer<String> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Content", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder) =
Expand All @@ -108,6 +123,10 @@ class GithubService : KoinComponent {
val sha: String
)

/**
* Retrieves CODEOWNERS file from repo.
* @param repoName in the <org>/<name> format
*/
private suspend fun getCodeOwnersFile(repoName: String): CodeOwnersResult {
val codeOwnersPath = "contents/.github/CODEOWNERS"

Expand All @@ -123,6 +142,10 @@ class GithubService : KoinComponent {
return CodeOwnersResult.Success(response)
}

/**
* Get the unique Sha reference for the repo, used for creating a branch.
* @param repoName in the <org>/<name> format
*/
private suspend fun getShaRepo(repoName: String): String {
val refPath = "git/ref/heads/main"
val response: Repo = ghClient.get("repos") {
Expand All @@ -132,6 +155,9 @@ class GithubService : KoinComponent {
return response.objectSha.sha
}

/**
* Create a branch with the name "add-[username]" on the remote.
*/
suspend fun createBranch(username: String, repo: Repository) {
@Serializable
data class RequestBody(val ref: String, val sha: String)
Expand All @@ -146,6 +172,9 @@ class GithubService : KoinComponent {
}
}

/**
* Create commit and push commit with "@[username]" string appended to CODEOWNERS file.
*/
suspend fun createCommit(username: String, repo: Repository) {
@Serializable
data class Commit(
Expand All @@ -172,6 +201,10 @@ class GithubService : KoinComponent {
}
}

/**
* Open Pull-Request on remote.
* @param repoName in the <org>/<name> format
*/
suspend fun openPR(username: String, repoName: String): String {
@Serializable
data class Pr(val title: String, val head: String, val base: String)
Expand Down
5 changes: 3 additions & 2 deletions src/commonMain/kotlin/HttpClient.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import io.ktor.client.*

/*
Creating an HttpClient with a platform specific implementation
/**
* Creating an [httpClient] with a platform specific implementation.
* @param config Platform specific [HttpClientConfig]
*/
expect fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient
12 changes: 11 additions & 1 deletion src/commonMain/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import kotlinx.serialization.json.Json
import org.koin.core.context.startKoin
import org.koin.dsl.module


/**
* Entry point of the application. Subcommands are added to using the [subcommands] function.
*/
fun main(args: Array<String>) = EditOwners().subcommands(Add()).main(args)

class EditOwners : CliktCommand(
Expand All @@ -34,6 +36,9 @@ class EditOwners : CliktCommand(
versionOption("0.1")
}

/**
* Interacting with the GitHub API requires the use of a Personal Access Token.
*/
private val token by option("-t", "--token", help = "Personal Access Token")
.required()
.check(
Expand All @@ -50,6 +55,11 @@ class EditOwners : CliktCommand(
}
}

/**
* Implementation of the dependency injection pattern using Koin. We declare a single [httpClient] that
* is used throughout the application.
* @param token GitHub Personal Access Token
*/
private fun initKoin(token: String) = run {
startKoin {
modules(
Expand Down
14 changes: 11 additions & 3 deletions src/commonMain/kotlin/commands/Add.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,24 @@ import model.printRepo
import okio.FileSystem
import okio.Path.Companion.toPath

/*
/**
* Add the @username to all the repositories provided with the --repos or --file flags.
*/
class Add : CliktCommand(
help = """
todo
Append @username to all repositories provided.
Recommended use:
./edit-owners \
-t <token> \
-f <path-to-file>
""".trimIndent(),
printHelpOnEmptyArgs = true
) {

/**
* Get list of repositories in format org/name.
*/
private val inputReposList by mutuallyExclusiveOptions(
option(
"-r",
Expand Down Expand Up @@ -68,6 +75,7 @@ class Add : CliktCommand(
throw CliktError("Exiting")
}

// create a PR for every READY repositories on the list.
repos.filter { it.status == Status.READY }.forEach {
ghService.createBranch(username, it)
ghService.createCommit(username, it)
Expand Down
6 changes: 6 additions & 0 deletions src/commonMain/kotlin/model/Repository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ enum class Status {
}
}

/**
* Print [repositoryList] with pretty colors and easy to read columns.
*/
fun Terminal.printAll(repositoryList: List<Repository>) {
this.println(
table {
Expand All @@ -52,6 +55,9 @@ fun Terminal.printAll(repositoryList: List<Repository>) {
)
}

/**
* Pretty print a single [repository].
*/
fun Terminal.printRepo(repository: Repository) {
this.println(
table { body { row(repository.name, repository.status) } }
Expand Down
1 change: 0 additions & 1 deletion src/macosArm64Main/kotlin/HttpClient.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import io.ktor.client.*
import io.ktor.client.engine.darwin.*


actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) {
config(this)
engine {
Expand Down
11 changes: 10 additions & 1 deletion token-guide.md
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
https://github.com/vinsg/edit-owners/blob/main/token-guide.md
# Personal Access Token Guide

How to get your GitHub Personnal Access Token and active SSO.

1. on GitHub go into the settings https://github.com/settings/tokens
2. Click "Generate new token"
3. Give "Repo" scope permission
4. Once created save the token **DON'T CLOSE THE PAGE**
5. If you are using SSO at your organization, click the "Configure SSO" dropdown next to the token and authorize the
token with your org.

0 comments on commit 9cc494e

Please sign in to comment.