Development Workflow
This document covers the development workflow for contributing to the Magma project.
General workflow
Magma follows the standard "fork and pull-request" development workflow. For more information on this workflow, consider the following
See the opinionated workflow section below for a low-friction version of these workflows.
Guidelines
Required: commits must be signed off. You must sign-off all commits on the originating branch for a PR, using the --signoff
flag in Git. There is a CI check that will fail if any commit in your branch has an unsigned commit. If you've forgotten to sign-off a commit, you can git commit --amend --signoff
, or git rebase --signoff
to sign-off an entire branch at once.
Required: label backward-breaking pull requests. Use the breaking change
label. All breaking changes and their mitigation steps will be aggregated in the subsequent release notes. A breaking change fits one or more of the following criteria
- Will require a manual intervention on the next upgrade (e.g. data migration script)
- Will break the southbound interfaces between AGW and Orchestrator in a way that will require both components to upgrade in a coordinated way.
Desired: convincing test plan. For non-trivial PRs, codeowners will require you to include a test plan detailing any manual verification steps you took.
Desired: use imperative mood for pull request title and description. A simple way to check this is to mentally prepend the phrase "This commit will ..." to the title and each bullet point of your description.
Productivity tools
- Git
hub
: Git CLI wrapper providing extended functionality, e.g. opening a PR
- GitHub
- Refined GitHub: browser extension simplifying GitHub interface and adding some useful features
- Notifier for GitHub: browser extension to get GitHub notifications sent to your desktop
- Sourcegraph: browser extension to add Sourcegraph functionality directly to GitHub
- Codecov: Sourcegraph extension to display code coverage metrics
- Code ownership: Sourcegraph extension to show codeowners for each file
- Open in IntelliJ: Sourcegraph extension to open a file in your dev machine's IntelliJ instance
- IntelliJ
Opinionated workflow
The references above should be sufficient to get started. This section provides an opinionated view on how to efficiently manage this workflow, assuming the following
- up-to-date version of Git
hub
wrapper command installed (see above)
Workflow
This opinionated workflow simplifies the complexities of dealing with Git directly.
It does this by keeping both your_dev_branch
and your_dev_branch_base
branches, allowing a straightforward mechanism for rebasing commit stacks.
# Note: see below for the aliases used in this code block
###############
# Get started #
###############
# Fork the Magma repo
# ...
# Clone your forked Magma repo
git clone git@github.com:YOUR_USERNAME/magma.git && cd magma
# Set upstream
git remote add upstream git@github.com:magma/magma.git
###########
# Open PR #
###########
# Checkout master and fast-forward to match upstream
git_update
# Create new dev branch on top of latest master
git_update YOUR_NEW_DEV_BRANCH
# Make changes, and package as a *single* commit on your dev branch
# ...
# Open pull request
git open_pr
# Make requested changes, without committing anything
# ...
# Amend the single commit and force-push to update the PR
git amend_pr
# [optional] Rebase PR onto master
git_rebase
# [optional] Rebase PR onto another PR
git_rebase TARGET_BRANCH
# [note] If there's a merge commit during git_rebase, after completing the
# merge, you need to finish updating the reference branches
git_rebase_finish
###############
# Look around #
###############
# Full commit graph -- super helpful for figuring out what's going on
git graph_all
# Diff between PR and trunk
git diff_base
# Diff between local dev branch and origin dev branch
git diff_origin
############
# Clean up #
############
# When you have no open PRs, you can clear all local branches to clean up
# your git commit graph
git delete_local_branches
Necessary aliases
# ~/.gitconfig
[alias]
delete_local_branches = !git branch | grep --invert-match master | xargs git branch --delete
commit_amend = commit --signoff --amend --no-edit
diff_base = !git diff $(git branch --show-current)_base
diff_origin = !git diff origin/$(git branch --show-current)
graph = graph_all --max-count=30
graph_all = log --graph --all --format=format:'%C(auto)%h%C(reset) %C(cyan)(%cr)%C(reset)%C(auto)%d%C(reset) %s %C(dim white)- %an%C(reset)'
amend_pr = !git add --all && git commit --signoff --amend --no-edit && git push --force
open_pr = !git push_branch && git pull-request --browse
push_branch = push --set-upstream origin HEAD
# shell rc file
# git_update updates master with upstream changes, and optionally creates a feature branch.
function git_update() {
git checkout master && git pull upstream master && git push origin master
local br=${1}
if [[ $br != "" ]]; then
local br_base=${br}_base
git branch ${br_base}
git checkout -b ${br}
fi
}
# git_rebase rebases current branch on master, or the specified target.
# $1 target
# $2+ args passed to rebase command
#
# Note: if there's a merge conflict, after handling the merge conflict,
# you need to finish by running git_rebase_finish.
function git_rebase() {
local to=${1:-master}
local args=${@:2}
local br=$(git branch --show-current)
local br_base=${br}_base
# Save values to file in case rebase fails
echo "${to} ${br} ${br_base}" > ~/.gitrebase
git rebase --onto ${to} ${br_base} ${br} ${args} && git checkout ${br_base} && git reset --hard ${to} && git checkout ${br}
}
# git_rebase_finish completes the rebase started by git_rebase.
function git_rebase_finish() {
local vals
read -r -a vals < ~/.gitrebase
local to=${vals[0]}
local br=${vals[1]}
local br_base=${vals[2]}
git checkout ${br_base} && git reset --hard ${to} && git checkout ${br}
}