Skip to content

Commit

Permalink
chore: update dev doc workflow for review when updating PR (#66)
Browse files Browse the repository at this point in the history
* Deploy documentation to Netlify

* Add Netlify prod deployment on develop
  • Loading branch information
florentmaitre committed Sep 20, 2024
1 parent d927fdd commit 969d4c7
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 23 deletions.
1 change: 0 additions & 1 deletion .github/workflows/app-distribution-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
jobs:
app-distribution-review:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down
54 changes: 49 additions & 5 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: build-docs

on:
# Runs on pushes targeting the default branch
push:
branches: [ "main" ]
branches:
- main
- develop

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

pull_request:
Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:
with:
instance: ${{ env.INSTANCE }}

deploy:
github-pages:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand All @@ -86,4 +86,48 @@ jobs:

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v4

netlify:
environment:
name: netlify
url: ${{ steps.deployment.outputs.deploy_preview_url }}
needs: [ build, test ]
runs-on: ubuntu-latest
if: github.event_name != 'push' || github.ref != 'refs/heads/master'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive

- name: Set up our JDK environment
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'

- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: docs

- name: Unzip artifact
run: unzip -O UTF-8 -qq '${{ env.ARTIFACT }}' -d dir

- name: Install Netlify CLI
run: npm install --save-dev netlify-cli

- name: Deploy to Netlify
id: deployment
run: |
# Git SHA is equal to github.event.pull_request.head.sha for pull requests
# This value is unset if workflow has not been triggered by a pull request, use GITHUB_SHA instead
BRANCH_SHA=${{ github.event.pull_request.head.sha }}
COMMIT_SHA=${BRANCH_SHA:-$GITHUB_SHA}
./gradlew publishDocumentationToNetlify -PdocumentationPath=dir -PnetlifySiteId=${{ secrets.NETLIFY_SITE_ID }} -PnetlifyToken=${{ secrets.NETLIFY_TOKEN }} -PcommitSha=$COMMIT_SHA
# Set environment URL
echo deploy_preview_url=$(cat netlify_deploy_preview_url.txt) >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ plugins {
alias(libs.plugins.google.services) apply false
id("github")
id("release")
id("netlify")
}
34 changes: 30 additions & 4 deletions buildSrc/src/main/kotlin/com/orange/ouds/gradle/GitHubApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,24 @@ class GitHubApi(private val token: String, private val repository: String) {
return parsePullRequests(jsonString)
}

fun Project.commentIssue(number: Int, comment: String) {
fun Project.getIssueComments(issueNumber: Int): List<GitHubIssueComment> {
val jsonString = launchRequest("issues/$issueNumber/comments", "GET")
return parseIssueComments(jsonString)
}

fun Project.createIssueComment(issueNumber: Int, body: String) {
launchRequest(
"issues/$number/comments",
"issues/$issueNumber/comments",
"POST",
"{\"body\":\"$comment\"}"
"{\"body\":\"$body\"}"
)
}

fun Project.updateIssueComment(commentId: Long, body: String) {
launchRequest(
"issues/comments/$commentId",
"PATCH",
"{\"body\":\"$body\"}"
)
}

Expand Down Expand Up @@ -68,7 +81,7 @@ class GitHubApi(private val token: String, private val repository: String) {
"-H", "Authorization: token $token",
"-H", "Accept: application/vnd.github.v3+json"
).apply {
if ((method == "POST" || method == "PUT") && body != null) {
if ((method == "POST" || method == "PUT" || method == "PATCH") && body != null) {
add("-d")
add(body)
}
Expand All @@ -90,4 +103,17 @@ class GitHubApi(private val token: String, private val repository: String) {
}
}
}

private fun parseIssueComments(jsonString: String): List<GitHubIssueComment> {
val jsonIssueComments = JSONArray(jsonString)

return List(jsonIssueComments.length()) { index ->
with(jsonIssueComments.getJSONObject(index)) {
GitHubIssueComment(
id = getLong("id"),
body = getString("body")
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ data class GitHubPullRequest(
val title: String,
val branchName: String,
)

data class GitHubIssueComment(
val id: Long,
val body: String,
)
7 changes: 7 additions & 0 deletions buildSrc/src/main/kotlin/com/orange/ouds/gradle/ProjectExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ inline fun <reified T> Project.findTypedProperty(propertyName: String): T? {
return findProperty(propertyName) as? T
}

inline fun <reified T> Project.requireTypedProperty(propertyName: String): T {
return findTypedProperty(propertyName) ?: throw GradleException("Please set the \"$propertyName\" project property.")
}

fun Project.execute(executable: String, vararg args: String): String {
val formattedArgs = args.joinToString(" ") { if (it.contains(" ")) "\"$it\"" else it }
println("\u001B[38;2;255;121;0;1m$executable $formattedArgs\u001B[0m")

val output = ByteArrayOutputStream()
exec {
standardOutput = output
Expand Down
22 changes: 14 additions & 8 deletions buildSrc/src/main/kotlin/firebase.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ tasks.register<DefaultTask>("appDistributionUpload") {
tasks.register<DefaultTask>("generateAppDistributionReleaseNotes") {
doLast {
// Generate release notes
val branchName = Environment.getVariables("GITHUB_REF").first().removePrefix("refs/heads/")
// GITHUB_HEAD_REF is equal to the branch name for a pull request and is empty otherwise
// GITHUB_REF_NAME is equal to X/merge for a pull request (where X is the pull request number) or to the branch name otherwise
// That's why we use GITHUB_HEAD_REF for a pull request and GITHUB_REF_NAME otherwise
val branchName = Environment.getVariablesOrNull("GITHUB_HEAD_REF", "GITHUB_REF_NAME").firstOrNull { it?.isNotBlank() == true }
var releaseNotes = if (branchName == "develop") {
// Retrieve latest Firebase App Distribution tag
// Firebase App Distribution tags are not annotated
Expand Down Expand Up @@ -156,9 +159,12 @@ tasks.register<DefaultTask>("publishAppDistributionQrCode") {
if (release != null) {
println("Found App Distribution release with version code $versionCode.")
gitHubApi {
// GITHUB_HEAD_REF is equal to the branch name for a pull request and is empty otherwise
// GITHUB_REF_NAME is equal to X/merge for a pull request (where X is the pull request number) or to the branch name otherwise
// That's why we use GITHUB_HEAD_REF for a pull request and GITHUB_REF_NAME otherwise
val branchName = Environment.getVariablesOrNull("GITHUB_HEAD_REF", "GITHUB_REF_NAME").firstOrNull { it?.isNotBlank() == true }
// Find pull request for current branch
val pullRequests = getPullRequests()
val branchName = Environment.getVariables("GITHUB_REF").first().removePrefix("refs/heads/")
val pullRequest = pullRequests.firstOrNull { it.branchName == branchName }
if (pullRequest != null) {
println("Found pull request #${pullRequest.number} for branch $branchName.")
Expand All @@ -177,19 +183,19 @@ tasks.register<DefaultTask>("publishAppDistributionQrCode") {
)

// Add a comment with a link to the QR code in the repository
println("Add comment with QR code to '${pullRequest.title} (#${pullRequest.number})'.")
println("Create comment with QR code to '${pullRequest.title} (#${pullRequest.number})'.")
val link = "![qrcode](https://github.com/Orange-OpenSource/ouds-android/raw/$sha/qrcodes/${qrCode.name})"
val comment =
val body =
"Flash the QR code below to download and install the OUDS Playground app which contains the changes of this pull request:\\n$link"
// Although we use the "issues/{issue_number}/comments" GitHub API, this will comment the pull request
// Although we use the "issues/{issue_number}/comments" GitHub API, this will comment the pull request because a pull request is an issue
// The "pulls/{pull_number}/comments" is used to add review comments on a pull request
commentIssue(pullRequest.number, comment)
createIssueComment(pullRequest.number, body)
} else {
println("Could not find a pull request for branch $branchName.")
throw GradleException("Could not find a pull request for branch $branchName.")
}
}
} else {
println("Could not find an App Distribution release with version code $versionCode.")
throw GradleException("Could not find an App Distribution release with version code $versionCode.")
}
}
}
Expand Down
92 changes: 92 additions & 0 deletions buildSrc/src/main/kotlin/netlify.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Software Name: OUDS Android
* SPDX-FileCopyrightText: Copyright (c) Orange SA
* SPDX-License-Identifier: MIT
*
* This software is distributed under the MIT license,
* the text of which is available at https://opensource.org/license/MIT/
* or see the "LICENSE" file for more details.
*
* Software description: Android library of reusable graphical components
*/

import com.orange.ouds.gradle.Environment
import com.orange.ouds.gradle.execute
import com.orange.ouds.gradle.gitHubApi
import com.orange.ouds.gradle.requireTypedProperty
import org.gradle.process.internal.ExecException

// This string is prepended to the Netlify comment and is used to retrieve and update the comment instead of creating another one
private val netlifyCommentPreamble = "<!-- Netlify comment -->"

tasks.register<DefaultTask>("publishDocumentationToNetlify") {
doLast {
val documentationPath = requireTypedProperty<String>("documentationPath")
val netlifySiteId = requireTypedProperty<String>("netlifySiteId")
val netlifyToken = requireTypedProperty<String>("netlifyToken")
val commitSha = requireTypedProperty<String>("commitSha")

// GITHUB_HEAD_REF is equal to the branch name for a pull request and is empty otherwise
// GITHUB_REF_NAME is equal to X/merge for a pull request (where X is the pull request number) or to the branch name otherwise
// That's why we use GITHUB_HEAD_REF for a pull request and GITHUB_REF_NAME otherwise
val branchName = Environment.getVariablesOrNull("GITHUB_HEAD_REF", "GITHUB_REF_NAME").firstOrNull { it?.isNotBlank() == true }

val args = mutableListOf("deploy", "--dir", documentationPath, "--site", netlifySiteId, "--auth", netlifyToken)
if (branchName == "develop") {
args += "--prod"
}

val output = try {
execute("netlify", *args.toTypedArray()).also { println(it) }
} catch (exception: ExecException) {
null
}

var exception = if (output == null) GradleException("Netlify deploy failed") else null

val outputLines = output.orEmpty()
.replace("\\x1B\\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]".toRegex(), "") // Removes ANSI colors from output
.split("\n")
// Output displays "Website draft URL" for draft deployments and "Website URL" for prod deployments
val netlifyDeployPreviewUrl = outputLines.firstNotNullOfOrNull { "^Website (?:draft |)URL:\\s+(.*)$".toRegex().find(it) }
?.groupValues
?.getOrNull(1)
val netlifyDeployLogUrl = outputLines.firstNotNullOfOrNull { "^Build logs:\\s+(.*)$".toRegex().find(it) }
?.groupValues
?.getOrNull(1)

// Save deploy preview URL in a file in order to update GitHub Netlify environment URL later on
File("netlify_deploy_preview_url.txt").writeText(netlifyDeployPreviewUrl.orEmpty())

if (branchName != "develop") {
gitHubApi {
// Find pull request for current branch
val pullRequests = getPullRequests()
val pullRequest = pullRequests.firstOrNull { it.branchName == branchName }
if (pullRequest != null) {
println("Found pull request #${pullRequest.number} for branch $branchName.")
val body = "$netlifyCommentPreamble\\n" + if (output != null) {
"### 🟢 Netlify deploy for commit $commitSha succeeded\\n\\nDeploy preview: $netlifyDeployPreviewUrl\\nDeploy log: $netlifyDeployLogUrl"
} else {
"### 🔴 Netlify deploy for commit $commitSha failed"
}
// Although we use the "issues/{issue_number}/comments" GitHub API, this will comment the pull request because a pull request is an issue
// The "pulls/{pull_number}/comments" is used to add review comments on a pull request
val issueComments = getIssueComments(pullRequest.number)
val netlifyComment = issueComments.firstOrNull { it.body.startsWith(netlifyCommentPreamble) }
if (netlifyComment != null) {
println("Update comment with Netlify deploy info to '${pullRequest.title} (#${pullRequest.number})'.")
updateIssueComment(netlifyComment.id, body)
} else {
println("Create comment with Netlify deploy info to '${pullRequest.title} (#${pullRequest.number})'.")
createIssueComment(pullRequest.number, body)
}
} else if (exception == null) {
exception = GradleException("Could not find a pull request for branch $branchName.")
}
}
}

exception?.let { throw it }
}
}
7 changes: 2 additions & 5 deletions buildSrc/src/main/kotlin/release.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

import com.orange.ouds.gradle.artifactId
import com.orange.ouds.gradle.execute
import com.orange.ouds.gradle.findTypedProperty
import com.orange.ouds.gradle.isPublished
import com.orange.ouds.gradle.requireTypedProperty

tasks.register<DefaultTask>("prepareRelease") {
doLast {
Expand Down Expand Up @@ -51,10 +51,7 @@ fun updateVersionCode() {

tasks.register<DefaultTask>("testSonatypeRepository") {
doLast {
val sonatypeRepositoryId = project.findTypedProperty<String>("sonatypeRepositoryId")
if (sonatypeRepositoryId == null) {
throw GradleException("Please set the \"sonatypeRepositoryId\" project property.")
}
val sonatypeRepositoryId = project.requireTypedProperty<String>("sonatypeRepositoryId")

// Add Sonatype Maven repository in root build.gradle.kts file
File("settings.gradle.kts").replace("(\\s*)mavenCentral\\(\\)".toRegex()) { matchResult ->
Expand Down

0 comments on commit 969d4c7

Please sign in to comment.