How to Publish your Software on Copr, Fedora’s User Repository
Table of Contents
- Prerequisites
- Step 1: Creating the package using tito
- Step 2: Publishing the package in a Copr repository
- Step 3: Automate package (re)-builds
- Step 4: Let tito manage the program version
- Release procedure in brief
- Packaging from source tarballs
This is a short tutorial on how to create and maintain a Copr repository for your software in an automated fashion. It assumes some basic familiarity with Git & how to create a RPM package.
In this guide, we’ll
create a RPM package for a program
create a Copr repository and publish the program to it
set up automatic management of program version, package release and package changelog
set up automatic building of new package versions
The aim is to let you keep your software up-to-date in Copr without ever having to interact with anything other than your software’s git repository.
You can set up similar automation when packaging someone else’s program, i.e. building from a downloaded source tarball. The needed modifications are described at the end of the tutorial. |
Prerequisites
The following is needed:
Our program’s source in a publicly available git repository somewhere. This tutorial uses a simple example program - hellocopr - to demonstrate the process. The program and all files referenced in this guide can be found in the project’s git repository. It’s a very simple (& pointless) python program with a setuptools installer:
user@host ~/copr-tito-quickdoc % ls
doc LICENSE README.md requirements.txt setup.py src
user@host ~/copr-tito-quickdoc % ls src/hellocopr
colors.py hellocopr.py __init__.py
A Fedora (FAS) account in order to be able to create repositories on Copr. This tutorial’s demo repository can be found here.
tito
installed on your system. Tito is capable of a lot of advanced automation for package creation, most of which we won’t need here. Check out its documentation to learn more.A specfile for our program. For more information on how to create one, refer to Creating RPM packages and How to Create a GNU Hello World RPM Package or adapt this tutorial’s annotated example specfile.
You can follow along with this tutorial by cloning or forking the repository and checking out the initial tag. This will put the repository in the state just before the next step. The repo’s commit history matches the steps followed in this tutorial. |
Step 1: Creating the package using tito
Copy the spec file into the project’s base directory. A few changes should be made before proceeding:
The values of
Version:
andRelease:
do not matter, since these will be managed by tito. It makes sense to set them toVersion: 0.0.0
andRelease: 0%\{?dist}
to mark that this package hasn’t been built yet.tito will also handle the creation of the source tarball from the git repository, so change the
Source0:
URL to the filename%{name}-%{version}.tar.gz
& add a comment to tell users how to get the tarballThe changelog can be left empty.
user@host ~/copr-tito-quickdoc % cat hellocopr.spec
...
Version: 0.0.0
Release: 0%\{?dist}
...
# Sources can be obtained by
# git clone https://pagure.io/copr-tito-quickdoc
# cd copr-tito-quickdoc
# tito build --tgz
Source0: %\{name}-%\{version}.tar.gz
...
%changelog
Commit the changes.
Next, we initialize the project for use with tito.
user@host ~/copr-tito-quickdoc % tito init
Creating tito metadata in: ~/copr-tito-quickdoc/.tito
- created ~/copr-tito-quickdoc/.tito
- wrote tito.props
- created ~/copr-tito-quickdoc/.tito/packages
- wrote ~/copr-tito-quickdoc/.tito/packages/.readme
- committed to git
Done!
This creates a subdirectory .tito
with some default configuration, which can be left unchanged for now.
We can now do a test build of the package using tito build
. Usually, tito will build from a tag, which we haven’t created yet. However, using the --test
flag, we can build from the most recent commit instead, which will be written to /tmp/tito
:
user@host ~/copr-tito-quickdoc % tito build --rpm --test
Creating output directory: /tmp/tito
WARNING: unable to lookup latest package tag, building untagged test project
WARNING: .tito/packages/hellocopr doesn't exist in git, using current directory
Building package [hellocopr-0.0.0-0]
Wrote: /tmp/tito/hellocopr-git-11.7a6919d.tar.gz
...
Successfully built: /tmp/tito/hellocopr-0.0.0-0.git.11.7a6919d.fc32.src.rpm
- /tmp/tito/noarch/hellocopr-0.0.0-0.git.11.7a6919d.fc32.noarch.rpm
Once we’ve fixed any issues with the package that might crop up, we can let tito create a package release using tito tag
. Since we haven’t set a proper version yet, we need to pass it to tito for the first tag:
user@host ~/copr-tito-quickdoc % tito tag --use-version 1.0.0
This will open the editor & display a pre-formatted changelog entry build up from all commits since the last release, which we can edit as needed. Since there have been none so far, the entry will just contain “- new package built with tito”. Save the file, and tito will
set the Version in the specfile to 1.0.0
set the Release in the specfile to 1
append the changelog entry to the specfile’s
%changelog
sectioncommit the result and tag it with
<name>-<version>-<release>
, i.e.hellocopr-1.0.0-1
user@host ~/copr-tito-quickdoc % tito tag --use-version 1.0.0
Creating output directory: /tmp/tito
Tagging new version of hellocopr: untagged -> 1.0.0-1
Created tag: hellocopr-1.0.0-1
View: git show HEAD
Undo: tito tag -u
Push: git push --follow-tags origin
Push to the commits & tags to the remote using git push --follow-tags
, and we’re ready to release the package on Copr.
Step 2: Publishing the package in a Copr repository
Go to https://copr.fedorainfracloud.org/ and log in. Once done, click on New Project to start creating a repository for our program. On the following input mask,
Under 1. Project information → Project name set the name to what you want your repo to be called - since this will only contain a single package, it makes sense to use projectname = packagename, i.e. hellocopr. This is the only settings that cannot be changed later.
Under 2. Build options tick all distributions you want to create repositories for - usually all Fedora versions & maybe EPEL versions as well
Under 4. Other Options make sure that Follow Fedora branching is ticked, this will ensure that your repository will automatically update for new Fedora release.
Go to Packages → New Package
Under 1. Provide the source, set the package name & the URL of your git repository
Under 2. How to build SRPM from the source select tito
Under 3. Generic package setup tick the box for Auto-rebuild
Your package will appear in the list of packages. Hit Rebuild to trigger a build. The following page lets you change any build options if necessary, we’ll just use the defaults, i.e. the options we set in the previous step. Hit Submit and Copr will build the package from the tito tag we created in Step 1.
Once the build has finished, you can test installing the package from Copr by activating your repository.
user@host ~/copr-tito-quickdoc % sudo dnf copr enable <username>/hellocopr
user@host ~/copr-tito-quickdoc % sudo dnf install hellocopr
Step 3: Automate package (re)-builds
Next, we want to set up Copr to automatically build a new package version whenever we create one, so that we no longer need to log in and trigger one manually. To achieve this, we simply need to trigger a build whenever we push a new tag to the repository.
This requires some configuration both of your Git repository and of the Copr project.
Configuration can be found under Settings → Integrations, the page also explains the steps to configure your git repository for all common Git forges (Pagure, Github, Gitlab & Bitbucket).
Now, to test this, let’s make some changes to our program that will come in handy for the final layer of automation and create a new release for our software.
Currently, the example program has its version hardcoded at multiple places. Let’s change this so that the version string is sourced from a single file. Which file this is doesn’t matter, but ideally the version variable should be the only thing in it that is likely to change. In this case, we use the previously empty src/hellocopr/__init__.py
. We name this new version ‘1.0.1’.
Commit the changes, and create a new release with tito
user@host ~/copr-tito-quickdoc % tito tag
Creating output directory: /tmp/tito
Tagging new version of hellocopr: 1.0.0-1 -> 1.0.1-1
Created tag: hellocopr-1.0.1-1
View: git show HEAD
Undo: tito tag -u
Push: git push --follow-tags origin
Note that by ommiting the --use-version
option, tito now updates the version automatically. It does so by
Increasing the Version’s final digit by 1 -
1.0.0
→1.0.1
Resetting the Release to 1 it it isn’t already.
If you want to bump to a different version, say 1.1.0
, you can do so again by passing --use-version
.
Push the resulting commit & tag, and if you now check your projects page on Copr, you’ll see that a new build of hellocopr-1.0.1-1
has been triggered by our pushing a tag.
Step 4: Let tito manage the program version
If you check the git log, you’ll find that I actually forgot to update hellocopr’s version variable to 1.0.1. We don’t want that to happen again. Luckily, since we single-source our version, we can let tito automatically generate this file from a template.
First, copy the version source file src/hellocopr/__init__.py
to .tito/templates/__init__.py.template
. Then, open the template file and replace the version string with $version
. It also makes sense to add a note that the file is managed by tito and should not be edited manually.
user@host ~/copr-tito-quickdoc % cat .tito/templates/__init__.py.template
...
# This file is automatically created from a template by tito. Do not edit it manually.
__version__ = '$version'
Next, add the following to .tito/tito.props
[version_template]
destination_file = src/hellocopr/__init__.py
template_file = .tito/templates/__init__.py.template
Commit the changes. Now, when we tag a new release, tito will take the template, replace $version
with whatever version was tagged, and copy the resulting file to src/hellocopr/__init__.py
before updating the spec file and commiting the changes.
We can test this by tagging a new release:
user@host ~/copr-tito-quickdoc % % tito tag
Creating output directory: /tmp/tito
Tagging new version of hellocopr: 1.0.1-1 -> 1.0.2-1
Created tag: hellocopr-1.0.2-1
View: git show HEAD
Undo: tito tag -u
Push: git push --follow-tags origin
user@host ~/copr-tito-quickdoc % cat src/hellocopr/__init__.py
...
# This file is automatically created from a template by tito. Do not edit it manually.
__version__ = '1.0.2'
If you again push the tag to the remote repo, Copr will again automatically trigger a rebuild.
Release procedure in brief
From now on, updating your software in the Copr repository is as simple as
Commit all changes for your new version.
Perform a test build using
tito build --test
Tag the release with
tito tag
(add--use-version
if necessary)Push the tag to your git repo using
git push --follow-tags
and Copr will take care of the rest.
Packaging from source tarballs
You can use a similar process to manage someone elses software on Copr, i.e. build from a tarball downloaded from upstream.
To do so, the following changes need to be made to the procedure described above:
Instead of the unpacked sources, download & commit the source tarball you want to package to your repository
Instead of modifying the source directly, add any changes you need to make in the form of patch files. List these as
PatchX:
in the spec fileAlso in the spec file, set the
Version:
back to whatever version the program is at andSource0:
back to the tarball URL. You can use macros like%{version}
for the latter to automatically follow version changes.Modify tito’s
.tito/tito.props
to, one, not try to build a source tarball and two, bump theRelease:
instead of theVersion:
when tagging[buildconfig]
builder = tito.builder.NoTgzBuilder
tagger = tito.tagger.ReleaseTagger
Don’t do any tito templating
The rest of the procedure stays the same. If you make changes to the package without changing the source, you can just tag a new release with tito. If you do update the source tarball, you need to update the Version:
field and reset Release:
to 0%\{?dist}
before tagging.
The tarball-adapted version of the project can be found in the foreign-sources branch of the git repo. |