Skip to content

Commit fdb0334

Browse files
authored
Implement CI pipeline (#11)
- support Changelog files and automatic update after a release - workflows to build and publish release drafts - support for automatic dependencies update via Github's dependabot.
1 parent 57e48ea commit fdb0334

File tree

8 files changed

+305
-23
lines changed

8 files changed

+305
-23
lines changed

.github/dependabot.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Dependabot configuration:
2+
# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates
3+
4+
version: 2
5+
updates:
6+
# Maintain dependencies for Gradle dependencies
7+
- package-ecosystem: "gradle"
8+
directory: "/"
9+
target-branch: "main"
10+
schedule:
11+
interval: "weekly"
12+
time: "06:00"
13+
timezone: "America/Chicago"
14+
ignore:
15+
# these depend on the toolbox API and should be updated manually
16+
- dependency-name: "org.jetbrains.kotlin.jvm"
17+
- dependency-name: "org.jetbrains.kotlin.plugin.serialization"
18+
- dependency-name: "com.google.devtools.ksp"
19+
# these can have breaking changes
20+
- dependency-name: "com.jetbrains.toolbox:core-api"
21+
- dependency-name: "com.jetbrains.toolbox:ui-api"
22+
- dependency-name: "com.jetbrains.toolbox:remote-dev-api"
23+
commit-message:
24+
prefix: "chore"
25+
# Maintain dependencies for GitHub Actions
26+
- package-ecosystem: "github-actions"
27+
directory: "/"
28+
target-branch: "main"
29+
schedule:
30+
interval: "weekly"
31+
time: "06:00"
32+
timezone: "America/Chicago"
33+
commit-message:
34+
prefix: "chore"

.github/workflows/build.yml

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# GitHub Actions workflow for testing and preparing the plugin release.
2+
# GitHub Actions reference: https://help.github.com/en/actions
3+
4+
name: Coder Toolbox Plugin Build
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
pull_request:
11+
12+
jobs:
13+
# Run plugin tests on every supported platform.
14+
test:
15+
strategy:
16+
matrix:
17+
platform:
18+
- ubuntu-latest
19+
- macos-latest
20+
- windows-latest
21+
runs-on: ${{ matrix.platform }}
22+
steps:
23+
- uses: actions/[email protected]
24+
25+
- uses: actions/setup-java@v4
26+
with:
27+
distribution: zulu
28+
java-version: 21
29+
cache: gradle
30+
31+
- uses: gradle/[email protected]
32+
33+
# Run tests
34+
- run: ./gradlew test --info
35+
36+
# Collect Tests Result of failed tests
37+
- if: ${{ failure() }}
38+
uses: actions/upload-artifact@v4
39+
with:
40+
name: tests-result
41+
path: ${{ github.workspace }}/build/reports/tests
42+
43+
build:
44+
name: Build
45+
needs: test
46+
runs-on: ubuntu-latest
47+
outputs:
48+
version: ${{ steps.properties.outputs.version }}
49+
changelog: ${{ steps.properties.outputs.changelog }}
50+
steps:
51+
# Check out current repository
52+
- name: Fetch Sources
53+
uses: actions/[email protected]
54+
55+
# Setup Java 21 environment for the next steps
56+
- name: Setup Java
57+
uses: actions/setup-java@v4
58+
with:
59+
distribution: zulu
60+
java-version: 21
61+
cache: gradle
62+
63+
# Set environment variables
64+
- name: Export Properties
65+
id: properties
66+
shell: bash
67+
run: |
68+
PROPERTIES="$(./gradlew properties --console=plain -q)"
69+
VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
70+
NAME="$(echo "$PROPERTIES" | grep "^group:" | cut -f2- -d ' ')"
71+
CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
72+
CHANGELOG="${CHANGELOG//'%'/'%25'}"
73+
CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
74+
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
75+
echo "version=$VERSION" >> $GITHUB_OUTPUT
76+
echo "name=$NAME" >> $GITHUB_OUTPUT
77+
echo "changelog=$CHANGELOG" >> $GITHUB_OUTPUT
78+
79+
# Run plugin build
80+
- name: Run Build
81+
run: ./gradlew clean pluginZip --info
82+
83+
# Prepare plugin archive content for creating artifact
84+
- name: Prepare Plugin Artifact
85+
id: artifact
86+
shell: bash
87+
run: |
88+
cd ${{ github.workspace }}/build/distributions
89+
FILENAME=$(ls *.zip)
90+
unzip "$FILENAME" -d content
91+
echo "filename=${FILENAME:0:-4}" >> $GITHUB_OUTPUT
92+
93+
# Store already-built plugin as an artifact for downloading
94+
- name: Upload artifact
95+
uses: actions/upload-artifact@v4
96+
with:
97+
name: ${{ steps.artifact.outputs.filename }}
98+
path: ./build/distributions/content/*/*
99+
100+
# Prepare a draft release for GitHub Releases page for the manual verification
101+
# If accepted and published, release workflow would be triggered
102+
releaseDraft:
103+
name: Release Draft
104+
if: github.event_name != 'pull_request'
105+
needs: build
106+
runs-on: ubuntu-latest
107+
steps:
108+
109+
# Check out current repository
110+
- name: Fetch Sources
111+
uses: actions/[email protected]
112+
113+
# Remove old release drafts by using GitHub CLI
114+
- name: Remove Old Release Drafts
115+
env:
116+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
117+
run: |
118+
gh api repos/${{ github.repository }}/releases \
119+
--jq '.[] | select(.draft == true) | .id' \
120+
| xargs -I '{}' gh api -X DELETE repos/${{ github.repository }}/releases/{}
121+
122+
# Create new release draft - which is not publicly visible and requires manual acceptance
123+
- name: Create Release Draft
124+
env:
125+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
126+
run: |
127+
echo "${{ needs.build.outputs.changelog }}" > RELEASE_NOTES.md
128+
gh release create v${{ needs.build.outputs.version }} \
129+
--draft \
130+
--target ${GITHUB_REF_NAME} \
131+
--title "v${{ needs.build.outputs.version }}" \
132+
--notes-file RELEASE_NOTES.md

.github/workflows/release.yml

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# GitHub Actions Workflow created for handling the release process based on the draft release prepared with the Build workflow.
2+
3+
name: Release
4+
on:
5+
release:
6+
types: [ prereleased, released ]
7+
8+
jobs:
9+
10+
# Prepare and publish the plugin to the Marketplace repository
11+
release:
12+
name: Publish Plugin
13+
runs-on: ubuntu-latest
14+
steps:
15+
16+
# Check out current repository
17+
- name: Fetch Sources
18+
uses: actions/[email protected]
19+
with:
20+
ref: ${{ github.event.release.tag_name }}
21+
22+
# Setup Java 21 environment for the next steps
23+
- name: Setup Java
24+
uses: actions/setup-java@v4
25+
with:
26+
distribution: zulu
27+
java-version: 21
28+
cache: gradle
29+
30+
# Set environment variables
31+
- name: Export Properties
32+
id: properties
33+
shell: bash
34+
run: |
35+
CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d'
36+
${{ github.event.release.body }}
37+
EOM
38+
)"
39+
40+
CHANGELOG="${CHANGELOG//'%'/'%25'}"
41+
CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
42+
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
43+
44+
echo "changelog=$CHANGELOG" >> $GITHUB_OUTPUT
45+
46+
# Update Unreleased section with the current release note
47+
- name: Patch Changelog
48+
if: ${{ steps.properties.outputs.changelog != '' }}
49+
env:
50+
CHANGELOG: ${{ steps.properties.outputs.changelog }}
51+
run: |
52+
./gradlew patchChangelog --release-note="$CHANGELOG"
53+
54+
# Publish the plugin to the Marketplace
55+
# TODO - enable this step (by removing the `if` block) when JetBrains is clear about release procedures
56+
- name: Publish Plugin
57+
if: false
58+
env:
59+
PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
60+
CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }}
61+
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
62+
PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
63+
run: ./gradlew publishPlugin --info
64+
65+
# Upload artifact as a release asset
66+
- name: Upload Release Asset
67+
env:
68+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69+
run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/*
70+
71+
# Create pull request
72+
- name: Create Pull Request
73+
if: ${{ steps.properties.outputs.changelog != '' }}
74+
env:
75+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
76+
run: |
77+
VERSION="${{ github.event.release.tag_name }}"
78+
BRANCH="changelog-update-$VERSION"
79+
80+
git config user.email "[email protected]"
81+
git config user.name "GitHub Action"
82+
83+
git checkout -b $BRANCH
84+
git commit -am "Changelog update - $VERSION"
85+
git push --set-upstream origin $BRANCH
86+
87+
gh pr create \
88+
--title "Changelog update - \`$VERSION\`" \
89+
--body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \
90+
--base main \
91+
--head $BRANCH

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ build
44
jvm/
55

66
# IntelliJ IDEA
7-
.idea
7+
.idea
8+
9+
# hidden macOS metadata files
10+
.DS_Store

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Coder Toolbox Plugin Changelog
2+
3+
## Unreleased
4+
5+
### Added
6+
7+
- initial support for JetBrains Toolbox 2.6.0.38311 with the possibility to manage the workspaces - i.e. start, stop,
8+
update and delete actions and also quick shortcuts to templates, web terminal and dashboard.

build.gradle.kts

+30-21
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ plugins {
1313
alias(libs.plugins.dependency.license.report)
1414
alias(libs.plugins.ksp)
1515
alias(libs.plugins.gradle.wrapper)
16+
alias(libs.plugins.changelog)
1617
}
1718

1819
buildscript {
@@ -50,6 +51,16 @@ dependencies {
5051
testImplementation(kotlin("test"))
5152
}
5253

54+
val pluginId = properties("group")
55+
val pluginName = properties("name")
56+
val pluginVersion = properties("version")
57+
58+
changelog {
59+
version.set(pluginVersion)
60+
groups.set(emptyList())
61+
title.set("Coder Toolbox Plugin Changelog")
62+
}
63+
5364
licenseReport {
5465
renderers = arrayOf(JsonReportRenderer("dependencies.json"))
5566
filters = arrayOf(ExcludeTransitiveDependenciesFilter())
@@ -65,17 +76,19 @@ tasks.test {
6576
useJUnitPlatform()
6677
}
6778

68-
val pluginId = "com.coder.toolbox"
69-
val pluginVersion = "0.0.1"
70-
7179
val assemblePlugin by tasks.registering(Jar::class) {
7280
archiveBaseName.set(pluginId)
7381
from(sourceSets.main.get().output)
7482
}
7583

7684
val copyPlugin by tasks.creating(Sync::class.java) {
7785
dependsOn(assemblePlugin)
86+
fromCompileDependencies()
87+
88+
into(getPluginInstallDir())
89+
}
7890

91+
fun CopySpec.fromCompileDependencies() {
7992
from(assemblePlugin.get().outputs.files)
8093
from("src/main/resources") {
8194
include("extension.json")
@@ -97,8 +110,14 @@ val copyPlugin by tasks.creating(Sync::class.java) {
97110
}
98111
},
99112
)
113+
}
100114

101-
into(getPluginInstallDir())
115+
val pluginZip by tasks.creating(Zip::class) {
116+
dependsOn(assemblePlugin)
117+
118+
fromCompileDependencies()
119+
into(pluginId)
120+
archiveBaseName.set(pluginName)
102121
}
103122

104123
tasks.register("cleanAll", Delete::class.java) {
@@ -126,26 +145,14 @@ private fun getPluginInstallDir(): Path {
126145
return pluginsDir / pluginId
127146
}
128147

129-
val pluginZip by tasks.creating(Zip::class) {
130-
dependsOn(assemblePlugin)
131-
132-
from(assemblePlugin.get().outputs.files)
133-
from("src/main/resources") {
134-
include("extension.json")
135-
include("dependencies.json")
136-
}
137-
from("src/main/resources") {
138-
include("icon.svg")
139-
rename("icon.svg", "pluginIcon.svg")
140-
}
141-
archiveBaseName.set("$pluginId-$pluginVersion")
142-
}
143-
144-
val uploadPlugin by tasks.creating {
148+
val publishPlugin by tasks.creating {
145149
dependsOn(pluginZip)
146150

147151
doLast {
148-
val instance = PluginRepositoryFactory.create("https://plugins.jetbrains.com", project.property("pluginMarketplaceToken").toString())
152+
val instance = PluginRepositoryFactory.create(
153+
"https://plugins.jetbrains.com",
154+
project.property("PUBLISH_TOKEN").toString()
155+
)
149156

150157
// first upload
151158
// instance.uploader.uploadNewPlugin(pluginZip.outputs.files.singleFile, listOf("toolbox", "gateway"), LicenseUrl.APACHE_2_0, ProductFamily.TOOLBOX)
@@ -163,3 +170,5 @@ tasks.register("classpath") {
163170
)
164171
}
165172
}
173+
174+
fun properties(key: String) = project.findProperty(key).toString()

gradle.properties

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version=0.1.0
2+
group=com.coder.toolbox
3+
name=coder-toolbox

0 commit comments

Comments
 (0)