Getting Started

This guide will provide getting started instructions for local and Docker Usage, along with GitHub Workflows.

Concepts

A Contributors File

A contributors file is something like a .zenodo.json, a codemeta.json, or an .all-contributorsrc. It’s a file that you might find in your repository, and it generally has metadata including a list of contributors. Tributors lets you interact with (create or update these files) via the tributors update command.

# auto-detect metadata files in the present working directory
$ tributors update

# target a specific metadata file, .all-contributorsrc
$ tributors update allcontrib

A Tributors Cache File

To share metadata between these files, tributors uses a shared cache, the .tributors file. This file is updated when you run tributors update-lookup, and is indexed by the GitHub login.

Lookup From

By default, whenever you issue a tributors update command, since the code lives in a GitHub repository and we are looking for contributors, we ping the GitHub API to find them. We can view this as a tributors resource, or basically any endpoint, service, or file that we can use to discover contributors. We are basically saying:

Tributors, update my metadata file with contributors from github.

However, let’s say that we have two metadata files, an .all-contributorsrc and .zenodo.json. By default they will (separately) be updated via the GitHub contributors API endpoint, and also share metadata via the .tributors cache. But what if there are contributors in one of the files that we want to add to the other, and those contributors aren’t found in the GitHub API (and thus would not be added?) We would equivalently want to say:

Tributors, update my metadata file with contributors from this other metadata file.

And in fact, we can do this with tributors update by adding the --from argument.

$ tributors update allcontrib --from zenodo

(note that this feature is currently under development)

Update .tributors Cache

There are many good places to find metadata about contributors that aren’t necessary contributor files. For example, a .mailmap file would have a mapping between names and emails, and any of the previously mentioned files (.zenodo.json, .all-contributorsrc, or codemeta.json) can be used as a metadata lookup without touching a contributors metadata file. Let’s say that we want to just update our .tributors shared metadata cache without touching any files. We can do that with tributors update-lookup:

# auto-detect lookup files in the present working directory
$ tributors update-lookup

# update from the GitHub API
$ tributors update-lookup github

# target a specific metadata file, .mailmap
$ tributors update-lookup mailmap

This would update fields in our .tributors file, and then we could run tributors update on one or more contributor files to update them. Notice that for all operations, if a field is already defined it won’t be over-written, as you might have edited it and don’t want to lose those edits. You of course are free to update or otherwise manually edit all of these files to your liking.

Quick Start

1. Install

Install tributors

pip install tributors

2. Environment

It’s recommended to export a GitHub token to increase your API limit:

export GITHUB_TOKEN=XXXXXXXXXXXXXXX

3. Update Lookups

Before you update your contribution files, you probably want to update your .tributors file, since we can update the contribution files using it. You can do this update by running tributors update-lookup:

# auto-detect known metadata files in the present working directory
$ tributors update-lookup

# update from the GitHub API
$ tributors update-lookup github

# update from a mailmap
$ tributors update-lookup mailmap

Once you’ve updated from the sources that you need, you can move forward to update your contribution metadata files, discussed next.

3. Update

If you have a repository with files already defined, you can use the auto-detect update (not specifying a particular contributor parser):

$ tributors update

or update a specific one:

$ tributors update allcontrib
$ tributors update zenodo
$ tributors update codemeta

If the client finds more than one orcid identifier for a name, you’ll be prompted to run in --interactive mode. Running in interactive mode will allow you to choose a number for each one:

$ tributors update zenodo --interactive
INFO:    zenodo:Updating .zenodo.json
INFO:    zenodo:Updating .tributors cache from .zenodo.json

Meyer, Kyle
======================================================
[1]
  Name: Meyer, Kyle
  Orcid: 0000-0002-1933-2908
  Institutions: University of California Davis, University of Michigan, University of Texas at Austin

[2]
  Name: Meyer, Kyle
  Orcid: 0000-0001-8632-4425
  Institutions: Kroger Co, Northeastern Ohio Medical University, University of Toledo, University of Toledo Medical Center

[3]
  Name: Meyer, Kyle
  Orcid: 0000-0001-8846-7411
  Institutions: University of Auckland, University of Oregon, University of Wisconsin Milwaukee

Please enter a choice, or s to skip.
[1:3 or s to skip] : 

3. Init

You can also create empty files if you don’t have them yet:

$ tributors init allcontrib
$ tributors init zenodo

You can read more about the various parsers for specific-parser arguments, and more details about the above commands in the sections below.

Docker Usage

If you don’t want to use the GitHub Action and don’t want to install npm on your local machine, you can instead interact with the tool in a container.

1. Prepare the Container

First, build the container from the included Dockerfile:

docker build -t tributors .

Then shell inside, ensuring that the entrypoint is changed to bash. You’ll also want to bind your repository to somewhere in the container (not /code).

docker run -it --entrypoint bash -v $PWD/:/data tributors

In the container, tributors is already installed and on the path:

$ which tributors
/usr/local/bin/tributors

The all contributors client is also on the path (and this might be the reason you want to use a container, because this install required npm/node).

$ which cli.js
/code/node_modules/all-contributors-cli/dist/cli.js

You’ll notice that the present working directory is the /github/workspace, and we do this so the container runs easily for a GitHub action (where the code for the user is found here).

2. Generate

Generation coincides with initializing a new file. This is supported for all-contributors and zenodo.json. For codemeta, there are already a suite of tools available.

Generate .all-contributorsrc

Let’s now change directory to where we bound our repository as a volume.

cd /data

If you don’t have an .all-contributorsrc in your present working directory (the root of the repository) you can use tributors to generate an empty one. Tributors will discover the repository name from the .git folder, so you don’t need to provide it.

$ tributors init allcontrib
INFO:allcontrib:Generating .all-contributorsrc for con/tributors

If you don’t have a .git repository, you can export your repository name to the environment as GITHUB_REPOSITORY (e.g., to run it for a repository outside of the one you are sitting in):

export GITHUB_REPOSITORY=singularityhub/sregistry
$ tributors init allcontrib
INFO:allcontrib:Generating .all-contributorsrc for con/tributors

and you can define the repository on the command line too:

$ tributors init allcontrib --repo singularityhub/sregistry
INFO:allcontrib:Generating .all-contributorsrc for con/tributors

or change the path to the file to generate:

$ tributors init allcontrib --allcontrib-file .mycontibrc
INFO:allcontrib:Generating .mycontibrc for con/tributors

In all cases, you’ll generate an empty file:

$ cat .all-contributorsrc 
{
    "projectName": "sregistry",
    "projectOwner": "singularityhub",
    "repoType": "github",
    "repoHost": "https://github.com",
    "files": [
        "README.md"
    ],
    "imageSize": 100,
    "commit": true,
    "commitConvention": "none",
    "contributors": [],
    "contributorsPerLine": 7
}

Generate .zenodo.json

If you want to generate a fresh Zenodo.json, you can do that as follows:

$ tributors init zenodo --doi 10.5281/zenodo.1012531

The same repository rules apply as stated previously - you can define the repository with --repo, in the environment via GITHUB_REPOSITORY, or allow it to be detected from a local .git folder.

If you need to change the path of the file, you can do that too:

$ tributors init zenodo --doi 10.5281/zenodo.1012531 --zenodo-file another-zenodo.json
INFO:zenodo:Generating another-zenodo.json

3. Update contributors

We next want to use the GitHub api to discover contributors to the repository, for either both the .all-contributorsrc and the .zenodo.json, or just one of the two.

Update all

If you want to update both the allcontributors file and the zenodo.json, you can kill two birds with one stone (and essentially cache the GitHub API request) and do the following:

$ tributors update all

Update (auto)

If you have a repository with one or more default contributor files, you can update all of these files that are detected by leaving out the parser name:

$ tributors update
INFO:zenodo:Updating .zenodo.json
INFO:allcontrib:Updating .all-contributorsrc

Note that for any multiple updates, we query the GitHub API to get updated contributors, and also use a cached .tributors file to keep track of shared metadata.

Update allcontributors

Since we already have the contributors file we don’t need to provide the repository name again, however it’s suggested that you export a GITHUB_TOKEN to increase your API limits (if necessary).

$ tributors update allcontrib
INFO:allcontrib:Updating .all-contributorsrc

You can optionally set a minimum number of contributors threshold to add (defaults to 1), or a string to represent the kind of contribution (defaults to “core”)

$ tributors update allcontrib --thresh 10 --allcontrib-type doc

Keep in mind that when you run the command above, the update will only happen for those users with contributors greater than or equal to the threshold.

Note that GitHub bots are not included as contributors, and they are indicated with “[bot]” in the name. If you find that you hit the API limit, then you will see this:

$ tributors update allcontrib
INFO:a2z:Updating .all-contributorsrc
Response 403: rate limit exceeded, cannot retrieve user RonaldEnsing.

And should export a GITHUB_TOKEN to increase it.

Update zenodo.json

Zenodo contributors can be updated similarly:

$ tributors update zenodo
INFO:zenodo:Updating .zenodo.json

You can again export GITHUB_REPOSITORY instead.

Update codemeta

You can quickly update your contributors for a codemeta.json or codemeta.jsonld file that already exists.

$ tributors update codemeta

Local Usage

Local usage means using the Python package directly on your local machine.

1. Install tributors

You can install it from pypi:

pip install tributors

or clone the repository and install locally:

git clone git@github.com:con/tributors
cd tributors
pip install .[all]

or for a development install:

pip install -e .[all]

2. Environment

You can set a log level via the environment via exporting TRIBUTORS_LOG_LEVEL:

export TRIBUTORS_LOG_LEVEL=DEBUG

Tokens can also be exported to increase interaction limits with various APIs:

export ZENODO_TOKEN=xxxxxx
export GITHUB_TOKEN=xxxxxx

2. Generate

Generate means that you don’t have a particular metadata file for a service, and you want to initialize an “empty” one. For each service this means the following:

  • zenodo: .zenodo.json
  • all-contributors: .all-contributorsrc

.all-contributorsrc

The main configuration file for all contributors is the .all-contributorsrc. While you can use the all contributors client to generate an empty file, this might not be ideal if you don’t want to install npm or use the GitHub bot. You can use tributors to generate one without needing these dependencies. To generate one, if you are sitting in the root of your repository, then you don’t need to provide a name:

$ tributors init allcontrib 
INFO:allcontrib:Generating .all-contributorsrc for con/tributors

Of course if the file already exists, you will need to use --force

$ tributors init allcontrib 
.all-contributorsrc exists, set --force to overwrite.

If you can’t parse the name from the repository, you can either define it on the command line:

$ tributors init allcontrib --repo singularityhub/sregistry
INFO:a2z:Generating .all-contributorsrc

or export it to the environment as GITHUB_REPOSITORY (this is how it would be discovered during a GitHub workflow run).

export GITHUB_REPOSITORY=singularityhub/sregistry
$ tributors init allcontrib
INFO:allcontrib:Generating .all-contributorsrc

In both cases, you’ll generate an empty file:

$ cat .all-contributorsrc 
{
    "projectName": "sregistry",
    "projectOwner": "singularityhub",
    "repoType": "github",
    "repoHost": "https://github.com",
    "files": [
        "README.md"
    ],
    "imageSize": 100,
    "commit": true,
    "commitConvention": "none",
    "contributors": [],
    "contributorsPerLine": 7
}

.zenodo.json

If you want to generate a fresh Zenodo.json, you can do that as follows:

$ tributors init zenodo --doi 10.5281/zenodo.1012531

You can also change the zenodo.json file from the default, for example, if you are generating one in a subfolder:

$ tributors init zenodo --doi 10.5281/zenodo.1012531 --zenodo-file subfolder/.zenodo.json

And akin to the all contributors parser, the client will either extract the GitHub repository name directly via git, or you can export it to GITHUB_REPOSITORY. By default, we parse contributors from the GitHub API, and include the creators already defined in Zenodo. You will need this .zenodo.json file to exist in order to update it.

3. Update contributors

Now that we’ve initialized one or more files and possibly also have a .tributors lookup (if one of the parsers generates it on init) we would want to use the GitHub API to discover contributors to the repository, for either both the .all-contributorsrc and the .zenodo.json, or just one of the two. Note that you can read more about the .tributors file, and notably you can edit it to add or change metadata that you want then used across your files.

Update all

If you want to update both the allcontributors file and the zenodo.json (or more generally all client parsers), you can kill two birds with one stone (and essentially cache the GitHub API request) and do the following:

$ tributors update all
INFO:zenodo:Updating .zenodo.json
INFO:allcontrib:Updating .all-contributorsrc

Update (auto)

If you have a repository with one or more default contributor files, you can update all of these files that are detected by leaving out the parser name:

$ tributors update

For an update, each parser will load cached metadata, and then update the contributor metadata file in question (e.g., a .zenodo.json) with new or updated fields.

Update allcontributors

It’s suggested that you export a GITHUB_TOKEN to increase your API limits (if necessary).

$ tributors update allcontrib
INFO:allcontrib:Updating .all-contributorsrc

You can optionally set a minimum number of contributors threshold to add (defaults to 1), or a string to represent the kind of contribution (defaults to “core”)

$ tributors update allcontrib --thresh 10 --allcontrib-type doc

or change the file path

$ tributors update allcontrib --thresh 10 --allcontrib-type doc --allcontrib-file subfolder/.all-contributorsrc

If you give an invalid type it will tell you:

$ tributors update allcontrib --thresh 10 --allcontrib-type pizza
INFO:allcontrib:Updating .all-contributorsrc
Invalid contribution type pizza. See https://allcontributors.org/docs/en/emoji-key for types.

Also note that GitHub bots are not included as contributors, and they are indicated with “[bot]” in the name. If you find that you hit the API limit, then you will see this:

$ tributors update allcontrib
INFO:allcontrib:Updating .all-contributorsrc
Response 403: rate limit exceeded, cannot retrieve user RonaldEnsing.

and should export a GITHUB_TOKEN to increase it.

Update zenodo.json

Here is how to update a .zenodo.json that must already exist.

$ tributors update zenodo
INFO:zenodo:Updating .zenodo.json

You can also provide the filename via --zenodo-file if different from the default.

GitHub Workflows

Since all-contributors requires node, you might find it easiest to interact with the tool via a GitHub action. You can see examples in the examples folder. Inputs are listed below.

Inputs

The command line arguments for the action are equivalent but with underscores instead of dashes.

name description required default
parsers a space separated list of parsers (e.g., “zenodo allcontrib”) or “all” or “unset” for autodetect false unset
zenodo_file .zenodo.json to update. If does not exist, must define zenodo_doi false .zenodo.json
zenodo_doi Zenodo DOI needed for init. Leave unset to skip init. false unset
log_level Log level to use, one of INFO, DEBUG, CRITICAL, ERROR, WARNING, FATAL (default INFO) false INFO
threshold the minimum number of contributions required to add a user false 1
force if files exist, force overwrit false false
allcontrib_file The all contributors file false .all-contributorsrc
allcontrib_type Contribution type, which defaults to “code” if not set. false code
allcontrib_skip_generate skip running all-contributors generate false false
codemeta_file the codemeta file to update, if defined false codemeta.json
mailmap_file the mailmap file to use for update-lookup, if needed false .mailmap
update_lookup one or more resources to use to update the .tributors file before running update false unset
run_twice if you find the action opens two PRs, run the command twice so new folks are added and then metadata updated false true

If you define update_lookup, you should list the (space separated) names of the parsers that you want to use. For example:

   update_lookup: mailmap zenodo

The same file names (e.g., *_file) will be used. Here is an example to update contributors, asking to not run twice.

name: allcontributors-auto-detect

on:
  push:
    branches:
      - main

jobs:
  Update:
    name: Generate
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Tributors Update      
        uses: con/tributors@main
        env:
          GITHUB_TOKEN: $
        with:        
          parsers: unset
          update_lookup: github
          log_level: DEBUG
          force: true
          threshold: 1
          run_twice: false

The above would be followed by a pull request action (e.g., commit and push to main branch or open a pull request).

If you aren’t familiar with all-contributors, you’ll need to add some commenting in your repository README so the client knows where to write.