Auto-tag Fedora package git repo from koji builds

January 26, 2012 in automation, fedora, git, packaging, tool

I often browse through various Fedora packages and miss having git tags in package repositories corresponding with builds done in koji. Therefore I created following simple bash script that will create git tags in current git repo (if it’s a Fedora package).


giturl=`fedpkg giturl`
if [ $? -ne 0 ];then
echo "This doesn't look like fedora package directory"
exit 1

pkgname=`echo "${giturl}" |\
sed -e 's|git://\(.*\)?.*|\1|'`
# make sure we are up-to-date
git fetch

# go through last 3 releases (incl. rawhide)
for dist in f15 f16 f17;do
builds=`koji list-tagged "${dist}" "${pkgname}" | \
grep "${pkgname}" | awk '{print $1}'`
for build in $builds;do
# task urls sometimes have ".git" suffix
git_sha=`koji buildinfo "${build}" | grep '^Task:' | \
sed -e "s|.*${pkgname}\(\.git\)*:\(.*\))|\2|"`
version=`echo $build | sed -e "s:${pkgname}-::"`
echo BUILD: $pkgname\($version\) = $git_sha
git tag "${version}" "${git_sha}"


Automatic squashing of last git commits

December 10, 2010 in git, howto, open source, software

I have written before about my workflow in Fedora. This workflow includes a relatively high number of rebasing where I squash last two commits into one. I use it to quickly refine and test patches. My history then usually looks something like this:

$ git log --format=oneline --decorate=no | head -3
2db8eacd7f7c20be88824caae5f5af16b9520d34 temp
443bb0f019c87f0090bb9da295a019c0eee23729 Add conditional BRs to enable ff merge between f14
b4c602f9f044598544cff3d68710f68b9447ea0f Fix installation of pom files for artifact jars

Where 443bb0f is my first attempt at the fix and 2db8eac is a fixed fix :-). Before pushing this into upstream repository I usually squash last two commits to look like this:

$ git log --format=oneline --decorate=no | head -2
f852c3e260d21bbc642f861e6fa6ea62caa7b69b Add conditional BRs to enable ff merge between f14
b4c602f9f044598544cff3d68710f68b9447ea0f Fix installation of pom files for artifact jars

I used to do it manually, but I do it often enough it made sense to automate this. So without further ado:


export EDITOR="sed -i '2s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'"

git rebase -i HEAD~2

Save this somewhere inside your $PATH and chmod +x (or set up shell alias). Then just running this will automatically squash last two commits, using HEAD~1 commit message and discarding last commit message. No warranties though :-)

Edit: Benjamin suggested to use “fixup” instead of “squash”. This is new thing in git 1.7+. For more information on this see this blogpost.

Packaging workflow, patch management and git magic in Fedoraland

October 15, 2010 in en, fedora, git, howto, linux, packaging

Big part of my job is packaging for Fedora Linux (I am pretty sure I haven’t mentioned this before :-) ). I have spent last 6 months working on various Java packages, adding new packages to Fedora, updating dependencies etc. I have developed certain workflow which I believe might be of interest to other packagers. So here goes. Most of these hints are about managing patches for your packages. I’ll also try to work on concrete package so it won’t be completely theoretical.

Let’s assume your project already has some history and patches. Let’s fix velocity bug 640660 for example. I’ll start with steps I took and what they meant, and I’ll summarize in the end with rationale what I have gained by using my workflow (and what could be improved).

After modifying BuildRequires and Requires to tomcat6 servlet api I tried to build velocity:

$ fedpkg mock

This is what I got:

[javac] Compiling 125 source files to /builddir/build/BUILD/velocity-1.6.3/bin/test-classes
[javac] /builddir/build/BUILD/velocity-1.6.3/bin/test-src/org/apache/velocity/test/ org.apache.velocity.test.VelocityServletTestCase.MockServletContext is not abstract and does not override abstract method getContextPath() in javax.servlet.ServletContext
[javac] static class MockServletContext implements ServletContext
[javac] ^
[javac] Note: /builddir/build/BUILD/velocity-1.6.3/bin/test-src/org/apache/velocity/test/ uses or overrides a deprecated API.
[javac] Note: Recompile with -Xlint:deprecation for details.
[javac] Note: Some input files use unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
[javac] 1 error
/builddir/build/BUILD/velocity-1.6.3/build/build.xml:251: Compile failed; see the compiler error output for details.
Total time: 47 seconds

The issue seems simple to fix, just missing stub function in a test case, right? So what now?

$ fedpkg prep
$ mv velocity-1.6.3 velocity-1.6.3.git
$ cd velocity-1.6.3.git
$ git init && git add . && git commit -m 'init'

This effectively created my small git repository for sources and populated it with all files. Using fedpkg prep step we extracted the tarball and applied already existing patches to unpacked sources. I suggest you create shell alias for last three commands as you’ll be using it a lot. We moved directory to velocity-1.6.3.git so that next (accidental?) fedpkg prep won’t erase our complicated changes (yes it happened to me once. I’ve had better days). Note that velocity-1.6.3.git is not a temporary directory. I will keep it around after fixing this bug so that I can use git history, diffs and other features in the future. It is especially nice when you have packages with lot of patches on top.

Now we can easily work in our new git repository, edit source file in question and do:

$ git add src/test/org/apache/velocity/test/
$ git commit -m 'Fix test for servlet api 2.5'
$ git format-patch HEAD~1

This created commit with descriptive message and generated a patch file 0001-Fix-test-for-servlet-api-2.5.patch in our current directory. This is how the patch looks like:

From 8758e3c83411ffadc084d241217fc25f1fd31f42 Mon Sep 17 00:00:00 2001
From: Stanislav Ochotnicky
Date: Thu, 14 Oct 2010 10:20:52 +0200
Subject: [PATCH] Fix test for servlet api 2.5

.../velocity/test/ | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/src/test/org/apache/velocity/test/ b/src/test/org/apache/velocity/test/
index 824583e..ac0ab5c 100644
--- a/src/test/org/apache/velocity/test/
+++ b/src/test/org/apache/velocity/test/
@@ -16,7 +16,7 @@ package org.apache.velocity.test;
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.

@@ -149,6 +149,11 @@ public class VelocityServletTestCase extends TestCase
return this;

+ public String getContextPath()
+ {
+ return "";
+ }
public String getServletContextName()
return "VelocityTestContext";

Now that we have patch prepared for velocity we need to use it in the spec file and we’re done.

Let’s say our first attempted patch wouldn’t work as expected and build (or test) still failed. We modify the sources again and do another commit. What we have now is:

$ git log --format=oneline
c15f7e02eaae93b755cc0bfde6def3d6e67d2b0f (HEAD, master) Fix previous commit
3e3d654c142c7028c9c7895579fba204c4c4bf08 Fix test for servlet api 2.5
2f32554ddf892f4cca3f78b1f82a7c3ab169c357 init

We don’t want two patches in the spec file for one fix so: time for git magic. You’ve probably heard of git rebase if you’ve been using git for a while. What we want to do now is merge last two commits into one, or in git-speak “squash” them. To do this you have to do:

$ git rebase -i HEAD~2

Now your editor should pop-up with this text:

pick 3e3d654 Fix test for servlet api 2.5
pick c15f7e0 Fix previous commit

# Rebase 2f32554..c15f7e0 onto 2f32554
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.

So we just need to change “pick c15f7e0 Fix previous commit” into “squash c15f7e0 Fix previous commit” (you can also use just ‘s’ instead of ‘squash’). Save. Close. Another editor window will open with something like this:

# This is a combination of 2 commits.
# The first commit's message is:

Fix test for servlet api 2.5

# This is the 2nd commit message:

Fix previous commit

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

For this case we will delete second message because we just want to pretend our first attempt was perfect :-). Save. Close. Now we have:

$ git log --format=oneline
cbabb6ac43f7bdb8e52ccd09c25cfd0a032b553c (HEAD, master) Fix test for servlet api 2.5
2f32554ddf892f4cca3f78b1f82a7c3ab169c357 init

Repeat as many times as you want. You can also re-order commits and change commit messages with rebase (note that if you just want to change last commit message you can do “git commit –amend”). I generally don’t create commits until I have working patch though.

So why do I think all this mumbo-jumbo improves my workflow? Let’s see:

  • I can have long comments for every patch I create (instead a line or two in spec file)
  • I can use the same patches to send directly to upstream
  • I don’t have to juggle around with diff and remember what files I changed where
  • Probably several other things I haven’t even realized

I have a few things that bother me of course. git format-patch generates filenames that are different from standard practice of %{name}-%{version}-message.patch. This is not a git problem. For packages where only my patches exist I stick with git naming, but when there are different patches I stick with naming they started. Another thing that is bothering me is that creating initial repository by using “fedpkg prep” hides patches that were applied to sources. That’s why I am thinking about re-working my packages so that all patches will be in my git repositories as commits with descriptive messages. No need for comments in the spec file anymore. Perhaps someone can suggest other improvements to my approach.