Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/main/kotlin/com/wire/github/EventsHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,10 @@ class EventsHandler : WireEventsHandlerSuspending() {
"conversationId: ${conversation.id}"
)
usageMetrics.onAppAddedToConversation()
val webhookSetup = commandHandler.webhookHelp(conversationId = conversation.id)
val message = buildString {
appendLine(WELCOME_TEXT)
appendLine(webhookSetup)
appendLine()
append("Use `${GitHubCommandHandler.HELP_COMMAND}` to see all available commands.")
append(GitHubCommandHandler.HELP_COMMANDS)
}

manager.sendMessage(
Expand Down
27 changes: 11 additions & 16 deletions src/main/kotlin/com/wire/github/GitHubCommandHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,14 @@ internal class GitHubCommandHandler(
): String? =
when (command.lowercase()) {
HELP_COMMAND -> trackedHelp(help())
TOKENS_COMMAND -> tokens(conversationId)
WEBHOOK_HELP_COMMAND -> trackedHelp(webhookHelp(conversationId))
ACTIONS_HELP_COMMAND -> trackedHelp(actionsHelp(conversationId))
else -> null
}

fun help(): String =
"GitHub App supports repository webhooks and workflow-authored Actions notifications.\n\n" +
"Available commands:\n" +
"- `$TOKENS_COMMAND` — show or create this conversation's credentials\n" +
"- `$WEBHOOK_HELP_COMMAND` — configure GitHub repository webhooks\n" +
"- `$ACTIONS_HELP_COMMAND` — send custom messages from GitHub Actions"

private fun tokens(conversationId: QualifiedId): String =
"Conversation credentials:\n\n" +
"GitHub webhook secret:\n`${getOrCreateSecret(conversationId)}`\n\n" +
"GitHub Actions token:\n`${getOrCreateActionsToken(conversationId)}`\n\n" +
"Store these values as secrets. Do not print them in workflow logs."
HELP_COMMANDS

fun webhookHelp(conversationId: QualifiedId): String {
val webhookUrl = "$normalizedHost/${conversationId.id}/${conversationId.domain}"
Expand All @@ -56,10 +46,11 @@ internal class GitHubCommandHandler(
private fun actionsHelp(conversationId: QualifiedId): String {
val actionsUrl = "$normalizedHost/actions/${conversationId.id}/${conversationId.domain}"
return "GitHub Actions notification setup:\n\n" +
"Store this URL as `WIRE_WEBHOOK_URL`:\n$actionsUrl\n\n" +
"Store this token as `WIRE_ACTIONS_TOKEN`:\n" +
"${getOrCreateActionsToken(conversationId)}\n\n" +
"Use the reusable action:\n\n" +
"1. Open **Settings / Secrets and Variables / Actions / New repository secret**\n" +
"1.1 Store this URL as **WIRE_WEBHOOK_URL**:\n$actionsUrl\n" +
"1.2 Store this token as **WIRE_ACTIONS_TOKEN**:\n" +
"`${getOrCreateActionsToken(conversationId)}`\n\n" +
"2. Use the reusable action into your **.yml**/**.yaml** files:\n\n" +
"```yaml\n" +
"uses: wireapp/github-app/.github/actions/notify-wire@v1\n" +
"with:\n" +
Expand Down Expand Up @@ -88,8 +79,12 @@ internal class GitHubCommandHandler(

companion object {
const val HELP_COMMAND = "/github help"
const val TOKENS_COMMAND = "/github tokens"
const val WEBHOOK_HELP_COMMAND = "/github webhook help"
const val ACTIONS_HELP_COMMAND = "/github actions help"
const val HELP_COMMANDS =
"Available commands:\n" +
"- `$WEBHOOK_HELP_COMMAND` - configure GitHub repository webhooks\n" +
"- `$ACTIONS_HELP_COMMAND` - send custom messages from GitHub Actions\n" +
"- `$HELP_COMMAND` - Show this help message"
}
}
36 changes: 0 additions & 36 deletions src/test/kotlin/com/wire/github/GitHubCommandHandlerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,11 @@ class GitHubCommandHandlerTest {
fun `help lists all available commands`() {
val response = handler.response("/GITHUB HELP", CONVERSATION_ID)

assertContains(response.orEmpty(), GitHubCommandHandler.TOKENS_COMMAND)
assertContains(response.orEmpty(), GitHubCommandHandler.WEBHOOK_HELP_COMMAND)
assertContains(response.orEmpty(), GitHubCommandHandler.ACTIONS_HELP_COMMAND)
verify(exactly = 1) { usageMetrics.onHelpCommand() }
}

@Test
fun `tokens returns existing webhook secret and Actions token`() {
every { storage.get(CONVERSATION_ID.toStorageKey()) } returns EXISTING_SECRET
every {
storage.get(CONVERSATION_ID.toActionsTokenStorageKey())
} returns EXISTING_ACTIONS_TOKEN

val response = handler.response(GitHubCommandHandler.TOKENS_COMMAND, CONVERSATION_ID)

assertContains(response.orEmpty(), EXISTING_SECRET)
assertContains(response.orEmpty(), EXISTING_ACTIONS_TOKEN)
verify(exactly = 0) { storage.set(any(), any()) }
verify(exactly = 0) { usageMetrics.onHelpCommand() }
}

@Test
fun `tokens creates and stores both credentials when they are missing`() {
every { storage.get(CONVERSATION_ID.toStorageKey()) } returns null
every { storage.set(CONVERSATION_ID.toStorageKey(), GENERATED_SECRET) } returns "OK"
every { storage.get(CONVERSATION_ID.toActionsTokenStorageKey()) } returns null
every {
storage.set(CONVERSATION_ID.toActionsTokenStorageKey(), GENERATED_ACTIONS_TOKEN)
} returns "OK"

val response = handler.response(GitHubCommandHandler.TOKENS_COMMAND, CONVERSATION_ID)

assertContains(response.orEmpty(), GENERATED_SECRET)
assertContains(response.orEmpty(), GENERATED_ACTIONS_TOKEN)
verify(exactly = 1) { storage.set(CONVERSATION_ID.toStorageKey(), GENERATED_SECRET) }
verify(exactly = 1) {
storage.set(CONVERSATION_ID.toActionsTokenStorageKey(), GENERATED_ACTIONS_TOKEN)
}
verify(exactly = 0) { usageMetrics.onHelpCommand() }
}

@Test
fun `webhook help includes webhook URL and token`() {
every { storage.get(CONVERSATION_ID.toStorageKey()) } returns EXISTING_SECRET
Expand Down