Skip to content

Commit

Permalink
Add release management documentation (#38)
Browse files Browse the repository at this point in the history
Closes #24
  • Loading branch information
wborn authored Dec 18, 2024
1 parent 51203e0 commit faef860
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 46 deletions.
80 changes: 48 additions & 32 deletions docs/developer-guide/working-on-the-mobile-consoles.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,42 @@ sidebar_position: 11

# Working on the mobile consoles

The OpenRemote mobile consoles load the web applications using a web view and provide bridging of native device functionality to provide a native app experience. Make sure you've pulled the latest code of the repository.
The OpenRemote mobile consoles load the web applications using a web view and provide bridging of native device functionality to provide a native app experience.
Make sure you've pulled the latest code of the repository.

## Android Console

Download and install [Android Studio](https://developer.android.com/studio/index.html), then open the `console/android` project.
Download and install [Android Studio](https://developer.android.com/studio/index.html), then open the [console-android](https://github.com/openremote/console-android) repository.

TODO: There is actually nothing to build right now, you have to create a custom project and a dependency on our Android console project from your own Android app.
TODO: There is actually nothing to build right now, you have to create a custom project and a dependency on our Android console project from your own Android app.

## iOS Console

### Developing for iOS is only possible on macOS.
### Developing for iOS is only possible on macOS

Download and install [Xcode](https://itunes.apple.com/nl/app/xcode/id497799835)

Open Xcode and create a new project. In the generals part, click on the plus symbol to add a new target. Select Notification Service Extension. Close the project.

Open Xcode and create a new project.
In the generals part, click on the plus symbol to add a new target.
Select Notification Service Extension.
Close the project.

Install cocoapods through a terminal window.

```shell
sudo gem install cocoapods
```
Navigate to your project directory and create a pod file.

```shell
pod init
```

Open up the Podfile with a text editor. Add the `ORLib` pod to both of the targets
Open up the Podfile with a text editor and add the `ORLib` pod:

```
workspace '<your_project>'
platform :ios, '11.2'
platform :ios, '14.0'
use_frameworks!
Expand All @@ -42,9 +48,9 @@ def shared_pods
pod 'Firebase/Messaging', '~> 4.6.0'
pod 'Fabric', '~> 1.10.2'
pod 'Crashlytics', '~> 3.13.4'
pod 'ORLib', '~> 0.3'
end
target '<your_project>' do
project '<your_project>'
shared_pods
Expand All @@ -54,23 +60,26 @@ target 'NotificationService' do
project '<your_project>'
shared_pods
end
target 'ORLib' do
project 'path_to/console-ios/ORLib/ORLib'
shared_pods
end
```

Save and close the Podfile.
In the terminal enter the following command

```shell
pod install
```
A xcworkspace file is created after installing the pod. Open this file and Xcode will start.

Click on the `Pods` icon in the project tree and then on ORLib in the targets pane. Search for Require Only App-Extension-Safe API and set it to `No`. A warning will appear which can be ignored.
A xcworkspace file is created after installing the pod.
Open this file and Xcode will start.

Click on the `Pods` icon in the project tree and then on ORLib in the targets pane.
Search for Require Only App-Extension-Safe API and set it to `No`.
A warning will appear which can be ignored.

Open `AppDelegate` in your project and make it inherit from `ORAppDelegate`.
Remove all the code and override `applicationDidFinishLaunchingWithOptions`.
Set the right project values.

Open `AppDelegate` in your project and make it inherit from `ORAppDelegate`. Remove all the code and override `applicationDidFinishLaunchingWithOptions`. Set the right project values.
```cpp
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

Expand All @@ -83,19 +92,25 @@ override func application(_ application: UIApplication, didFinishLaunchingWithOp
}
```
In the `Main.storyboard` add a second ViewController. The initial viewcontroller should be of class ORLoginViewController. The other ViewController should be of class ORViewController.
In the `Main.storyboard` add a second ViewController.
The initial viewcontroller should be of class ORLoginViewController.
The other ViewController should be of class ORViewController.
In the Notification Service Extension target, open `NotificationViewController` and make it inherit from `ORNotificationService`. Remove all the code inside.
In the Notification Service Extension target, open `NotificationViewController` and make it inherit from `ORNotificationService`.
Remove all the code inside.
When using Firebase, download the GoogleService-Info.plist and add it through Xcode. It shuld be placed in the root of the project. Make sure that `copy when needed` is checked when adding.
When using Firebase, download the `GoogleService-Info.plist` and add it through Xcode.
It shuld be placed in the root of the project.
Make sure that `copy when needed` is checked when adding.
Now your iOS app is setup to work with your OpenRemote project!
.
## Push Notifications / FCM setup
Our consoles are able to receive push notifications that are sent by the OpenRemote Manager.<br />
Through Firebase, together with the use of FCM tokens, you can set this up for your own project using your own account.<br />
Our consoles are able to receive push notifications that are sent by the OpenRemote Manager.
Through Firebase, together with the use of FCM tokens, you can set this up for your own project using your own account.
*(steps are unverified)*
### Setup Firebase and client
Expand All @@ -104,12 +119,11 @@ Through Firebase, together with the use of FCM tokens, you can set this up for y
2. When on the 'Project Overview' page, create a new app for your preferred platform; such as Android and iOS.
3. Fill in the correct details for your app, and follow the steps respectively. These should be no different than any other Android/iOS app.
After your config files are placed in the correct folder, (normally `google-services.json` and `GoogleService-info.plist`)<br />
and the Firebase Gradle dependencies have been added to your project, you are good to go!
After your config files are placed in the correct folder, (normally `google-services.json` and `GoogleService-info.plist`) and the Firebase Gradle dependencies have been added to your project, you are good to go!
### Configure Manager to send push notifications
To complete the setup process, you should configure the manager to send push notifications to the correct address on Firebase.<br />
To complete the setup process, you should configure the manager to send push notifications to the correct address on Firebase.
> Be sure that the `OR_FIREBASE_CONFIG_FILE` environment variable is set to the correct path.<br />
> Forks of OpenRemote should be correctly configured, but custom projects might need additional attention.<br />
Expand All @@ -120,21 +134,23 @@ To complete the setup process, you should configure the manager to send push not
3. Generate a new private key for your preferred account; the button will prompt a JSON file download. Store this safely.
4. In your project repository, place the JSON file inside the `/deployment/manager` folder, and rename it to `fcm.json`.
Now you should be set up to send notifications!<br />
Now you should be set up to send notifications!
You can send these programmatically, or by using the Rules feature in the OpenRemote Manager.
### Encrypt Firebase files in your repository (optional, but recommended)
For most projects, you want to keep Firebase related files secret for security reasons.<br />
For most projects, you want to keep Firebase related files secret for security reasons.
We have built-in gradle scripts to help you with this;
1. Open to the `build.gradle` file in the root of your repository.
2. Add/replace the paths specified in the `gradleFileEncrypt` task with the files you want to encrypt.<br />
Normally this is your `fcm.json` file, but also the files related to the consoles like `google-services.json`.
2. Add/replace the paths specified in the `gradleFileEncrypt` task with the files you want to encrypt.
Normally this is your `fcm.json` file, but also the files related to the consoles like `google-services.json`.
3. Double check whether these files you want to encrypt are present in your `.gitignore` files. **This is required.**
4. Generate/specify a password to encrypt the files with, by using the `GFE_PASSWORD` environment variable. Save this somewhere safe.
5. Run the `./gradlew encryptFiles` task
You are now set up!
*To decrypt the files again, you can use the `./gradlew decryptFiles` command.<br />*
*To decrypt the files again, you can use the `./gradlew decryptFiles` command.*
16 changes: 2 additions & 14 deletions docs/developer-guide/working-on-ui-and-apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar_position: 5
# Working on UI and apps

## Overview
Front end applications are [webcomponent](https://www.webcomponents.org/) based using the [lit](https://lit.dev/) library and [Material Design](https://material.io/components?platform=web) for styling. We use a combination of Polymer LIT, Material Design and our own OpenRemote elements. The UI components are [published on NPM](https://www.npmjs.com/~openremote). The applications themselves are composed of our re-usable modular UI components which can be found in the code base in the [ui/component](https://github.com/openremote/openremote/tree/master/ui/component) folder, these are also published to [NPM](https://www.npmjs.com/~openremotedeveloper).
Front end applications are [webcomponent](https://www.webcomponents.org/) based using the [lit](https://lit.dev/) library and [Material Design](https://material.io/components?platform=web) for styling. We use a combination of Polymer LIT, Material Design and our own OpenRemote elements. The UI components are [published on NPM](https://www.npmjs.com/org/openremote). The applications themselves are composed of our re-usable modular UI components which can be found in the code base in the [ui/component](https://github.com/openremote/openremote/tree/master/ui/component) folder, these are also published to [NPM](https://www.npmjs.com/org/openremote).

## Working on an app (e.g. Manager UI)
To work on an app for example the `Manager UI` then `cd` into the app directory e.g. `ui/app/manager` and run the following `npm` script:
Expand Down Expand Up @@ -97,16 +97,4 @@ Apps bring together components and/or public NPM modules and can be written usin
compatible with web components (see [here](https://custom-elements-everywhere.com/)).

### Demos
These are apps for development purposes Generally a 1-1 mapping between components and demos; they provide a simple harness for the components that can be used during development and optionally can be deployed to offer component demos.

## Publishing to NPM
Publishing is done using lockstep versioning; we use yarn version plugin to manage workspace package version incrementing as follows:

1. The public packages are marked for version bump:
`yarn workspaces foreach --no-private --topological version --deferred <patch | minor | major>`
1. The new versions are applied:
`yarn version apply --all`
1. The components are prepared:
`yarn workspaces foreach --no-private --topological npm prepublishOnly`
1. The public packages are packed and published:
`yarn workspaces foreach --no-private --topological npm publish`
These are apps for development purposes Generally a 1-1 mapping between components and demos; they provide a simple harness for the components that can be used during development and optionally can be deployed to offer component demos.
119 changes: 119 additions & 0 deletions docs/user-guide/deploying/release-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Release Management

Software releases are created to be able to run OpenRemote in a reproducible and controlled manner.
All the OpenRemote code is open-source and available on GitHub in repositories in the [OpenRemote](https://github.com/openremote/) organization.

## Manager

The Manager UI and backend is versioned in the [openremote/openremote](https://github.com/openremote/openremote) repository on GitHub.
The code in this repository is used for building the [openremote/manager](https://hub.docker.com/r/openremote/manager) Docker image which is available on Docker Hub.
You can find the release notes of each version on the [Releases](https://github.com/openremote/openremote/releases) page on GitHub.

When using the `openremote/manager` Docker image in production, it is recommended to always use a version tag (e.g. 1.2.0) so you know exactly what version is deployed.

Besides the version tags you can also use the "latest" and "develop" tags which are convenient during testing:

* **latest**: this tag is updated to always contain the most recent release.
* **develop**: this tag is used during development for testing changes before an actual release is created. A new "develop" image is built for every commit pushed to the "master" branch. It is not recommended to use this tag in production because it can be unstable.

## Custom Projects

When using a [custom deployment](custom-deployment) you need to specify what OpenRemote version it customizes.

A custom project always depends on the following versioned OpenRemote Manager artifacts:

* Docker images (published to [Docker Hub](https://hub.docker.com/u/openremote))
* Java code (packaged as JARs, published to [Maven Central](https://search.maven.org/search?q=g:io.openremote))
* TypeScript code (packaged as NPMs, published to [npmjs.com](https://www.npmjs.com/settings/openremote/packages))

All these artifacts share the same version number as they are all created by the [openremote/openremote](https://github.com/openremote/openremote) repository.

### Updating to new a release

When updating a custom project to a new OpenRemote release, you can follow the steps below:

1. Read the [release notes](https://github.com/openremote/openremote/releases) to get familiar with the changes
2. Update the code to use the new version:
1. Docker images: Update the `openremote/manager` image tag in the `docker-compose.yml` file (or environment variable)
2. Java code: Update the `openremoteVersion` in the `gradle.properties` file
3. TypeScript code: Update the openremote package dependencies, e.g. using `yarn up -E "@openremote/*@^1.2.0"`
3. Check that the code in your custom project still builds correctly using: `./gradlew clean installDist`

### Using snapshot artifacts

If you want to use changes before they are released, it is also possible to use development snapshot artifacts in your custom projects instead.
E.g. if the next version will be 1.3.0 use the following versions:

1. Docker images: Update the `openremote/manager` image tag to `develop` in the `docker-compose.yml` file (or environment variable)
2. Java code: Update the `openremoteVersion` to `1.3.0-SNAPSHOT` in the `gradle.properties` file (requires the Maven repository https://s01.oss.sonatype.org/content/repositories/snapshots to be added to your `project.gradle` file)
3. TypeScript code: Update the openremote package dependencies using `yarn up -E "@openremote/*@^1.3.0-snapshot"`

### Using ORLib

Optionally you can also add a custom Android or iOS App using the [mobile consoles](../../developer-guide/working-on-the-mobile-consoles) to your custom project.
For this you can use the ORLib library which simplifies integrating OpenRemote into your App.
ORLib has its own release cycle because it is maintained in separate repositories and is only released when there are changes.

The Android ORLib is maintained in the [console-android](https://github.com/openremote/console-android) repository and published as a JAR to [Maven Central](https://search.maven.org/artifact/io.openremote/orlib).
The iOS ORLib is maintained in the [console-ios](https://github.com/openremote/console-ios) repository and published as a CocoaPod to [Trunk](https://cocoapods.org/pods/orlib).

You can find the release notes for ORLib versions on the "Releases" page of the respective GitHub repositories.

### Migration from submodules to versioned artifacts

Previously Git submodules were used in custom projects for versioning.
This has been replaced with dependencies of versioned artifacts.
Using submodules for versioning is no longer supported.

If you have an exising custom project using submodules, the easiest way to apply all the changes is to create a new custom project using the [template](https://github.com/openremote/custom-project) and add your customizations to it.

Another way to migrate an existing project is to manually apply all changes of the [commit](https://github.com/openremote/custom-project/commit/6f4870c3ae81c7eb00c5b283afe0240790e8b1e6) used for migrating the custom project template.

As you can see in the commit the manual migration steps are:

1. Remove the submodule(s)
2. Add dependencies to the new artifacts in your build.gradle and package.json files
3. Add the new "model" and "rest" UI component module code
4. Update the TypeScript code so classes are loaded from the new modules:
1. Add `import rest from "rest";` to your imports if necessary
2. Replace `manager.rest.api` with `rest.api` where applicable

If you have additional questions regarding this migration, we encourage you to reach out to our [forum](https://forum.openremote.io/).

## Local development practices

### Local artifacts

When developing a custom project you may also need to test changes you make to the manager code before your code gets merged.
You can test your local changes in a custom project by first publishing them to the local Maven repository using:

`./gradlew clean installDist publishToMavenLocal`

Note that the custom project build first resolves artifacts from `mavenLocal()` which is defined in the `project.gradle` file.
So once you publish snapshot artifacts to your local Maven repository these will no longer be downloaded from the https://s01.oss.sonatype.org/content/repositories/snapshots repository.
To undo this, either comment the `mavenLocal()` repository or remove your local artifacts in `~/.m2/repository/io/openremote`.

### Version resolution

The manager build version is resolved based on tags and commits of the Git repository using the Gradle [axion-release-plugin](https://axion-release-plugin.readthedocs.io/en/latest/).
For this to work correctly it is important your local Git repository has all published tags (i.e. use `git pull --tags`).

You can also configure Git to always fetch tags using:

* Per repository: `git config remote.origin.tagOpt --tags`
* Globally: `git config --global fetch.tagOpt --tags`

## Creating releases

The OpenRemote Manager and Android/iOS Console projects are released using a GitHub Actions "Release" workflow (release.yml).

When the release workflow is started it will:

1. Create a tag for the release
2. Create a release with release notes
3. Trigger a CI/CD build to publish all the release artifacts (i.e. Docker images, JARs, NPMs, CocoaPods)

Most of the release process is now automated but after a release some versions still need to be manually updated:

* openremote/openremote: The "version" in the `package.json` files of all modules in the 'ui' directory
* openremote/console-ios: The CocoaPod "version" in the `ORLib/ORLib.podspec` file

0 comments on commit faef860

Please sign in to comment.