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
22 changes: 5 additions & 17 deletions .github/workflows/qa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: apt update
run: sudo apt update
- name: apt install
run: sudo apt install python3-poetry
- uses: snok/install-poetry@v1
- name: poetry install
run: poetry install
- name: pytest
Expand All @@ -23,10 +20,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: apt update
run: sudo apt update
- name: apt install
run: sudo apt install python3-poetry
- uses: snok/install-poetry@v1
- name: poetry install
run: poetry install
- name: pytest
Expand All @@ -38,25 +32,19 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: apt update
run: sudo apt update
- name: apt install
run: sudo apt install python3-poetry
- uses: snok/install-poetry@v1
- name: poetry install
run: poetry install
- name: pytest
run: poetry run mypy --check-untyped-defs .
run: poetry run mypy --check-untyped-defs . --exclude ubuntu_lint/dput.py
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: apt update
run: sudo apt update
- name: apt install
run: sudo apt install python3-poetry distro-info-data
- uses: snok/install-poetry@v1
- name: poetry install
run: poetry install
- name: pytest
Expand Down
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ubuntu-lint (0.1.0ubuntu) UNRELEASED; urgency=medium

* Initial release.

-- Nick Rosbrook <enr0n@ubuntu.com> Tue, 27 Jan 2026 11:36:22 -0500
51 changes: 51 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Source: ubuntu-lint
Section: devel
Priority: optional
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Build-Depends:
debhelper-compat (= 13),
dh-sequence-python3,
pybuild-plugin-pyproject,
python3-all,
python3-debian,
python3-distro-info,
python3-dput,
python3-launchpadlib,
python3-poetry,
python3-pytest,
python3-requests,
python3-requests-mock,
Standards-Version: 4.7.2
Homepage: https://github.com/ubuntu/ubuntu-lint
Vcs-Git: https://github.com/ubuntu/ubuntu-lint.git

Package: ubuntu-lint
Architecture: all
Depends:
${misc:Depends},
${python3:Depends},
python3-ubuntu-lint (= ${binary:Version}),
Description: linter for Ubuntu packaging workflows
ubuntu-lint is a CLI linter for Ubuntu packaging. It operates on source
packages, and is designed to be used by uploaders and reviewers alike.
.
ubuntu-lint supplements existing tools like lintian, and defines additional
checks for Ubuntu-specific processes such as Stable Release Updates (SRUs).
.
This package includes the ubuntu-lint CLI, and dput-ng hooks.

Package: python3-ubuntu-lint
Architecture: all
Section: python
Depends:
${misc:Depends},
${python3:Depends},
Description: linter for Ubuntu packaging workflows (Python3 Library)
ubuntu-lint is a CLI linter for Ubuntu packaging. It operates on source
packages, and is designed to be used by uploaders and reviewers alike.
.
ubuntu-lint supplements existing tools like lintian, and defines additional
checks for Ubuntu-specific processes such as Stable Release Updates (SRUs).
.
This package can be integrated with other tools like dput-ng (via hooks), and
is used to implement the ubuntu-lint CLI tool.
14 changes: 14 additions & 0 deletions debian/copyright
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ubuntu-lint
Upstream-Contact: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>

Files: *
Copyright: 2026, Canonical Ltd.
License: GPL-3

License: GPL-3
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 3 dated June, 2007.
On Debian systems, the complete text of version 3 of the GNU General
Public License can be found in '/usr/share/common-licenses/GPL-3'.
6 changes: 6 additions & 0 deletions debian/rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/make -f

export PYBUILD_NAME=ubuntu-lint

%:
dh $@ --buildsystem pybuild
1 change: 1 addition & 0 deletions debian/source/format
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0 (native)
2 changes: 2 additions & 0 deletions debian/ubuntu-lint.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ubuntu-lint usr/bin
dput.d/* etc/dput.d/
5 changes: 5 additions & 0 deletions dput.d/hooks/missing-git-ubuntu-references.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "check if Ubuntu changes are missing git-ubuntu references",
"path": "ubuntu_lint.dput.dput_missing_git_ubuntu_references",
"pre": true
}
5 changes: 5 additions & 0 deletions dput.d/hooks/missing-launchpad-bugs-fixed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "check if Ubuntu changes are missing Launchpad-Bugs-Fixed",
"path": "ubuntu_lint.dput.dput_missing_launchpad_bugs_fixed",
"pre": true
}
5 changes: 5 additions & 0 deletions dput.d/hooks/missing-pending-changelog-entry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "check if Ubuntu changes are missing the changelog for a pending upload",
"path": "ubuntu_lint.dput.dput_missing_pending_changelog_entry",
"pre": true
}
5 changes: 5 additions & 0 deletions dput.d/hooks/missing-ubuntu-maintainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "check if Ubuntu changes are missing Ubuntu maintainer",
"path": "ubuntu_lint.dput.dput_missing_ubuntu_maintainer",
"pre": true
}
5 changes: 5 additions & 0 deletions dput.d/hooks/sru-bug-missing-release-tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "check if SRU bugs are missing the correct release tasks",
"path": "ubuntu_lint.dput.dput_sru_bug_missing_release_tasks",
"pre": true
}
5 changes: 5 additions & 0 deletions dput.d/hooks/sru-bug-missing-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "check if SRU bugs are missing the template",
"path": "ubuntu_lint.dput.dput_sru_bug_missing_template",
"pre": true
}
10 changes: 10 additions & 0 deletions dput.d/profiles/ubuntu.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"+hooks": [
"missing-git-ubuntu-references",
"missing-launchpad-bugs-fixed",
"missing-pending-changelog-entry",
"missing-ubuntu-maintainer",
"sru-bug-missing-release-tasks",
"sru-bug-missing-template"
]
}
23 changes: 12 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
[tool.poetry]
[project]
name = "ubuntu-lint"
version = "0.1.0"
description = ""
authors = ["Nick Rosbrook <enr0n@ubuntu.com>"]
description = "Ubuntu packaging linter"
authors = [
{name = "Nick Rosbrook", email = "enr0n@ubuntu.com"},
]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.12"
python-debian = "^1.0.1"
requests = "^2.32.5"
distro-info = "^1.0"
launchpadlib = "^2.1.0"

dependencies = [
"python-debian (>=1.0.1)",
"requests (>=2.32.5)",
"distro-info (>=1.0)",
"launchpadlib (>=2.1.0)",
]
requires-python = ">=3.10"

[tool.poetry.group.dev.dependencies]
black = "^26.1.0"
Expand Down
3 changes: 3 additions & 0 deletions tests/test_linters.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

import copy
import pytest
import ubuntu_lint
Expand Down
9 changes: 9 additions & 0 deletions ubuntu-lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python3

# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

from ubuntu_lint.cli import main

if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions ubuntu_lint/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

from .context import Context, LintFailure
from .linters import (
check_missing_ubuntu_maintainer,
Expand Down
7 changes: 3 additions & 4 deletions ubuntu_lint/cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

import argparse
import os
import sys
Expand Down Expand Up @@ -182,7 +185,3 @@ def main():

if not runner.run(context):
sys.exit(1)


if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions ubuntu_lint/context.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

import distro_info

from debian import deb822, changelog
Expand Down
115 changes: 115 additions & 0 deletions ubuntu_lint/dput.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

import ubuntu_lint

from dput.changes import Changes
from dput.exceptions import HookException
from dput.interfaces.cli import CLInterface
from typing import Callable


def call_lint_as_hook(
lint: Callable[[ubuntu_lint.Context], None],
changes: Changes,
profile: dict,
interface: CLInterface,
can_ignore: bool = False,
):
context = ubuntu_lint.Context(changes=changes.get_raw_changes())
try:
lint(context)
except ubuntu_lint.LintFailure as e:
msg = str(e)
if can_ignore and interface.boolean("WARNING", f"{msg} - ignore?"):
return
raise HookException(f"ERROR: {msg}")


def dput_missing_launchpad_bugs_fixed(
changes: Changes, profile: dict, interface: CLInterface
):
"""
Hook wrapper around ubuntu_lint.check_missing_launchpad_bugs_fixed.
"""
call_lint_as_hook(
ubuntu_lint.check_missing_launchpad_bugs_fixed,
changes,
profile,
interface,
can_ignore=True,
)


def dput_missing_ubuntu_maintainer(
changes: Changes, profile: dict, interface: CLInterface
):
"""
Hook wrapper around ubuntu_lint.check_missing_ubuntu_maintainer.
"""
call_lint_as_hook(
ubuntu_lint.check_missing_ubuntu_maintainer,
changes,
profile,
interface,
)


def dput_missing_git_ubuntu_references(
changes: Changes, profile: dict, interface: CLInterface
):
"""
Hook wrapper around ubuntu_lint.check_missing_git_ubuntu_references.
"""
call_lint_as_hook(
ubuntu_lint.check_missing_git_ubuntu_references,
changes,
profile,
interface,
can_ignore=True,
)


def dput_missing_pending_changelog_entry(
changes: Changes, profile: dict, interface: CLInterface
):
"""
Hook wrapper around ubuntu_lint.check_missing_pending_changelog_entry.
"""
call_lint_as_hook(
ubuntu_lint.check_missing_pending_changelog_entry,
changes,
profile,
interface,
can_ignore=True,
)


def dput_sru_bug_missing_template(
changes: Changes, profile: dict, interface: CLInterface
):
"""
Hook wrapper around ubuntu_lint.check_sru_bug_missing_template.
"""
call_lint_as_hook(
ubuntu_lint.check_sru_bug_missing_template,
changes,
profile,
interface,
can_ignore=True,
)


def dput_sru_bug_missing_release_tasks(
changes: Changes, profile: dict, interface: CLInterface
):
"""
Hook wrapper around ubuntu_lint.check_sru_bug_missing_release_tasks.
"""
call_lint_as_hook(
ubuntu_lint.check_sru_bug_missing_release_tasks,
changes,
profile,
interface,
can_ignore=True,
)
3 changes: 3 additions & 0 deletions ubuntu_lint/linters.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2026 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

import distro_info
import re
import requests
Expand Down