Making a debian package

Tags: / debian / emacs /

A description of the process of packaging an emacs-elisp MELPA package for Debian.

Earlier this year, I attended MiniDebcamp Kochi 2026 at Bolgatty, Kochi. During this 4-day event, I had the opportunity to interact and learn from long-time debian contributors. I ended up attempting to package an emacs-lisp package. This blog post is a description of the stuff that I did or came across during this packaging.

Objective

The immediate goal in packaging a piece of software for use in debian is the generation of source and binary distributions.

But, how do they look like?

Binary distribution is the one we are more likely to be familiar with: the .deb file. This is what is being used when we install packages via apt. The .deb file targeting specific architectures are built from a source distribution, which is a tar ball.

How do we produce these files? Let's find out.

(Outputs shown are sometimes truncated or edited for clarity.)

ITP

Once you decide on a piece of software that you want to package, you should first make an 'Intent to Package' (ITP) mail to bugs.debian.org. This is to let others know that you are gonna start working on this package and thereby help others avoid duplicating that effort. ITP also helps to figure out if someone has already started working on that project.

It is good to make the ITP a bit detailed without being wordy. Bullet points would be nice, I guess. Points like the following could be addressed:

Fun fact: I actually went on quite a bit with a package before thinking of filing an ITP, only to realize that the package was already available in debian stable. So, better raise an ITP first, so that the risk of your work being wasted is lesser.

I chose to package speed-type, a emacs package that lets us practice touch typing within emacs.

We should receive an acknowledgement mail with the bug number for the ITP some time after submitting the ITP. If you haven't received a bug number even after a few hours, it would be good to ask in IRC or something.

reportbug

In addition to sending mail directly, we can file an ITP using the reportbug tool as well.

$ reportbug --email famubu@domain.tld wnpp

Warning: no reportbug configuration found.  Proceeding in novice mode.
Detected character set: UTF-8
Please change your locale if this is incorrect.

Using 'Julin Shaji <famubu@domain.tld>' as your from address.
Will send report to Debian (per lsb_release).
What sort of request is this? (If none of these things mean anything to you, or you are trying to report a bug in an existing package, please press Enter to exit reportbug.)

1 ITP  This is an `Intent To Package'. Please submit a package description along with copyright and URL in such a report.
2 O    The package has been `Orphaned'. It needs a new maintainer as soon as possible.
3 RFA  This is a `Request for Adoption'. Due to lack of time, resources, interest or something similar, the current maintainer is asking for someone else to maintain this package. They will
       maintain it in the meantime, but perhaps not in the best possible way. In short: the package needs a new maintainer.
4 RFH  This is a `Request For Help'. The current maintainer wants to continue to maintain this package, but they need some help to do this because their time is limited or the package is
       quite big and needs several maintainers.
5 RFP  This is a `Request For Package'. You have found an interesting piece of software and would like someone else to maintain it for Debian. Please submit a package description along with
       copyright and URL in such a report.

Choose the request type: 1
Please enter the proposed package name: speed-type
Checking package information...
Please briefly describe this package; this should be an appropriate short description for the eventual package: Practice touch and speed typing within emacs
Your report will be carbon-copied to debian-devel, per Debian policy.
Querying Debian BTS for reports on wnpp...
7609 bug reports found:

 Bugs with severity normal: 1406 remain
     1)  #140577  RFA: knews -- Graphical threaded news reader
     2)  #332498  RFH: openssl -- Secure Socket Layer (SSL) binary and related cryptographic tools
     3)  #354174  RFA: nas -- Network Audio System - local server
     4)  #374643  O: htdig -- web search and indexing system
     5)  #375733  O: htdig -- web search and indexing system
....
....
....
  2723)  #808427  RFP: kaldi -- Kaldi speech recognition toolkit
  2724)  #808428  RFP: mage-numediart -- toolkit for speech and singing synthesis
  2725)  #808434  RFP: libkgeomap -- Libkgeomap is a wrapper around different world-map components, to browse and arrange photos over a map.
  2726)  #808895  RFP: lofreq -- sensitive variant calling from sequencing data
(2704-2726/7592) Is the bug you found listed above [y|N|b|m|r|q|s|f|e|?]? ?
y - Problem already reported; optionally add extra information.
N - (default) Problem not listed above; possibly check more (skip to Next page).
b - Open the complete bugs list in a web browser.
m - Get more information about a bug (you can also enter a number without selecting "m" first).
r - Redisplay the last bugs shown.
q - I'm bored; quit please.
s - Skip remaining problems; file a new report immediately.
f - Filter bug list using a pattern.
e - Open the report using an e-mail client.
? - Display this help.
(2704-2726/7592) Is the bug you found listed above [y|N|b|m|r|q|s|f|e|?]? s

Spawning sensible-editor...
Report will be sent to Debian Bug Tracking System <submit@bugs.debian.org>
Submit this report on wnpp (e to edit) [Y|n|a|c|e|i|l|m|p|q|d|t|?]? Y
Sending message via /usr/sbin/sendmail...

Bug report submitted to: Debian Bug Tracking System <submit@bugs.debian.org>
Copies sent to:
  Debian Bug Tracking System <submit@bugs.debian.org>
  Julin Shaji <famubu@domain.tld>

If you want to provide additional information, please wait to receive the bug tracking number via email; you may then send any extra information to n@bugs.debian.org (e.g.
nnnnnn@bugs.debian.org), where n is the bug number.  Normally you will receive an acknowledgement via email including the bug report number within an hour; if you haven't received a
confirmation, then the bug reporting process failed at some point (reportbug or MTA failure, BTS maintenance, etc.).
Thank you for using reportbug

Caveat: I couldn't make reportbug work as expected. The report seemed to have gone off successfully, as the tool showed no error. But the ITP never reached bugs.debian.org. I had to manually send a mail afterwards. I think this may be because of a configuration of some tool that actually sends out the mail from my computer.

Packaging

Once obtaining the bug number for the ITP, we can start the packaging. Broadly speaking, debian packaging involves the following steps:

  1. Get a copy of the upstream source code
  2. Adapt it for debian
  3. Build the source and binary distributions

Let us examine each step, one by one.

Get upstream code

First, we set a couple of variables with the name and email id of the person doing the packaging. Value of these variables will be used by the tools that we will be using:

export DEBFULLNAME="My name" 
export DEBEMAIL=my@email.com

Now, we get the source of the software that we are going to package:

git clone -o upstream https://github.com/dakra/speed-type

The -o upstream instructs git to name the remote as upstream instead of the origin. This is the debian recommended name while packaging.

Before proceeding further, following git config commands can be helpful too. Ignore them if not needed.

# Set name used in commits
git config user.name "My name"

# Set email used in commits
git config user.email "my@email.com"

# Set pgp key used to sign commits
git config user.signingkey 5C3B9F1EF93CB7A6A5C66769DDF7D61086BA8EED

# Sign all commits by default
git config commit.gpgsign true

With that out of the way, we enter the cloned repo and adjust branch names to suit DEP-14.

cd speed-type

# Rename default branch from master or main to upstream/latest
# This makes upstream/latest to point to the latest commit in the
# development branch of source repo
git branch -m upstream/latest

# Remove upstream tracking information from repo
git branch --unset-upstream 

# Check out tag latest release
git checkout 1.7

# Duplicate latest release branch with the name debian/latest
# This branch points to the last commit in the debianized source
git checkout -b debian/latest

Initial 'debianization'

Now, we need to make few files that will adapt the source to work well with debian. These files should be within a directory named debian/. In most cases, the original source of software being packaged is not changed. There are tools to generate a boilerplate for the debian/ files, by examining files in the source and values of shell variables.

Since, speed-type is already available on MELPA, so we can use dh-make-elpa. This tool can do most of the work in 'debianizing' an ELPA package. Similar tools like dh-make-perl, dh-make-golang exist to generate template files for other languages in this manner.

I am not sure how the case of a software having source written in multiple languages is handled. But I am guessing it will be complicated.

We can generate the debian/ directory along with most of the required contents using the following command:

dh-make-elpa --pkg-emacsen

Debian has the Debian Emacsen team which collectively maintain many emacs packages. The --pkg-emacsen flag will instruct dh-make-elpa to mention this team in the files under debian/.

The above command will make a debian/ directory that roughly looks like this:

debian/
├── changelog
├── control
├── copyright
├── docs
├── elpa
├── gbp.conf
├── rules
├── source
│   └── format
└── watch
  • control: specifies package name, maintainer and author names, pre-requisite packages, etc
  • copyright: clearly mentions the license and copyright holders of the files in the package
  • docs: lists files that are only for documentation
  • gbp.conf: info used by the gbp command
  • rules: kind of like a Makefile
  • source/format: determines the format of source package
  • watch: Used by uscan to see if there are newer releases

Among these files, control and copyright are probably the ones that requires the most attention.

I just mentioned a couple of tools like gbp and uscan. Debian comes with a bunch of packages that people have created over time to help with packaging. Some of them are very commonly used. gbp and uscan are two of them. You can read more about it if you find them interesting.

  • gbp: Git build package
    • git integration for debian build system
    • Among other things, can import a debian package into git
  • uscan: upstream scan
    • check upstream for changes to help maintainer figure out if it's time for a new release

Anyway, at this point, we could make a commit.

git add debian
git commit -S -m "initial Debianisation"

Fine-tuning debianization

The files generated by dh-make-elpa inside the debian/ directory serves as a starting point. We need to modify these files to suit our package. Let's look at few of the files and directories within debian/.

Patches

Sometimes, the upstream source of the target software cannot be used in debian as is. In such cases, we patch the original source to apply appropriate modifications. Such patches will be stored in debian/patches/. We can create patches using the quilt tool.

I needed to first set the QUILT_PATCHES variable to make quilt generate the patches in the correct directory. Just to be safe, we first apply all existing patches, in case there are pre-existing patches.

QUILT_PATCHES=debian/patches
quilt push -a

Suppose the upstream source has a file named random.txt that we don't wish to include in the source distribution. We can make a new patch named remove-random like:

# Make a new patch named 'remove-random'
quilt new remove-random

# Indicate that the file to be patched
quilt add random.txt

# Make the edits for the patch
# We could also simply use and editor for this.
quilt edit random.txt

# Include the edit to the 'remove-random' patch
quilt refresh

# At this point, we can see the changes if we want
quilt diff

# Remove all patches, restoring the source to its original state
quilt pop -a

Note: gbp pq can also be used to set up patches.

changelog

As the name implies, the debian/changelog file records the history of changes to the debian package. This file mentions many things, including the version and target debian distribution. We also indicate that the acceptance of this package will close the bug number associated with the ITP that we made for it. I think eventually, the corresponding RFS bug number will also get included, but that will be for the sponsor to include.

See: https://www.debian.org/doc/manuals/debmake-doc/ch06.en.html#changelog

The changelog for the first debian revision of our package looked like:

emacs-speed-type (1.7-1) UNRELEASED; urgency=medium

  * Initial release (Closes: #1139675)

 -- Julin Shaji <famubu@domain.tld>  Thu, 11 Jun 2026 09:06:35 +0530

The most important part of the changelog is probably the version number. This is the only place where the version of the package is mentioned. There are some conventions in determining the version number of the package. For example, in our package, the version number is 1.7-1. The upstream release version is 1.7, the -1 indicates that this is the first revision for debian.

Few examples:

  • 1.0~alpha: an alpha pre-release
  • +dfsg: non-free parts removed
  • ~dfsg1: debian release before upstream release
  • 1.2~git20260101.abcdef: package from git snapshot
  • 2.3+really2.2-1: a newer upstream v2.3 rolled back to an older version v2.2-1
  • 1.4-5+deb10u2: second stable update to v1.4-5 in debian 10
  • 1.4-5+deb10u1~bpo9u1: a package in debian 10 backported in debian 9
  • Version without a hyphen to indicate debian revision means that the package is debian native

See:

Lintian is going to get annoyed with the UNRELEASED in this file, but you should not change it till the package is ready for final upload to the actual debian FTP server (not mentors.debian.net, I guess). I think changing the UNRELEASED part also comes under purview of the sponsor. It could get changed to unstable.

The dch -i command (debian change) may be used to bump the version number of the package. It will trigger the opening up of a modified debian/changelog for us to add notes.

control file

The debian/control file contains information about the source and binary packages being created. Among other things, it specifies their dependencies.

In our case, most of the file is as generated by dh-make-elpa. I only needed to change the package names and description. This is the control file that I ended up with:

Source: emacs-speed-type
Section: editors
Maintainer: Debian Emacsen team <debian-emacsen@lists.debian.org>
Uploaders: Julin Shaji <famubu@domain.tld>
Build-Depends: debhelper-compat (= 13),
 dh-elpa
Standards-Version: 4.7.4
Vcs-Browser: https://salsa.debian.org/emacsen-team/speed-type
Vcs-Git: https://salsa.debian.org/emacsen-team/speed-type.git
Homepage: https://github.com/dakra/speed-type
Testsuite: autopkgtest-pkg-elpa

Package: elpa-speed-type
Architecture: all
Depends: ${elpa:Depends}, ${misc:Depends}
Recommends: emacs
Enhances: emacs
Description: Practice touch and speed typing
 Speed-type allows you to practice your touch typing skills.  You can
 test yourself by typing snippets from online books or use any piece
 of text or code you have in Emacs.  Speed-type keeps track of your
 stats (WPM, CPM, accuracy) while you are typing.

As per the Debian emacsen team policy, the source and binary distribution for my target package must have different names (emacs-speed-type and elpa-speed-type respectively).

The names like ${elpa:Depends} are substvars (substitution variables). In this case, it's a substvar defined by dh_elpa which is implicitly invoked by dh while building the package. We can also define substvars of our own if needed inside debian/substvars.

See:

gbp

The debian/gbp.conf file has information that can be used when gbp needs to be invoked. For my package, I modified the template made by dh-make-elpa and got it to look like this:

[DEFAULT]
upstream-branch = upstream/latest
debian-branch = debian/latest
upstream-tag = %(version)s
debian-tag = debian/%(version)s

sign-tags = True
pristine-tar = False
pristine-tar-commit = False

For example, this makes gbp use upstream/latest as the value for its --git-upstream-branch option.

Remember how we named/re-named branches after cloning source repo in the beginning? The resultant names are in line with DEP-14, and are the names mentioned in here.

  • upstream/latest: latest commit in the development branch of upstream
  • debian/latest: latest commit in debianized version of the source code

At first, I wasn't sure if upstream/latest and debian/latest were meant to be branches or just tags. But I later realized that those two are branches, but names like upstream/<version> are to be tags.

See:

Pristine tar: We can have the original source tar ball from upstream (if any) in a separate branch named pristine-tar. I didn't include a pristine tar ball, since my upstream doesn't provide an explicit tarball. But since the source is hosted on github, it does have git tags corresponding to latest release, which means github auto-generates a tarball. But I still didn't use it since the other emacs packages doesn't seem to be having them either.

See: https://wiki.debian.org/DebianPackaging--pristine-tar-option-explained

watch file

uscan uses the watch file at debian/watch to figure out where to look to see if there are new releases for the package. The watch file for the package that I had been trying ended being like this:

Version: 5

Template: Github
Owner: dakra
Project: speed-type

dh-make-elpa generated a watch file with version 4, which looked more complex.

For comparison, the version 4 one made by dh-make-elpa looked like this:

version=4
opts="filenamemangle=s/(?:.*?)?v?(@ANY_VERSION@@ARCHIVE_EXT@)/@PACKAGE@-$1/" \
    https://github.com/dakra/speed-type/tags \
    (?:.*?/)?@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate

These specify values for various options of uscan. Values like @ARCHIVE_EXT@ are special strings that will automatically get substituted with appropriate values by uscan.

See:

source/format

If I understand correctly, this file specifies how the source package distribution is built. 3.0 (quilt) seems to be the usual choice, although others choices are also available. Like 3.0 (native) for native packages. As per a page on wiki.debian.org, 'Less than 5 % of Debian's source packages are not in 3.0 (quilt) format' This format has the advantage of letting us keep the patches distinct from the source.

In my case, the source/format generated by dh-make-elpa was sufficient uncharged:

3.0 (quilt)

See:

upstream/metadata

debian/upstream/metadata is a yml file contains metadata related to the upstream in machine readable form. I don't think I saw any lintian errors nudging me to include this file, but many emacs packages that recently got accepted to unstable had this file, so I thought I would add one too. I got it like:

---
Bug-Database: https://github.com/dakra/speed-type/issues
Bug-Submit: https://github.com/dakra/speed-type/issues/new
Repository: https://github.com/dakra/speed-type.git
Repository-Browse: https://github.com/dakra/speed-type

This information will be useful for uscan.

I am not sure, but I think this file is especially relevant if we are using a watch file with version 5 onwards.

rules

The debian/rules is the build script of the package. It is an executable Makefile that specifies how to build the package. In our case, we delegate the whole thing to debhelper commands so there is not much left to do. I didn't have to change the debian/rules generated by dh-make-elpa, which looked like:

#!/usr/bin/make -f

%:
    dh $@ --with elpa

Using the rules Makefile, we should be able to do stuff like:

  • Clean build environment: debian/rules clean
  • Build package: /debian/rules build
  • And others like binary, binary-arch, build-arch, etc.

An example:

$ debian/rules clean
dh clean --with elpa
   dh_clean

Building

We got all the files needed for building the package ready, so let us get on with building the package.

For a package, we need the following:

  • Source distribution
  • Binary distribution

We can make a tar ball of the original source with:

git deborig

This creates a speed-type_1.7.orig.tar.xz file containing the source from upstream as is. deborig is not a part of a standard git installation and is from the devscripts package of debian.

Note: Somehow deborig will also create a file named test.bin. I needed to delete it before building the package.

By this point, we are all set to build the package. The package can be built with:

dpkg-buildpackage

This created a few extra files.

  • elpa-speed-type_1.7-1_all.deb: binary distribution
  • speed-type_1.7-1.debian.tar.xz: contents of the debian/ directory
  • speed-type_1.7-1.dsc: metadata, with info like files involved
  • speed-type_1.7-1_amd64.buildinfo: for reproducible builds. Has info on the environment used to build the package
  • speed-type_1.7-1_amd64.changes: contains information used while uploading the package

Thus, we have obtained the source and binary distributions. These can now be uploaded to the FTP servers. But before that, we should push all the files that we got to the repo mentioned under Vcs-git in the debian/control file. I did it like this:

git push https://salsa.debian.org/emacsen-team/emacs-speed-type --all
git push https://salsa.debian.org/emacsen-team/emacs-speed-type --tags

Uploading

Before uploading, the built package needs to be signed by the packager. This can be done via debsign:

$ debsign -k 5C3B9F1EF93CB7A6A5C66769DDF7D61086BA8EED emacs-speed-type_1.7-1_amd64.changes
 signfile dsc emacs-speed-type_1.7-1.dsc 5C3B9F1EF93CB7A6A5C66769DDF7D61086BA8EED

 fixup_buildinfo emacs-speed-type_1.7-1.dsc emacs-speed-type_1.7-1_amd64.buildinfo
 signfile buildinfo emacs-speed-type_1.7-1_amd64.buildinfo 5C3B9F1EF93CB7A6A5C66769DDF7D61086BA8EED

 fixup_changes dsc emacs-speed-type_1.7-1.dsc emacs-speed-type_1.7-1_amd64.changes
 fixup_changes buildinfo emacs-speed-type_1.7-1_amd64.buildinfo emacs-speed-type_1.7-1_amd64.changes
 signfile changes emacs-speed-type_1.7-1_amd64.changes 5C3B9F1EF93CB7A6A5C66769DDF7D61086BA8EED

Successfully signed dsc, buildinfo, changes files

Our package needs to reviewed before it can be considered for inclusion to debian repos. We can upload it to mentors.debian.net for this. mentors.debian.net is a platform facilitating review of packages. We can upload our source packages there and other people, including non-DDs, can make comments to provide feedback. It is like a staging area for debian packages.

Our package can be uploaded to mentors.debian.net with:

$ # Can use `dput --force` if re-uploading without version change
$ dput mentors emacs-speed-type_1.7-1_amd64.changes

Checking signature on .changes
gpg: /home/user/speed-type/emacs-speed-type_1.7-1_amd64.changes: Valid signature from 26AF96E2D752882F
Checking signature on .dsc
gpg: /home/user/speed-type/emacs-speed-type_1.7-1.dsc: Valid signature from 26AF96E2D752882F
Uploading to mentors (via https to mentors.debian.net):
  Uploading emacs-speed-type_1.7-1.dsc: done.
  Uploading emacs-speed-type_1.7.orig.tar.xz: done.
  Uploading emacs-speed-type_1.7-1.debian.tar.xz: done.
  Uploading elpa-speed-type_1.7-1_all.deb: done.
  Uploading emacs-speed-type_1.7-1_amd64.buildinfo: done.
  Uploading emacs-speed-type_1.7-1_amd64.changes: done.
Successfully uploaded packages.

You should get an acknowledgement mail from mentors.debian.net after a few minutes, and the package should show up in their webpage.

Fun fact: dput is used upload package to FTP server. Similarly dget can be used to download a package.

RFS

Once the package is ready and uploaded to mentors.debian.net, we need it reviewed and need a sponsor to upload it to debian repos. Only a debian developer (DD) can sponsor packages. We try to get the attention of potential sponsors with a 'Request For Sponsors' (RFS). This can be done with a mail to submit@bugs.debian.org. Template for such a mail can be found at mentors.debian.net. The system will generate a bug number for the RFS.

Note that sending out RFS by no means signify that your package is guaranteed to get sponsored or even reviewed. As I understand, it is generally difficult to find a sponsor (I haven't found one yet for my package). Because the sponsor would need to go through your package (and probably get vexed at mistakes/omissions that you made) and suggest changes, involving a lot of back-forth mails in the process. Bottom line is, sponsor would need to put some work in too, so you might need to be patient (and persistent) before you finally get a sponsor.

Updating RFS

We can reply to the bug number associated with our RFS if we need to mention anything more with regard to that RFS.

I, for one, needed to change the title of the package specified in RFS. So sent this mail to my-rfs-bug-no@bugs.debian.org get it fixed:

Control: retitle -1 RFS: emacs-speed-type/1.7-1 [ITP] -- Practice touch and speed typing
thanks

As I understand it, similar messages can be used to update any bug at bugs.debian.org. And that includes ITPs too. Control mailserver commands are documented here.

Testing

Building the package was the first part of the packaging process. Next thing to do is to check whether software installed via that package works as expected in the latest debian unstable. If the upstream comes with tests, we can use that. Otherwise, not much we can do, I guess. Thankfully, my upstream did have tests.

lintian

Lintian is a tool that acts like linter for debian packages. It is quite good at flagging errors and potential errors We can run lintian on a package like:

$ lintian
W: elpa-speed-type: copyright-contains-automatically-extracted-boilerplate
W: elpa-speed-type: initial-upload-closes-no-bugs [usr/share/doc/elpa-speed-type/changelog.Debian.gz:1]
W: speed-type source: unknown-paragraph-in-dep5-copyright [debian/copyright:30]

Lintian expects the .changes file as argument, but can use the one in current directory if available.

Errors/warning produced by lintian are associated with tags. We can ask lintian to explain the meaning of that tag with lintian-explain-tags. For example:

$ lintian-explain-tags missing-license-paragraph-in-dep5-copyright
N:
W: missing-license-paragraph-in-dep5-copyright
N:
N:   The Files paragraph in the machine readable copyright file references a license for which no stand-alone License paragraph exists.
N:
N:   Sometimes this tag appears because of incorrect ordering. Stand-alone License paragraphs must appear *after* all Files paragraphs.
N:
N:   Please refer to https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ and Bug#959067 for details.
N:
N:   Visibility: warning
N:   Show-Always: no
N:   Check: debian/copyright/dep5
N:

Also, flags can be used to make lintian 'stricter':

lintian -EviIL +pedantic ../emacs-speed-type_1.7-1_amd64.changes

Caveat: The lintian used at mentors.debian.org was outdated when I tried. So some of the errors/warnings that it showed were not relevant. I felt that using the latest lintian version locally would be more instructive.

sbuild

sbuild can build our package in clean, isolated environment. It works on top of a tool named mmdebstrap (usually with unshare backend), if I understand correctly.

The full output of sbuild is too long to include here, but parts of it looks pretty much like how we install packages with apt, because that's exactly what's happening.

Before using sbuild, I did the following to allow my user to use sbuild:

sudo sbuild-adduser famubu

This adds the user named famubu to the group named sbuild. Only members of the sbuild group can invoke sbuild.

$ groups famubu
famubu : famubu audio video users ....... sbuild

Then, invoking sbuild is as simple as:

sbuild

Among other things, sbuild does the following:

  • Make a complete debian sid chroot
  • Install packages that are prerequisite for our package
  • Build the package
  • Run the tests present in the source package
    • Including lintian checks if --run-lintian option is used

Finally, sbuild produces a summary like the one below.

+------------------------------------------------------------------------------+
| Summary                                      Sat, 23 May 2026 06:36:39 +0000 |
+------------------------------------------------------------------------------+

Build Architecture: amd64
Build Type: binary
Build-Space: 1384
Build-Time: 2
Distribution: unstable
Host Architecture: amd64
Install-Time: 28
Job: /home/famubu/speed-type/emacs-speed-type_0.7.0-1.dsc
Lintian: warn
Machine Architecture: amd64
Package: emacs-speed-type
Package-Time: 80
Source-Version: 0.7.0-1
Space: 1384
Status: successful
Version: 0.7.0-1
--------------------------------------------------------------------------------
Finished at 2026-05-23T06:36:17Z
Build needed 00:01:20, 1384k disk space

Looks like sbuild sets up the chroot at: /home/username/.cache/sbuild/unstable-amd64.tar.

autopkgtest

Warning: This section is all guesses. I haven't completely tried them yet.

autopkgtest is used to test the package after installing it from its binary distribution. Its working is described in the current draft of DEP-8. Unlike sbuild which runs tests from the source, autopkgtests are run against the package installed from its binary in a debian environment.

The tests to be run, along with their necessary parameters, are specified in the test control file at debian/tests/control.

  • A test is considered to have passed if it returns 0 and doesn't print anything to stderr
  • The tests are like scripts inside debian/tests/
  • The tests would run with root of the source package as the working directory, but the tests would be testing the installed version of the package.
  • Also see:
    • /usr/share/docs/autopkgtest/README.package-tests.rst.gz
    • /usr/share/docs/autopkgtest/README.running-tests.rst.gz

For example, with the following test control file,

Tests: verbose
Depends: @, build-essential
Restrictions: needs-root
Architecture: amd64 arm64 i386

the debian/tests/verbose test itself could be

!/bin/bash

foo --verbose

and autopkgtest should be able to run the test.

See:

autodep8

The test control is meant to be written in a way that is compliant with DEP-8. The autodep8 tool is helpful to generate the test control file template specific to the target package. The output of autodep8 is meant to be the contents of debian/tests/control.

For example, for the emacs elpa package that I had been using, it gave this:

$ autodep8
Test-Command: dh_elpa_test --autopkgtest
Depends: @, @builddeps@,
Restrictions: rw-build-tree,
Features: test-name=dh-elpa-test-autopkgtest

autopkgtest can automatically use autodep8 by looking at the value of Testsuite in debian/control. This value should be like autopkgtest-pkg-TYPE where TYPE is a package type supported by autodep8. In our case, TYPE is elpa, which is indeed supported, thereby making things easier for us.

salsa tests

Warning: This section is all guesses. I haven't completely tried them yet.

Debian salsa has CI/CD that can run before a package is admitted into unstable. Looks like it runs only basic checks like lintian By default, but we can request it to run the tests meant for autopkgtest as well by making a debian/salsa-ci.yml file like below:

---
include:
  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml

'Manual testing' with containers

Tests like those run by from sbuild and autopkgtest are kind of automatic. Once the configuration has been done, we need not be involved further. But what if you want to play around with the installed package to see if it actually feels all right? Sometimes hiccups can creep in even when all the tests pass. Though it is an ad-hoc way, a way to enter into an environment where the package and its dependencies are installed would be nice. It would let us tinker around and see things from the usability point of view. A full blown VM is unnecessary for this, a container would be sufficient. I went with podman, since it seemed lighter than docker.

Podman is like docker except that it doesn't need a daemon to run. Dockerfiles meant for docker can usually be used with podman without any modification, except that the file name is Containerfile instead of Dockerfile.

snapshot.debian.org provides snapshots that can be used as a basis to build our own pods.

I used this Containerfile:

FROM debian:sid

# Use snapshot
RUN echo "deb http://snapshot.debian.org/archive/debian/20260611T082845Z sid main" \
    > /etc/apt/sources.list

WORKDIR /root

# Install dependencies
RUN apt-get update
RUN apt-get install -y \
      lintian \
      devscripts \
      debhelper \
      dh-elpa \
      git \
      gnupg

# Download source distribution from mentors.debian.net
RUN mkdir ~/.gnupg && \
    chmod 700 ~/.gnupg && \
    gpg --keyserver keyserver.ubuntu.com --recv-keys D752882F && \
    dget -x -u https://mentors.debian.net/debian/pool/main/e/emacs-speed-type/emacs-speed-type_1.7-1.dsc

WORKDIR /root/emacs-speed-type-1.7

# Build package
RUN dpkg-buildpackage -us -uc && \
    lintian -EviIL +pedantic ../emacs-speed-type_1.7-1_amd64.changes

CMD ["bash"]

PWD is location of the Containerfile:

# Build image. 
podman build -t sid:20260611T082845Z .

# Start the pod
podman run -it sid:20260611T082845Z

This will create a sid snapshot, install our package and run the tests. Once that is done, it will enter bash shell where we can examine the leftover files or take out our installed package for a spin.

I can't help feel that someone in debian must have made a tool to sort of automate this when using podman. Especially since it looks as if there are tools for testing via docker like debdocker and debocker are already there.

Useful tools

As mentioned earlier, there is a whole host of tools that debian packagers have developed over the years. Let me mention something about a couple of them.

Many of these tools are implicitly used by other tools.

See: https://wiki.debian.org/PackagingTools

Conclusion

So, in conclusion, I figure the flow for a new-comer to submit a package for inclusion into debian is like this:

  1. Find a package
  2. File ITP
  3. Package the sofware
  4. File RFS
  5. Get package reviewed
  6. Sponsor found

Acknowledgements: Thanks to,