Introducing a new way of managing, packaging and publishing Nextcloud apps
I’ve been writing a lot of Rust code this year, partly because I used it for some university projects and also because I’ll start writing a master thesis about concurrency in Rust soon.
There are many things I like about Rust and its ecosystem. One of them is the great CLI tooling with Cargo. Cargo is Rust’s build, testing, packaging and crate publishing tool.
So far I haven’t seen anything comparable for Nextcloud. Historically, many of the apps use Makefiles for the dev setup and packing. While some more sophisticated methods have been developed (I wrote about a similar topic a year ago), every project has a different kind of script to do the setup and packaging. That means the workflow is anything but standardized. Moreover, Makefiles aren’t the right tool for this job.
Since Makefiles are part of each app’s version control system, changes to the workflow have to be applied to each app.
That combined, I tried to implement the concepts I liked in Cargo but missed in Nextcloud in a new tool called Krankerl. It’s a very simple command line tool that shall help developers manage, package, sign and publish their apps. The goal is to establish a standardized and reproducible workflow for Nextcloud app devs. While I’m happy if others find this tool useful, I primarily develop this for my own needs since I’m maintainer of a few apps.
A quick overview
Right now, those are the commands included in Krankerl 0.4:
Usage:
krankerl enable
krankerl disable
krankerl init
krankerl list apps <version>
krankerl list categories
krankerl login [--appstore | --github] <token>
krankerl package
krankerl publish (--nightly) <url>
krankerl sign --package
krankerl --version
Options:
-h --help Show this screen.
--version Show version.
Packaging
One of the key features of Krankerl is app packaging. This means, taking an
app’s files and putting them into a .tar.gz
. For very simple apps it isn’t really
more than that. However, more complex apps will require some additional steps for
the packaging. For that purpose, Krankerl uses a krankerl.toml
configuration
files that lets you specify commands to run before packaging.
Too keep things reproducible, the tool assumes git is used as version control system.
Krankerl doesn’t change the state of the local app repository. Instead, it clones
the current HEAD
into a new directory, from where it starts the packaging process.
There’s an additional setting for exclude patterns. This allows to shrink the size of app archives by excluding git, testing and unnecessary files.
Note: The app will fall back to sensible configuration defaults if no krankerl.toml
file is found.
Signature
Nextcloud apps distributed via the official app store are signed. Thus, before we
can push a new release to the app store, we have to invoke OpenSSL and have it
do its crypto magic. Historically, this was one of the commands of a typical
Makefile. Krankerl has a simple command for it. It follows the convention of
finding app keys in the ~/.nextcloud/certificates
directory and thus locates
your keys automatically by reading the app ID from appinfo/info.xml
.
Note that Krankerl only creates a signature for the archive. Nextcloud also has
got a code signature support where it basically generates a hash values for every
file in the app directory and signs the JSON-encoded list of file hashes. I’ve
tried to re-implement this feature in Rust but I’ve failed at the point where
I realized PHP uses a JSON encoding different to the one used in the serde_json
crate for Rust and thus the signatures are wrong.
Publishing
Currently, I manually publish app release in the following way:
- git tag the current commit
- push the tag to GitHub
- run
make appstore
- open the GitHub releases page and upload the
.tar.gz
- copy the
.tar.gz
URL - open the publish page on the app store
- paste the archive URL
- go back to the terminal and copy the archive signature (generated by the Makefile script)
- paste the signature on the app store
- hit submit
Those are simple, but many steps I have to take every single time I want to publish an app release. Obviously, this quickly gets annoying, especially if you are maintainer of a bunch of apps.
The Nextcloud app store has a simple and well documented REST API.Thus it’s easily possible to automate the task of registering the app release. From the above steps, Krankerl can take over step 3, 6, 7, 8, 9 and 10. That means, the only manual tasks left are uploading the archive to GitHub. The rest is fully automated and thus can be done a lot faster.
More helpers
Since we’ve got a neat little helper for the CLI, I thought it wouldn’t hurt to have a few
shortcuts to enhance the CLI experience. I find myself enabling/disabling apps a lot, thus
I’ve added an enable
and disable
command that simply invokes the occ
with the app ID
extracted from the info.xml
file.
Download and run
Thanks to Rust, all you need to run the tool is to download and execute it. It should just work without installing any dependencies, assuming it’s being used on 64bit Linux, which is what I’ve compiled it for.
The name
In case you wondered about the app’s (strange) name: the word Krankerl means tendril in Lower Austrian dialect. This is what they look like: I chose it in lack of a better name.
Feedback welcome
Though, as noted my goal isn’t to change every Nextcloud app developer’s workflow by introducing this tool, I’d be more than happy if others find this useful and we can further improve those workflows. If you have any further ideas, questions or problems, please let me know in the GitHub issue tracker!
Some personal ideas for future enhancements are
- Automatically upload the archive to a GitHub release
- Specify the test commands (e.g. karma, phpunit) in
krankerl.toml
and execute them withkrankerl test
- Detect local changes in the app repo and force developers to commit before packaging to keep things reproducible
- Automatically add git tags and update the version number in
info.xml
Update 2018-03-27: Replaced externally hosted image with embedded one.