Versioning code
Quartz is a long-lived product, people will come and go. Keeping a clean history of work is crucial to help future maintainers of Quartz understand what was done and why.
Start by reading and understanding the General version management principles, as they apply to all the assets of the system.
Contribution lifecycle
Repository owners are in charge of maintaining a good level of security and quality in their code. Using GitHub forks and pull requests is the recommended way of keeping track of every change that is pushed to the code.
Making a change to your repository requires to follow specific steps in order.
- Fork the repository in GitHub (when possible), and clone it locally.
- Create a branch when you start working on a task
- Commit changes to your branches.
- Clean your commit history when you're ready to push your changes to the main repository
- Push and check the CI runs successfully
- Create a Pull Request to review and merge your changes back into the main repository.
Fork and clone the repository
When possible, fork the repository first. Read the GitHub forking guide to learn how to do so.
Whether or not you can fork the repository, you must clone it to get a local copy on your computer. There are several ways of doing so, as explained in the GitHub cloning documentation.
Create a branch
Whether or not you can fork a repository,when you start working on a task,
create a new branch from next
using a consistent branch naming
convention. You can do so in several ways:
- let GitHub create the branch for you using the link provided in the Development section of the issue you're working on. Be careful to review the proposed settings and adjust the source branch as necessary.
- use a graphical Git client to make a new branch deriving from
next
. - use the
git
CLI in your command prompt:git checkout next
git checkout -b <type/the-new-branch-name>
Default branches
Quartz repositories come with two essential branches:
- the
main
branch, in which each commit is tied to a specific production release (ex:v1.2.3
) - the
next
branch, in which each commit is tied to a specific beta release (ex:2.0.0-beta.3
)
Commit changes to your branch
Your commits should follow the Conventional commits specification. Make sure to read and understand the Conventional commits section below.
In the early stages, you may fall back to using the chore: <summary>
commit
pattern for quick, less formal commits. Use meaningful labels anyway to help you
cleaning your history later.
For example:
chore: update dependencies
chore: draft Foo parsing
chore: draft Foo linting
chore: finish Foo linting
chore: finish Foo parsing
chore: chore: lint Foo in build
Conventional commits
We use the Conventional commits specification for that purpose. Make sure you understand it. Even if you never used it before, you will quickly get used to it and see the clarity and consistency it brings to project's history.
A typical commit message goes like this:
<type>[optional scope]: <description>
[optional body]
[optional footer]
where:
<type>
is a keyword (see table below) indicating the nature of the commit<description>
starts with a lowercase infinitive verb and has to be short[optional scope]
provides context in parenthesis[optional body]
is a lengthier description of the change, supporting Markdown syntax (bullet lists, emphasis, etc.)[optional footer]
is mostly used to describe breaking changes (see below).
Here are a few correct examples:
-
Simplest commit:
fix: make tooltip visible again
-
With context:
feat(button): show tooltip when label is truncated
-
With description:
feat(button): show tooltip when label is truncated
Tooltip is shown when:
- button has a fixed width
- **and** label is too long
- **and** the `overflow` option is set to `truncate`
Breaking changes
To indicate breaking changes, add an exclamation mark (!
) just before the
column (:
), and document the impact of the change in the footer, starting with
BREAKING CHANGE:
. Like this:
feat(button)!: show tooltip when label is truncated
Tooltip is shown when:
- button has a fixed width
- **and** label is too long
- **and** the `overflow` option is set to `truncate`
BREAKING CHANGE: the `overflow` option is now a string
attribute instead of a boolean, accepting the
`visible` and `truncate` options.
Commit types
The following table lists the commit types used by Quartz, their purpose, and how they impact version numbers and release notes generation:
Commit type | Purpose | Version increment | Included in release notes |
---|---|---|---|
feat | A new feature | Minor | ✅ Yes |
fix | A bug fix | Patch | ✅ Yes |
perf | A code change that improves performance | Patch | ✅ Yes |
revert | A previous change that was reverted | Major | ✅ Yes |
*! | Any type with BREAKING CHANGES | Major | ✅ Yes |
build | Changes that affect the build system | Ignored | 🚫 No |
ci | Changes to CI configuration | Ignored | 🚫 No |
docs | Documentation only changes | Ignored | 🚫 No |
refactor | A code change that neither fixes a bug nor adds a feature | Ignored | 🚫 No |
style | Changes that do not affect the meaning of the code (formatting, etc.) | Ignored | 🚫 No |
test | Adding missing tests or correcting existing tests | Ignored | 🚫 No |
chore | Other changes that don't modify source files. Don't overuse it! | Ignored | 🚫 No |
commit-msg hook
We use husky to install a commit-msg
hook that will run
commitlint to ensure the message follows that standard. commitlint
is
configured with a custom preset implementing the Quartz
specific practices.
Clean commit history
We use semantic-release
to handle the release process,
which generates the release notes from your commit history. That's why it is
crucial that you always review and clean your commit history before submitting
your changes for review and release.
You can do so by using the Interactive Rebase Git feature, as described in the Rewriting History chapter from The Git book.
Be aware that using interactive rebase, you will most often have to
force push
your changes to the remote repository. That's why
working in your branch avoids accidentally overwriting the commit history from
the upstream repository.
We could clean the history from the previous example by:
- Squashing together the draft/finish commit pairs
- Rewording the build commit to use the proper commit type. Also, our consumer's
build may fail due to the added Foo syntax linting. We indicate that by adding
an exclamation mark (
!
) after the commit type and describing the breaking changes in the commit's description (not shown here).
Which would result in the following history:
chore: update dependencies
feat: support the Foo syntax
build!: add Foo syntax linting
Thanks to that clean history, when the owners release a version,
semantic-release
will automatically increment the major version number
(because we indicated a breaking change) and generate clean release notes in
the repository's CHANGELOG.md
file:
# Change log
# @quartzds/my-package 2.0.0
## ⚠ BREAKING CHANGES
- The build now parses the Foo syntax
## ✨ Features
- Support the Foo syntax
Push your branch and check the CI
Create a Pull Request
Create a Pull Request when you're ready to merge your changes into the upstream repository:
The CI will first run checks on your branch, then the repository owners will review your PR.
Adding changes to your PR
While the PR is open, if the owners request changes from you, you just have to push changes to your branch. GitHub will automatically re-run the checks and notify the owners of your update.
Once the repository owners approve your PR, they will first merge it into the
next
branch and create a beta release. You can then
collect feedback from your early testers.
Adding changes after a beta release
Once a beta version has been released, you must create a new PR and start a new beta cycle to contribute additional changes.
Releasing to production
After releasing a beta version, if your early testers are happy with your changes, request the owners to release a production version.