© 2021 The original authors.

1. Target Audience

This document is a guide to the setup of Github, preparing and developing changes and contributing to WildFly.

This guide assumes you know how to deal with the CLI of your OS, for example the Linux bash or MacOS zsh.

2. Prerequisites

You are very welcome to improve WildFly, please read why:

2.1. GitHub account

Create a GitHub account if you don’t have one already Signing up for a new GitHub account

Create a Personal Access Token to work with on the command line. Account Security - Creating a personal access token

2.2. Jira account

Create an account for Red Hat’s Jira [https://issues.redhat.com/] Choose "Sign up"

3. Getting started

3.2. Clone

Clone your newly forked copy onto your local workspace

$ git clone git@github.com:[your user]/wildfly.git
Cloning into 'wildfly'...
remote: Counting objects: 533023, done.
remote: Compressing objects: 100% (170/170), done.
remote: Total 533023 (delta 60), reused 0 (delta 0), pack-reused 532777
Receiving objects: 100% (533023/533023), 140.25 MiB | 1.75 MiB/s, done.
Resolving deltas: 100% (210143/210143), done.
Checking connectivity... done.

$ cd wildfly

3.3. Remote

Add a remote ref to upstream, for pulling future updates

git remote add upstream git@github.com:wildfly/wildfly.git

3.4. Safety

As a precaution, disable merge commits to your main

git config branch.main.mergeoptions --ff-only

3.5. Working with git later

3.5.1. Pulling updates

Pulling later updates from upstream

$ git checkout -f main
$ git pull --rebase upstream main
From github.com:wildfly/wildfly
 * branch            main     -> FETCH_HEAD
Updating 3382570..1fa25df
 {parent => bom}/pom.xml                            |   70 ++++----------
 build/pom.xml                                      |   13 +--
 domain/pom.xml                                     |   10 ++
 .../src/main/resources/examples/host-example.xml   |    2 +-
 .../resources/examples/jboss-domain-example.xml    |   28 +++---
 .../main/resources/schema/jboss-domain-common.xsd  |   12 +--
 .../main/resources/schema/jboss-domain-host.xsd    |    2 +-
 domain/src/main/resources/schema/jboss-domain.xsd  |   17 ++--
 pom.xml                                            |  100 ++++++++++++++++++--
 process-manager/pom.xml                            |    3 +-
 10 files changed, 156 insertions(+), 101 deletions(-)
 rename {parent => bom}/pom.xml (85%)

(--rebase will automatically move your local commits, if you have any, on top of the latest branch you pull from, you can leave it off if you do not).

Best practice is to never add your own commits to your local 'main' branch. Instead create a topic branch from 'main' and add commits to your topic branch. Only use your local 'main' to track the current state of the 'upstream' remote’s 'main' branch.

Please note that --rebase is very important if you do have commits. What happens is that when git pull can’t fast forward, it does a merge commit, and a merge commit puts the sucked in changes ON TOP of yours whereas a rebase puts them BELOW yours. In other words a merge commit makes the history a graph, and we prefer a cleaner, easier to follow linear history (hence the rebasing). Further once you do a merge commit it will be difficult to rebase the history before that commit (say you want to combine two commits to one later) as described in "Commit and push". Luckily the option set in step Safety will prevent this from happening.

One way to not forget --rebase the rebase option is you may want to create an alias

 $ git config --global alias.up "pull --rebase"

and then just use the new alias instead of pull

$ git up upstream main

One last option, which some prefer, is to avoid using pull altogether, and just use fetch + rebase (this is of course more typing) For some reasons tags are not updated (e.g. not part of an active branch). Update the tags with

$ git fetch --tags upstream

3.5.2. Rebasing a feature branch

Assume you have a feature branch WFLY-815_upgrade_sample_dep and you have rebased the local main branch to be up to date with upstream main as described before.

git checkout -f WFLY-815_upgrade_sample_dep
git rebase upstream/main

Do not pull the upstream main to your local feature branch! You’ll be stuck in duplicate commit hell.

3.5.3. Push

Pushing pulled updates (or local commits if you aren’t using topic branches) to your private github repo (origin)

$ git push
Counting objects: 192, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (44/44), done.
Writing objects: 100% (100/100), 10.67 KiB, done.
Total 100 (delta 47), reused 100 (delta 47)
To git@github.com:[your user]/wildfly.git
   3382570..1fa25df  main -> main

You might need to say -f to force the changes. Read Topic Branch though before you do it.

If you fetch the tags separately you have to push the tags also. Consider if you need them in your personal GitHub repository.

git push --tags

4. Development environment

5. Maven

Use maven. Simplest is to use the build.sh or build.bat scripts in the root of the source tree. If you don’t use those scripts and use the mvn command directly, note that WildFly’s root pom will enforce a minimum maven version.

Building WildFly requires Java 11 or newer. Make sure you have JAVA_HOME set to point to the JDK11 installation. Build uses Maven 3.

$ ./build.sh
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] WildFly: BOM ..................... SUCCESS [1.834s]
[INFO] WildFly: Parent Aggregator ....... SUCCESS [0.022s]
[INFO] WildFly: Domain Core ............. SUCCESS [3.051s]
[INFO] WildFly: Server Manager .......... SUCCESS [0.204s]
[INFO] WildFly: Server .................. SUCCESS [0.283s]
[INFO] WildFly: Domain Controller ....... SUCCESS [0.084s]
[INFO] WildFly: Process Manager ......... SUCCESS [0.314s]
[INFO] WildFly: Remoting ................ SUCCESS [0.390s]
[INFO] WildFly: Build ................... SUCCESS [5.696s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------

6. Community interaction

Discuss your planned changes (if you want feedback)

Getting feedback first is recommended before starting on any large-scale work. Large scale could mean many things including a complex change in a focused area, or a simple change made in many different parts of the code base.

Getting feedback first is strongly recommended before beginning work on a new feature. Any change that introduces new user-controllable behavior will be regarded as a new feature. Before merging new features we require a larger set of inputs than are required for other types of fixes, including a formal requirements analysis, a more formally considered plan for testing, and appropriate additions to the WildFly documentation. Before getting too far along with a feature it is best to discuss with other WildFly developers what’s needed and how best to ensure those things can be delivered.

7. IDE Integration

7.1. Eclipse

The "formal" rules to format code are based on Eclipse. You can find them here WildFly Core IDE Eclipse Configuration

  1. in Eclipse go to Window → Preferences → Java → Code Style → Formatter.

  2. click Import.

  3. select formatting rules which you have downloaded

Same for cleanup and templates

7.2. IntelliJ IDEA

7.2.1. Code Formatter

There is a plugin for IntelliJ to use the Eclipse formatter: Eclipse Code Formatter

7.2.2. Import WildFly as Maven project in IntelliJ IDEA

Before importing you have to set the VM Options of the IntelliJ Maven importer. Please follow this guide https://www.jetbrains.com/help/idea/maven-importing.html and add -DallTests to the field VM options for importer. This is necessary because the testsuite poms do not contain all necessary modules by default.

8. Jira

Make sure there is a JIRA somewhere for the enhancement/fix

8.1. Good First Issues

Want to contribute to the WildFly project but aren’t quite sure where to start? Check out our issues with the good-first-issue label. These are a triaged set of issues that are great for getting started on our project.

Once you have selected an issue you’d like to work on, make sure it’s not already assigned to someone else. If you’ve resolved a WildFly issue before, to assign an issue to yourself, you should be able to simply click on "Start Progress" or Change the assignee by clicking on "Assign to me". This will automatically assign the issue to you. If you haven’t resolved an issue before, please start a thread expressing your interest in the issue in the wildfly-developers stream in zulip.

8.2. Special cases

For component upgrades select this type for the Jira. The title must reflect the library and the new version. In the description please offer a links to the release notes, the git tag diff.

If you are aware that the component upgrade brings a fix for CVE, it’s good to note that in the JIRA title, as later that will make this information more visible in the WildFly release notes.

Sample title: Upgrade netty.io 4.1.68 (resolves [CVE-2021-37136|https://github.com/advisories/GHSA-grg4-wf29-r9vv], [CVE-2021-37136|https://github.com/advisories/GHSA-grg4-wf29-r9vv])
Jira Body:
Release Notes [https://netty.io/news/2021/09/09/4-1-68-Final.html]
GitDiff [https://github.com/netty/netty/compare/netty-4.1.67.Final...netty-4.1.68.Final]

9. Heaven - Coding

9.1. Topic branch

Create a simple topic branch to isolate that work

git checkout -b WFLY-XXXX_my_cool_feature

9.2. Code

9.2.1. Extending WildFly

There is an excellent documentation and guide Extending WildFly and you can rely on Maven Archetypes to generate a skeleton WildFly Subsystem Archetype.

9.2.2. Adding a new external dependency

Take care that maintainers agree to pick up a new dependency.

  • Edit pom.xml and add a property of the form "version.groupId.artifactId" which contains the Maven version of the dependency. Add your new property in the proper alphabetical order with respect to the existing version properties. Add your dependency to the <dependencyManagement> section, and use the property for the version. If your new dependency has any transitive dependencies, be sure to <exclude> them (or if possible, update the project so that all its dependencies are of provided scope).

  • Add your dependency to any AS modules that require it, but only with group/artifact. If your dependency will be provided by an existing WildFly module, add a new artifact element to the module.xml file for the existing module, with the value of the element’s name attribute an expression of the form ${groupId:artifactId}

  • In the pom.xml file for the maven module where you added a new module.xml or updated an existing one for your new dependency, add a new dependency entry to the pom’s dependencies section.

  • If your dependency will be provided by a new WildFly module, create a directory in the relevant feature-pack maven module, e.g. ee-feature-pack/common/src/main/resources/modules/system/layers/base/ corresponding to the module’s name (which will differ from the Maven group/artifact name; look at other modules to get a feel for the naming scheme), with a version of "main", like this: modules/system/layers/base/org/jboss/foo/main. If the correct maven module to choose for your new directory is unclear, be sure to ask!

  • Create a module.xml file inside the "main" directory. Use a module.xml from another similar module as a template. JBoss Modules Reference Documentation

  • Important: Make sure you did not introduce any transitive dependencies by using "mvn dependency:tree". If you did, be sure to add <exclusion>s for each of them to your dependency as described above.

  • Important: Do not introduce a dependency on the "system" module. The JBoss Modules reference manual lists JDK packages. Please avoid deprecated packages.

  • Add license information to the license declaration file located in the maven module whose pom you just updated. For example, if you added a dependency entry to ee-feature-pack/common/pom.xml, please add an entry to ee-feature-pack/common/src/license/ee-feature-pack-common-licenses.xml. Add a new element in the appropriate spot. The elements are ordered by the maven groupId and artifactId of the entries. If the needed content for the entry is unclear, be sure to ask!

9.2.3. Commit and push

Make the changes and commit one or more times (Don’t forget to push)

git commit -m 'WFLY-XXXX Frunubucate the Fromungulator'
First time: git push --set-upstream origin WFLY-XXXX_my_cool_feature
Second and ongoing: git push origin WFLY-XXXX_my_cool_feature

Note that git push references the branch you are pushing and defaults to main, not your working branch.

9.3. Rebase topic branch on latest main

Rebase your branch against the latest main (applies your patches on top of main)

git fetch upstream
git rebase -i upstream/main
# if you have conflicts fix them and rerun rebase
# The -f, forces the push, alters history, see note below
git push -f origin WFLY-XXXX_my_cool_feature

The -i triggers an interactive update which also allows you to combine commits, alter commit messages etc. It’s a good idea to make the commit log very nice for external consumption. Note that this alters history, which while great for making a clean patch, is unfriendly to anyone who has forked your branch. Therefore you want to make sure that you either work in a branch that you don’t share, or if you do share it, tell them you are about to revise the branch history (and thus, they will then need to rebase on top of your branch once you push it out).

10. Quality and Testing

A must read is the WildFly Testsuite documentation. It will save you time and nerves.

10.1. Checkstyle Errors

If you need to first verify that your changes pass the checkstyle audit, do this first.

mvn checkstyle:checkstyle

Then you can proceed with the build.

10.2. How do I ensure that my code does not blow up the testsuite?

First try to run the tests as part of the build before sending a pull request.

$> ./build.sh clean install -DallTests

Sometimes there are test failures that are not related to your code changes. Most times it’s your code change. Try to discuss this on Zulip.

You can get a full run using

$> ./build.sh clean install -DallTests -fae

This additional option will allow the build to continue even when there are test failures. Doing this, you can get a stock of all the test failures and figure out how many are related to your code changes.

11. Pull requests to upstream

Get your changes merged into upstream

  • Read the documentation to ensure that you follow a good Pull Request Standards WildFly Pull Request Standards and Guidelines

  • Make sure your repo is in sync with other unrelated changes in upstream before requesting your changes be merged into upstream by repeating Rebase topic branch on latest main.

  • Send a github pull request, by clicking the pull request link while in your repo’s fork. Quickstart - Create a pull request

  • In general, WildFly maintainers are watching the project, so they will receive a notification on each new PR.

  • As part of the review you may see an automated test run comment on your request.

  • After review a maintainer will merge your patch, update/resolve issues by request, and reply when complete

  • Don’t forget to switch back to main and pull the updates

git checkout main
git pull --ff-only upstream main

Update the main branch of your github repository (otherwise you will see a message like 'Your branch is ahead of 'origin/main' by XXX commits.' if you use 'git status' on your local main branch.

git push origin main

12. WildFly Pull Request Standards and Guidelines

12.1. Describe the pull request adequately

The PR title should include a JIRA number directly from the project in question, whose corresponding JIRA issue will in turn have been linked to the pull request you are just now creating. The description should include a link to the JIRA. The description should also include a decent, human-readable summary of what is changing. Proper spelling and grammar is a plus!

Sample PR [WFLY-815] This is the sample title

12.1.1. Commit message

The commit message for each commit should also reference a JIRA number.

12.2. Make sure it builds and tests pass first

It is highly annoying to reviewers when they find they’ve spent a great deal of time reviewing some code only to discover that it doesn’t even compile. In particular, it’s common for a patch to trip CheckStyle if it hadn’t been previously compile-tested at the least.

While it is tempting to rely on the automated CI/GitHub integration to do our build and test for us (and I’m guilty of having done this too), it generally just causes trouble, so please don’t do it!

12.3. Separate your changes - but not too much

This comes directly from [1], and I agree with it 100% (where the source document says "patch", think "commit"):

Separate each logical change into a separate patch. For example, if your changes include both bug fixes and performance enhancements for a single driver, separate those changes into two or more patches. If your changes include an API update, and a new driver which uses that new API, separate those into two patches. On the other hand, if you make a single change to numerous files, group those changes into a single patch. Thus a single logical change is contained within a single patch. The point to remember is that each patch should make an easily understood change that can be verified by reviewers. Each patch should be justifiable on its own merits. If one patch depends on another patch in order for a change to be complete, that is OK. Simply note "this patch depends on patch X" in your patch description. When dividing your change into a series of patches, take special care to ensure that [WildFly] builds and runs properly after each patch in the series. Developers using "git bisect" to track down a problem can end up splitting your patch series at any point; they will not thank you if you introduce bugs in the middle. If you cannot condense your patch set into a smaller set of patches, then only post say 15 or so at a time and wait for review and integration.

I also want to emphasize how important it is to separate functional and non-functional changes. The latter category includes reformatting (which generally should not be done without a strong justification).

12.3.1. Creating per maven-module subtasks and doing one subtask per PR

If you have one logical change (for example you’re removing manual null checks and put a JDK or utility method instead) which affects more than one top-level maven module, please split them by top-level maven module. For the logical change description use a top level JIRA (Bug, task, enhancement) and add sub-task for each top-level maven module.

Reason behind: WildFly and WildFly Core have a really huge codebase with several different full-time maintainers to review and approve the code. Afterward different project leads and/or release stewards do merge and Jira management work.

If there is a serious reason to deviate from this rule, please ask before on Zulip.

12.4. Avoid massive and/or "stream of consciousness" branches

We all know that development can sometimes be an iterative process, and we learn as we go. Nonetheless, we do not need or want a complete record of all the highs and lows in the history of every change (for example, an "add foobar" commit followed later by a "remove foobar" commit in the same PR) - particularly for large changes or in large projects (like WildFly proper). It is good practice for such change authors to go back and rearrange and/or restructure the commits of a pull request such that they incrementally introduce the change in a logical manner, as one single conceptual change per PR.

Note that this advice is not meant to discourage multiple commits in a single PR that are all steps on the way to an overall complex change. To the contrary, multiple well structured commits are sometimes critical to getting proper review of complex changes. For example a PR to refactor code away from an ill-fitting set of abstractions and to a new set can be difficult to review in a single commit. But doing so can be quite straightforward when broken up into, for example, four commits, one to make some small change to clean up something that would get in the way of the overall change, one introducing the new abstractions, one moving the implementation to the new abstractions, and one removing the old abstractions.

If a PR consists of dozens or hundreds of nontrivial commits, you will want to strongly consider dividing it up into multiple PRs, as PRs of this size simply cannot be effectively reviewed. They will either be merged without adequate review, or outright ignored or closed. Which one is worse, I leave to your imagination.

12.5. Pay attention and respond to review comments

While in general it is my experience that WildFly contributors are good about this, I’m going to quote this passage from [1] regardless:

Your patch will almost certainly get comments from reviewers on ways in which the patch can be improved. You must respond to those comments; ignoring reviewers is a good way to get ignored in return. […​] Be sure to tell the reviewers what changes you are making and to thank them for their time. Code review is a tiring and time-consuming process, and reviewers sometimes get grumpy. Even in that case, though, respond politely and address the problems they have pointed out.

In addition, when something needs to be changed, the proper manner to do so is generally to modify the original commit, not to add more commits to the chain to fix issues as they’re reported. See Avoid massive and/or "stream of consciousness" branches.

12.6. Don’t get discouraged

It may come to pass that you have to iterate on your pull request many times before it is considered acceptable. Don’t be discouraged by this - instead, consider that to be a sign that the reviewers care highly about the quality of the code base. At the same time though, consider that it is frustrating for reviewers to have to say the same things over and over again, so please do take care to provide as high-quality submissions as possible, and see Pay attention and respond to review comments!

12.7. You can review code too!

You don’t have to be an official reviewer in order to review a pull request. If you see a pull request dealing with an area you are familiar with, feel free to examine it and comment as needed. In addition, all pull requests need to be reviewed for basic (non-machine-verifiable) correctness, including noticing bad code, NPE risks, and anti-patterns as well as "boring stuff" like spelling and grammar and documentation.

If you review a PR and you feel you understand it in total and that it is correct, it is helpful to the WildFly mergers if you use the 'Approve' option discussed in the Github pull request review documentation. Don’t worry that your approval will trigger automatic merging; it won’t. It’s just easier for others to see that you regard the PR as correct if you use the Github workflow. (Please don’t, however, use the 'Approve' option if you are not expressing an approval of the PR overall; e.g. if you only looked at one part and made some comments that were addressed. Use comments for that kind of input.)

If you do review a pull request and make suggestions for changes, please do pay attention to the PR and try to acknowledge if your suggestions have been resolved. This is particularly important if it won’t be quickly obvious to others if your input was addressed.

12.8. On major refactorings

When doing major and/or long-term refactors, while rare, it is possible that the above constraints become impractical, especially with regard to grouping changes. In this case, you can use a work branch on a (GitHub) fork of WildFly, applying the above rules in micro-scale to just that branch. In this case you could possibly ask a reviewer to also review some or all of the pull requests to that branch. Merge commits would then be used to periodically synchronize with upstream.

In this way, when the long-term branch is ready to "come home" to the main branch, the reviewers may have a good idea that the (potentially quite numerous) changes in the work branch have been reviewed already.