Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/actions/setup-uv/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Setup uv with caching
description: Install Python, uv, and sync dependencies with caching

inputs:
dependency-group:
description: 'Dependency group to sync (e.g., dev, test, docs)'
required: true

runs:
using: composite
steps:
- name: Set up Python
id: setup-python
uses: actions/setup-python@v6
with:
python-version-file: ".python-version"

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true

- name: Cache dependencies
uses: actions/cache@v5
with:
path: .venv
key: ${{ runner.os }}-py-${{ steps.setup-python.outputs.python-version }}-uv-${{ inputs.dependency-group }}-${{ hashFiles('pyproject.toml') }}
restore-keys: |
${{ runner.os }}-py-${{ steps.setup-python.outputs.python-version }}-uv-${{ inputs.dependency-group }}-

- name: Sync dependencies
shell: bash
run: uv sync --group ${{ inputs.dependency-group }}
20 changes: 20 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: 2
updates:
# Python dependencies (uv)
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
minor-patch:
update-types:
- "minor"
- "patch"

# GitHub Actions updates
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
88 changes: 88 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: CI (uv)

on:
push:
branches: ["main", "master"]
pull_request:
branches: ["*"]

jobs:
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup uv environment
uses: ./.github/actions/setup-uv
with:
dependency-group: dev

- name: Ruff format (check)
run: uv run ruff format --check

- name: Ruff check
run: uv run ruff check --output-format=github

test:
name: Test (pytest)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup uv environment
uses: ./.github/actions/setup-uv
with:
dependency-group: test

- name: Run pytest with coverage
run: uv run pytest --cov=src/sw_metadata_bot --cov-report=term-missing tests/

- name: Generate coverage badge
run: uv run coverage-badge -o coverage.svg -f
continue-on-error: true

- name: Commit coverage badge
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add coverage.svg
git diff --quiet && git diff --staged --quiet || git commit -m "chore: update coverage badge"
git push
continue-on-error: true

docs:
name: Docs (Sphinx)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup uv environment
uses: ./.github/actions/setup-uv
with:
dependency-group: docs

- name: Build Sphinx HTML
run: uv run sphinx-build -b html docs docs/_build/html

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/_build/html

publish-docs:
name: Publish Docs
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: docs
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
15 changes: 14 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
__pycache__/

.env
.env

# package files
*.egg
*.egg-info/
dist/
build/

# generated files
outputs/*

# docs
docs/_build/
site/
23 changes: 23 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
repos:
- repo: https://github.com/astral-sh/uv-pre-commit
# uv version.
rev: 0.9.26
hooks:
- id: uv-lock
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.13
hooks:
# Run the linter.
- id: ruff-check
types_or: [ python, pyi ]
args: [ --fix ]
# Run the formatter.
- id: ruff-format
types_or: [ python, pyi ]

- repo: https://github.com/PyCQA/bandit
rev: '1.9.3' # Update me!
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# sw-metadata-bot

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![CI](https://github.com/codemetasoft/sw-metadata-bot/workflows/CI/badge.svg)](https://github.com/codemetasoft/sw-metadata-bot/actions)
![coverage](https://img.shields.io/badge/coverage-placeholder-blue)
[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
![coverage](coverage.svg)

An automated bot that analyzes repository metadata quality and creates issues with improvement suggestions.

Part of the [CodeMetaSoft](https://w3id.org/codemetasoft) project to improve research software metadata quality.
Expand Down
19 changes: 19 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os
import sys

project = "sw-metadata-bot"
author = "Tom François"

# Ensure src is on the path for autodoc
sys.path.insert(0, os.path.abspath("../src"))

extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
]

templates_path = ["_templates"]
exclude_patterns = []

html_theme = "furo"
html_static_path = ["_static"]
15 changes: 15 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Welcome to sw-metadata-bot's documentation
==========================================

.. toctree::
:maxdepth: 2
:caption: Contents:


API Reference
-------------

.. automodule:: sw_metadata_bot.main
:members:
:undoc-members:
:show-inheritance:
32 changes: 31 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ authors = [
]
dependencies = [
"click>=8.3.1",
"metacheck",
"metacheck>=0.2.0",
"requests>=2.32.5",
]

Expand All @@ -30,5 +30,35 @@ package = true
package-dir = {"" = "src"}
packages = { find = { where = ["src"] } }

[dependency-groups]
dev = [
"bandit>=1.9.3",
"pre-commit>=4.5.1",
"ruff>=0.14.13",
"ty>=0.0.12",
]
test = [
"pytest",
"pytest-cov",
"coverage-badge",
]
docs = [
"furo>=2025.12.19",
"sphinx",
]

[tool.uv.sources]
metacheck = { git = "https://github.com/SoftwareUnderstanding/RsMetaCheck"}


[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = "-v --tb=short"

[tool.bandit]
exclude_dirs = ["tests",".venv", ".ruff-cache"]
tests = ["B201", "B301"]
skips = ["B101", "B601"]
77 changes: 77 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]

# Same as Black.
line-length = 88
indent-width = 4

# Assume Python 3.9
target-version = "py39"

[lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = ["E4", "E7", "E9", "F"]
ignore = []

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[format]
# Like Black, use double quotes for strings.
quote-style = "double"

# Like Black, indent with spaces, rather than tabs.
indent-style = "space"

# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false

# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"

# Enable auto-formatting of code examples in docstrings. Markdown,
# reStructuredText code/literal blocks and doctests are all supported.
#
# This is currently disabled by default, but it is planned for this
# to be opt-out in the future.
docstring-code-format = false

# Set the line length limit used when formatting code snippets in
# docstrings.
#
# This only has an effect when the `docstring-code-format` setting is
# enabled.
docstring-code-line-length = "dynamic"
4 changes: 2 additions & 2 deletions src/sw_metadata_bot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""sw-metadata-bot: RSMetaCheck bot for pushing issues with existing repository metadata."""

from importlib.metadata import version, PackageNotFoundError
from importlib.metadata import PackageNotFoundError, version

try:
__version__ = version("sw-metadata-bot")
except PackageNotFoundError:
# Package is not installed
__version__ = "unknown"

__all__ = ["__version__"]
__all__ = ["__version__"]
11 changes: 11 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Tests for conftest module - shared pytest fixtures."""

import pytest


@pytest.fixture
def tmp_config_file(tmp_path):
"""Create a temporary config file for testing."""
config_file = tmp_path / "config.json"
config_file.write_text('{"test": "value"}')
return config_file
Loading