Context

A beta version of your awesome open-source software has been released. Great news so far. Except from introducing new features, fixing bugs and answering users’ questions, it’s really important to have an estimation of the total number of users. In case you are not the only user of your OSS, it’s significant to monitor the active users for the following reasons:

  1. Motivation. Knowing that people are using you software will motivate you to keep maintaining and improving your project.
  2. Trustworthy software. Spreading the total number of active users indicates that your OSS is trustworthy.

So, this article is going to present a way to count active users and installations using Github Actions.

Numerous package distributors

Nowadays, there are numerous ways to distribute your OSS. Snapcraft and Flatpak are two of the most known package management tools. Have in mind that you always have to provide the option to “Build from source” to keep your geek users happy too. In a nutshell, you have to provide various installation methods, therefore, you have to summarize active users from more than one sources.

Count installations

So, let’s dig into how to count installations and active users for each installation method.

Kickstart script

A common way to distribute your OSS is by providing a kickstart shell script, the purpose of this script is to download, build and install the software locally. In the case of dropboxignore, there is a kickstart script, and the installation instructions look like:

MethodCommand
curlsudo sh -c “$(curl -fsSL https://rb.gy/12plgs)" c
wgetsudo sh -c “$(wget -qO- https://rb.gy/12plgs)" w

as you can see, I’m using and extra parameter at the end of each command in order to specify which lib was used to download the script (via wget or curl)

Inside the kickstart file, when installation is completed, I’m making few HTTP requests in order to count the installation process that just finished:

INSTALL_COUNT_URL="https://api.countapi.xyz/hit/dropboxignore.simakis.me"

if [ "$0" == c ]; then
  curl -s --request GET --url "${INSTALL_COUNT_URL}/wget" > /dev/null
  curl -s --request GET --url "${INSTALL_COUNT_URL}/total" > /dev/null
elif [ "$0" == w ]; then
  wget -q "${INSTALL_COUNT_URL}/curl" -O /dev/null 2> /dev/null
  wget -q "${INSTALL_COUNT_URL}/total" -O /dev/null 2> /dev/null
fi

CountAPI is a simple way to store stateful information like the total number of installations. You have to create a namespace for your project, and after that, make an GET /hit/:namespace?/:key to increase total installations by one.

Finally, you can get the total number of installations by making an GET /info/:namespace?/:key. In case of dropboxignore:

$ MANUAL_INSTALLATIONS=$(curl -s https://api.countapi.xyz/info/dropboxignore.simakis.me/total | jq -r .value)
$ echo $MANUAL_INSTALLATIONS
12

At the time of writing dropboxignore has been installed 12 times using the kickstart.

Snapcraft

Another common way to distribute your software is as a snap. Snapcraft provides a nice monitoring dashboard:

Snapcraft-dashboard

But in our case, this is not enough, we have to extract the raw data programmatically. For this reason we are going to use Snapcraft CLI and Snapcraft Action

To get snapcraft metrics, you have to export a credential file and to create a github secret using the content of the exported file:

$ snapcraft login
$ snapcraft export-login exported

In order to get the current total number of active user, you have to use the snapcraft metric command:

$ SNAP_INSTALLATIONS=$( \
  snapcraft metrics dropboxignore --name installed_base_by_channel \
                                  --start "$(date +"%Y-%m-%d" --date="yesterday")" \
                                  --end "$(date +"%Y-%m-%d" --date="yesterday")" \
                                  --format=json \
  | jq '.series[].values[]' \
  | awk '{s+=$1} END {printf "%.0f\n", s}' \
)
$ echo $SNAP_INSTALLATIONS
118

So, 118 users have installed dropboxignore using snap.

Summarize

The easy part is to summarize user from different sources:

$ TOTAL_INSTALLATIONS=$((MANUAL_INSTALLATIONS + SNAP_INSTALLATIONS))
$ echo $TOTAL_INSTALLATIONS
130

130 users. I’m already boosted morally 🤣.

Automate the boring staff using Github Actions

Finally, given that we retrieved the necessary information programmatically, we are going to create a nightly job to store active users. The wiki of the repo should be enabled, so, we will use the wiki to store the statistics.

JSON_BADGE_STRING=$(cat <<-END
{"schemaVersion": 1, "label": "installations", "message": "$TOTAL_INSTALLATIONS"}
END
)
JSON_FULL_STRING=$(cat <<-END
{"manual-installations": "$MANUAL_INSTALLATIONS", "snap-installations": "$SNAP_INSTALLATIONS", "total-installations": "$TOTAL_INSTALLATIONS"}
END
)
FILENAME="$(date +"%Y-%m-%d" --date="yesterday")-stats.json"
echo "$JSON_BADGE_STRING" > latest-stats.json
echo "$JSON_FULL_STRING" > "$FILENAME"

git add latest-stats.json
git add "$FILENAME"

if ! git diff --staged --exit-code
then
    git config --global user.email "coverage-comment-action"
    git config --global user.name "Coverage Comment Action"
    git commit -m "$(date +"%Y-%m-%d" --date="yesterday") stats"

    git push -u origin
else
    echo "No change detected, skipping."
fi

Badges everywhere

There is always space for one more badge with the total number of installations-badge

Badges

Cronjob using Github Actions

The number of active users is updated every night using the following job:

name: Nightly stats

on:
  schedule:
    - cron: "1 1 * * *"
  workflow_dispatch:

jobs:
  stats:
    runs-on: ubuntu-latest

    steps:
      - name: Install Snapcraft
        uses: samuelmeuli/action-snapcraft@v1
        with:
          snapcraft_token: ${{ secrets.SNAPCRAFT_LOGIN_FILE }}
      - name: Install os dependencies
        run: sudo apt update && sudo apt install curl jq git
      
      - name: Create stats file
        run: sh -c "$(curl -fsSL https://raw.githubusercontent.com/sp1thas/dropboxignore/master/utils/stats.sh)" '${{ secrets.GITHUB_TOKEN }}'

Next steps

  • Count manual uninstalls.
  • Count flatpak installations.

References