We use git for source control. The core projects:
follow this model for branching:
test_develop
in Jenkins ensures our tests are passing at all times for various configurations.git cherry-pick -x
into this branch.And this is how these projects tag each stable release point:
git cherry-pick -x
into this tag.We do not force push to any of these branches. If a commit must be reverted, use git revert
, and push the reverted commit.
Core projects have a linear history (like this). A way to achieve this is to never create merge commits, by always rebasing your changes with develop git pull --rebase upstream develop
. This allows us to easily revert our code to any point in time, which is helpful to detect in what commit we introduced an error using git bisect
.
We encourage developers to adopt this strategy for managing their repositories because git linear history makes it very easy to rollback or reverse a certain commit without getting conflicts. It also makes it easier to cherry pick commits for a stable release.
Changelogs are generated by scripts, see an example here
The purpose of the Foreman coding standards is to create a baseline for collaboration and review within various aspects of the Foreman project and community, from core code to plugins.
Coding standards help avoid common coding errors, improve the readability of code, and simplify modification. They ensure that files within the project appear as if they were created by a single person.
All pull requests need to have an associated issue in the Foreman issue tracker.
Foreman’s PR processor will parse all pull requests, assign labels, and run tests for all major projects. Pull requests are always rebased on top of the develop branch so that the git log stays linear.
Provide a brief description of the change in the first line (50 chars or less), including a issue number.
The title must start with Fixes #xxxx
. If your fix extends a previous fix that has not been shipped in a release, use Refs #xxxx
. Our PR processor will understand these formats and will auto associate the pull request with the issue in the tracker.
You can use the following model:
Fixes #9999 - launch mars probe in V2 API
Some collaboration between teams will be necessary to accomplish this
task. Other features, #2932 and #2933 will be closed after this. V1
changes to the API were not necessary.
Insert a single blank line after the first line.
Optionally, include more detailed explanatory text if necessary and wrap it to about 72 characters or so. On some editors, git commit
automatically wraps the text to these limits as you type in.
Ensure the description is of the change and not the bug title, e.g. “X now accepts Y when doing Z” rather than “Z throws error”.
If the commit that you are adding fixes multiple, distinct issues you can follow this example:
Fixes #9998,#9999 - launch mars probe in V2 API
Some collaboration between teams will be necessary to accomplish this
task. Other features, #2932 and #2933 will be closed after this. V1
changes to the API were not necessary.
We follow the Ruby Style Guide and the Rails Style Guide. We use Rubocop (in Jenkins) to enforce most of these rules. New projects such as plugins should enforce all Rubocop rules and disabling them should be done under a very specific circumstances.
blank?
over empty?
for strings.authorized
.Foreman::Exception
validates :name, :uniqueness => true, :presence => true
.html.erb
extension.%>
instead of -%>
ActiveSupport::Concern
fully, with no class_eval, InstanceMethods etc.:mark_translated: true
in config/settings.yaml
to spot missing string i18n extractions..present?
over .nil?
. Only use the latter if you are truly checking for nil, which is uncommon.:only_explicit
when added to scoped search.Foreman::WrappedException
Foreman::Exception
make sure the ERF code is displayed to the user. Update the Error Codes wiki with possible fixes for the ERF code.:success, :not_authorized, etc...
, instead of actual HTTP status codes..to_sym
, .send
, eval
or other reflection on untrusted inputs.Foreman::Exception
.We are supporting and encouraging the use of ES2015. (For more information see Learn ES2015.) For browser compatibility, we use Babel to transform the code to es5.
We use eslint to enforce linting rules. Run eslint by typing npm run lint
in the command line at the root directory.
window.tfm
object as implemented in bundle.js
.tfm.tools.deprecate
function.Node modules shared between Foreman and plugins are contained in a separate repository, foreman-js. This repository contains several NPM packages which are listed in Foreman’s package.json
as dependencies. For more info, view the README for that repository.
The latest lint rules for foreman can be found here. See ESLint Rules for more information regarding rule configuration.
It is possible to disable a specific rule temporarily. You should have a good reason for doing this. For more information see Configuring ESLint.
We use MiniTest::Unit syntax.
test 'description' do
instead of def test_description
assert_empty variable
instead of assert variable.empty?
. These assertions produce errors that are easier to read.:success, :not_authorized, etc...
, instead of actual HTTP status codes.create
unless necessary, and use build
instead. The former will save the object to the database (slow), the latter keeps the object in memory (faster and garbage collectible)context
block, or write a helper that takes in the changes through arguments and generates the tests.setup_user
if you need to create a user with special permissions and roles instead of doing it yourself in the test.rails test
rails test <relative-path-to-file>
i.e rails test test/model/host_test.rb
rails test <path-to-test>:<linenumber-of-testcase>
i.e rails test test/model/host_test.rb:8
require 'test_plugin_helper.rb'
), use require_relative
, otherwise rails will fail at finding the files that have been required. For a good example see this PR.bundle exec rails test ~/dev/plugins/foreman_plugin/test/models/model_test.rb
. Its not yet known why the absolute path is needed for plugin tests - feel free to push a PR ;)All date and time information should be saved in UTC to the database, for consistency. Similarly, all date and time information shown to users must either take into account the user time zone (accessible through User.current.timezone) or not specify anything. Foreman’s controllers will call ‘set_timezone’ upon every request, which is a method that will automatically set a time zone and modify Time objects in Ruby to use it.
Be mindful of our Translating guide. A quick overview:
_('My string')
_("String with param: %s") % param
_("Params: %s and %s") % [param1, param2]
which is translator-unfriendly_("Params: %{a} and %{b}") % {:a => foo, :b => bar}
N_("String")
n_("One", "Two", number)
- note this function always accepts three parameters as the base language is usually English but translators are able to define as many plural forms as they need.n_("%s minute", "%s minutes", @param) % @param
_('Test <%%= %{var1} %%>') % { :var1 => "xxx" }
"blah #{_('key')} blah"
__
and n__
functions are available and work in much the same way as in Ruby, with the following exceptions..tfm.i18n.sprintf
on the translated string, so for a single parameter: tfm.i18n.sprintff(__("Foo: %s"), "bar")
tfm.i18n.sprintf(__("Example: %(foo) %(bar)"), {foo: "a", bar: "b"})
npm run storybook
We review pull requests on GitHub. Most projects have one or two maintainers that review pull requests. Everyone is invited to review code.
Write a good description, a good title, and explain why the change is necessary. A line or two explaining the problem, the solution, and a way to reproduce the issue (extra points if it’s a script) help enormously.
Assume reviewers have no idea or background about your patch. Even if the usual reviewers know you personally and you know they know why your change is necessary, maybe not all reviewers are aware of it. Furthermore, after some time, they might not remember well, and new reviewers will not be able to review your code without background and a good explanation.
Generally, if you want to submit significant changes to the code, discuss it first on #theforeman-dev:matrix.org (Matrix) or the Development board on our forum. If you know who are the usual maintainers for the code you want to change, try to ask them to validate your assumptions, your design, and if they can, ask them to review your code. This will save you a lot of going back and forth with reviewers that do not understand the reasoning behind your pull request.
Submit changes incrementally. If you are submitting a pull request that will break compatibility with older APIs, spend the effort to make it compatible first. If you think your feature is not ready for prime time yet, it’s OK to submit small changes and hide the feature using feature flags.
Feel free to bring the attention of reviewers by calling them using ‘@’ on GitHub.
Remember the old saying, you are not your code. Reviewers will be consistent with style and good practice, and it’s important to know you’re not being criticised personally when that happens.
Simply start reviewing patches - as detailed above, all patches are available publicly as GitHub Pull Requests. Use the guidelines below to assist you in your review, and don’t be afraid to question. We all started out not knowing the code, and reviews are a good way to learn why things are done a certain way.
Be open to change, but respect the borders between core and plugins. Refer to What exactly is core? for that.
Be strict about tests. The project has required tests for most changes to the Ruby code base, however we have not been historically as strict with UI changes. Ask for integration tests for any change that could break in future versions without tests. Testing is a powerful weapon to ensure regressions don’t happen.
Be mindful of the use of the word ‘you’. It can be easily misunderstood as you reviewing the ‘person’ not the ‘code’. Try not to personalize any references to code. I.e: ‘you changed that in line 42’ vs ‘that change in line 42’.
Back up your reviews by facts when they are not obvious or when contributors might not know why they should make some change. Adopt a “teaching” approach, but again, back up your ‘teachings’ with links to other sources.
Use ‘@’ to raise the attention of the contributor about any issue. If an user is not ‘watching’ the project on GitHub or is not subscribed to a particular issue, GitHub will not show notifications nor send emails to that user.
If there is conflict, point to this handbook for reference.
Labels help reviewers understand the status of a pull request. Thanks to them, reviewers can make sure no pull request remains unreviewed and when they get updated, they see it.
Not all our repositories use labels, so always make sure to comment after you update a pull request to notify the reviewer and explain the new changes.
Not reviewed
and Needs testing
when a pull request has just been submitted.Waiting on contributor
if it needs changes or you’re expecting answers.Needs re-review
and Needs testing
.Reached an impasse
.As a maintainer, your responsibility is to keep a project running, taking care of certain parts of it. Examples of such parts are:
Traditionally, the process to become a maintainer has been simple. Take care of something for long enough and people will expect you to maintain it. We might ask you directly if you want to be a maintainer if you’re maintaining something for some time. If you have made contributions only on a very specific topic (an Operating System, for instance), we might ask you to be a maintainer for that part of the code.
The following process applies to the core projects mentioned at the beginning (Foreman, Smart-Proxy, Foreman-installer and Foreman-SElinux). Most plugins follow a more informal process.
A Foreman committer is a person with commit access to one or more of the repositories under the Foreman organization. Committers are members of the Foreman contributors community who exhibit most of the following behaviors:
We ask new Foreman contributors to ‘act as a committer’ to the extent we feel they are capable.
If you want to become a committer, we expect you help with some of these tasks:
Other things that are nice to do:
One person has to nominate you to the group of existing committers. The person who nominates you has to:
This nomination is public and should be made to the Development forum board. After the nomination is submitted, two other committers have to second the nomination. If no one objects in one week, the nomination is accepted.
Such objections may happen in public on the nomination thread. Understandably, however, not everyone is comfortable giving objections publicly. Therefore, it is acceptable for other committers to raise their concerns with the sponsor and/or other committers privately if they wish to do so. The sponsor is expected to update the nomination thread to show that it is on hold pending private concerns.
Regardless, during any objections, private or public, the nomination is on hold until the objections are resolved or the nomination is rejected. In the event of a failed nomination, the sponsor (as part of the discussing group) will know the grounds for the rejection, and can pass along constructive feedback to the candidate. Care should be taken to do this sensitively.
If you are inactive in the community for one year, we will remove you from the committers list and revoke your permission, but we will make a mention of you in theforeman.org list of previous committers.
In the event that a committer continues to disregard good citizenship (or actively disrupts the project), we may need to revoke that person’s status. The process is the same as for nominating a new committer: someone suggests the revocation with a good reason, two people second the motion, and a vote may be called if consensus cannot be reached. We hope that’s simple enough, and that we never have to test it in practice.
Special thanks to Chromium, Mozilla, V8, FreeBSD and Apache Hive for providing the basis of this procedure.
We follow Semantic versioning 2.0 for anything above ‘0.x’ releases. This means incompatible changes, such as breaking an API endpoint, not working with a previous Foreman version (in the case of a plugin), require increasing the major version. The bulk of your changes should only require increasing the minor and patch versions, for backwards-compatible functionality and bugfixes.
We strive to remain compatible and not break other people’s workflows, so if you have made some breaking changes that will need increasing the major version, please use Foreman::Deprecation
to deprecate anything and warn in which version will it be removed. It supports two calls:
Foreman::Deprecation.api_deprecation_warning(message)
Foreman::Deprecation.deprecation_warning(foreman_version_deadline, message)
The controls in core, such as deep code reviews, plus being subject to quarterly releases, make it difficult to quickly develop some features. For this reason, you might decide to start off your feature as a plugin. Then, once your code has been released, tested, and after review, it could be pulled into core if deemed appropriate.
The Spring preloader is installed and enabled by default for development installations to help run Rails consoles and tests quickly.
What you need to know:
Running bin/rake test test/unit/example_test.rb
, bin/rails c
and similar commands will automatically start and use Spring. Note the bin/ prefix!
Spring runs background processes to speed up commands: use spring status
to see them and spring stop
to stop (i.e. restart) them. They should automatically restart when required, but improve config/spring.rb if necessary.
Other useful information:
bin/rake test test/unit/example_test.rb
will also run all installed plugin tests, use ruby -Itest test/unit/example_test.rb
as a workaround.
export DISABLE_SPRING=true
if you don’t want to use it at all.
echo PATH_add bin > .envrc
in Foreman’s dirTo allow live reload of front-end assets, Foreman includes a small node.js server provided by webpack. In order to run foreman in development with the webpack development server, you have two options:
foreman start
will start both servers simultaneously. Note that using pry for debugging in this option is limited, as foreman does not echo back your input. You can choose to run a different rails server then the default (which is bin/rails server
) by setting the RAILS_STARTUP
environment variable.bin/rails server
and ./node_modules/.bin/webpack-dev-server --config config/webpack.config.js
. This will allow you to run pry inside the rails application as usual.If you do not want to use the webpack development server (for example, if you only work on the backend), you can set :webpack_dev_server: false
in config/settings.yaml
which will disable it. You can then proceed to running foreman as usual (e.g. bin/rails s
). In this case, however, you will need to manually run rake webpack:compile
to generate the webpack managed assets.
Please note that bin/rails server
is bound to localhost by default. Should you need to change the binding (e.g., to a specific ip address or to 0.0.0.0), please use either BIND=:: foreman start
or create a .env file with BIND=::
Foreman 3.12.0 has been released! Follow the quick start to install it.
Foreman 3.11.4 has been released! Follow the quick start to install it.