Hi everyone,
I am trying to build client-extensions in Bitbucket Pipelines the same way they work locally, but the ZIP never gets produced in CI.
Environment
-
Liferay Workspace plugin:
com.liferay.gradle.plugins.workspace: 11.0.2 -
Gradle / Java: Gradle (8.5 wrapper),
openjdk:21container -
DXP: (2025.q1.0-lts)
-
CI: Bitbucket Pipelines
-
Node/Angular: Node 22.12, Angular CLI builds run before Gradle
Workspace setup
settings.gradle dynamically includes CE projects (parallel to modules/):
apply plugin: "com.liferay.workspace"
file("client-extensions").listFiles()?.each { dir ->
if (dir.isDirectory() && file("${dir}/client-extension.yaml").exists()) {
include "client-extensions:${dir.name}"
}
}
Example CE YAML (custom element):
# client-extensions/post-form-ce/client-extension.yaml
assemble:
- from: ../dist/post-form/browser
into: static
post-form:
type: customElement
htmlElementName: post-form
friendlyURLMapping: post-form
useESM: true
urls:
- polyfills.js
- main.js
cssURLs:
- styles.css
instanceable: false
portletCategoryName: category.client-extensions
name: Post Form
What works locally
Running from workspace root:
./gradlew clean deploy
→ CE ZIP is generated and appears in the deploy folder (works fine on my machine).
What I’m doing in Bitbucket
-
Build Angular first so
client-extensions/dist/...exists. -
Pre-seed
~/.liferay/workspace/releases.json. -
Run Gradle like local:
./gradlew --no-daemon buildService assemble
./gradlew --no-daemon test
./gradlew --no-daemon clean deploy -Pliferay.workspace.home.dir="$PWD/build/liferay-home"
(I also tried the module task:)
./gradlew --no-daemon :client-extensions:post-form-ce:buildClientExtensionZip
Symptoms in CI
-
./gradlew clean deploycompletes without error, but I don’t see any CE ZIP at:-
build/liferay-home/deploy/*.zip, or -
build/client-extensions/*.zip, or -
client-extensions/*-ce/build/*.zip
-
-
When I call the module task directly, either:
-
Gradle says task not found for
buildClientExtensionZip, or -
it runs but still no zip is emitted.
-
-
Listing projects in CI sometimes doesn’t show the CE modules as included.
Minimal CI snippet (Bitbucket)
image: openjdk:21
script:
- set -e
# Node for Angular
- apt-get update && apt-get install -y xz-utils curl unzip
- NODE_V=22.12.0
- curl -fsSLO https://nodejs.org/dist/v$NODE_V/node-v$NODE_V-linux-x64.tar.xz
- xz -dc node-v$NODE_V-linux-x64.tar.xz | tar -x -C /usr/local --strip-components=1
- cd client-extensions && npm ci && npm run build:all && cd ..
# Workspace releases.json
- mkdir -p /root/.liferay/workspace
- curl -fsSL https://releases.liferay.com/releases.json -o /root/.liferay/workspace/releases.json
# Build like local
- chmod +x gradlew
- ./gradlew --no-daemon clean deploy -Pliferay.workspace.home.dir="$PWD/build/liferay-home"
# Debug inventories
- ./gradlew -q projects
- ls -la build/liferay-home/deploy || true
- ls -la build/client-extensions || true
- ls -la client-extensions/*-ce/build || true
Questions
-
Which Gradle task is the canonical one (on Workspace plugin 11.0.2) to produce the client-extension ZIP in CI? Is
clean deploystill the recommended path, or should I call a specific CE task (e.g.buildClientExtensions/assembleClientExtensions/ per-modulebuildClientExtensionZip)? -
Is it supported to assemble assets from a sibling
dist/(as infrom: ../dist/...inclient-extension.yaml), or should the build artifacts be copied inside the CE module before packaging? -
Are there known gotchas in CI where CEs are not included by the
settings.gradledynamic include? (e.g., working directory assumptions, filename must be exactlyclient-extension.yaml, etc.) -
Any additional property needed when using
-Pliferay.workspace.home.dirin CI fordeployto emit CE zips? -
If
buildClientExtensionZipis the correct task, is there a minimal example CE project where that task is present on plugin 11.0.2 so I can compare?
Log excerpts
(please see attached, or let me know which specific lines you need; happy to paste the output of ./gradlew -q projects and :client-extensions:<my-ce>:tasks --all from CI)
Thanks in advance! Any guidance or a small reproducible example would be greatly appreciated.