Many open source projects use Bugzilla, JIRA, or some other workflow where contributions are submitted via a patch file attached to a bug report or even an email. This workflow means working with a raw patch file. Working with these files can be a bit of a pain as one tries to figure out what patch level to apply it with, whether it is a git binary patch and other mundane details.
Various Apache projects use a tool called smart-apply-patch
to streamline the patch contribution process. It was originally part of the Apache Hadoop project but then split off into many different forks. As part of the Apache Yetus project, the team merged many of the features of these multiple versions into a rewritten version.
Installing smart-apply-patch
Apache Yetus is a suite of tools to assist in source code management and release. It has a download page that provides access to a tarball of the latest version. Using the tarball requires working versions of curl
, git
, patch
, and GNU diff
also to be installed.
On Mac OS X, it is also available via homebrew:
1 2 |
brew tap apache/yetus https://github.com/apache/yetus brew install yetus |
Using homebrew, it will also install any extra dependencies required for the full Apache Yetus toolset.
Using smart-apply-patch
In its simplest form:
1 2 |
cd src smart-apply-patch filename.patch |
This command will attempt to do a dry-run of the patch to determine the patch level and then, if successful, apply the patch to the source tree. If it is a git patch, it will also use the appropriate flag to keep binaries intact.
At this point, the patch is in the source tree, ready to be worked. It has not been committed and any new files/directories the patch may have added are still unknown to the source code software.
git Committer-mode
Given its roots in open source, smart-apply-patch
supports the --committer
flag for git repositories. For example:
1 |
smart-apply-patch --committer file.patch |
This mode does a few extra things:
- Verifies that the source tree is clean by checking the porcelain status
- Adds any files to the repo that were created by the patch
- Sets
--whitespace=fix
and--signoff
- Commits the patch
If the repository also supports GPG signatures, adding the --gpg-sign
will also make it a signed commit:
1 |
smart-apply-patch --committer --gpg-sign file.patch |
At this point, the patch is probably ready to be pushed into the remote repository. If the commit message was incorrect in the patch, then using git commit --amend
will allow you to modify the message as necessary. For example, changing the ‘Signed-off-by:’ to include more people.
URL Support
Because smart-apply-patch
uses curl
under the hood, it can also process patches that are available via URL. For example:
1 |
smart-apply-patch https://github.com/apache/yetus/pull/1.diff |
This command will download the GitHub PR and apply it without requiring you to download it.
Not Just Files
One of the big advantages of using smart-apply-patch
is that it integrates with the rest of the Apache Yetus toolset. This integration means it can take advantage of project specific settings and can pull content from any configured systems. For example:
1 |
smart-apply-patch --project=hbase HBASE-1 |
Using --project=hbase
will tell smart-apply-patch to use the built-in settings for the Apache HBase project. This flag triggers some extra rules that inform smart-apply-patch
that HBASE-1
is an issue from the Apache Software Foundation’s JIRA instance.
Using that method, it also activates automatic GitHub PR support:
1 |
smart-apply-patch --project=hadoop GH:1 |
This example tells smart-apply-patch to use Apache Hadoop’s settings to pull down PR #1 from Apache Hadoop’s GitHub repository.
Apache Yetus Has Personality
Or, more specifically, it could have your project’s personality!
Yetus has the concepts of personalities that allow a user to configure project specific settings. These are generally small bits of bash code. For example, a simple one for Apache Kafka might look like this:
1 2 3 4 5 6 7 8 9 10 11 |
#!/usr/bin/env bash personality_plugins "all" function personality_globals { PATCH_BRANCH_DEFAULT=trunk JIRA_ISSUE_RE='^KAFKA-[0-9]+$' PATCH_NAMING_RULE="http://kafka.apache.org/contributing.html" BUILDTOOL=gradle GITHUB_REPO="apache/kafka" } |
We can use that as a template to build one for our project. Let’s also make it interesting by making it an internal project using non-Internet-facing resources.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/env bash personality_plugins "all" function personality_globals { PATCH_BRANCH_DEFAULT=master JIRA_ISSUE_RE='^PROJECT-[0-9]+$' JIRA_URL="https://issues.example.org/jira" PATCH_NAMING_RULE="https://project.example.org/contributing.html" BUILDTOOL=cmake GITHUB_API_URL="https://api.gh.example.org/" GITHUB_BASE_URL="https://gh.example.org/" GITHUB_REPO="dev/example" } |
In this example, our project has a custom JIRA instance and a custom GitHub instance. Now we need to save this to a file, and tell smart-apply-patch
to use it:
1 |
smart-apply-patch --personality=personality.sh PROJECT-1 |
Now smart-apply-patch
will use the personality file as guidance on how to get the patch attached to our custom JIRA instance.
Open Source Projects: We Welcome You!
The Apache Yetus project is open to more than just Apache Software Foundation projects. If you would like to contribute your project’s personality, contributions are always welcome!