Skip to main content
Version: 1.5.X

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

  1. Will require a manual intervention on the next upgrade (e.g. data migration script)
  2. 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

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}
}