This website is centralizing all resources useful for eXo developers and contributors.

1. Sources Management

1.1. Git - Repositories

1.1.1. Platform codebase

1.1.1.1. Platform 5

eXo Platform is built from several projects stored in different Git repositories. You will find below the list of repositories used to build eXo Platform 5.

Platform Components
Figure 1. Overview of eXo Components for PLF 5.0
platform-public-distributions

Main project used to package the standalone community edition based on Apache Tomcat 8.

platform

eXo Platform

integration

Integration of eXo services

calendar

eXo Calendar

forum

eXo Forum

wiki

eXo Wiki

social

eXo Social

ecms

eXo Content Management System

commons

Commons services

platform-ui

eXo Platform UI customizations

GateIn Portal

GateIn Portal

GateIn SSO

GateIn SSO

GateIn PC

GateIn PC

JCR

eXo JCR

WS

eXo WS

Core

eXo Core

Kernel

eXo Kernel

GateIn WCI

GateIn WCI

1.1.1.2. Platform 4
Platform 4.4 Components
Figure 2. Overview of eXo Components for PLF 4.4

1.2. Git - Settings

1.2.1. GitHub

GitHub is the platform we chose to host our Git repositories. To contribute to eXo projects you have to create a GitHub account.

For eXo employees it is recommended to create one with the same username as the one provided by the company (GoogleApp Id) when you joined us. You have to commit using your exoplatform.com email by setting it in your global git configuration or locally into each eXo repository clone (see below).

To retrieve your rights to push changes or to pull private repositories you have to register your github account into your profile in our internal IDM My eXo.

GitHub provides a lot of documentation and especially an installation/configuration guide for each operating system :

Please follow these guides to setup your environment.

1.2.2. Git Configuration

It is recommended to create an SSH private key (with a password) and to use it to access to your Git(Hub) repositories (see Github guides above).

By default you have at least to setup your default identity that will be used for all git instances on the system if you don’t override them locally.

git config --global user.name "John Doe"
git config --global user.email "jdoe@exoplatform.com"

We recommend also :

  • to configure git to activate use colors if you terminal supports it :

git config color.ui true
  • to configure git to push only the current branch by default to avoid to send to the server some changes in others branches you weren’t ready to share

git config --global push.default current
  • to setup line endings preferences for Unix/Mac users

git config --global core.autocrlf input
git config --global core.safecrlf true
  • to setup line endings preferences for Windows users

git config --global core.autocrlf true
git config --global core.safecrlf true
  • to reduce the number of files to consider when performing rename detection during a merge. The merge is working pretty well on small repositories (with move and rename of files). But it’s not working on large repositories as the detection of file renaming is O(n²), so we need to update some threshold (more explanations are available in this post : http://blogs.atlassian.com/2011/10/confluence_git_rename_merge_oh_my/) :

 git config --global merge.renameLimit 10000
  • to configure git to add some command aliases to easily call them with git <ALIAS_NAME>. You just add a section [alias] in your ~/.gitconfig file with entries like bellow

[alias]

[source]
##### Basic aliases
# Long status
st = status
# Short status
s = status -s
# Show all branches
br = branch -a
# Show branches with commit message
sb = show-branch
# Commit
ci = commit
# Checkout
co = checkout
# Show remote repositories
r  = remote -v
# Amend last commit
amend = ci --amend
# Removes files/directories from staging
unadd = rm -r --cached

##### Diff aliases
# Diff and show commands with word-diff style
wd = diff --word-diff
ws = show --word-diff
# Show diff before pull
do = diff ORIG_HEAD HEAD
# Show modified lines in the index
staged = diff --cached
# Show modified files
changes= diff --name-status -r
# Diff with statistics
ds = diff --stat -r

##### Log aliases
# Show HEAD commit
head = log --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative -n1
# Short one line logs with ref-names
l  = log --oneline --decorate=short
# Shows the last git logentry (hash, author, date commitmessage)
llm = log -1
# Short one line logs with ref-names and statistics
gl = log --oneline --decorate --stat --graph
# Short one line logs with ref-names (yellow, date (green) and author (blue)
glog = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
# Show last commit
lc = log ORIG_HEAD.. --stat --no-merges
# Graph log with full commit message
glaaa = log --graph --abbrev-commit --date=relative

##### Misc
# Show last commiter
whois = !sh -c 'git log -i -1 --pretty=\"format:%an <%ae>\n\" --author=\"$1\"' -
# Show last commit message
whatis = show -s --pretty='tformat:%h (%s, %ad)' --date=short
# Hash of HEAD
h = rev-list --max-count=1 HEAD
# Show users which have commits in current branch
ul = !git log --format='%aN' | sort -u
# Number of commits in current branch
c  = !git log --oneline | wc -l
# Creates a tar.gz archive named after the last commits hash from HEAD! in the directory above the repository
ahg = !git archive HEAD --format=tar | gzip > ../`git h`.tar.gz
# shows ignored directories
ignored = !git ls-files --others -i --exclude-standard --directory
# Move to the root of the repository
root = !cd $(git rev-parse --show-cdup)
# Show the root directory of the repository
sroot = rev-parse --show-toplevel
# Prune remote branches
prune-all = !git remote | xargs -n 1 git remote prune
# Show aliases
aliases = !git config --get-regexp 'alias.*' | colrm 1 6 | sed 's/[ ]/ = /'
# Show upstream for the current branch
upstream = !git for-each-ref --format='%(upstream:short)' `git symbolic-ref HEAD`

1.2.3. Git & IDEs

Git is natively supported by all IDE :

1.3. Git - Workflow

Our workflow is built on two principles :

  • The repository architecture (development vs blessed) that has to be followed by all projects involved in products produced eXo (and thus that require to be supported).

  • The branching model that has to be followed by all projects at eXo

1.3.1. Repository architecture

Aiming security and backup purpose, we are using two repository kinds (owned by two distinct github organizations).

These are blessed and development repositories hosted respectively on exoplatform and exodev organizations.

Development repositories are forked from blessed repositories.

This strategy is applied to all repositories/projects involved in eXo products. Others projects are using a single repository hosted on "exoplatform" organization.

Git Organization
Figure 3. Git Repository Architecture
1.3.1.1. Development repository

This repository is the developers repository. The main development branch is develop branch. Depending the contribution kind (one shot contribution or feature contribution), the developer can use a dedicated feature branch if needed. The most of development activity will be done in this repository by a lot of contributors :

  • maintainers (formerly known as sl3) : To develop fix. These developments are done in dedicated fix branches (more details below).

  • all development teams : To do one shot contribution and handle feature branch life cycle.

In this repository, develop branch and feature branch will be under CI.

1.3.1.2. Blessed repository

In this repository you can find stable branches and release tags. Only some people are able to write on this repository :

  • maintainers : To integrate pull request on stable branches.

  • release manager : To perform release operations on stable (supported) branches.

  • keepers : Repository keepers are Project Leader, Team Leader and Technical Leader. They are able to pull changes from dev to blessed when the develop is stable enough and they can process releases for non supported versions of products (alpha, beta, RCs, …)

The continuous integration is applied on stables branches (stable/1.0.x, stable/1.1.x, etc) on blessed repository.

1.3.2. Branching model

Branching model are 6 kinds of branch :

  • develop : Develop branch contains the latest delivered development changes.

  • feature/xxx : Feature branches are dedicated branch for one big feature (lot of commits), "xxx" is the feature name.

  • stable/xxx : Stable branch are used to perform releases and write / accept fix. "xxx" is the stable version name (e.g 1.0.x).

  • fix/xxx : Fix branch is dedicated to integrate bugfix on Develop branch. If needed the fix is then cherry pick on stable branch.

  • integration/xxx : Integration branches are dedicated branch to automatic integration task (like Crowdin translation).

  • poc/xxx : Poc branches are dedicated branch to develop a Prove of Concept (PoC).

1.3.2.1. Develop Branch

Develop branch contains the latest delivered development changes. This is our backbone where all the different fix and new feature are mixed with each other.

Git Workflow - Develop Branch
Figure 4. Git Workflow - Develop Branch

1.3.3. Feature Branch

Feature branches are dedicated branch to develop a new feature.

Git Workflow - Feature Branch
Figure 5. Git Workflow - Feature Branch
1.3.3.1. Actions
Create a new Feature Branch

When: A new feature is specified and planified.

Who: PL/TL

How:

  • If you want the branch deploy on Acceptance, do not create the branch by yourself but create a SWF ticket on Jira for the full package (Branches+CI+Acceptance).

  • If it’s a local feature project without need for CI or Acceptance you can create it by yourself.

Rebase Develop to Feature Branch

When: Frequently

Who: Team responsible of the branch with support of team responsible each project.

How:

git checkout develop
git pull
git checkout feature/x
git rebase develop
git push --force
Merge Feature Branch to Develop

When: Feature has been successfully tested by FQA. VPs give a GO.

Who: Team responsible of the branch with support of team responsible of each project

How:

git checkout feature/x
git rebase -i origin/develop
(remove initial commit)
git checkout develop
git pull
git merge --no-ff feature/x
git push
Remove a Feature Branch

When: Just after the merge of the feature branch to Develop

Who: PL/TL

How: Create SWF ticket on Jira to remove the full package (Branches+CI+Acceptance).

1.3.4. Fix Branch

Fix Branch are dedicated branch to fix a bug. The validation process may be different if the bug has been raised by FQA/TQA or by SM.

A fix branch is always created from Develop branch (except exceptional circumstance: fix on stable only).

Git Workflow - Fix Branch
Figure 6. Git Workflow - Fix Branch
1.3.4.1. Actions
Create a Fix Branch

When: A Jira issue has been created, time to resolve it is already estimated.

Who: Team responsible to fix the issue.

How:

git checkout develop
git pull
git checkout -b fix/issue
git push
Merge a Fix Branch to Develop

When:

  • If issue raised by TQA/FQA: After Engineering test

  • If issue raised by SM: After SM test

Who:

  • If issue raised by TQA/FQA: Team responsible to fix the issue

  • If issue raised by SM: SM

How:

git checkout fix/issue
git pull
git rebase origin/develop
git checkout develop
git pull
git merge fix/issue --squash
git commit -a
git push
Remove a Fix Branch

When: After the merge of the fix branch to Develop

Who: Team responsible to fix the issue.

How:

git push origin --delete fix/issue
git branch -d fix/issue

1.3.5. Stable Branch

Stable branch are used to perform releases and write / accept fix.

Git Workflow - Stable Branch
Figure 7. Git Workflow - Stable Branch
1.3.5.1. Actions
Create a new Stable Branch

When: When create the first Release Candidate version

Who: SWF

How: With a script similar to [createFB.sh](github.com/exoplatform/swf-scripts/blob/master/createFB.sh)

Create a Fix Branch to fix Stable Branch

In exceptional circumstance

When: A fix need to be done on a specific version but not on the on development version (fix a performance issue for instance)

Who: Team responsible to fix the issue after a Go from SM.

How:

git checkout stable/4.1.x
git pull
git checkout -b fix/4.1.x-issue
Merge a Fix Branch to Stable

In exceptional circumstance

When: After SM test

Who: SM Team

How:

git checkout fix/4.1.x-issue
git checkout stable/4.1.x
git pull
git merge fix/4.1.x-issue --squash
git commit -a
git push
Remove a Fix Branch

When: After the merge of the fix branch to stable branch

Who: SM

How:

git push origin --delete fix/4.1.x-issue
git branch -d fix/4.1.x-issue
Perform a release

When: After FQA/TQA test campaign. VPs give a GO.

Who: Release managers

How:

git clone git@github.com:exoplatform/xxx.git
cd xxx
# You checkout the release branch on which you need to perform a release.
git checkout stable/A.B.x
# You follow the classical maven release process
mvn release:prepare
mvn release:perform
Move a release tag

In really special case (when the test campaign show a critical issue after tagging but before nexus publishing) release manager still can apply a last minute commit and move the tag.

When: After FQA/TQA test campaign. VPs give a GO.

Who: Release managers

How:

# After your commit, just delete the remote tag, and create another one in this way
git tag -d 1.0.0
git push origin :refs/tags/1.0.0
git tag 1.0.0
git push origin 1.0.0

1.3.6. Integration Branch

Integration branches are dedicated branch to automatic integration task (like Crowdin translation for instance).

1.3.6.1. Actions
Create a new Integration Branch

When: Whenever an integration is needed with a third-party system.

Who: SWF

How:

git checkout develop
git pull
git checkout -b integration/my-integration
git push

1.3.7. PoC Branch

Engineering

Poc branches are dedicated branch to develop a Prove of Concept (PoC).

Git Workflow - POC Branch
Figure 8. Git Workflow - POC Branch
1.3.7.1. Actions
Create a new PoC Branch

When: A new PoC is planified.

Who: PL/TL

How:

$ git checkout develop
$ git pull
$ git checkout -b poc/x
[Modify all pom: initial commit]
$ git add pom.xml
$ git commit -m "details"
$ git push

1.3.8. Release Process

A release must never involve a freeze of the develop branch. This section explain the release process to follow when doing an intermediate release (Milestone, Release Candidate) or the final release.

1.3.8.1. Intermediate Release

When: Product Leader give a go to do an intermediate release of PLF (Milestone, Release Candidate)

Who: PLF Team with support of team responsible of each project

Intermediate Release
Figure 9. Intermediate Release
1.3.8.2. Final Release

When: Product Leader give a go to do the final release of PLF

Who: PLF Team with support of team responsible of each project

Final Release process

1.3.9. Improvement

1.3.9.1. What is changing compare to 4.1
  • Clean history by using git rebase.

  • No more weekly merge between develop and master.

  • All fixes are push firstly to develop branch. Then SM backport what they need to stable.

  • Rebase develop to feature branch:

    • To do it regularly

    • To do it ONLY if develop branch is ok : build + acceptance are ok otherwise you’ll distribute shitty code everywhere

    • To do it for all projects in a given FB at the same time (to keep the coherency)

  • No more master branch on exodev repository. Master is only on blessed repository.

1.4. Git - Cheat Sheet

Git Big Picture

1.4.1. Features

1.4.1.1. Create

From existing data

cd  <DIRECTORY>
git init
git add .
git commit

From existing repo

git clone <EXISTING_REPO> <NEW_REPO>

default protocol is ssh EXISTING_REPO is a local path or a remote URL, for examples :

1.4.1.2. Update

Fetch latest changes from origin

git fetch

this does not merge them

Pull latest changes from origin

git pull

does a fetch followed by a merge

In case of conflict, resolve the conflict and

git am —resolve
1.4.1.3. Track Files

Start tracking files

git add <FILES>

Interactive selection of files to track

git add -i

Move/Rename a file

git mv <OLD_NAME> <NEW_NAME>
git mv <OLD_PATH> <NEW_PATH>

Stop tracking and delete files in working directories

git rm <FILES>

Stop tracking but keep files in working directory

git rm —cached <FILES>
1.4.1.4. Commit

Commit all local changes

git commit -a +

Commit messages

Commits must relate to a JIRA issue. Convention for messages inspired by this article :

  • The first line must be short (50 chars or less) and auto-descriptive in a format " ", for example AM-101 : Fix the behavior of archives download

  • Write your commit message in the present tense: Fix bug and not Fixed bug.

  • The second line is blank.

  • Next lines optionally define a short summary of changes (wrap them to about 72 chars or so).

Example :

AM-101 : Fix the behavior of archives download

* —no-cache has no effect on it
* The add-ons manager always retry to download the archive from the
downloadUrl. The download is skipped if the local file exists, it has
the same size as the remote one and its modifiedDate is > to the remote
one (It will allow to install new SNAPSHOTs without enforcing to
download the archive each time)
* The same behavior is applied for all URLs (http(s), file) +
1.4.1.5. Publish

Prepare a patch for other developers

git format-patch origin

Push changes to origin

git push origin <BRANCH>

Use option --all to push all local references (branches, tags..), --tags to push all tags, --force to push non fast-forward changes (must be avoided to not risk to loose commits)

Make a version or milestone

git tag <TAG_NAME>
1.4.1.6. Branch

List all branches

git branch

Switch to the BRANCH branch

git checkout <BRANCH>

Merge branch B1 into branch B2

git checkout <B2>
git merge <B1>

Create branch based on HEAD

git branch <BRANCH>

Create branch based on another

git branch <NEW> <BASE>

Delete a local branch

git branch -d <BRANCH>

Delete a remote branch

git push <origin> :<BRANCH>
1.4.1.7. Remote

List all your remote repositories

$ git remote -v
origin git@github.com:exodev/platform (fetch)
origin git@github.com:exodev/platform (push)

Add a new remote repository

git remote add upstream git@github.com:exoplatform/platform.git

Rename a remote repository

git remote rename upstream foo

Delete a remote repository

git remote rm upstream foo
1.4.1.8. Browse

Files changed in working directory

git status

Changes to tracked files

git diff

Changes between ID1 and ID2

git diff <ID1> <ID2>

History of changes

git log

Who changed what and when in a file

git blame <FILE>

A commit identified by ID

git show <ID>

A specific file from a specific ID

git diff <ID>:<FILE>

Search for patterns

git grep <PATTERN> <PATH>
1.4.1.9. Revert

Return to the last committed state

git checkout -f | git reset —hard

you cannot undo a hard reset

Revert the last commit

git revert HEAD

Creates a new commit

Revert specific commit

git revert <ID>

Creates a new commit

Fix the last commit

git commit -a —amend

after editing the broken files

Checkout the ID version of a file

git checkout <ID> <FILE>

Restoring lost commits

So, you just did a git reset --hard HEAD^ and threw out your last commit. Well, it turns out you really did need those changes. You’ll never be able to implement that algorithm that perfectly twice, so you need it back. Don’t fear, git should still have your commit. When you do a reset, the commit you threw out goes to a dangling state. It’s still in git’s datastore, waiting for the next garbage collection to clean it up. So unless you’ve ran a git gc since you tossed it, you should be in the clear to restore it.

git cherry-pick ORIG_HEAD

HEAD vs ORIG_HEAD

ORIG_HEAD is previous state of HEAD, set by commands that have possibly dangerous behavior, to be easy to revert them. It is less useful now that Git has reflog: HEAD@{1} is roughly equivalent to ORIG_HEAD (HEAD@{1} is always last value of HEAD, ORIG_HEAD is last value of HEAD before dangerous operation).

Removing a File from Every Commit (Powerful filter-branch)

This occurs fairly commonly. Someone accidentally commits a huge binary file with a thoughtless git add ., and you want to remove it everywhere. Perhaps you accidentally committed a file that contained a password, and you want to make your project open source. filter-branch is the tool you probably want to use to scrub your entire history. To remove a file named passwords.txt from your entire history, you can use the --tree-filter option to filter-branch:

git filter-branch —tree-filter 'rm -f passwords.txt' HEAD

The --tree-filter option runs the specified command after each checkout of the project and then recommits the results. In this case, you remove a file called passwords.txt from every snapshot, whether it exists or not. If you want to remove all accidentally committed editor backup files, you can run something like git filter-branch --tree-filter 'rm -f *~' HEAD. Using --index-filter with git rm yields a significantly faster version. Like with using rm filename, git rm --cached filename will fail if the file is absent from the tree of a commit. If you want to completely forget a file, it does not matter when it entered history, so we also add --ignore-unmatch:

git filter-branch —index-filter 'git rm —cached —ignore-unmatch passwords.txt' HEAD

1.5. Contributions

1.5.1. Workflow

The contribution workflow mainly relies on Github Pull Requests.

1.5.1.1. Creating the PR

Once a contribution is ready to be shared, commit the changes (see Commits messages best practices for Commits best practices) and create a PR. Creating a PR is easy and allows to share, discuss and validate more easily the contribution. To create a PR :

  • create a branch locally with your fix and push it to Github

  • in Github, select your branch, and click on New pull request Git PR Create

  • select the right base branch (most of the time develop) and check that the PR contains only your commits Git PR Create

  • fill the description ! See Pull Requests best practices for more details.

  • click on Create pull request

PR must always be done on exodev:develop or exo-addons:develop, not on exoplatform:develop (we fix on develop first, then we backport to stable if needed). There are only 2 exceptions :

  • the fix is different between develop and stable - in such a case, 2 PRs are necessary, one on develop, one on stable

  • the bug only occurs on stable - in such a case, the PR must be done on stable

1.5.1.2. Setting the PR as ready to be reviewed

After having submitted a PR, the developer must change the status of the related Jira issue to PR Review by clicking on the button review needed. The link to the PR must be set in the field Git Pull Request.

If the fix is composed of several PRs, all the PR links must be set in the field Git Pull Request, separated by semicolons. If the list of PRs is too long, it can exceed the max length of this field. In such a case, list all the PRs links in a comment of the Jira issue, and set the permalink of this comment in the field Git Pull Request.

1.5.1.3. Reviewing the PR

When a PR is submitted, it has to be reviewed by at least one peer.

Please refer to the chapter Contributions reviews to learn more about review best practices.

During the review iterations, the developer may have to update the contribution. In order to update a PR, just push a new commit in the same branch, no need to create a new branch and a new PR. Creating a new PR for each update prevents from following easily the discussion and the updates history.

Code Review does NOT mean Test, Reviewers are NOT Testers
The role of the reviewers is to review the code changes (code best practices, better/easier solution, …​). They do not necessarily have to test (they can if they want/need of course). The author of the PR must not rely on the reviewers to test it, he/she is responsible for that (and the QA people will help during their test campaigns).
1.5.1.4. Automatic checks on PR

Besides reviews by peer, all PR are submitted to the following automatic checks:

  • compilation - Each time a PR is submitted or updated, the project is compiled. If the compilation fails, the PR is automatically rejected.

  • unit tests - Each time a PR is submitted or updated, the unit tests are executed. If at least one test fails, the PR is automatically rejected.

  • minimum test coverage - Each time a PR is submitted or updated, a check is done on test coverage to make sure it does not decrease (see Test coverage for more details). If the new test coverage is lower than the one set in the Maven configuration, the PR is automatically rejected.

1.5.1.5. Merging the PR

When the PR has been validated by the peer and has passed all the automatic checks, the PR can be merged in the target branch. Before merging the PR in the target branch, make sure the branch of the PR is up to date (rebase && push --force), otherwise the PR will not appear as Merged in Github.

Git PR Merged

1.5.1.6. Cleaning the mess

Once the PR has been merged, delete the branch in Github, and close the PR if it is not already marked as Merged or Closed.

1.5.2. Community Contributions

Anyone with a Github account can contribute to eXo Platform. The only difference for people outside of the eXo Platform organization is they must sign a Contribution License Agreement. The Contributor License Agreement is needed to clarify the terms of usage of contributions by eXo Platform and the entire open source community.

The CLA must be printed, signed, then scanned as a PDF file and sent at cla@exoplatform.com.

1.5.3. Commits messages best practices

It is often important to browse the source code history to understand when and why a change has been done. Good commits message are therefore crucial to help developers in maintaining a code base. In order to improve the quality of the commit messages, the following rules must be respected:

  • use

    git commit

    instead of

    git commit -m “My commit message”

    when committing a change, in order to write a more detailed commit message and use the commit template

  • the commit message must start with a line containing a short subject (max 100 characters) which starts by the Jira issue number and then describes briefly what the commit does. For example : PLF-7916 : Make Setting Service cache ayncInvalidation

  • the commit subject must not be a copy/paste of the Jira issue summary. As said previously, it must describe what the commit does, as if the sentence would start with “If applied, this commit will …​”.

  • after the subject, one blank line must be added before starting the body

  • the body describes in details what the commit does and must answer 2 questions : why is this change needed and how does this change address the issue. It should give as much information as possible to make it easy for another developer who does not know deeply the context to understand the commit. Therefore the body is never too long.

  • after the body, a list of links to relevant resources can be added (optional). It must be separated from the body by one blank line.

Here is an example of commit message following these rules:

PLF-8070 : remove useless configuration about settings and notifications services

At first access after startup, if the eXo instance has never been registered, the servlet /registration/software-register is called, then the servlet /registration/software-register-action when clicking on a button.
The servlet /registration/software-register-action needs to read and update a setting, so it needs the service org.exoplatform.commons.api.settings.SettingService.
The JPA implementation of this service needs the EntityManagerService to fetch data, which is available only in the PortalContainer.
And the available container when accessing the servlet is actually the RootContainer.
In PLF 5.0.0-M10 (in which the bug does not occur), the SettingService implementation used is the cached impl (org.exoplatform.settings.cache.CacheSettingServiceImpl), and when we call the get method to read a settings, it calls the method org.exoplatform.commons.api.settings.data.SettingContext#getCurrentRepositoryName which creates the PortalContainer instance by calling PortalContainer.getInstance().
Therefore, luckily, when the EntityManagerService is retrieved from the container, the current container is the PortalContainer and it is available and everything works fine.

From SOC-5917, a configuration has been added in social project which changes the implementation of the SettingService from the cached one to org.exoplatform.settings.jpa.JPAUserSettingServiceImpl :  25c143c#diff-a874bcc27e08363c8bcf7f9ce8eab5a7R346
And this implementation never calls PortalContainer.getInstance(), which means the container available in the servlet is the RootContainer which does not contain EntityManagerService, which makes the setting read fails.

This fix removes the configuration added in SOC-5917 about settings, so the cached impl will be used again.
Also, a fix in the servlet is done (in the platform project) to ensure that the PortalContainer is created when fetching the setting, no matter what the implementation of SettingService.

Of course, all commit messages do not need to be that long, but it must contain all relevant information to understand what and why the changes have been done.

In order to help developers, a template is available.

Template

# <jira-issue-id>: (If applied, this commit will...) <subject>
# |<----  Using a Maximum Of 100 Characters  ---->|

# Why is this change needed?
# Prior to this change, ...
# How does it address the issue?
# This change ...
# |<----   Try To Limit Each Line to a Maximum Of 72 Characters   ---->|

# Provide links or keys to any relevant tickets, articles or other resources

# --------------------
# Remember to
#    Capitalize the subject line
#    Use the imperative mood in the subject line
#    Do not end the subject line with a period
#    Separate subject from body with a blank line
#    Use the body to explain what and why vs. how
#    Can use multiple lines with "-" for bullet points in body
# --------------------

How to apply it

The template can be applied globally with the following command:

git config --global commit.template <.git-commit-template.txt file path>

For example, if you saved it to your home folder, try:

git config --global commit.template ~/.git-commit-template.txt

You can also apply it on a particular project by running it at the root of the project, and without the --global option:

git config commit.template <.git-commit-template.txt file path>

1.5.4. Pull Requests best practices

As well as good commits messages are important for code base maintainers, good PRs descriptions are important for reviewers. It helps to understand what the developer has done and why. The PR title must start with the Jira issue, then describe briefly what the PR does. For example : PLF-7916 : Make Setting Service cache ayncInvalidation

The PR description must at least provide the information given in the commit message body : why is this change needed and how does this change address the issue (Tip: using the first line of the commit message as the PR title and the commit message body as the PR description is a good start for the PR description).

It can also give the following information when relevant:

  • Alternative solutions tried and why they failed

  • Any question, remark or doubt that the developer has

  • Tested environments (tomcat/jboss, databases, ldap, browsers, addons, …)

  • Links to resources which can help to understand the contribution

The PR does not need to describe the issue (functional impacts, reproduction steps, …​) since it is already done in the related Jira issue.

1.5.5. Contributions reviews

1.5.5.1. How to ask for reviewers ?

After having submitted a PR, the developer must change the status of the related Jira issue to “PR Review” by clicking on the button “review needed”. The link to the PR must be set in the field “Git Pull Request”.

If the fix is composed of several PRs, all the PR links must be set in the field “Git Pull Request”, separated by semicolons. If the list of PRs is too long, it can exceed the max length of this field. In such a case, list all the PRs links in a comment of the Jira issue, and set the permalink of this comment in the field “Git Pull Request”.

Once the jira is set as “PR Review”, others developers are supposed to review it in a reasonable delay. If the developer wants to ask a specific person or some specific persons to do the review, the field “Reviewers” of the Github PR can be used:

Git PR Ask Reviewers

1.5.5.2. How to do a review ?

The reviewers must use the review feature of Github to do the review. On the first comment, the button “Start review” must be used. Then, once the review is done, the developer must submit the review by clicking on the button “Review changes”, then select the right option:

  • Comment: the review contains only remarks or questions which ask for clarifications but do not necessarily ask for changes

  • Approve: the PR is approved

  • Request changes: the review contains at least a comment asking for a change in the PR

If the option Approve is selected, the PR is validated, and the Jira issue status must be changed to Merge. If the option Comment or Request changes is selected, the PR is not validated, and the Jira issue status must be changed to PR Refused.

1.5.5.3. What should I care when reviewing a Pull Request ?

When reviewing a Pull Request, the following things must be checked:

  • Correctness of the fix/feature

  • Learning

  • Coding best practices

  • Unit Tests

  • Security

  • Performance

  • Maintainability

  • Troubleshooting

  • Upgrades

  • API breaking

  • Code formatting (if not yet automated)

  • Documentation

This list does not only apply to reviewers, but also to contributors!
Correctness of the fix/feature

Most of the time of the review must be spent to understand the ultimate goals of the code changes, which means going back to the issue and understanding how it is fixed. The reviewer must check if the PR fixes the issue, as well as if it handles correctly corner cases and if it does not add regressions or unexpected impacts on related features.

Also, even if the PR review is not QA, if there is any doubt on the correctness of the fix/feature, it should be tested.

Correctment does not only mean that the PR fixes the issue, but also that it is the most adequate and simple solution. The reviewer should not hesitate to propose any others solutions or questions to exchange with the committer and make sure it is the right solution to apply.

Learning

The review is not only a process to validate others people code, it is also an ideal moment to learn from them. Reviewers are encouraged to ask any question if there is something they do not understand or want more details on.

Coding best practices

The reviewer must check the PR follows the best practices described in the eXo Coding Best Practices (WIP). Beyond this document, the reviewer must check the PR follows the best practices generally admitted in software development. If a practice is not described in the eXo Coding Best Practices document and is used in the PR, it is a good opportunity to discuss about it and add it if necessary in the document.

Unit Tests

Unit Tests are essential to minimize regressions. The reviewer must check that unit tests are implemented to cover the related bug or the feature, especially:

  • Are the test titles adequately descriptive?

  • Are the key scenarios captured?

  • Are there enough edge cases covered for comfort?

  • Are the tests written with good assertions?

  • If a test fails, would it be easy to track down the error?

  • Are the tests independent from each others (especially if they manage data)?

The reviewer must also ensure that the unit tests coverage minimum ratio defined in Maven configuration (see Test coverage for more details) is not decreased and advise to increase it if the test coverage has been improved.

Security

The reviewer must check that the contribution does not introduce security issues, especially in the following areas:

  • Data/Input Validation of data from all untrusted sources

    All input data must be validated before being used and/or stored in the system (UI forms, REST APIs inputs, …).

  • Authentication

  • Session Management

  • Authorization

    All the resources of the system (web pages, documents, REST APIs, …) must only be accessible by the authorized population.

  • Cryptography (Data at rest and in transit)

    Sensitive information must not be transmitted or persisted in clear text. Also, secure method must be used for cryptography (for example do not use MD5 to encode users’ passwords).

  • Error Handling / Information Leakage

    Sensitive information should not end up in error messages (logs, UI, …). For example do not include passwords or security tokens in logs.

  • Logging / Auditing

    Some operations require logging/auditing to allow to understand what happened during a security breach or detect security issues as they happen.

Performance

The reviewer must try to detect if the fix/feature could have significant bad impacts on the performances of the application. Performances issues can be expensive to find and fix, so it is important to raise any concern on this topic at this stage. Here are some examples of performance issues causes: too many database requests, slow database query, missing index in the database, too many HTTP requests, …​

Maintainability

The maintainability measure how easy it is to make changes in a code base (fixing bugs, adding new features, replacing a faulty or obsolete component, …​). This means:

  • Tests are implemented to ensure a good test coverage and help understand how code should behave

  • Classes and methods have a clear and single responsibility

  • Classes, methods and variables names are self-descriptive and/or well documented

  • Classes and methods are short

  • Cyclomatic complexity of a method should be low

  • Components are loosely coupled

  • Code duplication should be avoided

  • Code must respect formatting rules

More generally, if it was hard for the reviewer to understand, the code should probably be reworked to make it easy to understand since it means it will be hard to understand for next developers in the future.

Troubleshooting

When problems occur in production, it is generally not possible to debug or to update easily the code to find the cause. Therefore, the developer must try to anticipate the potential issues and provide the information and/or tools to help finding the error cause and fixing it. The reviewer must evaluate if the contribution contains the right elements to help this troubleshooting. Here are some examples of question to answer:

  • Is there enough logs ?

  • Do the logs have the appropriate level ?

  • If relevant, in case of problem, is there any tool (JMX bean, …) to gather more information or to recover ?

Upgrades

Any contribution must be considered to be installed on an existing environment. In such a case it must be ensured that the upgrade is done as transparently as possible:

  • If data are impacted, an upgrade plugin must be developed

  • If any configuration change is required, the documentation and the upgrade notes must be updated

API breaking

API must be stable and can be broken only in major releases. Contributions targeted to minor or maintenance versions must not break the public API. Public API includes:

  • Java API

  • REST API

  • Javascript API

  • Configuration

Documentation

A documentation Jira issue must be opened as soon as the fix or the new feature has an impact on the documentation. For example:

  • New feature to be described

  • Update of the behavior of an existing feature

  • API change

  • Configuration change

The documentation issue must be as detailed as possible (especially for technical documentation items) to ease the work of the documentation writer.

1.5.5.4. How to know if someone is not already reviewing a PR ?

You cannot (except by talking to your colleagues of course 😉), there is no status for such a thing in Github and Jira, and we don’t need it. It is not a problem if several persons review the same PR. It means more feedbacks, more learning, … therefore it is all positive.

1.5.6. Tips for …

1.5.6.1. …​ contributors
  • Provide descriptive PR title and description

    Once again, the more explanation the contributor gives about a PR, the easiest it will be for the reviewer to understand and therefore to review. This will save a lot of time for all people.

  • Make small PRs

    Beyond a certain amount of lines of code, the review becomes very difficult to be done efficiently.

  • Don’t get it personally

    People can feel personally offended by others people’s comments. It is important to understand that the comments and criticisms are related to the code, not to the person.

1.5.6.2. …​ reviewers
  • Understand and agree to the Prime Directive

    The Prime Directive states that “Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand.”

  • Use the right tone

    Kindness is a keyword when doing reviews, but it is not always sufficient. The written language is a difficult art since it is not always easy to see the tone and the intuition behind the words, so it must be done carefully. Here are some examples:

    • Instead of “This is the wrong way to structure the test. There are too many cases in this test.”, prefer “I think it would help with readability to split this test into multiple tests.”

    • Instead of “These 3 lines really belong in a separate method.”, prefer “What do you think about extracting these lines into another method to isolate the calculation logic?”

    • Avoid words like “just” which assumes the contributors missed something obvious.

  • It’s OK to say “It’s all good”

    The reviewer does not have to find an issue in every review.

  • Take your time

    It is important to understand what the contributor did and why before validating a contribution, so the reviewer must take his/her time to do the review.

1.5.6.3. …​ contributors and reviewers
  • Adopt a positive attitude

    A review is not a fight to know who is right and who is wrong, it is a collaboration process to provide the best contribution for the given issue. It is important that both contributors and reviewers adopt of a positive attitude with constructive criticisms to achieve this goal.

  • Switch to live review whenever it is necessary

    When the review takes too much time or when the reviewer and/or the contributor feel the need to switch to a live review, it should be done. It is sometimes more efficient to discuss some minutes. The important point is to write the conclusion of the discussion in the PR comments to let everybody know it.

2. IDE Settings to work on eXo Platform projects

2.1. Eclipse - Settings

Eclipse settings are available in /resources/ide/eclipse.

Configure Eclipse at "Window" → "Preferences…"

2.1.1. Clean Up Settings:

Java → Code Style → Clean Up

Choose: "Import…" exo-Java-CodeStyle-CleanUp.xml

Eclipse Clean Up Settings

2.1.2. Code Templates Settings:

Java → Code Style → Code Templates

Eclipse Code Style Settings

2.1.3. Formatter Settings:

Java → Code Style → Formatter

Choose: "Import…" exo-Java-CodeStyle-Formatter.xml

Eclipse Formatter Cleanup

2.1.4. Organize Imports Settings:

Java → Code Style → Organize Imports

Eclipse Organize Imports Settings

2.2. IntelliJ - Settings

Intellij IDEA users must install the plugin Eclipse Code Formatter and import Eclipse settings files from /resources/ide/eclipse.

IntelliJ Eclipse Code Formatter

3. Build Management

3.1. Maven - Setup guide

3.1.1. Prerequisites

To build eXo projects you need to install a Java JDK 6, 7 or 8 depending of the Platform version you are targeting :

  • Platform 5.0: Java 8 / Maven 3.3.9

  • Platform 4.4+ : Java 8 / Maven 3.2.x (PLF & GateIn components) / Maven 3.0.x (CF components)

  • Platform 4.1 / 4.2 / 4.3 : Java 7 / Maven 3.2.x (PLF) / Maven 3.0.x (GateIn & CF components)

  • Platform 4.0.x : Java 6

3.1.2. Install Apache Maven

The version 3.3.9 of Apache Maven is currently recommended to build eXo projects.

The minimal version required is 3.0.4.
The version 3.2.2 must be avoided due to MNG-5663.
  1. Download a fresh and clean copy of Apache Maven. It is critical to take a fresh copy to be sure that the file apache-maven-X.Y.Z/conf/settings.xml isn’t modified !!

  2. Unzip the distribution archive, i.e. apache-maven-X.Y.Z-bin.(zip|tar.gz) to the directory you wish to install Maven. The subdirectory apache-maven-X.Y.Z will be created from the archive. It is recommended to not store it under a path with spaces.

  3. Add the path of apache-maven-X.Y.Z/bin in your PATH environment variable.

    • On Windows use the preferences screen of "Environment Variables"

    • On Linux/MacOS export the variable PATH from a startup script like .bash_profile (it depends of the OS and the shell you are using)

  4. Add a system environment variable MAVEN_OPTS (it could be in a .profile startup script on Linux/MacOS operating systems or in the global environment variables panel on Windows)with the value -Xshare:auto -Xms128M -Xmx1G -XX:MaxPermSize=256M

  5. Run mvn --version to verify that it is correctly installed.

Maven and MacOSX

Apple provides for several years now, Maven as a standard tool in MacOSX distributions. You can see the version provided with mvn --version. You can find where the mvn script is located with which mvn (in theory in /usr/bin). It recommended to deactivate the one provided with MacOS X to use the one you’ll define yourself. Take care if you upgrade your system, because Apple can restore the default version on your system. To deactivate the Maven version bundled in OSX, just remove the symlink : sudo rm /usr/bin/mvn

3.1.3. Configure Apache Maven

3.1.3.1. Basic setup

Since Platform 4, no specific settings are required to build eXo public projects. Just clone any project and launch mvn install

3.1.3.2. Advanced setup

If you need to release a project or to build a project relying on private or staging binaries you’ll need to customize your maven settings.

Using our template create a file settings.xml in your home directory under a directory called .m2 (if you already launched maven this directory must already exist and it should contain a subdirectory repository where Maven stores all artifacts it processes).

<?xml version="1.0" encoding="UTF-8"?>
<settings
  xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <servers>
    <!-- eXo Platform credentials -->
    <!-- Used to upload binaries on repository.exoplatform.org -->
    <server>
      <id>repository.exoplatform.org</id>
      <username><!-- Your eXo LDAP/Crowd Identifier --></username>
      <password><!-- Your eXo LDAP/Crowd Password --></password>
    </server>
    <!-- Used to download private binaries from repository.exoplatform.org -->
    <server>
      <id>exo.private</id>
      <username><!-- Your eXo LDAP/Crowd Identifier --></username>
      <password><!-- Your eXo LDAP/Crowd Password --></password>
    </server>
    <!-- Used to download staging binaries from repository.exoplatform.org -->
    <server>
      <id>exo.staging</id>
      <username><!-- Your eXo LDAP/Crowd Identifier --></username>
      <password><!-- Your eXo LDAP/Crowd Password --></password>
    </server>
    <!-- Used to download custom projects binaries from repository.exoplatform.org -->
    <server>
      <id>exo.cp</id>
      <username><!-- Your eXo LDAP/Crowd Identifier --></username>
      <password><!-- Your eXo LDAP/Crowd Password --></password>
    </server>
    <!-- Used to release projects on repository.jboss.org -->
     <server>
      <id>jboss-releases-repository</id>
      <username><!-- Your JBoss.org Identifier --></username>
      <password><!-- Your JBoss.org Password --></password>
    </server>
  </servers>
  <mirrors>
    <mirror>
      <id>exo-mirror</id>
      <mirrorOf>external:*,!exo.private,!exo.cp,!exo.staging</mirrorOf>
      <url>https://repository.exoplatform.org/public</url>
    </mirror>
  </mirrors>
  <profiles>
    <profile>
      <id>exo-central</id>
      <!-- This "hack" change the behavior of maven to let it use our public mirror
      as the central repository (with snapshots activation).
      The URL is never used and is overrided by the mirror entry.
      -->
      <repositories>
        <repository>
          <id>central</id>
          <url>http://fake</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>central</id>
          <url>http://fake</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
    <!-- Specific settings used while releasing a project -->
    <profile>
      <id>exo-release</id>
      <properties>
        <gpg.keyname><!-- The GPG Key to use to sign eXo releases --></gpg.keyname>
        <gpg.passphrase><!-- The passphrase of your GPG Key --></gpg.passphrase>
      </properties>
    </profile>
    <profile>
      <id>exo-private</id>
      <!-- Repositories to download eXo private binaries -->
      <repositories>
        <repository>
          <id>exo.private</id>
          <url>https://repository.exoplatform.org/private</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>exo.private</id>
          <url>https://repository.exoplatform.org/private</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
    <profile>
      <!-- Repositories to download eXo custom projects binaries and products patchs -->
      <id>exo-cp</id>
      <repositories>
        <repository>
          <id>exo.cp</id>
          <url>https://repository.exoplatform.org/cp</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>exo.cp</id>
          <url>https://repository.exoplatform.org/cp</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
    <profile>
      <id>exo-staging</id>
      <!-- Repositories to download eXo staging binairies -->
      <!-- TAKE CARE TO ACTIVATE IT ONLY IF REQUIRED -->
      <!-- These repositories are delivering binaries marked as released but allowed to be replaced -->
      <!-- Maven never updates released binaries thus you have to cleanup your local repository to grab an updated version -->
      <repositories>
        <repository>
          <id>exo.staging</id>
          <url>https://repository.exoplatform.org/staging</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>exo.staging</id>
          <url>https://repository.exoplatform.org/staging</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
    <profile>
      <id>jboss-staging</id>
      <!-- Repositories to download JBoss staging binairies -->
      <!-- TAKE CARE TO ACTIVATE IT ONLY IF REQUIRED -->
      <!-- These repositories are delivering binaries marked as released but allowed to be replaced -->
      <!-- Maven never updates released binaries thus you have to cleanup your local repository to grab an updated version -->
      <repositories>
        <repository>
          <id>jboss.staging</id>
          <url>https://repository.jboss.org/nexus/content/groups/staging/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>jboss.staging</id>
          <url>https://repository.jboss.org/nexus/content/groups/staging/</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
    <!-- This profile is always activated and let you define properties for dependent environment stuffs -->
    <profile>
      <id>local-properties</id>
      <properties>
        <!--
        <exo.projects.directory.dependencies>${user.home}/Applications</exo.projects.directory.dependencies>
        <exo.projects.app.tomcat.version>apache-tomcat-6.0.29</exo.projects.app.tomcat.version>
        <exo.projects.app.jboss.version>jboss-5.1.0.GA</exo.projects.app.jboss.version>
        -->
      </properties>
    </profile>
  </profiles>
  <activeProfiles>
    <!-- make these profiles active all the time -->
    <activeProfile>exo-central</activeProfile>
    <activeProfile>local-properties</activeProfile>
  </activeProfiles>
</settings>

In the ~/.m2/settings.xml configuration file you have to fill your credentials to access to protected binaries or to publish artifacts on repository.exoplatform.org. For a better security, you can encrypt passwords in your settings file, however you must first configure a master password. For more information on both server passwords and the master password, see the Guide to password encryption and the dedicated chapter in the Maven Reference Guide. To release a project you have also to define the GPG key to use and its passphase (see the GPG setup guide).

When your setup is done you can activate the following profiles :

  • -Pexo-release : Automatically activated while releasing projects. This profile is also activated on our CI server. Your GPG key must be configured (see the GPG setup guide).

  • -Pexo-private : To access to private binaries on repository.exoplatform.org (eXo employees only).

  • -Pexo-staging : To access to staging binaries (releases in validation) on repository.exoplatform.org (eXo employees only). TAKE CARE TO ACTIVATE IT ONLY IF REQUIRED. These repositories are delivering binaries considered by maven as released but allowed to be replaced. Maven never updates released binaries thus you have to cleanup your local repository to grab an updated version.

  • -Pexo-cp : To access to custom projects binaries on repository.exoplatform.org (eXo employees only).

  • -Pjboss-staging : To access to staging binaries on repository.jboss.org. TAKE CARE TO ACTIVATE IT ONLY IF REQUIRED. These repositories are delivering binaries considered by maven as released but allowed to be replaced. Maven never updates released binaries thus you have to cleanup your local repository to grab an updated version.

3.1.3.3. Maven and GPG
Install gnupg for your OS.
MacOS

For homebrew users :

brew install gnupg

For macport users :

sudo port install gnupg

Others, you can use the native package.

Ubuntu
sudo aptitude install gnupg
Windows

TBD

Validate your installation
$ gpg --version
gpg (GnuPG) 1.4.10
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html[http://gnu.org/licenses/gpl.html]
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, RSA-E, RSA-S, ELG-E, DSA
Cipher: 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128,
 CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
Generate your private GPG Key
Configure GPG

Enforce the level of encryption. Edit ~/.gnupg/gpg.conf

$ vi .gnupg/gpg.conf

At the end of the file add :

personal-digest-preferences SHA512
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
Generate the key

Launch the key generation

$ gpg --gen-key

ALWAYS SELECT DEFAULT CHOICES AND DON’T USE AN EMPTY PASSPHRASE

Enter your personal information like here :

Your key is created.

You can list the key you just generated with :

$ gpg --list-key
pub 4096R/2CF0CC82 2009-11-17
uid Arnaud Héritier (eXo Platform CODE SIGNING KEY) arnaud.heritier@exoplatform.com
sub 4096R/37540EAE 2009-11-17

You send your key to a PGP server (you use the ID from the "pub" line)

$ gpg --keyserver hkp://pgp.mit.edu[hkp://pgp.mit.edu] --send-keys 2CF0CC82

Your GPG key is now ready to be used

Configure your GPG Key for Maven

Fill the GPG keyname and passphrase in the exo-release profile of your maven settings like described in Advanced settings

 <profile>
   <id>exo-release</id>
   <properties>
     <gpg.keyname>2CF0CC82</gpg.keyname><!-- This is the public ID is displayed with the gpg list-key command described above -->
     <gpg.passphrase>My awesome passphrase</gpg.passphrase>
   </properties>
 </profile>
Test it

Clone this project : git@github.com:exodev/maven-sandbox-project.git

Launch the command : mvn install -Pexo-release

You should see .asc files installed along others artifacts in the target directory of the project

To end tests, try to release this project : mvn release:prepare followed by mvn release:perform.

You are ready. Your environment is setup to do a release with GPG signature.

Don’t forget to logon into https://repository.exoplatform.org and drop your staging repository

3.2. Maven - Checks

When building a project, beyond compilation and packaging, some checks are performed.

3.2.1. Unit tests

When a project is built, the unit tests are automatically executed. If one of the unit tests fails, the project build fails.

3.2.2. Test coverage

When a project is built on our Continuous Integration server, a check is done on the test coverage ratio to make sure it does not decrease. The test coverage ratio is set in each Maven module in the property exo.test.coverage.ratio. For example

<properties>
  <exo.test.coverage.ratio>0.72</exo.test.coverage.ratio>
</properties>

The value is set between 0.0 (0%) and 1.0 (100%). If the new test coverage is lower than the one set in the Maven configuration, the PR is automatically rejected. The rules to change this test coverage ratio are:

  • it can NEVER be decreased

  • when a developer increases the test coverage, he CAN (but this is highly recommended) increase the ratio.

  • ratio must always be defined with a 2 digits precision (for example 0.64, not 0.6)

3.2.2.1. How to run this check locally

The test coverage check is triggered when the coverage Maven profile is activated. Therefore, in order to run this check locally, you must activate this profile:

mvn clean install -Pcoverage

In case the check passes succesfully, you will see this kind of message:

[INFO] --- jacoco-maven-plugin:0.7.6.201602180812:check (check-coverage) @ platform-component-organization ---
[INFO] Analyzed bundle 'eXo PLF:: Platform - Organization Model Integration' with 36 classes
[INFO] All coverage checks have been met.

In case the check fails, you will see this kind of message:

[INFO] --- jacoco-maven-plugin:0.7.6.201602180812:check (check-coverage) @ platform-component-organization ---
[INFO] Analyzed bundle 'eXo PLF:: Platform - Organization Model Integration' with 36 classes
[WARNING] Rule violated for bundle eXo PLF:: Platform - Organization Model Integration: instructions covered ratio is 0.34, but expected minimum is 0.35
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
3.2.2.2. How to check if the ration can be increased in a module

According to the rules about the minimum test coverage ratio update, if a contributor increases the test coverage ratio, he/she can update the minimum ratio. But Maven does not give the actual value in its standard output (console). Instead, this value is available in the jacoco reports, in target/site/test-coverage-ut/index.html. Here is an example:

Test Coverage Report

This report gives the test coverage on each package and the total test coverage of the Maven module. This last value is the one checked during the test coverage check. If this value is higher than the one set in the prooperty exo.test.coverage.ratio, it can be updated in the pom.xml.

4. Development

4.1. Test

eXo Platform is delivered as a zip bundle, built on every commit, and available in our maven repository and in our acceptance platform.

If you want to test the zip bundle with one of the supported databases, it is recommended to use the available Docker images.

4.1.1. Databases

eXo Platform uses by default an HSQLDB database. eXo Platform supports several RDBMS databases, each of them in multiple versions. In order to test easily all these versions, it is recommended to use Docker containers.

First, setup eXo to connect to your database following the eXo documentation. Then start the database container.

4.1.1.1. MySQL

There is no specific Docker image for MySQL for eXo, you should use the official image from Docker hub. For example this command starts a MySQL database server exposed on the default port (3306) and creates a database plf :

docker run -d --name mysql-5.7.22 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=plf -e MYSQL_DATABASE=plf mysql:5.7.22

You can connect from your eXo instance with the user root and the password plf. Please refer to the Docker hub page for full details and configuration options.

4.1.1.2. PostgreSQL

There is no specific Docker image for PostgreSQL for eXo, you should use the official image from Docker hub. For example this command starts a PostgreSQL 9.6.6 database server exposed on the default port (5432) and creates a database plf :

docker run -d --name postgres-9.6.6 -p 5432:5432 -e POSTGRES_PASSWORD=plf -e POSTGRES_DB=plf postgres:9.6.6

You can connect from your eXo instance with the user postgres and the password plf. Please refer to the Docker hub page for full details and configuration options.

4.1.1.3. Oracle

A Docker image for Oracle database has been created and pushed to Docker hub for testing purpose. Here is a command example to start an Oracle 12cR2 database server exposed on the default port (1521) with a database plf :

docker run -d --name oracle -p 1521:1521 exoplatform/oracle:12cR2_plf

You can connect from your eXo instance with the SID plf, the user plf and the password plf. Please refer to the Docker hub page for full details and configuration options.

4.1.1.4. SQL Server

A Docker image for SQL Sserver database has been created and pushed to Docker hub for testing purpose. Here is a command example to start a SQL Server 2017 database server exposed on the default port (1433) and creates a database plf :

docker run -d --name sqlserver -p 1433:1433 -e SA_PASSWORD=Mypassword1 -e SQLSERVER_DATABASE=plf -e SQLSERVER_USER=plf -e SQLSERVER_PASSWORD=Mypassword1 exoplatform/sqlserver:2017-CU2

You can connect from your eXo instance with the the user plf and the password Mypassword1 (All your password must match the SQL Server rule : at least 8 chars, with lower, upper and digits). Please refer to the Docker hub page for full details and configuration options.

4.2. Translations

All the translations are managed in Crowdin. For each PLF version, a Crowdin project is created and linked. A synchronization between the eXo source code and Crowdin is performed once per day.

4.2.1. How to update an existing translation string?

Updating a string must be done in Crowdin directly (if it is done in the source code, it will be reset by the next synchronization). Once validated the translated string will be pushed in the sources during the next synchronization.

4.2.2. How to add a new translation string in an existing localization file?

In order to add a new string, simply add it in the master localization file. The master localization file is the file without a language suffix if it exists, for example resources.properties. Otherwise it is the english version, for example resources_en.properties. It will automatically be added in Crowdin during the next synchronization. You can add the string in others localization files, for testing purpose, but it will be reset during the next synchronization.

4.2.3. How to delete a translation string?

Deleting a string must be done in the sources by simply removing the string in all the localization files containing this string. The string will be automatically deleted in Crowdin during the next synchronization.

4.2.4. How to add a new localization file?

All localization files of a given project must be referenced in the file translations.properties located at the root of the project. Each line must be formatted as follows:

crowdin-path=source-path

where

  • crowdin-path is the path of the localization file in Crowdin relative to the root of the Crowdin project

  • source-path is the path of the english (en) localization file in the project sources, relative to the value of the property "baseDir"

For example:

baseDir=platform/calendar/
webapp/CalendarPortlet.properties=calendar-webapp/src/main/resources/locale/portlet/calendar/CalendarPortlet_en.properties

IntellIJ IDEA      

Crowdin      

JProfiler