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 ayear ago http://blog.wuc.me/2016/11/29/sign-nextcloud-app.html), 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.tomlfile 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_jsoncrate 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
The Nextcloud app store has asimple and well documented REST API https://nextcloudappstore.readthedocs.io/en/latest/restapi.html.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 todownload https://github.com/ChristophWurst/krankerl/releases 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 meanstendril https://www.instagram.com/p/BatDv1DhhOe/ in Lower Austrian dialect. 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 https://github.com/ChristophWurst/krankerl/issues!Some personal ideas for future enhancements are
- Automatically upload the archive to a GitHub release https://github.com/ChristophWurst/krankerl/issues/8
- Specify the test commands (e.g. karma, phpunit) in krankerl.toml and execute them with krankerl 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