Skip to main content

Detect drift between GitHub releases and Zenodo archives

Project description

zenodo-release-drift

Detect drift between GitHub releases and Zenodo archives.

When a repository is connected to Zenodo via the GitHub–Zenodo webhook, every new release should be automatically archived. In practice the webhook silently fails, gets disabled, or simply falls behind. zenodo-release-drift surfaces those gaps so you can act on them.

Installation

pip install zenodo-release-drift
# or with uv
uv add zenodo-release-drift

Quick start

Check a single repository:

zenodo-release-drift check owner/repo

Scan every repository owned by a GitHub user or org:

zenodo-release-drift check example-org

Example output:

GitHub user or org: example-org
28 repos found, 5 with Zenodo integration.

Repository                  Code    Description              Details
--------------------------  ------  -----------------------  -------------------------------------------
example-org/example-repo    ZRD001  Release(s) not archived  15 release(s) not archived:
                                                             1.2.0, 1.1.4, 1.0.1, ...
example-org/example-repo    ZRD002  Zenodo out of date       Zenodo latest: 1.1.3  |  GitHub latest: 1.2.0

Exit code is 1 when drift is found (single-repo mode), 0 when clean — suitable for CI and pre-commit hooks.

Commands

check

zenodo-release-drift check [OPTIONS] TARGET

TARGET is either owner/repo (single repository) or a GitHub username/org (scans all owned repositories).

Option Description
--json Output findings as JSON
--markdown Output as a Markdown table (single repo only)
--explain Full human-readable explanation of each finding (single repo only)

lint

Explicit single-repository check — useful in pre-commit hooks where the command name should be unambiguous.

zenodo-release-drift lint [OPTIONS] OWNER/REPO

Same options as check.

fix

Upload releases that are missing from Zenodo back to the archive.

zenodo-release-drift fix [OPTIONS] OWNER/REPO

Requires a ZENODO_TOKEN environment variable — a personal access token created at https://zenodo.org/account/settings/applications/.

Option Description
--version Upload only this specific version (default: all missing ones)
--from Only upload versions at or above this semver (inclusive)
--to Only upload versions at or below this semver (inclusive)
--sandbox Target sandbox.zenodo.org instead of production
--json Output results as JSON

How versions are grouped: if Zenodo already holds records for the repository, each upload is created as a new version under the same concept DOI so all versions remain linked. If no existing records are found, a new concept is created.

Note on uploaded source content: the archive uploaded for each version is fetched from GitHub's tag archive endpoint at the moment fix runs, and reflects where the tag points at that time. For the vast majority of repositories this is identical to the original release — tags are not normally moved after publishing. If a tag has been amended since the original release was made, the archive will reflect the current state of the tag rather than its historical state; this is a property of how git tags work rather than a limitation of this tool.

Important — record ownership

The ZENODO_TOKEN you supply must belong to the same Zenodo account that owns the existing records. When the original records were created by the GitHub–Zenodo webhook they are owned by whichever Zenodo account connected the webhook — not necessarily yours. If your token belongs to a different account the newversion API call will return HTTP 403 and the upload will fail with a clear hint message.

To resolve a 403:

  1. Log in to Zenodo as the record owner.
  2. Open the existing record and go to Edit → Share.
  3. Grant your account the Curator role, or ask the Zenodo support team to transfer ownership.
  4. Re-run fix once access is granted.
# Upload every missing release
export ZENODO_TOKEN=your-token-here
zenodo-release-drift fix owner/repo

# Upload a single specific release
zenodo-release-drift fix owner/repo --version 1.2.3

# Upload all missing releases from 1.0.0 onwards
zenodo-release-drift fix owner/repo --from 1.0.0

# Upload all missing releases up to and including 1.4.0
zenodo-release-drift fix owner/repo --to 1.4.0

# Upload missing releases within a range
zenodo-release-drift fix owner/repo --from 1.0.0 --to 1.4.0

# Test against the Zenodo sandbox before touching production
export ZENODO_TOKEN=your-sandbox-token-here
zenodo-release-drift fix owner/repo --sandbox

version

zenodo-release-drift version

Check codes

Code Description
ZRD001 A GitHub release exists with no matching Zenodo archive
ZRD002 The latest Zenodo version is behind the latest GitHub release

Authentication

GitHub (GITHUB_TOKEN)

By default the tool makes unauthenticated GitHub API calls (60 requests/hour limit). Set GITHUB_TOKEN to raise this to 5,000 requests/hour:

export GITHUB_TOKEN=ghp_...
zenodo-release-drift check my-org

Zenodo (ZENODO_TOKEN)

The fix command requires a Zenodo personal access token with the deposit:write scope.

  1. Log in to https://zenodo.org (or https://sandbox.zenodo.org for testing).
  2. Go to Account → Applications → Personal access tokens.
  3. Create a token with the deposit:write scope.
  4. Export it before running fix:
export ZENODO_TOKEN=your-token-here
zenodo-release-drift fix owner/repo

Pre-commit hook

Add to .pre-commit-config.yaml to gate commits on a single repository. Set args to the repository you want to check:

- repo: local
  hooks:
    - id: zenodo-release-drift
      name: Zenodo release drift
      entry: zenodo-release-drift lint
      args: ["owner/repo"]
      language: python
      pass_filenames: false
      always_run: true

Python API

from zenodo_release_drift import lint_repo, lint_repo_explain

# Returns a list of finding dicts
findings = lint_repo("owner", "repo")

# Returns a Markdown string with explanations
report = lint_repo_explain("owner", "repo")

Development

git clone https://github.com/d33bs/zenodo-release-drift
cd zenodo-release-drift
uv sync --all-groups
uv run poe pipeline   # pre-commit + tests

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zenodo_release_drift-0.0.2.tar.gz (119.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zenodo_release_drift-0.0.2-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file zenodo_release_drift-0.0.2.tar.gz.

File metadata

  • Download URL: zenodo_release_drift-0.0.2.tar.gz
  • Upload date:
  • Size: 119.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for zenodo_release_drift-0.0.2.tar.gz
Algorithm Hash digest
SHA256 d66ad734ac35aac1fa854a8ff130d58a8987149df457b34de782f1fef6fd8ed2
MD5 e062eac51cc3020d599f7164825778db
BLAKE2b-256 c89788ae9c67cab8a5cd7a4b0e7ee5f9eaef09621b4f80fba8777512cc1916e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for zenodo_release_drift-0.0.2.tar.gz:

Publisher: publish-pypi.yml on CU-DBMI/zenodo-release-drift

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zenodo_release_drift-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for zenodo_release_drift-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 28ba9332f15dd8265b9e67847b786be4c5aa6d62b94807f9b2455ea1d4abfb5d
MD5 c8464e4f02b9a22b10f008d47bbfbdaa
BLAKE2b-256 727cab859873b35762c5271f78ba1f630501d55bac9e594b81a1a3a6968b343b

See more details on using hashes here.

Provenance

The following attestation bundles were made for zenodo_release_drift-0.0.2-py3-none-any.whl:

Publisher: publish-pypi.yml on CU-DBMI/zenodo-release-drift

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page