Skip to content
Open
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
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.git
.github
.venv
__pycache__
*.pyc
node_modules
dist
build
*.egg-info
.pytest_cache
.ruff_cache
.mypy_cache
.coverage
cov.xml
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI

on:
pull_request:
push:
branches: [master]

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
quality:
name: Format, lint & type check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
python-version: "3.14"
- name: Install dependencies
run: uv sync --frozen
- name: Check formatting
run: uv run ruff format --check
- name: Lint
run: uv run ruff check
- name: Type check
run: uv run pyrefly check

test:
name: Test (Python ${{ matrix.python-version }})
needs: quality
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --frozen
- name: Run tests with coverage
run: uv run pytest
2 changes: 1 addition & 1 deletion .github/workflows/danger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Run Danger
uses: ./
env:
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ target/
# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version
# pyenv / uv — .python-version IS tracked: it pins the uv-managed interpreter (3.14)

# celery beat schedule file
celerybeat-schedule
Expand Down Expand Up @@ -106,3 +105,5 @@ venv.bak/
# Coverage report
cov.xml


.ruff_cache
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.14
18 changes: 0 additions & 18 deletions .travis.yml

This file was deleted.

15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

* No changes.

### 0.2.0

**BREAKING** — Toolchain modernization and runtime baseline bump. The Danger DSL, the
danger-js invocation contract, and the model JSON shapes are unchanged; the 100%
test-coverage gate is preserved.

* **BREAKING:** Dropped support for Python 3.7–3.12. `danger-python` now requires **Python 3.13+** (developed and tested on 3.14).
* **BREAKING:** Migrated the runtime from **pydantic v1 to pydantic v2** (implementation only — model JSON input/output is byte-compatible).
* **BREAKING:** Migrated the CLI from **click 7 to click 8**.
* Replaced **Poetry** with **uv** for environment, dependency, and lockfile management: PEP 621 `[project]` metadata, committed `uv.lock`, and the `uv_build` backend.
* Replaced **black + isort + flake8 + pylint** with **Ruff** for linting and formatting.
* Replaced **mypy** with **Pyrefly** for type checking.
* Consolidated all tool configuration into `pyproject.toml`; removed `setup.cfg`.
* Replaced **Travis CI** with **GitHub Actions** (`ci.yml`, Python 3.13/3.14 matrix); updated the `Dockerfile` to `python:3.14-slim` + Node 20 + uv.

### 0.1.0

* Initial release of the plugin. - [@turekj]
Expand Down
41 changes: 26 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
FROM python:3.7
FROM python:3.14-slim

LABEL maintainer="Jakub Turek <jkbturek@gmail.com>"
LABEL "com.github.actions.name"="danger-python"
LABEL "com.github.actions.description"="Runs Python Dangerfiles"
LABEL "com.github.actions.icon"="zap"
LABEL "com.github.actions.color"="blue"

# Install dependencies
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get install -y nodejs
# danger-python shells out to danger-js, so the image needs Node. Install
# Node 20 via NodeSource. python:*-slim ships without curl / gnupg /
# ca-certificates, which the NodeSource setup script requires.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
gnupg \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*

RUN python -m pip install --upgrade pip
RUN pip install poetry
# Install uv (dependency / environment manager) from its official image.
COPY --from=ghcr.io/astral-sh/uv:0.11 /uv /uvx /bin/

RUN mkdir -p /usr/src/danger-python
COPY . /usr/src/danger-python
RUN cd /usr/src/danger-python && \
poetry config virtualenvs.create false && \
poetry install --no-dev
WORKDIR /usr/src/danger-python
COPY . .

# Install the package and its runtime dependencies from the committed lockfile
# into an in-project virtualenv (no dev tools), then put that venv on PATH so
# the `danger-python` console script the entrypoint calls is resolvable. Use
# the base image's Python 3.14 rather than downloading a second interpreter.
ENV UV_LINK_MODE=copy \
UV_PYTHON_DOWNLOADS=never \
UV_PYTHON_PREFERENCE=only-system
RUN uv sync --frozen --no-dev --no-editable
ENV PATH="/usr/src/danger-python/.venv/bin:${PATH}"

ENTRYPOINT ["npx", "--package", "danger", "danger-python", "ci"]
76 changes: 38 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![PyPI](https://img.shields.io/pypi/v/danger-python)](https://pypi.org/project/danger-python/)
![Python versions](https://img.shields.io/pypi/pyversions/danger-python)
[![Build Status](https://travis-ci.org/danger/python.svg?branch=master)](https://travis-ci.org/danger/python)
![Python versions](https://img.shields.io/badge/python-3.13%20%7C%203.14-blue)
[![CI](https://github.com/giancarlosisasi/danger-python/actions/workflows/ci.yml/badge.svg)](https://github.com/giancarlosisasi/danger-python/actions/workflows/ci.yml)

# python

Expand All @@ -12,7 +12,7 @@ Write your Dangerfiles in Python.

Running `danger-python` requires:

* Python 3.7 (tested under Python 3.7.5)
* Python 3.13+ (developed and tested under Python 3.14)
* danger-js 9.2 (tested under danger-js 9.2.10)

### Installation
Expand Down Expand Up @@ -61,63 +61,63 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: danger/python@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Using as a CI step (Travis)
### Using as a CI step

1. Create a `dangerfile.py` in the root directory of your repository.
2. Set up the CI to execute the `danger-python` script after the test suite.

Example `.travis.yml` configuration:
If you already run your own pipeline, add `danger-python` as a step after your test suite
instead of using the prebuilt action above. This works on any CI provider — the example
below uses GitHub Actions:

```yaml
language: python
python:
- "3.7"
cache:
yarn: true
pip: true
directories:
- node_modules
install:
- pip install poetry
- poetry install
script:
- poetry run pytest
after_script:
- nvm install 10.16.0
- nvm use 10.16.0
- yarn global add danger
- pip install danger-python
- danger-python ci -v
name: CI
on: [pull_request]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
- uses: actions/setup-node@v4
with:
node-version: "20"
# ... install dependencies and run your test suite here ...
- run: npm install -g danger
- run: pip install danger-python
- run: danger-python ci -v
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Development

To develop the `danger-python`, clone the repository and run the following commands:

```sh
# install danger
# install danger-js
npm install -g danger
# install poetry
pip install poetry
# install project dependencies
poetry install
# activate virtual environment
poetry shell
# run tests
pytest
# install uv (https://docs.astral.sh/uv/getting-started/installation/)
# create the virtual environment and install all dependencies from uv.lock
uv sync
# run the full local gate: format, lint, type-check, tests (enforces 100% coverage)
uv run ruff format --check
uv run ruff check
uv run pyrefly check
uv run pytest
```

To regenerate the input JSONSchema, put the latest version in `scripts/input_schema.json` and run the following commands:

```sh
cd scripts
python generate_scheme.py
uv run python generate_scheme.py
```

This should update the `danger_python/models.py` file.
Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: "danger-python"
description: "Runs Python Dangerfiles"
branding:
icon: "zap"
color: "blue"
runs:
using: "docker"
image: "Dockerfile"
15 changes: 7 additions & 8 deletions danger_python/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import sys
from typing import List

import click
from click_default_group import DefaultGroup
Expand All @@ -21,9 +20,9 @@ def run() -> None:


@danger_command(cli, "runner")
def runner(arguments: List[str]) -> None:
def runner(arguments: list[str]) -> None:
"""Runs dangerfile.py as a danger process, ignoring unknown options"""
with open("dangerfile.py", "r") as dangerfile:
with open("dangerfile.py") as dangerfile:
try:
execute_dangerfile(dangerfile.read())
except DangerfileException as exc:
Expand All @@ -32,25 +31,25 @@ def runner(arguments: List[str]) -> None:


@danger_command(cli, "pr")
def pr(arguments: List[str]) -> None:
def pr(arguments: list[str]) -> None:
"""Runs your local Dangerfile against an existing GitHub PR.
Will not post on the PR"""
Will not post on the PR"""
_execute_danger_js("pr", arguments)


@danger_command(cli, "local")
def local(arguments: List[str]) -> None:
def local(arguments: list[str]) -> None:
"""Runs danger standalone on a repo, useful for git hooks"""
_execute_danger_js("local", arguments)


@danger_command(cli, "ci")
def ci(arguments: List[str]) -> None:
def ci(arguments: list[str]) -> None:
"""Runs Danger on CI"""
_execute_danger_js("ci", arguments)


def _execute_danger_js(command_name: str, arguments: List[str]) -> None:
def _execute_danger_js(command_name: str, arguments: list[str]) -> None:
command = [command_name]
command.extend(arguments)

Expand Down
Loading