Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
-->

## Description

<!--
Please describe the changes and add a link to the related issue(s) #
-->

## Checklist

<!--
With all these boxes checked this PR conforms to our Definition of Done.
-->
Expand All @@ -18,6 +20,6 @@
- [ ] 3. Changes are manually tested by you and the reviewer
- [ ] 4. Documentation is written or updated

<!--
Thank you for your contribution <3
<!--
Thank you for your contribution <3
-->
26 changes: 15 additions & 11 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ on:
# Push on main and release tags
push:
branches:
- 'main'
- "main"
tags:
- '[0-9]+.[0-9]+.[0-9]+'
- "[0-9]+.[0-9]+.[0-9]+"

# PR
pull_request:
branches:
- 'main'
- "main"

# Manual trigger
workflow_dispatch:
Expand All @@ -33,7 +33,6 @@ permissions:
contents: write

jobs:

build:
name: CI/CD
runs-on: ubuntu-latest
Expand All @@ -55,9 +54,9 @@ jobs:
id: java
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'temurin'
java-version: '21'
cache: 'gradle'
distribution: "temurin"
java-version: "21"
cache: "gradle"

- name: Check if main repo
id: is_main_repo
Expand All @@ -66,6 +65,11 @@ jobs:
echo "value=true" >> $GITHUB_OUTPUT
fi

- name: Run Spotless check
if: ${{ inputs.is_release != true }}
timeout-minutes: 10
run: ./gradlew spotlessCheck

- name: Run installDist
timeout-minutes: 20
run: ./gradlew installDist
Expand All @@ -77,10 +81,10 @@ jobs:
# Run build
# Make temp dir with 777 mask as docker seems to run as root
mkdir -pm 777 tmp

# Start the dev-testing stack
docker compose -f openremote/profile/dev-testing.yml up -d --no-build

./gradlew test

- name: Login to DockerHub
Expand Down Expand Up @@ -183,11 +187,11 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: '**/build/reports/tests'
path: "**/build/reports/tests"

- name: Archive coverage report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-report
path: '**/build/reports/jacoco/test/html'
path: "**/build/reports/jacoco/test/html"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ bin-release/
.local/
.DS_*
node_modules/
.eslintcache
.pnp.*
.yarn/*
!.yarn/patches
Expand Down
944 changes: 944 additions & 0 deletions .yarn/releases/yarn-4.17.1.cjs

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
nodeLinker: node-modules

npmMinimalAgeGate: 1w

npmPreapprovedPackages:
- "@openremote/*"

yarnPath: .yarn/releases/yarn-4.17.1.cjs
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Subprojects are included automatically when they contain a `build.gradle` file,
## Available extensions

| Extension | Description |
|--------------|-------------------------------------------------------------------------------------------|
| ------------ | ----------------------------------------------------------------------------------------- |
| `demo-setup` | Adds the OpenRemote Demo setup. |
| `ems` | A new extension-based implementation of the Energy Management System with GOPACS support. |
| `energy` | Adds the energy domain extension with several energy related assets. |
Expand Down Expand Up @@ -87,14 +87,14 @@ After the custom project is rebuilt and the OpenRemote Manager is restarted, the

When adding or updating an extension:

* Keep extension code in its own Gradle subproject.
* Use the package namespace `org.openremote.extension.<extension-name>`.
* Register extension components using the appropriate OpenRemote SPI files under `META-INF/services`.
* Keep extension-specific resources under an extension-specific resource path.
* Add tests for extension behavior, preferably following the existing OpenRemote testing conventions.
- Keep extension code in its own Gradle subproject.
- Use the package namespace `org.openremote.extension.<extension-name>`.
- Register extension components using the appropriate OpenRemote SPI files under `META-INF/services`.
- Keep extension-specific resources under an extension-specific resource path.
- Add tests for extension behavior, preferably following the existing OpenRemote testing conventions.

Typical extension integration points include:

* `AssetModelProvider`
* `ContainerService`
* `SetupTasks`
- `AssetModelProvider`
- `ContainerService`
- `SetupTasks`
84 changes: 42 additions & 42 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,69 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

plugins {
id 'jacoco'
id 'test-report-aggregation'
alias libs.plugins.axionRelease
alias libs.plugins.nexusPublish
alias libs.plugins.testLogger apply false
id 'jacoco'
id 'test-report-aggregation'
alias libs.plugins.axionRelease
alias libs.plugins.nexusPublish
alias libs.plugins.testLogger apply false
}

// Configure version based on Git tags
scmVersion {
releaseOnlyOnReleaseBranches = true
releaseBranchNames = ['main']
unshallowRepoOnCI.set(true)
versionCreator('simple')
versionIncrementer('incrementMinor')
repository {
remote.set('origin')
}
tag {
prefix.set('')
initialVersion({config, position -> '0.1.0'})
}
releaseOnlyOnReleaseBranches = true
releaseBranchNames = ['main']
unshallowRepoOnCI.set(true)
versionCreator('simple')
versionIncrementer('incrementMinor')
repository {
remote.set('origin')
}
tag {
prefix.set('')
initialVersion({config, position -> '0.1.0'})
}
}

allprojects {
// Apply common project setup
apply from: "${project.rootDir}/project.gradle"
version = rootProject.scmVersion.version
// Apply common project setup
apply from: "${rootDir}/project.gradle"
version = rootProject.scmVersion.version
}

def jacocoToolVersion = libs.versions.jacoco.get()

jacoco {
toolVersion = jacocoToolVersion
toolVersion = jacocoToolVersion
}

subprojects {
pluginManager.withPlugin('java') {
pluginManager.apply('jacoco')
jacoco { toolVersion = jacocoToolVersion }
test {
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
}
pluginManager.withPlugin('java') {
pluginManager.apply('jacoco')
jacoco { toolVersion = jacocoToolVersion }
test {
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
}
}

tasks.withType(JacocoReport) {
reports {
xml.required = true
html.required = true
}
tasks.withType(JacocoReport) {
reports {
xml.required = true
html.required = true
}
}
}

nexusPublishing {
repositories {
sonatype {
nexusUrl = uri(findProperty('releasesRepoUrl'))
snapshotRepositoryUrl = uri(findProperty('snapshotsRepoUrl'))
username = findProperty('publishUsername')
password = findProperty('publishPassword')
}
repositories {
sonatype {
nexusUrl = uri(findProperty('releasesRepoUrl'))
snapshotRepositoryUrl = uri(findProperty('snapshotsRepoUrl'))
username = findProperty('publishUsername')
password = findProperty('publishPassword')
}
}
}
group = 'io.openremote.extension'
18 changes: 18 additions & 0 deletions buildSrc/src/main/groovy/TestSummaryListener.groovy
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
* Copyright 2026, OpenRemote Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestListener
import org.gradle.api.tasks.testing.TestResult
Expand Down
Loading