Module 8: Releasing your app on OpenStore

In this last module you’ll prepare your app so it’s ready to be released into the wild. The end result is your app in the OpenStore, the official Ubuntu Touch app store.

1. Introduction

In this course you have developed a shopping list app. We hope this has inspired you to develop your own idea into an Ubuntu Touch app. In this last module of the course we’ll show you how to make it ready to release it on the OpenStore. We’ll also show you the ropes of version control with Git.

2. Choosing a license for your app

When we created the shopping list app from the template in the second module of this course, the clickable create command asked you to choose a license for your app. It offered you the following choices:

  1. GNU General Public License v3

  2. MIT license

  3. BSD license

  4. ISC license

  5. Apache Software License 2.0

  6. Not open source

Take some time to think about what license you want to choose for your app. The most important choice is between an open-source license and a proprietary ("Not open source", or closed-source) license. The Open Source Initiative lists the criteria of an open-source license in the Open Source Definition. This is a summary of the criteria:

  1. Free Redistribution

  2. Source Code

  3. Derived Works

  4. Integrity of The Author’s Source Code

  5. No Discrimination Against Persons or Groups

  6. No Discrimination Against Fields of Endeavor

  7. Distribution of License

  8. License Must Not Be Specific to a Product

  9. License Must Not Restrict Other Software

  10. License Must Be Technology-Neutral

Read the full definition on the Open Source Initiative’s web site for the details.

A software license that doesn’t adhere to these criteria is a proprietary license. Most often it means that the source code isn’t distributed. But it’s also possible that the license has some severe restrictions on the use of the software.

We in the UBports community believe in the power of open-source software, so we won’t advocate the use of a proprietary license for you app. But if you really want to, you can. The OpenStore also accepts proprietary apps.

Now if you believe in open-source software, there are some differences between copyleft licenses such as the GNU General Public License v3 (GPLv3) on the one hand and permissive licenses such as the MIT license, BSD license, ISC license and Apache Software License 2.0 on the other hand.

A copyleft license requires the licensee to distribute derivative works under the same license. This means that if you distribute your app under the GPLv3, no one can create a derivative of your app while relicensing it, for instance under a proprietary license without distributing the source code. Most of the core apps in Ubuntu Touch are distributed under the GPLv3.

On the other hand, if you distribute your app under a permissive license such as the MIT license, someone else can create a derivative of your app and relicense it, even under a proprietary app and without distributing the source code, as long as the software includes a copy of the terms of the MIT License and a copyright notice (with your name, as the original author).

You can find more information about some popular open source licenses on the web site of the Open Source Initiative, and if you want a translation of the legalese to plain English, consult the web site tl;drLegal. GitHub also has a page Choose an open source license that helps you with making the choice.

3. Version control with Git

You don’t develop your app in one session. Just like we did in the modules of this course, you start with a basic app, add some functionality, fix bugs, and this is an ongoing process that never ends. Ultimately you’ll get contributions from others.

To track and manage all these changes to your app’s code, you need a version control system, such as Git. It tracks every change you make, and lets you easily return to earlier versions or merge versions contributed by other developers.

While it’s possible to develop your app without using a version control system, it’s not recommended. That’s why we’re giving a crash course in Git in this section.

3.1. Install and configure Git

In Ubuntu you can easily install Git from the distribution’s standard repository:

sudo apt install git

Now configure your name and email address as global configuration values for Git with the following commands:

git config --global user.name "Koen Vervloesem"
git config --global user.email "koen@ubports.com"

Replace these by your own name and email address. These details will be linked to any code you’ll put in version control.

3.2. Initialize your Git repository

A Git repository is a collection of files in a project. You can turn any directory into a Git repository by typing git init in the directory. This creates a hidden .git directory with information about the files and changes to track.

So go to your app’s directory and initialize a repository:

cd shoppinglist
git init

If you now enter git status, you’ll see:

$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore
        .gitlab-ci.yml
        CMakeLists.txt
        LICENSE
        README.md
        assets/
        clickable.yaml
        manifest.json.in
        po/
        qml/
        shoppinglist.apparmor
        shoppinglist.desktop.in

nothing added to commit but untracked files present (use "git add" to track)

This shows you that Git knows a lot of files in the repository, but it doesn’t track them yet.

Git doesn’t show the build and .clickable directories because they are listed in the .gitignore file from the Clickable template. Files and directories listed in .gitignore are never tracked, added or committed.

Now let’s add all files in the directory and commit them:

git add .
git commit -m "Initial commit"

We’ll explain these commands in the next subsection, but here it suffices to know that this adds all existing files to the repository and saves their current state.

3.3. Creating an online repository on GitLab

Normally you’re working with two repositories: one local and one online. The local repository is the one you created earlier on your computer’s (or virtual machine’s) disk. This is where you do all your coding. The online repository is the one where you share changes with others. You can synchronize both repositories (in both ways), and we’ll see later how this works.

But first you need to create an online repository for your project. You can do this on many web sites, and the two most popular ones are GitHub and GitLab. The UBports community is using both, but in recent years the focus has been on GitLab. That’s why we’re showing here how you create an online repository for your Ubuntu Touch app on GitLab.

GitLab is free for individual users. Look at the Pricing page, click on Get started in the Free column, and choose Sign-up for free under GitLab SaaS. Enter your name, choose a username, and then enter your email address and a password.

After you’ve registered, you’ll find your projects on the home page. Click on New project at the top right and then choose Create blank project. Then fill in your project name, a project slug, and a description.

You can choose whether you want to make this project private or public. A private project is only visible for yourself and for users you explicitly grant access. A public project can be accessed by anyone.

You can perfectly make the project private at first so you can start developing your app, and then later make it public when you want to release your app.

Then untick the checkbox before Initialize repository with a README, because the Clickable template of your local repository already has a README file. Finally, click on Create project.

Create a new project on GitLab to publish your repository.
Figure 1. Create a new project on GitLab to publish your repository.

Now GitLab shows you some instructions to link your local repository to the online repository of the project. First add your online repository as a remote:

git remote add origin git@gitlab.com:koenvervloesem/ubuntu-touch-shopping-list.git

Change this to your own URL, which consists of your username on GitLab and the project slug you chose.

Then push your local changes to the remote, while setting it as an upstream:

git push --set-upstream origin master

You’ll have to enter your credentials.

If you refresh your browser page, you’ll see that the project contains all files of your local repository, and it shows your README file (from the Clickable template) under the list of files:

You’ve pushed your local repository to GitLab.
Figure 2. You’ve pushed your local repository to GitLab.

3.4. Working with Git

Now that you have a local and an online repository that are linked to each other, it’s time to explain some basic tasks with Git.

You’ve already seen the command git status, which shows the status of your repository. If your local and online repository are identical, the command shows:

$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

Now if you’ve modified the README.md file and ask the status again, you’ll see this:

$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

You’ll see that Git has detected that README.md has been modified, and it says that this change is "not staged for commit".

To understand this, you need to know that adding changes into your repository is a two-step process. First you have to add your change to your repository’s index (also called staging area). This is done with the suggested git add command.

Reading Git’s output attentively is recommended, because it often suggests what commands to use.

Let’s add the README.md file to the index and then have a look at the status again:

$ git add README.me
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   README.md

Now Git says that your changed file is ready "to be committed". You can commit it to your repository with a commit message:

$ git commit -m "Add OpenStore link"
[master 63fa2fc] Add OpenStore link
 1 file changed, 2 insertions(+)
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

Now your changes have been committed into your local repository, but not yet into your online repository. To share your changes with your online repository, you need to push them:

$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 390 bytes | 390.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To gitlab.com:koenvervloesem/ubuntu-touch-shopping-list.git
   61c68e5..63fa2fc  master -> master
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
These are really the basic Git commands you need to get started. There’s much more to say about Git. Have a look at Git’s online documentation for the reference manual, cheat sheets, videos, and links to external resources, including books.

4. GitLab CI/CD

The project structure you created in the second course module with clickable create created a file that we’ve not yet explained: .gitlab-ci.yml. This is one of the reasons that we chose GitLab als the platform to publish your repository on: Clickable’s templates already have this file to support GitLab CI/CD.

GitLab CI/CD is a tool integrated into GitLab, supporting your app’s development with Continuous Integration, Continuous Delivery and Continuous Deployment. For our purpose, Continuous Integration is the most interesting aspect of GitLab CI/CD. For every push to your app’s repository, the .gitlab-ci.yml file defines commands to build your app automatically.

If you click on CI/CD (with the rocket icon) at the left side bar of your app’s online repository on the GitLab web site, you’ll see what GitLab CI/CD has done for your code:

GitLab CI/CD checks whether your app builds successfully.
Figure 3. GitLab CI/CD checks whether your app builds successfully.

For every commit you pushed to the repository, GitLab CI/CD runs the commands in your .gitlab-ci.yml file, in this case essentially clickable build. If building your app fails, the commit shows failed in the Status column, otherwise passed.

The fact that your app builds successfully doesn’t mean that it works correctly. Especially with a QML-only app a lot of things can still fail at run time.

The commands for each push are run in a pipeline, and a pipeline can run various stages, with potentially multiple jobs for each stage. The .gitlab-ci.yml file from Clickable’s template runs a build stage with a job for each supported processor architecture: armhf, arm64 and amd64.

If you click on the checkbox icon of the build stage of a pipeline in the Stages column, you’ll see the three jobs with their status. Click on one of them to see the output of the clickable build command:

Have a look at the output of the commands run by GitLab CI/CD.
Figure 4. Have a look at the output of the commands run by GitLab CI/CD.

5. Publishing your app on OpenStore

Now that all this is ready, it’s time to publish your app on OpenStore, the official app store of Ubuntu Touch. Let’s go through this step by step.

You need an account on OpenStore to manage your apps. Click on Log In at the top right of the web site. You can choose between logging in via GitHub, GitLab or Ubuntu One. Just choose the one you prefer or the one you have an account for.

5.1. Submit your app

When logged in, click on Submit App at the top right. Carefully read the rules for submission, the app content policy and the list of prohibited apps. If your app conforms to all those rules, enter the app name and app title at the bottom of the page.

To know what values to enter here, have a look at the file manifest.json.in from your app’s repository. This looks like this:

{
    "name": "shoppinglist.koenvervloesem",
    "description": "A simple shopping list app",
    "architecture": "@CLICK_ARCH@",
    "title": "Shopping List",
    "hooks": {
        "shoppinglist": {
            "apparmor": "shoppinglist.apparmor",
            "desktop":  "shoppinglist.desktop"
        }
    },
    "version": "1.0.0",
    "maintainer": "Koen Vervloesem <koen@vervloesem.eu>",
    "framework" : "@CLICK_FRAMEWORK@"
}

Your app name is a unique identifier of your app on OpenStore. It has to match exactly the "name" field in the manifest file, so shoppinglist.koenvervloesem in this case. The app title is shown in the list of apps on OpenStore and on the app’s store page. It has to match exactly the "title" field in the manifest file, so Shopping List in this case. Then click Submit.

5.2. Manage your app

Now you need to enter some information that will be shown on your app’s store page. This information is subdivided into three tabs: Presentation, Discovery and Info. The other two tabs, Stats and Badge, are informational.

In the tab Presentation, add the title, a tag line (shown right under the title on the app’s store page) and a description. Keep the changelog empty for the first time: this will be filled later when you upload a new revision. You can also add up to five screen shots.

You can create a screen shot on Ubuntu Touch by simultaneously holding the volume up and volume down buttons of your phone until you hear a sound and see your screen flashing.
Enter the basic information that OpenStore should show for your app.
Figure 5. Enter the basic information that OpenStore should show for your app.

In the next tab, Discovery, you choose a category and add some keywords that help people to discover your app. If your app contains some "not safe for work" material, enable the NSFW checkbox.

Choose the right category and keywords to make your app more discoverable.
Figure 6. Choose the right category and keywords to make your app more discoverable.

In the Info tab you choose your app’s license from the list and add some URLs. The source URL should be the URL of your app’s online repository. The support URL should be the URL of the issues on this repository, where people can open issues to report bugs or request new features. You can also add a URL for donations and to show a video. Click on Save after you’ve entered all information.

Make sure to add some important URLs for your app’s source code and support.
Figure 7. Make sure to add some important URLs for your app’s source code and support.

5.3. Create a new revision

Now that the information for your app’s OpenStore page is ready, you should create a first version of your app. So first make sure that your manifest.json.in contains the version number you want to use in its "version" field, for instance "1.0.0". Then build your app with the following command:

clickable build

This creates a click file in build/all/app/shoppinglist.koenvervloesem_1.0.0_all.click. The name of the click file will differ of course for your situation.

Now click on New Revision in OpenStore. Make sure Upload Revision via is set to File and then select the click file you just built next to File Upload. For the QML-only app we’ve built we only need to upload one file, because it’s built for the architecture all.

If you build a Clickable app that’s compiled, for instance in Go, Rust or C++, you need to add the click files for every architecture you want the app to run on: armhf, arm64 and amd64.

Then enter something in the changelog. This will tell users what has changed in this version.

Create a new revision for your app.
Figure 8. Create a new revision for your app.

If you click on Create, this creates the new revision and adds this changelog’s revision to the beginning of your app’s changelog. Then set Publish to Yes.

If all goes well, you can see your app in OpenStore now and everyone can install it on their Ubuntu touch phone:

Your app has now been published on OpenStore.
Figure 9. Your app has now been published on OpenStore.
By default your app will have a grey Ubuntu 'circle of friends' logo. If you want to change this, modify the icon file in assets/logo.svg. For instance, you can find more than 300,000 SVG icons on https://www.svgrepo.com/.

6. Maintaining and updating your app

So now users can install your app from OpenStore, but that doesn’t mean your job is done. You need to maintain and update your app. Maybe you find a bug, or someone else reports a bug. Or maybe you add some functionality to your app, or someone else offers you some extra functionality. An app is something that lives!

6.1. Collaborating with others

Your app’s code lives in your own repository, and you probably don’t want anyone else to mess with it. However, others that have an idea to improve your app can create a personal copy of your repository, work on their copy, and then offer you their changes. You can then merge these changes in your own repository.

Let’s show how this works, step by step, by imagining how another person can add a Dutch translation for your app.

In this module we suppose your repository is on GitLab. For other Git hosting providers, such as GitHub, the procedure is generally the same but looks slightly different.

6.1.1. Forking your repository

The other person should visit your project’s home page on GitLab and then click on Fork at the top right:

For this repository to create a personal copy.
Figure 10. For this repository to create a personal copy.

He then selects a namespace for the project URL of the fork, for instance his name. He can change the project name, project slug (part of the URL) or the project description, as well as the visibility level (this probably should be Public):

Forking a repository allows you to make changes without affecting the original project.
Figure 11. Forking a repository allows you to make changes without affecting the original project.

After a click on Fork project, the personal copy of your project is made in the user’s namespace.

If you look at the original project, you’ll now see the number one next to Fork. This shows that your repository has one fork.

Now the other person can clone his fork locally. He needs the repository URL for it, which he gets by clicking on the Clone button of his fork’s home page on GitLab. He chooses the SSH or HTTPS URL and then runs this command (with the URL changed to the one of his repository):

git clone git@gitlab.com:koenvervloesem/ubuntu-touch-shopping-list.git

He can then enter the local repository’s directory and start workin on the code:

cd ubuntu-touch-shopping-list

6.1.2. Creating changes in a branch

It’s recommended to create a branch for a set of related changes you make. So the other person should create a new branch first on his local repository:

git checkout -b i18n-nl

This creates a branch named i18n-nl and checks it out (switches to it) locally.

He then creates his changes by copying the pot file to a file nl.po and adding translations of the strings in msgid to the corresponding msgstr lines:

cp po/shoppinglist.koenvervloesem.pot po/nl.po

Then after thoroughly testing these changes, he adds the new file, commits it and pushes it to his online repository:

git add po/nl.po
git commit -m "Add Dutch translation"
git push

Git complains that the branch doesn’t have an upstream branch (because it’s only created locally):

fatal: The current branch i18n-nl has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin i18n-nl

So he follows the command’s advice and enters this command to push the branch and set the online repository as upstream:

git push --set-upstream origin i18n-nl

6.1.3. Creating a merge request

Git already shows how to create a merge request for this branch:

Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.24 KiB | 632.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote:
remote: To create a merge request for i18n-nl, visit:
remote:   https://gitlab.com/koenvervloesem/ubuntu-touch-shopping-list/-/merge_requests/new?merge_request%5Bsource_branch%5D=i18n-nl
remote:
To gitlab.com:koenvervloesem/ubuntu-touch-shopping-list.git
 * [new branch]      i18n-nl -> i18n-nl
Branch 'i18n-nl' set up to track remote branch 'i18n-nl' from 'origin'.

If the person visits his fork’s home page on GitLab, he also sees this message:

Create a merge request for your branch.
Figure 12. Create a merge request for your branch.

He clicks on Create merge request. This shows that he wants to merge code from koenvervloesem/ubuntu-touch-shopping-list:i18n-nl into ubports/teams/marketing/education/ubuntu-touch-shopping-list:master. He can change the title, add a description, ask for a reviewer, add labels, and more:

GitLab makes it easy to create a merge request.
Figure 13. GitLab makes it easy to create a merge request.

After this, he clicks on Create merge request at the bottom of the page.

If the GitLab CI/CD runs and fails, this will show on the merge request’s page, and the person should fix this locally and pushing the changes again to the branch. The pipeline will run again, and hopefully shows a green checkbox after a while.

6.1.4. Merging a merge request

So now you’ve received a merge request. This will show up as a 1 next to Merge requests in the left side bar of your project on GitLab:

Your project has a merge request.
Figure 14. Your project has a merge request.

Click on the title of the merge request and have a look at the changes by clicking on the Changes tab.

Have a look at the changes in the merge request.
Figure 15. Have a look at the changes in the merge request.

If the changes are trivial, you could just merge this. However, you often want to try the changes before merging them. To make this easier, first add an alias to your ~/.gitconfig file:

[alias]
    mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' -

After this, look at the URL of the merge request. This ends with a number, in this case 1. Then you can check out the merge request with this command:

git mr origin 1

Now test the changes. If they work, click on the Merge button on the merge request’s page.

Then check out the default branch and pull the latest changes from the online repository:

git checkout master
git pull

6.2. Creating new releases

when you have merged some merge requests, fixed some bugs and added some new functionality, it’s time to create a new release of your app.

Every release has its own version number. A popular set of rules for choosing a version number is Semantic Versioning. Basically it says that, given a version number MAJOR.MINOR.PATCH, you increment the:

  • MAJOR version when you make incompatible API changes.

  • MINOR version when you add functionality in a backwards compatible manner.

  • PATCH version when you make backwards compatible bug fixes.

For instance, for a backwards compatible bug fix, change the version number in manifest.json.in from 1.0.0 to 1.0.1. Add and commit this file and push the changes to your repository.

Then rebuild your app with clickable build, log into your OpenStore account and create a new revision. Upload the Clickable file for the new version and create the new release.

Make sure to always change the version in your manifest file before uploading a new release to Open-Store.

7. And much more…​

This is the end of this course, but hopefully not the end of your Ubuntu Touch app development career. Programming is a skill you need to learn by doing. So start with your own app, and let us know what you create!