Skip to content

Commit

Permalink
Update Releasing script and workflow
Browse files Browse the repository at this point in the history
Most of it was taken from Splitties
  • Loading branch information
LouisCAD committed Aug 23, 2021
1 parent e58cc97 commit 2314ee9
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 25 deletions.
16 changes: 9 additions & 7 deletions .github/workflows/release-plugins.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
# https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
# https://github.com/marketplace/actions/gradle-command
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
name: Publish plugins
on:
push:
workflow_dispatch:
pull_request:
types: [opened]
paths:
- 'plugins/version.txt'
branches:
- main
- release
jobs:
gradle-plugins-publishing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: 11
- uses: gradle/gradle-build-action@v1
with:
gradle-executable: plugins/gradlew
build-root-directory: plugins
arguments: publishToAppropriateRepo --scan -Pgradle.publish.key=${{ secrets.gradle_publish_key }} -Pgradle.publish.secret=${{ secrets.gradle_publish_secret }}
arguments: publishPlugins --scan -Pgradle.publish.key=${{ secrets.gradle_publish_key }} -Pgradle.publish.secret=${{ secrets.gradle_publish_secret }}
env:
sonatype_username: ${{ secrets.SONATYPE_USERNAME }}
sonatype_password: ${{ secrets.SONATYPE_PASSWORD }}
Expand Down
132 changes: 114 additions & 18 deletions Releasing.main.kts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
#!/usr/bin/env kotlin

/*
* Copyright 2019 Louis Cognault Ayeva Derman. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Repository("https://repo.maven.apache.org/maven2/")
//@file:Repository("https://oss.sonatype.org/content/repositories/snapshots")
//@file:Repository("file:///Users/louiscad/.m2/repository")
@file:DependsOn("com.louiscad.incubator:lib-publishing-helpers:0.2.1")
@file:DependsOn("com.louiscad.incubator:lib-publishing-helpers:0.2.3")

import Releasing_main.CiReleaseFailureCause.*
import java.io.File
import Releasing_main.ReleaseStep.*

import lib_publisher_tools.cli.CliUi
import lib_publisher_tools.cli.defaultImpl
import lib_publisher_tools.cli.runUntilSuccessWithErrorPrintingOrCancel
Expand All @@ -21,8 +17,20 @@ import lib_publisher_tools.versioning.Version
import lib_publisher_tools.versioning.checkIsValidVersionString
import lib_publisher_tools.versioning.stabilityLevel

val gitHubRepoUrl = "https://github.com/jmfayard/refreshVersions"

val dir = File(".")

val publishWorkflowFilename = "release-plugins.yml".also {
check(dir.resolve(".github").resolve("workflows").resolve(it).exists()) {
"The $it file expected in the `.github/workflows dir wasn't found!\n" +
"The filename is required to be correct.\n" +
"If the release workflow needs to be retried, it will be used to make a valid link."
}
}

val publishWorkflowLink = "$gitHubRepoUrl/actions/workflows/$publishWorkflowFilename"

val cliUi = CliUi.defaultImpl
val git = Vcs.git

Expand All @@ -41,18 +49,23 @@ enum class ReleaseStep { // Order of the steps, must be kept right.
`Change this library version`,
`Request doc update confirmation`,
`Request CHANGELOG update confirmation`,
`Commit "prepare for release" and tag`,
`Commit 'prepare for release' and tag`,
`Push release to origin`,
`Request PR submission`,
`Wait for successful release by CI`,
`Push tags to origin`,
`Request PR merge`,
`Request GitHub release publication`,
`Change this library version back to a SNAPSHOT`,
`Commit "prepare next dev version"`,
`Commit 'prepare next dev version'`,
`Push, at last`;
}

sealed interface CiReleaseFailureCause {
enum class RequiresNewCommits : CiReleaseFailureCause { BuildFailure, PublishingRejection }
enum class RequiresRetrying : CiReleaseFailureCause { ThirdPartyOutage, NetworkOutage }
}

val ongoingReleaseFile = dir.resolve("ongoing_release.tmp.properties")
val versionsFile = dir.resolve("plugins/version.txt")

Expand All @@ -77,6 +90,8 @@ var startAtStep: ReleaseStep //TODO: Make a val again when https://youtrack.jetb

val versionTagPrefix = "v"

fun tagOfVersionBeingReleased(): String = "$versionTagPrefix${OngoingRelease.newVersion}"

if (ongoingReleaseFile.exists()) {
OngoingRelease.load()
startAtStep = ReleaseStep.valueOf(OngoingRelease.currentStepName)
Expand Down Expand Up @@ -121,8 +136,22 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
printInfo("Before proceeding to the release, we will ensure we merge changes from the release branch into the main branch.")
printInfo("Will now checkout the `release` branch and pull from GitHub (origin) to update the local `release` branch.")
requestUserConfirmation("Continue?")
git.checkoutBranch("release")
git.pullFromOrigin()
if (git.hasBranch("release")) {
git.checkoutBranch("release")
git.pullFromOrigin()
} else {
printInfo("The branch release doesn't exist locally. Fetching from remote…")
git.fetch()
if (git.hasRemoteBranch(remoteName = "origin", branchName = "release")) {
printInfo("The branch exists on the origin remote. Checking out.")
git.checkoutAndTrackRemoteBranch("origin", "release")
} else {
printInfo("Creating and checking out the release branch")
git.createAndCheckoutBranch("release")
printInfo("Pushing the new release branch…")
git.push(repository = "origin", setUpstream = true, branchName = "release")
}
}
}
`Update main branch from release` -> {
printInfo("About to checkout the main branch (and update it from release for merge commits).")
Expand All @@ -140,6 +169,7 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
}
`Request doc update confirmation` -> {
arrayOf(
"README.md",
"mkdocs.yml"
).forEach { relativePath ->
do {
Expand All @@ -152,13 +182,14 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
}
if (askIfYes(
yesNoQuestion = "Are you sure the $relativePath file doesn't need to be updated?"
)) {
)
) {
break
}
} while (true)
}.also {
if (askIfYes(
yesNoQuestion = "Apart from the changelog, is there other files that " +
yesNoQuestion = "Apart from the changelog, are there any other files that " +
"need to be updated for this new release?"
)
) {
Expand All @@ -172,9 +203,9 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
requestManualAction("Update the `CHANGELOG.md` for the impending release.")
dir.resolve("CHANGELOG.md").checkChanged()
}
`Commit "prepare for release" and tag` -> with(OngoingRelease) {
`Commit 'prepare for release' and tag` -> with(OngoingRelease) {
git.commitAllFiles(commitMessage = "Prepare for release $newVersion")
git.tagAnnotated(tag = "$versionTagPrefix$newVersion", annotationMessage = "Version $newVersion")
git.tagAnnotated(tag = tagOfVersionBeingReleased(), annotationMessage = "Version $newVersion")
}
`Push release to origin` -> {
printInfo("Will now push to origin repository")
Expand All @@ -183,23 +214,88 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
git.pushToOrigin()
}
`Request PR submission` -> {
requestManualAction("Create a pull request from the `main` to the `release` branch on GitHub for the new version, if not already done.")
printInfo("You now need to create a pull request from the `main` to the `release` branch on GitHub for the new version,")
printInfo("if not already done.")
printInfo("You can do so by heading over to the following url:")
printInfo("$gitHubRepoUrl/compare/release...main")
printInfo("Here's a title suggestion which you can copy/paste:")
printInfo("Prepare for release ${OngoingRelease.newVersion}")
printInfo("Once submitted, GitHub should kick-off the release GitHub Action that will perform the publishing.")
requestManualAction("PR submitted?")
}
`Wait for successful release by CI` -> {
printInfo("To perform this step, we need to wait for the artifacts building and uploading.")
requestUserConfirmation("Did the publishing/release Github Action complete successfully?")
do {
printInfo("The build and publishing workflow is expected to take about 3 minutes.")
printInfo("")
printInfo("We recommend to set a timer to not forget to check the status.")
printInfo("Suggestion: In case it's not complete after that time, set a 2min timer to check again, until completion.")
val succeeded = askIfYes("Did the publishing/release Github Action complete successfully?")
if (succeeded.not()) {
printQuestion("What was the cause of failure?")
val failureCause: CiReleaseFailureCause = askChoice(
optionsWithValues = listOf(
"Outage of a third party service (GitHub actions, Gradle plugin portal, Sonatype, MavenCentral, Google Maven…)" to RequiresRetrying.ThirdPartyOutage,
"Network outage" to RequiresRetrying.NetworkOutage,
"Build failure that requires new commits to fix" to RequiresNewCommits.BuildFailure,
"Publication was rejected because of misconfiguration" to RequiresNewCommits.PublishingRejection
)
)
when (failureCause) {
is RequiresRetrying -> {
printInfo("The outage will most likely be temporary.")
when (failureCause) {
RequiresRetrying.ThirdPartyOutage -> "You can search for the status page of the affected service and check it periodically."
RequiresRetrying.NetworkOutage -> "You can retry when you feel or know it might be resolved."
}.let { infoMessage ->
printInfo(infoMessage)
}
printInfo("Once the outage is resolved, head to the following url to run the workflow again, on the right branch:")
printInfo(publishWorkflowLink)
requestManualAction("Click the `Run workflow` button, select the `main` branch and confirm.")
}
is RequiresNewCommits -> {
if (git.hasTag(tagOfVersionBeingReleased())) {
printInfo("Removing the version tag (will be put back later on)")
git.deleteTag(tag = tagOfVersionBeingReleased())
printInfo("tag removed")
}
printInfo("Recovering from that is going to require new fixing commits to be pushed to the main branch.")
printInfo("Note: you can keep this script waiting while you're resolving the build issue.")
requestManualAction("Fix the issues and commit the changes")
printInfo("Will now push the new commits")
requestUserConfirmation("Continue?")
git.pushToOrigin()
printInfo("Now, head to the following url to run the workflow again, on the right branch:")
printInfo(publishWorkflowLink)
requestManualAction("Click the `Run workflow` button, select the `main` branch and confirm.")
}
}
}
} while (succeeded.not())
printInfo("Alright, we take your word.")
}
`Push tags to origin` -> {
printInfo("Will now push with tags.")
requestUserConfirmation("Continue?")
if (git.hasTag(tagOfVersionBeingReleased()).not()) with(OngoingRelease) {
printInfo("The tag for the impeding release is missing, so we're putting it back too.")
git.tagAnnotated(tag = tagOfVersionBeingReleased(), annotationMessage = "Version $newVersion")
}
git.pushToOrigin(withTags = true)
}
`Request PR merge` -> {
requestManualAction("Merge the pull request for the new version on GitHub.")
printInfo("Now that the pull request has been merged into the release branch on GitHub,")
printInfo("we are going to update our local release branch")
requestUserConfirmation("Ready?")
git.updateBranchFromOrigin(targetBranch = "release")
}
`Request GitHub release publication` -> {
requestManualAction("Publish release on GitHub with the changelog.")
printInfo("It's now time to publish the release on GitHub, so people get notified.")
printInfo("Copy the section of this release from the CHANGELOG file, and head over to the following url to proceed:")
printInfo("$gitHubRepoUrl/releases/new")
requestManualAction("Publish the release ${OngoingRelease.newVersion} on GitHub with the changelog.")
}
`Change this library version back to a SNAPSHOT` -> {
val newVersion = Version(OngoingRelease.newVersion)
Expand Down Expand Up @@ -230,7 +326,7 @@ fun CliUi.runReleaseStep(step: ReleaseStep): Unit = when (step) {
versionsFile.writeText(nextDevVersion)
printInfo("${versionsFile.path} has been edited with next development version ($nextDevVersion).")
}
`Commit "prepare next dev version"` -> git.commitAllFiles(
`Commit 'prepare next dev version'` -> git.commitAllFiles(
commitMessage = "Prepare next development version.".also {
requestUserConfirmation(
yesNoQuestion = """Will commit all files with message "$it" Continue?"""
Expand Down

0 comments on commit 2314ee9

Please sign in to comment.