Nov 11, 2011
For package to be included in default Fedora repositories, it has to go through process called package review. If you've done a few package reviews you know big chunks of this process are repeated ad-nausea in every review.
There have been quite a few tools aimed at automating and simplifying this process. However they all had one major flaw. They have been designed for reviewing specific class of packages, be it Perl, Python or generic C/C++ packages. Few us us decided to change this.
We used Tim Lauridsen's FedoraReview package as a base for our work and started adding new features and tweaks. Current work has a website on fedorahosted where you'll find all important information. Full feature list would be quite long, but I'll list a few major things:
  • Bugzilla integration
  • Mock integration
  • JSON api for external plugins (more info further down)
  • Several automated tests
The tool runs all checks/tests on spec file and rpms and writes output into a text file. Snippet of the output looks like this:
Package Review

- = N/A
x = Check
! = Problem
? = Not evaluated

==== Generic ====
[ ]: MUST License field in the package spec file matches the actual license.
[ ]: MUST License file installed when any subpackage combination is installed.
[!]: MUST Package consistently uses macros (instead of hard-coded directory names).
        Using both %{buildroot} and $RPM_BUILD_ROOT
[x]: SHOULD Spec use %global instead of %define.

==== Java ====
[!]: MUST If package uses "-Dmaven.local.depmap" explain why it was needed in a comment
[!]: MUST If package uses "-Dmaven.test.skip=true" explain why it was needed in a comment

[!]: MUST Package consistently uses macros (instead of hard-coded directory names).
        Using both %{buildroot} and $RPM_BUILD_ROOT
[!]: MUST If package uses "-Dmaven.local.depmap" explain why it was needed in a comment
[!]: MUST If package uses "-Dmaven.test.skip=true" explain why it was needed in a comment
We display only relevant results. In other words if there are no post/postun scriptlets there is no reason to include sanity output checking in the template. This will make more and more sense as we add more checks.


So how is it that different people will be able to write additional plugins for this review tool? We provide a relatively simple JSON api through stdin/stdout.
So to create a new check plugin you create a script or program in your language of choice. There is only one requirement:
  • Programming language has to have JSON format support
When the review tool runs your plugin it will send following message on its stdin:
    "supported_api": 1,
    "pkgname": "package name",
    "version": "package version",
    "release": "package release",
    "spec":{ path: "path/to/spec",
            "text": "spec text with expanded macros"},
    "rpms":[ "path/to/rpm", ...],
    "rpmlint": "rpmlint output",
    "build_dir": "/path/to/src/directory/after/build"
When your plugin is done with checks it returns following message by writing it to stdout:
    "command": "results",
    "supported_api": 1,
         "name": "CheckName",
         "url": "URL to guidelines usually",
         "group": "Group for this test.(Java, Perl, etc.)",
         "text": "Check description that shows on review template",
         "deprecates":["DeprecatedTest", ...]
         "type": "MUST"|"SHOULD",
         "result": "pass"|"fail"|"inconclusive",
         "extra_output": "text",
If the plugin closes stdout without writing anything there, it means there were no relevant automated tests to run and no non-automated tests to include in template for manual evaluation. This is useful so we don't include for example Perl-related test output for Java packages and vice-versa.


While the tool is already usable and soon to be packaged in Fedora, there are still quite a few things we want to improve:
  • Add more functions to API (currently there is just get_section)
  • Automate all automatable tests currently available
  • Get rid of redundant tests (don't duplicate rpmlint)
  • Add more tests of course!
  • Maybe add templating support?
We have currently 3-4 active committers, checks for C/C++, generic, Java, R packages. There is already and example external plugin written in Perl. If you have any improvement ideas, bugreports or just want to tell us we suck because we should have done X...get in touch!

Nov 3, 2011

My job: I am a software chef

How often are you asked what is your job? Most non-IT people will not be able to understand packaging, dependencies, rpms and whatnot. Hell, I even had trouble explaining what I do to my ex-schoolmates from university working in a traditional corporate environments. And they are software developers.
Was that just my problem? I don't think so. I had an epiphany while on a vacation few months back. I am almost sure the idea was not mine and it was just my subconsciousness that stole it from someone else. So what is my revelation? As you might have guessed from the title:

I am a software chef. I create recipes and prepare them.

I work in a restaurant, that we call Linux distribution. There are many restaurants, each having their own recipes, rules and so on. Some restaurants form "chains" where they share most of their recipes. In these cases there is usually one restaurant that creates most recipes (Debian is such a restaurant in its Linux ecosystem).
Each restaurant usually has hundreds of chefs, some of them specialize in few recipes (build scripts), some are more flexible. In my case I specialize in a type of recipes dealing with coffee (i.e. Java).
Every recipe starts with customer (user) ordering some meal they have heard about. I look up ingredients (upstream projects) the food is made of and start recreating recipe for our restaurant. Quite often the food is made of more recipes (dependencies) and I have to create those first. Sometimes these recipes are already being prepared by other chefs, so I just use their work for my final meal. However our ingredients can be slightly bit different from the original. For example we have cow milk, but no goat milk that was in original recipe. So I have to find a way to fix the recipe using spices (patches).
Creating recipes is only part of my job though. I also work with our suppliers of ingredients (upstream developers). Sometimes the ingredients are bad, or I have found a way to improve the ingredient so I contact the suppliers and we work together.
Third part of my job is improving cooking process (simplifying packaging). So sometimes I move some furniture around so that other chefs don't have so much between the fridge and other places. Or I create a new mixer (tools) that speeds up mixing of ingredients.
Final part of my job is to work in a VIP part of the restaurant (RHEL). Only some customers can go there, most meals are usually very similar to normal restaurant, but each meal is tasted (tested) before we give it to customers and if they don't like it they can complain and we bring them improved recipe.
I find this metaphor kind of works for most things to a surprising degree. For the record:
  • Package maintainers - chefs
  • QE/QA - tasters
  • Security - bouncers
  • Release engineering - waiters (sorry guys)
Do you have an idea where this came from? Or can you think of a better metaphor for packaging? I'll probably keep updating and expanding this post as I go so I can point people to this when then want to know what I do..


Automatic javadoc subpackage generation

Do you hate repeating the same thing over and over again? I know I do...
Java packaging guidelines state that we have to include javadocs with all java packages. This means we have to repeat following code in almost all packages (except pom and resource projects):
%package        javadoc
Summary:        API documentation for %{name}
Group:          Documentation
Requires:       jpackage-utils

%description    javadoc

# javadoc
install -d -m 755 %{buildroot}%{_javadocdir}/%{name}
cp -pr target/site/apidocs/* %{buildroot}%{_javadocdir}/%{name}


%files javadoc
%doc %{_javadocdir}/%{name}
The code is practically the same in all packages so why not automate this? Well there were two main reasons why this wasn't done before:
  • Copying of files needs to be done during install phase
  • If package contains license, javadoc has to have it too
We solved both of these in a fairly reasonable way. Resulting macro help looks like this:
# %create_javadoc_subpackage can be used to completely create
# javadoc subpackage for java projects.
# !!! Needs to be used at the end of %install section
# There are these variables that change its behaviour:
# %__javadoc_license - set if the license is in non-standard place to
#                prevent Requires on main package
# %__apidocs_dir - set custom path to directory with javadocs
#                (defaults to target/site/apidocs)
# %__javadoc_skip_requires - if defined javadoc subpackage will not
#                require main package under any circumstances (useful
#                if upstream doesn't provide separate license file)
Is it understandable enough? If you need to generate javadocs, just make them build and then add %create_javadoc_subpackage macro call at the end of %install section. Normally you shouldn't have to change anything. We search in a few standard places for licenses. More specifically we look for LICENSE* COPYING* doc/LICENSE* doc/COPYING* license*. Do you have more ideas where to look? It's easy to add. If we don't find license we automatically add requires on main package and assume you put license in there. If upstream doesn't provide separate license file you can do %global __javadoc_skip_requires t and we will ignore licensing completely.
I'd like this added to our packaging guidelines so we can start using it. My testing shows it works fairly well. I'd love to improve it so you could place it anywhere in the spec, not just %install section, but rpm macros are...complicated.
*Note*: For gory details head over to our git repository. For now it's in separate feature branch.