Skip to content

Commit 28c9794

Browse files
[build][Jenkins] more efficient Jenkins CI, builds, improved linter config
This is a significant refactoring of the repo and CI. 1) Jenkins CI: more efficient, quicker builds I propose that we adopt a "run often, run quickly" approach to our Jenkins CI. ATM we mostly run Jenkins when it's time to release new Blueprint installers (when a PR is merged on master). The other case is if "jenkins" is detected in the PR branch or PR title, then almost a full Jenkins build is done, just stopping short of publishing new Blueprint installers (full signing and notarization is done, which can take a couple of hours). I made it so we run a very light version of the Jenkins CI by default, that builds the "dev" version of the app and pre-packages it using electron builder, generating a directory that contains the app but no installers. We really ought to run tests then, on the unpacked pre-packaged app, but it will need to be done separately. Until then, we do not require the built-in extensions (plugins), so I gave openvsx.org a rest and skip fetching them, by default. When it's detected that the Jenkins CI is processing the result of a merge on master or if the new "release dry-run" mode is enabled [1], a production version of the Blueprint apps will be produced, including built-in plugins, which will then be packaged for "real", producing genuine OS-specific installers, signed and notarized as required. This will take a lot longer to run, of course, but may be required only a minority of the time. Conclusion: with this PR, running Jenkins CI now takes about 12 minutes, and since this is relatively quick, we can afford to run this when any PR branch is created or updated. Running the same CI in "release dry-run mode" takes about an hour. A release will take longer, a bit over an hour, since additional steps are executed, like copying the various installers to a release folder. [1] About the "release dry-run" mode, it can be enabled in JenkinsFile, "pipeline" definition near the top, in "environment": BLUEPRINT_JENKINS_RELEASE_DRYRUN = 'true' I wish I found a better mechanism to enable this "release dry-run" mode. But this will serve for now. The "release dry-run" mode should be disabled before merging a PR to master, but can in the meantime be used to test or troubleshoot the whole pipeline, in particular signing and notarizing. 2) tsconfig/eslint configs: Added configs, to improve linter coverage. This made it possible for some source files, not previously covered, to get ts/linter feedback, both while editing and when running `yarn lint`. This will help keep code in-line with our standards. The config is not perfect and I would welcome further improvements. But for now I think it's a nice improvement. 3) Build "scripts" (package.json) Refactored the build commands ("scripts" section in package.json) - previously, merely running 'yarn" in the repo's root would rebuild every application from scratch. This prevents running a quick "yarn install", e.g. just to re-install build dependencies - the new version permits a granular build, with simple defaults - inspired from a similar change not so long ago in the main repo - see updated README for some examples Other misc items: - renamed extensions / applications - made the browser application a first class citizen, equal to the Electron application - all applications now share a common 'plugins' folder rather than each having their own. Moved the plugin-related entries to root package.json - to gain flexibility about which `yarn workspaces` are invoked for a given `lerna` command, using the `--scope=` CLI option.I renamed the repo's extensions and applications. This permits easily composing commands that target only the extensions or only the applications. e.g.: ``` json "build:extensions": "lerna run --scope=\"blueprint*ext\" build", "build:applications": "lerna run --scope=\"blueprint*app\" build --concurrency 1"," ``` - renamed the extensions folders, made them more straightforward - For systems with limited RAM, like on a Raspberry Pi 4B board with 4GB of RAM, it's now possible to successfully build Blueprint. e.g. use the following cmd: `yarn && yarn build:dev`, optionally followed by a packing command like: `yarn electron package` - (build:dev will build the Blueprint app in dev mode, which can be achieved in 4GB RAM) - [windows][jenkins] stash only dist folder: Currently, and only for Windows, we stash the whole git repo, which is very big and takes long to stash and un-stash. For the other OS, we only stash the dist folder, that contains the platform-specific installer, that we built. Let's try that for Windows too, and see if it works. - [jenkins] Decrease timeout from 5h to 3h" Looking at the build history, all recent builds that succeeded, did do under 2h30. OTOH, when a build hangs, it needs to wait for the timeout to expire, wasting time at the current value of 5h. Let's compromise at 3 hours and see how it goes? - [jenkins][installer build] exclude browser app for now: We do not yet publish the browser app, so let's skip building it to save time/resources. We may revisit when we use the new browser app bundling, recently made available upstream in the Theia framework. Signed-off-by: Marc Dumais <[email protected]>
1 parent bf31e6c commit 28c9794

File tree

60 files changed

+392
-262
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+392
-262
lines changed

.eslintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ module.exports = {
1313
],
1414
parserOptions: {
1515
tsconfigRootDir: __dirname,
16-
project: 'tsconfig.json'
16+
project: ['./configs/tsconfig.eslint.json', './theia-extensions/*/tsconfig.json', 'applications/electron/tsconfig.eslint.json']
1717
}
1818
};

.github/workflows/build.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ jobs:
4646
shell: bash
4747
run: |
4848
yarn --skip-integrity-check --network-timeout 100000
49-
yarn electron package
49+
yarn build:dev
50+
yarn download:plugins
51+
yarn package:applications:preview
5052
env:
5153
NODE_OPTIONS: --max_old_space_size=4096
5254
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9
@@ -62,7 +64,7 @@ jobs:
6264
shell: bash
6365
run: |
6466
yarn electron test
65-
67+
6668
- name: Test (macOS)
6769
if: matrix.tests != 'skip' && runner.os == 'macOS'
6870
shell: bash

Jenkinsfile

+102-40
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,60 @@
11
/**
22
* This Jenkinsfile builds Theia across the major OS platforms
33
*/
4+
5+
/* groovylint-disable NestedBlockDepth */
46
import groovy.json.JsonSlurper
57

6-
distFolder = "applications/electron/dist"
78
releaseBranch = "master"
8-
// Attempt to detect that a PR is Jenkins-related, by looking-for
9-
// the word "jenkins" (case insensitive) in PR branch name and/or
9+
distFolder = "applications/electron/dist"
10+
11+
toStashDist = "${distFolder}/**"
12+
toStashDistInstallers = "${distFolder}/*"
13+
// default folder to stash
14+
toStash = toStashDistInstallers
15+
16+
// Attempt to detect whether a PR is Jenkins-related, by looking-for
17+
// the word "jenkins" (case insensitive) in PR branch name and/or
1018
// the PR title
1119
jenkinsRelatedRegex = "(?i).*jenkins.*"
1220

1321
pipeline {
1422
agent none
1523
options {
16-
timeout(time: 5, unit: 'HOURS')
24+
timeout(time: 3, unit: 'HOURS')
1725
disableConcurrentBuilds()
1826
}
1927
environment {
2028
BLUEPRINT_JENKINS_CI = 'true'
29+
30+
// to save time and resources, we skip some release-related steps
31+
// when not in the process of releasing. e.g. signing/notarizing the
32+
// installers. It can sometimes be necessary to run these steps, e.g.
33+
// when troubleshooting. Set the variable below to 'true' to do so.
34+
// We will still stop short of publishing anything.
35+
BLUEPRINT_JENKINS_RELEASE_DRYRUN = 'false'
36+
// BLUEPRINT_JENKINS_RELEASE_DRYRUN = 'true'
2137
}
2238
stages {
2339
stage('Build') {
24-
// only proceed when merging on the release branch or if the
25-
// PR seems Jenkins-related
2640
when {
2741
anyOf {
2842
expression {
2943
env.JOB_BASE_NAME ==~ /$releaseBranch/
3044
}
3145
expression {
32-
env.CHANGE_BRANCH ==~ /$jenkinsRelatedRegex/
46+
env.CHANGE_BRANCH ==~ /$jenkinsRelatedRegex/
3347
}
3448
expression {
3549
env.CHANGE_TITLE ==~ /$jenkinsRelatedRegex/
3650
}
51+
expression {
52+
// PR branch?
53+
env.BRANCH_NAME ==~ /PR-(\d)+/
54+
}
55+
expression {
56+
env.BLUEPRINT_JENKINS_RELEASE_DRYRUN == 'true'
57+
}
3758
}
3859
}
3960
parallel {
@@ -83,11 +104,11 @@ spec:
83104
container('theia-dev') {
84105
withCredentials([string(credentialsId: "github-bot-token", variable: 'GITHUB_TOKEN')]) {
85106
script {
86-
buildInstaller(1200, false)
107+
buildInstaller(120)
87108
}
88109
}
89110
}
90-
stash includes: "${distFolder}/*", name: 'linux'
111+
stash includes: "${toStash}", name: 'linux'
91112
}
92113
post {
93114
failure {
@@ -101,9 +122,9 @@ spec:
101122
}
102123
steps {
103124
script {
104-
buildInstaller(60, false)
125+
buildInstaller(60)
105126
}
106-
stash includes: "${distFolder}/*", name: 'mac'
127+
stash includes: "${toStash}", name: 'mac'
107128
}
108129
post {
109130
failure {
@@ -125,9 +146,9 @@ spec:
125146
bat "wmic OS get FreePhysicalMemory"
126147
bat "tasklist"
127148

128-
buildInstaller(60, true)
149+
buildInstaller(60)
129150
}
130-
stash name: 'win'
151+
stash includes: "${toStash}", name: 'win'
131152
}
132153
post {
133154
failure {
@@ -138,19 +159,23 @@ spec:
138159
}
139160
}
140161
stage('Sign and Upload') {
141-
// only proceed when merging on the release branch or if the
142-
// PR seems Jenkins-related
162+
// only proceed when merging on the release branch or if the
163+
// PR seems Jenkins-related. Note: for PRs, we do not by default
164+
// run this stage since it will be of little practical value.
143165
when {
144166
anyOf {
145167
expression {
146168
env.JOB_BASE_NAME ==~ /$releaseBranch/
147169
}
148170
expression {
149-
env.CHANGE_BRANCH ==~ /$jenkinsRelatedRegex/
171+
env.CHANGE_BRANCH ==~ /$jenkinsRelatedRegex/
150172
}
151173
expression {
152174
env.CHANGE_TITLE ==~ /$jenkinsRelatedRegex/
153175
}
176+
expression {
177+
env.BLUEPRINT_JENKINS_RELEASE_DRYRUN == 'true'
178+
}
154179
}
155180
}
156181
parallel {
@@ -246,37 +271,53 @@ spec:
246271
}
247272
}
248273

249-
def buildInstaller(int sleepBetweenRetries, boolean excludeBrowser) {
250-
int MAX_RETRY = 3
274+
def buildInstaller(int sleepBetweenRetries) {
275+
int maxRetry = 3
276+
String buildPackageCmd
251277

252278
checkout scm
253-
if (excludeBrowser) {
254-
sh "npm install -g ts-node typescript '@types/node'"
255-
sh "ts-node scripts/patch-workspaces.ts"
279+
280+
// only build the Electron app for now
281+
buildPackageCmd = 'yarn --frozen-lockfile --force && \
282+
yarn build:extensions && yarn electron build'
283+
284+
if (isRelease()) {
285+
// when not a release, build dev to save time
286+
buildPackageCmd += ":prod"
256287
}
257-
sh "node --version"
258-
sh "export NODE_OPTIONS=--max_old_space_size=4096"
259-
sh "printenv && yarn cache dir"
260-
sh "yarn cache clean"
288+
289+
sh 'node --version'
290+
sh 'export NODE_OPTIONS=--max_old_space_size=4096'
291+
sh 'printenv && yarn cache dir'
261292
try {
262-
sh(script: 'yarn --frozen-lockfile --force')
263-
} catch(error) {
264-
retry(MAX_RETRY) {
293+
sh(script: buildPackageCmd)
294+
} catch (error) {
295+
retry(maxRetry) {
265296
sleep(sleepBetweenRetries)
266-
echo "yarn failed - Retrying"
267-
sh(script: 'yarn --frozen-lockfile --force')
297+
echo 'yarn failed - Retrying'
298+
sh(script: buildPackageCmd)
268299
}
269300
}
270301

271-
sh "rm -rf ./${distFolder}"
272302
sshagent(['projects-storage.eclipse.org-bot-ssh']) {
273-
sh "yarn electron deploy"
303+
if (isRelease()) {
304+
sh 'yarn download:plugins && yarn electron package:prod'
305+
} else {
306+
// ATM the plugins are not useful for non-releases, so
307+
// let's skip ketching them
308+
sh 'yarn electron package:preview'
309+
}
274310
}
275311
}
276312

277313
def signInstaller(String ext, String os) {
314+
if (!isRelease()) {
315+
echo "This is not a release, so skipping installer signing for branch ${env.BRANCH_NAME}"
316+
return
317+
}
318+
278319
List installers = findFiles(glob: "${distFolder}/*.${ext}")
279-
320+
280321
// https://wiki.eclipse.org/IT_Infrastructure_Doc#Web_service
281322
if (os == 'mac') {
282323
url = 'https://cbi.eclipse.org/macos/codesign/sign'
@@ -296,6 +337,11 @@ def signInstaller(String ext, String os) {
296337
}
297338

298339
def notarizeInstaller(String ext) {
340+
if (!isRelease()) {
341+
echo "This is not a release, so skipping installer notarizing for branch ${env.BRANCH_NAME}"
342+
return
343+
}
344+
299345
String service = 'https://cbi.eclipse.org/macos/xcrun'
300346
List installers = findFiles(glob: "${distFolder}/*.${ext}")
301347

@@ -325,15 +371,20 @@ def notarizeInstaller(String ext) {
325371
}
326372

327373
def updateMetadata(String executable, String yaml, String platform, int sleepBetweenRetries) {
328-
int MAX_RETRY = 4
374+
if (!isRelease()) {
375+
echo "This is not a release, so skipping updating metadata for branch ${env.BRANCH_NAME}"
376+
return
377+
}
378+
379+
int maxRetry = 4
329380
try {
330381
sh "export NODE_OPTIONS=--max_old_space_size=4096"
331-
sh "rm -rf node_modules"
382+
// make sure the npm dependencies are available to the update scripts
332383
sh "yarn install --force"
333384
sh "yarn electron update:blockmap -e ${executable}"
334385
sh "yarn electron update:checksum -e ${executable} -y ${yaml} -p ${platform}"
335-
} catch(error) {
336-
retry(MAX_RETRY) {
386+
} catch (error) {
387+
retry(maxRetry) {
337388
sleep(sleepBetweenRetries)
338389
echo "yarn failed - Retrying"
339390
sh "yarn install --force"
@@ -344,7 +395,7 @@ def updateMetadata(String executable, String yaml, String platform, int sleepBet
344395
}
345396

346397
def uploadInstaller(String platform) {
347-
if (env.BRANCH_NAME == releaseBranch) {
398+
if (isReleaseBranch()) {
348399
def packageJSON = readJSON file: "package.json"
349400
String version = "${packageJSON.version}"
350401
sshagent(['projects-storage.eclipse.org-bot-ssh']) {
@@ -366,7 +417,7 @@ def uploadInstaller(String platform) {
366417
* Due to a bug in the nsis-updater the downloaded exe for an update needs to have a different name than initially however.
367418
*/
368419
def copyInstallerAndUpdateLatestYml(String platform, String installer, String extension, String yaml, String UPDATABLE_VERSIONS) {
369-
if (env.BRANCH_NAME == releaseBranch) {
420+
if (isReleaseBranch()) {
370421
def packageJSON = readJSON file: "package.json"
371422
String version = "${packageJSON.version}"
372423
sshagent(['projects-storage.eclipse.org-bot-ssh']) {
@@ -385,8 +436,19 @@ def copyInstallerAndUpdateLatestYml(String platform, String installer, String ex
385436
} else {
386437
echo "No updateable versions"
387438
}
388-
389439
} else {
390440
echo "Skipped copying installer for branch ${env.BRANCH_NAME}"
391441
}
392442
}
443+
444+
def isReleaseBranch() {
445+
return (env.BRANCH_NAME == releaseBranch)
446+
}
447+
448+
def isDryRunRelease() {
449+
return env.BLUEPRINT_JENKINS_RELEASE_DRYRUN == 'true'
450+
}
451+
452+
def isRelease() {
453+
return isDryRunRelease() || isReleaseBranch()
454+
}

README.md

+22-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<br/>
22
<div id="theia-logo" align="center">
33
<br />
4-
<img src="https://raw.githubusercontent.com/eclipse-theia/theia-blueprint/master/theia-extensions/theia-blueprint-product/src/browser/icons/TheiaBlueprintLogo-blue.png" alt="Theia Logo" width="300"/>
4+
<img src="https://raw.githubusercontent.com/eclipse-theia/theia-blueprint/master/theia-extensions/product/src/browser/icons/TheiaBlueprintLogo-blue.png" alt="Theia Logo" width="300"/>
55
<h3>Eclipse Theia Blueprint</h3>
66
</div>
77

@@ -53,24 +53,40 @@ Documentation on how to package Theia as a Desktop Product may be found [here](h
5353
- `browser` contains a browser based version of Eclipse Theia Blueprint that may be packaged as a Docker image
5454
- `electron` contains the electron app to package, packaging configuration, and E2E tests for the electron target.
5555
- `theia-extensions` groups the various custom theia extensions for Blueprint
56-
- `theia-blueprint-product` contains a Theia extension contributing the product branding (about dialogue and welcome page).
57-
- `theia-blueprint-updater` contains a Theia extension contributing the update mechanism and corresponding UI elements (based on the electron updater).
56+
- `product` contains a Theia extension contributing the product branding (about dialogue and welcome page).
57+
- `updater` contains a Theia extension contributing the update mechanism and corresponding UI elements (based on the electron updater).
58+
- `launcher` contains a Theia extension contributing, for AppImage applications, the option to create a script that allows to start blueprint from the command line by calling the 'theia' command.
5859

5960
### Build
6061

62+
For development and casual testing of Blueprint, one can build it in "dev" mode. This permits building Blueprint on systems with less resources, like a Raspberry Pi 4B with 4GB of RAM.
63+
6164
```sh
62-
yarn
65+
# Build "dev" version of the Blueprint app. Its quicker, uses less resources,
66+
# but the front end app is not "minified"
67+
yarn && yarn build:dev && yarn download:plugins
6368
```
6469

65-
### Package the Electron Application
70+
Production Blueprint applications:
6671

6772
```sh
73+
# Build production version of the Blueprint app
74+
yarn && yarn build && yarn download:plugins
75+
```
76+
77+
### Package the Applications
78+
79+
ATM we only produce packages for the Electron application.
80+
81+
```sh
82+
yarn package:applications
83+
# or
6884
yarn electron package
6985
```
7086

7187
The packaged application is located in `applications/electron/dist`.
7288

73-
### Create a Preview Electron Application (without packaging it)
89+
### Create a Preview Electron Electron Application (without packaging it)
7490

7591
```sh
7692
yarn electron package:preview
@@ -93,10 +109,6 @@ yarn electron test
93109
The browser app may be started with
94110

95111
```sh
96-
# Download Plugins for browser app
97-
yarn browser download:plugins
98-
99-
# Start browser app
100112
yarn browser start
101113
```
102114

0 commit comments

Comments
 (0)