Skip to content
Matt Magoffin edited this page Jun 19, 2024 · 11 revisions

There are two build systems used in SolarNetwork, one for SolarNode and one for SolarNet.

Building SolarNode

For SolarNode, which is merely collections of OSGi bundles (otherwise known as "plugins"), building any one application involves building the individual bundles that application requires and then deploying them into the appropriate OSGi container environment. This guide will detail how individual bundles are built, along with some details on specific SolarNetwork applications.

SolarNode build requirements

In order to build SolarNode bundles you need Ant and Java (Java 8 minimum). These can be installed on macOS using Homebrew:

# macOS install using Homebrew
brew install ant openjdk@8

Linux distributions provide similar packages.

SolarNode Git repository setup

To build the SolarNode bundles you must clone the solarnetwork-build, solarnetwork-common, solarnetwork-external, and solarnetwork-node repositories. You must adhere to the following filesystem directory structure for the various Git repositories, i.e. clone all the repositories into a common parent directory and keep the repository directory named exactly as named on GitHub:

<SolarNode build home>/
├── solarnetwork-build/
├── solarnetwork-common/
├── solarnetwork-external/
└── solarnetwork-node/

⚠️ Note that the solarnetwork-build repository requires Git LFS support. On macOS this can be installed using Homebrew with brew install git-lfs. On Linux most distributions provide a git-lfs package you can install.

For example, these commands create a new build home directory and clone the Git repositories:

mkdir solarentwork-dev
cd solarnetwork-dev
git clone git@github.com:SolarNetwork/solarnetwork-build.git
git clone git@github.com:SolarNetwork/solarnetwork-common.git
git clone git@github.com:SolarNetwork/solarnetwork-external.git
git clone git@github.com:SolarNetwork/solarnetwork-node.git

Within each of the Git repositories will be a set of directories, each representing a single OSGi bundle project. For example the solarnetwork-common repository looks like this:

solarnetwork-common
├── LICENSE
├── net.solarnetwork.common/
├── net.solarnetwork.common.expr.spel/
├── net.solarnetwork.common.expr.spel.test/
├── net.solarnetwork.common.internal.test/
├── net.solarnetwork.common.jdbc.pool.hikari/
├── net.solarnetwork.common.jdbc.pool.hikari.test/
├── net.solarnetwork.common.jdt/
├── net.solarnetwork.common.jdt.test/
├── net.solarnetwork.common.log4j2/
...

Building an individual OSGi bundle JAR

To build a bundle JAR, cd into that bundle's project directory and execute

ant jar

For example, to build the net.solarnetwork.common bundle, you'd do the following:

$ cd solarnetwork-common/net.solarnetwork.common
$ ant jar

Buildfile: build.xml

...

jar.classes:
     [echo] [====> Building JAR target/net.solarnetwork.common-1.10.0.jar <====]
jar.no.classes:

jar:

BUILD SUCCESSFUL
Total time: 1 second

From the build output, you can see the target/net.solarnetwork.common-1.10.0.jar bundle JAR was built.

OSGi bundle unit tests

Most bundle projects have a companion unit test project that is configured as an OSGi fragment on the bundle being tested. Generally the unit test projects have the same name as the main project, with .test added to the end. For example, the net.solarnetwork.common.web project has a unit test project named net.solarnetwork.common.web.test. The MANIFEST.MF for the unit test project declares it as a fragment on the net.solarnetwork.common.web bundle:

Bundle-Name: SolarNetwork Common Web Test
Bundle-SymbolicName: net.solarnetwork.common.web.test
Bundle-Version: 1.3.1
Bundle-Vendor: SolarNetwork
Fragment-Host: net.solarnetwork.common.web;bundle-version="1.14.1"

Configuring the unit tests in fragment bundles like this has the advantages of keeping the unit test code outside the host bundles and allows the unit tests to have full access to the imported classpath of the host bundle.

Running unit tests

Unit tests can be run inside Eclipse by simply right-clicking on any test or test project and choosing Run As > JUnit Test. They can be run on the command line via the test Ant target (after running the jar target). For example:

$ cd net.solarnetwork.common.web.test
$ ant jar test

Buildfile: build.xml

...

test.run:
    [mkdir] Created dir: target/reports

jacoco.init:

test.run.coverage:

test:

BUILD SUCCESSFUL
Total time: 2 seconds

Running all OSGi bundle unit tests

You can run all available unit tests from all the Git repositories by running the test-all-clean Ant task in the solarnetwork-build/solarnetwork-osgi-lib/test.xml build script (i.e. from the solarnetwork-build repository). Ant needs a fair bit of memory for the tests to complete successfully, so you can pass ANT_OPTS=-Xmx4g to give Ant more memory:

$ cd solarnetwork-build/solarnetwork-osgi-lib
$ ANT_OPTS=-Xmx4g ant -f test.xml test-all-clean

Once the tests have completed a HTML report of the results will be available at reports/unittest/index.html. Be aware that running all tests in this way can take a while to complete!

Running a subset of all OSGi bundle unit tests

You can also run a subset of all OSGi bundle unit tests by providing a test.buildfiles property to your execution. For example to run only the solarentwork-common repository tests you could define test.buildfiles=solarnetwork-common/\*.test/build.xml, like this:

$ cd solarnetwork-build/solarnetwork-osgi-lib
$ ANT_OPTS=-Xmx4g ant -f test.xml -Dtest.buildfiles=solarnetwork-common/\*.test/build.xml test-all-clean

Publishing OSGi bundles to Maven Central

To publish SolarNetwork plugins to Maven Central, run the stage task, which will publish to a Sonatype staging area. You can then use the Sonatype UI to release the staged artifacts.

Sonatype credentials

The Sonatype credentials (which are your Sonatype JIRA credentials) are configured in ~/.m2/settings.xml:

<server>
	<id>ossrh</id>
	<username>USERNAME</username>
	<password>PASSWORD</password>
</server>

GPG Configuration

GPG must be configured in ~/.m2/settings.xml for signing the artifacts:

<profile>
	<id>gpg</id>
	<properties>
		<gpg.keyname>4BC94956</gpg.keyname>
		<gpg.passphrase>{GAHTJ...PHR6}</gpg.passphrase>
	</properties>
</profile>

The gpg.passphrase value must be the encrypted password for the GPG private key, which you encrypt via

mvn --encrypt-password

See the Maven Docs for more information.

Building SolarNet

SolarNet uses Gradle for its build system.

SolarNet build requirements

In order to build SolarNet you need Java (Java 21 minimum). This can be installed on macOS using Homebrew:

# macOS install using Homebrew
brew install ant openjdk@21

Linux distributions provide a similar package.

SolarNet Git repository setup

To build SolarNet you must clone the solarnetwork-central repository.

mkdir solarentwork-dev
cd solarnetwork-dev
git clone git@github.com:SolarNetwork/solarnetwork-central.git

The repository structure contains a solarnet directory for the SolarNet application code and a solarnet-db-setup directory for the Postgres database setup scripts. The solarnet directory contains many subdirectories which are all compontents that make up the SolarNet platform. The main SolarNet applications — SolarIn, SolarJobs, SolarQuery, and SolarUser — are all located in similarly named directories solarin, solarjobs, solarquery, and solaruser.

The solarnet directory strcuture looks like this (some folders have been omitted for brevity):

solarnetwork-central/
├── LICENSE
├── README.md
├── solarnet/
│   ├── LICENSE
│   ├── README.md
│   ├── application.yml
│   ├── build.gradle
│   ├── common/
│   ├── common-test/
│   ├── config/
│   ├── datum/
│   ├── gradle/
│   ├── gradle.properties
│   ├── gradlew*
│   ├── gradlew.bat
│   ├── solarin/           # the SolarIn application
│   ├── solarjobs/         # the SolarJobs application
│   ├── solarquery/        # the SolarQuery application
│   ├── solaruser/         # the SolarUser application
│   └── user/
└── solarnet-db-setup/
    ├── README.md
    └── postgres/

The solarnet-db-setup directory contains one main postgres sub-directory. Within that are all the SQL setup files along with a bin/setup-db.sh script for creating, or re-creating, the Postgres database. The directory strcture looks like this (some items have been omitted for brevity):

solarnetwork-central/solarnet-db-setup/
├── README.md
└── postgres/
    ├── README.md
    ├── bin/
    │   └── setup-db.sh*                 # script to (re)create the database
    ├── migrations/                      # migration scripts for changes to existing databases
    ├── postgres-create.sql
    ├── postgres-disable-triggers.sql
    ├── postgres-enable-triggers.sql
    ├── postgres-init-common-schema.sql
    ├── postgres-init-common.sql
    ├── postgres-init-core-schema.sql
    ├── postgres-init-core.sql
    ├── postgres-init-users.sql
    ├── postgres-init.sql
    └── updates/                          # update SQL for changes to existing databases

See the SolarNet Development Guide for information on creating the database.

Building SolarNet

To build SolarNet run the build -x test Gradle task in the solarentwork-central/solarnet directory. For example:

# on POSIX platforms
cd solarnetwork-central/solarnet
./gradlew build -x test

# on Windows
.\gradlew.bat build -x test

SolarNet unit tests

To run the SolarNet unit tests, execute the test task in Gradle:

./gradlew test

# or run tests implicitly with the build task by omitting the '-x test' arguments
./gradlew build

⚠️ Note that some unit tests require access to the Postgres database, and by default expect Postgres to be available on port 5432 with a database named solarnetwork_unittest using credentials solartest/solartest. Once Postgres is installed with all SolarNet's required extensions you can create a unit test database like:

cd solarnetwork-centrl/solarnet-db-setup
./bin/setup-db.sh -rv -u solartest -d solarnetwork_unittest

See the SolarNet Development Guide for more information.

Clone this wiki locally