Compare commits
	
		
			14 Commits
		
	
	
		
			8-backport
			...
			unify-outp
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3064d0231c | |||
| 5c73d55d91 | |||
| 9e70fc25d4 | |||
| 63ee619aef | |||
| 06abde6f6f | |||
| 99e0887505 | |||
| 4bc78716ee | |||
| a27f88a62b | |||
| 2d94c8b561 | |||
| b4b2b2ec5d | |||
| ec8e3e491e | |||
| 2245698405 | |||
| 9ee3ec2018 | |||
| 356da4d8ec | 
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @@ -5,15 +5,27 @@ Nixpkgs PR status checker. | |||||||
| ## Example | ## Example | ||||||
|  |  | ||||||
| ```console | ```console | ||||||
| $ nixprstatus 345501                                               | $ nixprstatus pr 345501          | ||||||
|  | ktailctl: 0.18.0 -> 0.18.1 | ||||||
|  |  | ||||||
|  | ✅ merged | ||||||
| ✅ master | ✅ master | ||||||
| ❌ nixos-unstable-small | ✅ nixos-unstable-small | ||||||
| ❌ nixos-unstable | ✅ nixos-unstable | ||||||
| ❌ nixos-24.05 | ❌ nixos-24.05 | ||||||
|  |  | ||||||
|  | $ nixprstatus --help | ||||||
|  | Usage: python -m nixprstatus [OPTIONS] COMMAND [ARGS]... | ||||||
|  |  | ||||||
|  | Options: | ||||||
|  |   --install-completion  Install completion for the current shell. | ||||||
|  |   --show-completion     Show completion for the current shell, to copy it or | ||||||
|  |                         customize the installation. | ||||||
|  |   --help                Show this message and exit. | ||||||
|  |  | ||||||
|  | Commands: | ||||||
|  |   pr         Get merge status of pull request. | ||||||
|  |   since      Return the count of commits that has happened between the... | ||||||
|  |   watchlist  Manage watchlist. | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## TODO |  | ||||||
|  |  | ||||||
| * Support backported commits |  | ||||||
| * JSON output |  | ||||||
|   | |||||||
| @@ -32,7 +32,12 @@ | |||||||
|       { |       { | ||||||
|         packages = { |         packages = { | ||||||
|           nixprstatus = mkPoetryApplication { |           nixprstatus = mkPoetryApplication { | ||||||
|             projectDir = ./.; |             projectDir = pkgs.lib.sourceFilesBySuffices ./. [ | ||||||
|  |               "pyproject.toml" | ||||||
|  |               "poetry.lock" | ||||||
|  |               "README.md" | ||||||
|  |               ".py" | ||||||
|  |             ]; | ||||||
|             python = pkgs.python312; |             python = pkgs.python312; | ||||||
|             nativeBuildInputs = [ pkgs.installShellFiles ]; |             nativeBuildInputs = [ pkgs.installShellFiles ]; | ||||||
|             postInstall = '' |             postInstall = '' | ||||||
|   | |||||||
| @@ -1,11 +1,14 @@ | |||||||
| import typer | import typer | ||||||
| import json | import json | ||||||
| from typing import Annotated | from typing import Annotated | ||||||
| from rich.console import Console |  | ||||||
| from nixprstatus.pr import pr_merge_status | from nixprstatus.pr import pr_merge_status | ||||||
| from nixprstatus.pr import commits_since | from nixprstatus.pr import commits_since | ||||||
|  | from nixprstatus.watchlist import Watchlist | ||||||
|  | from nixprstatus.watchlist import OutputFormat | ||||||
|  |  | ||||||
| app = typer.Typer() | app = typer.Typer(rich_markup_mode=None) | ||||||
|  | watchlist_app = typer.Typer() | ||||||
|  | app.add_typer(watchlist_app, name="watchlist", help="Manage watchlist.") | ||||||
|  |  | ||||||
| DEFAULT_HEADERS = { | DEFAULT_HEADERS = { | ||||||
|     "Accept": "application/vnd.github.text+json", |     "Accept": "application/vnd.github.text+json", | ||||||
| @@ -20,24 +23,17 @@ def pr( | |||||||
|     branches: Annotated[ |     branches: Annotated[ | ||||||
|         list[str] | None, typer.Option(help="Check specific branch") |         list[str] | None, typer.Option(help="Check specific branch") | ||||||
|     ] = None, |     ] = None, | ||||||
|  |     format: Annotated[ | ||||||
|  |         OutputFormat, typer.Option(help="Output format") | ||||||
|  |     ] = OutputFormat.CONSOLE, | ||||||
| ): | ): | ||||||
|     """Get status of pull request""" |     """Get merge status of pull request.""" | ||||||
|     console = Console() |  | ||||||
|  |  | ||||||
|     if branches: |     if branches: | ||||||
|         status = pr_merge_status(pr, branches) |         status = pr_merge_status(pr, branches) | ||||||
|     else: |     else: | ||||||
|         status = pr_merge_status(pr) |         status = pr_merge_status(pr) | ||||||
|     merged = ":white_check_mark: merged" if status.merged else ":x: merged" |  | ||||||
|     console.print(merged, highlight=False) |  | ||||||
|  |  | ||||||
|     for branch in status.branches: |     status.print(format=format) | ||||||
|         output = ( |  | ||||||
|             f":white_check_mark: {branch}" |  | ||||||
|             if status.branches[branch] |  | ||||||
|             else f":x: {branch}" |  | ||||||
|         ) |  | ||||||
|         console.print(output, highlight=False) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.command() | @app.command() | ||||||
| @@ -60,6 +56,34 @@ def since( | |||||||
|     typer.echo(count) |     typer.echo(count) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @watchlist_app.command() | ||||||
|  | def list(watchlist: str | None = None, format: OutputFormat = OutputFormat.CONSOLE): | ||||||
|  |     """List PRs in watchlist.""" | ||||||
|  |     wl = Watchlist.from_file(path=watchlist) | ||||||
|  |     wl.print(format=format) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @watchlist_app.command() | ||||||
|  | def add(pr: int, watchlist: str | None = None): | ||||||
|  |     """Add PR to watchlist.""" | ||||||
|  |     wl = Watchlist.from_file(path=watchlist) | ||||||
|  |     info = wl.add_pr(pr) | ||||||
|  |     wl.to_file(path=watchlist) | ||||||
|  |     print(f"Added #{info.pr}: {info.title} to watchlist.") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @watchlist_app.command() | ||||||
|  | def remove(pr: int): | ||||||
|  |     """Remove PR from watchlist.""" | ||||||
|  |     wl = Watchlist.from_file() | ||||||
|  |     if pr not in wl: | ||||||
|  |         print(f"#{pr} not in watchlist.") | ||||||
|  |         return | ||||||
|  |     wl.remove(pr) | ||||||
|  |     wl.to_file() | ||||||
|  |     print(f"Removed #{pr} from watchlist.") | ||||||
|  |  | ||||||
|  |  | ||||||
| def main(): | def main(): | ||||||
|     app() |     app() | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								nixprstatus/output.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								nixprstatus/output.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | from enum import Enum | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class OutputFormat(str, Enum): | ||||||
|  |     CONSOLE = "console" | ||||||
|  |     JSON = "json" | ||||||
| @@ -1,5 +1,8 @@ | |||||||
| import requests | import requests | ||||||
| from pydantic import BaseModel | from pydantic import BaseModel | ||||||
|  | from rich.console import Console | ||||||
|  |  | ||||||
|  | from nixprstatus.output import OutputFormat | ||||||
|  |  | ||||||
| DEFAULT_HEADERS = { | DEFAULT_HEADERS = { | ||||||
|     "Accept": "application/vnd.github.text+json", |     "Accept": "application/vnd.github.text+json", | ||||||
| @@ -9,9 +12,30 @@ BACKPORT_LABEL = "backport release-24.05" | |||||||
|  |  | ||||||
|  |  | ||||||
| class PRStatus(BaseModel): | class PRStatus(BaseModel): | ||||||
|  |     title: str | ||||||
|     merged: bool |     merged: bool | ||||||
|     branches: dict[str, bool] |     branches: dict[str, bool] | ||||||
|  |  | ||||||
|  |     def print(self, format: OutputFormat = OutputFormat.CONSOLE): | ||||||
|  |         match format: | ||||||
|  |             case OutputFormat.JSON: | ||||||
|  |                 print(self.model_dump_json()) | ||||||
|  |             case OutputFormat.CONSOLE: | ||||||
|  |                 console = Console(highlight=False) | ||||||
|  |                 console.print(f"{self.title}\n") | ||||||
|  |                 merged = ":white_check_mark: merged" if self.merged else ":x: merged" | ||||||
|  |                 console.print(merged) | ||||||
|  |  | ||||||
|  |                 for branch in self.branches: | ||||||
|  |                     output = ( | ||||||
|  |                         f":white_check_mark: {branch}" | ||||||
|  |                         if self.branches[branch] | ||||||
|  |                         else f":x: {branch}" | ||||||
|  |                     ) | ||||||
|  |                     console.print(output) | ||||||
|  |             case _: | ||||||
|  |                 raise ValueError(f"Unknown format: {format}") | ||||||
|  |  | ||||||
|  |  | ||||||
| def commit_in_branch(commit_sha: str, branch: str) -> bool: | def commit_in_branch(commit_sha: str, branch: str) -> bool: | ||||||
|     url = f"https://api.github.com/repos/NixOS/nixpkgs/compare/{branch}...{commit_sha}" |     url = f"https://api.github.com/repos/NixOS/nixpkgs/compare/{branch}...{commit_sha}" | ||||||
| @@ -32,6 +56,14 @@ def commits_since(first_ref: str, last_ref: str) -> int: | |||||||
|     return commit_response.json()["behind_by"] |     return commit_response.json()["behind_by"] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_pr(pr: int) -> dict: | ||||||
|  |     url = f"https://api.github.com/repos/NixOS/nixpkgs/pulls/{pr}" | ||||||
|  |     pr_response = requests.get(url, headers=DEFAULT_HEADERS) | ||||||
|  |     pr_response.raise_for_status() | ||||||
|  |  | ||||||
|  |     return pr_response.json() | ||||||
|  |  | ||||||
|  |  | ||||||
| def pr_merge_status( | def pr_merge_status( | ||||||
|     pr: int, branches: list[str] = DEFAULT_BRANCHES, check_backport: bool = True |     pr: int, branches: list[str] = DEFAULT_BRANCHES, check_backport: bool = True | ||||||
| ) -> PRStatus: | ) -> PRStatus: | ||||||
| @@ -40,10 +72,13 @@ def pr_merge_status( | |||||||
|     pr_response.raise_for_status() |     pr_response.raise_for_status() | ||||||
|  |  | ||||||
|     pr_data = pr_response.json() |     pr_data = pr_response.json() | ||||||
|  |     title = pr_data["title"] | ||||||
|  |  | ||||||
|     merged = pr_data["merged"] |     merged = pr_data["merged"] | ||||||
|     if merged is False: |     if merged is False: | ||||||
|         return PRStatus(merged=False, branches={branch: False for branch in branches}) |         return PRStatus( | ||||||
|  |             title=title, merged=False, branches={branch: False for branch in branches} | ||||||
|  |         ) | ||||||
|  |  | ||||||
|     commit_sha = pr_data.get("merge_commit_sha") |     commit_sha = pr_data.get("merge_commit_sha") | ||||||
|  |  | ||||||
| @@ -54,6 +89,13 @@ def pr_merge_status( | |||||||
|  |  | ||||||
|     results = {} |     results = {} | ||||||
|  |  | ||||||
|  |     # Check if base branch is in our list, if it is | ||||||
|  |     # no need to call commit_in_branch | ||||||
|  |     merge_base_branch = pr_data.get("base", {}).get("ref") | ||||||
|  |     if merge_base_branch in branches: | ||||||
|  |         results[merge_base_branch] = True | ||||||
|  |         branches.remove(merge_base_branch) | ||||||
|  |  | ||||||
|     for branch in branches: |     for branch in branches: | ||||||
|         in_branch = commit_in_branch(commit_sha, branch) |         in_branch = commit_in_branch(commit_sha, branch) | ||||||
|         results[branch] = in_branch |         results[branch] = in_branch | ||||||
| @@ -77,11 +119,11 @@ def pr_merge_status( | |||||||
|                 backport_sha = backport_response.json().get("merge_commit_sha") |                 backport_sha = backport_response.json().get("merge_commit_sha") | ||||||
|                 if backport_sha is None: |                 if backport_sha is None: | ||||||
|                     results[f"nixos-24.05 (#{backport_pr})"] = False |                     results[f"nixos-24.05 (#{backport_pr})"] = False | ||||||
|                     return PRStatus(merged=True, branches=results) |                     return PRStatus(title=title, merged=True, branches=results) | ||||||
|  |  | ||||||
|                 results.pop("nixos-24.05") |                 results.pop("nixos-24.05") | ||||||
|                 results[f"nixos-24.05 (#{backport_pr})"] = commit_in_branch( |                 results[f"nixos-24.05 (#{backport_pr})"] = commit_in_branch( | ||||||
|                     backport_sha, "nixos-24.05" |                     backport_sha, "nixos-24.05" | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|     return PRStatus(merged=True, branches=results) |     return PRStatus(title=title, merged=True, branches=results) | ||||||
|   | |||||||
							
								
								
									
										88
									
								
								nixprstatus/watchlist.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								nixprstatus/watchlist.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | import json | ||||||
|  | import os | ||||||
|  | from pathlib import Path | ||||||
|  | from pydantic import BaseModel | ||||||
|  | from rich.console import Console | ||||||
|  |  | ||||||
|  | from nixprstatus.pr import get_pr | ||||||
|  | from nixprstatus.output import OutputFormat | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class PRInfo(BaseModel): | ||||||
|  |     pr: int | ||||||
|  |     title: str | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Watchlist(BaseModel): | ||||||
|  |     prs: list[PRInfo] | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def from_file(cls, path: str | None = None) -> "Watchlist": | ||||||
|  |         if not path: | ||||||
|  |             path = _default_path() | ||||||
|  |  | ||||||
|  |         p = Path(path).expanduser() | ||||||
|  |  | ||||||
|  |         if not p.exists(): | ||||||
|  |             return cls(prs=[]) | ||||||
|  |  | ||||||
|  |         with open(p, "r") as f: | ||||||
|  |             data = json.load(f) | ||||||
|  |         return cls(**data) | ||||||
|  |  | ||||||
|  |     def to_file(self, path: str | None = None): | ||||||
|  |         if not path: | ||||||
|  |             _ensure_default_path() | ||||||
|  |             path = _default_path() | ||||||
|  |  | ||||||
|  |         p = Path(path).expanduser() | ||||||
|  |  | ||||||
|  |         with open(p, "w") as f: | ||||||
|  |             f.write(self.model_dump_json()) | ||||||
|  |  | ||||||
|  |     def add_pr(self, pr: int) -> PRInfo: | ||||||
|  |         # Lookup PR info | ||||||
|  |         info = get_pr(pr) | ||||||
|  |  | ||||||
|  |         title = info["title"] | ||||||
|  |         info = PRInfo(pr=pr, title=title) | ||||||
|  |         self.prs.append(info) | ||||||
|  |         return info | ||||||
|  |  | ||||||
|  |     def remove(self, pr: int): | ||||||
|  |         self.prs = [p for p in self.prs if p.pr != pr] | ||||||
|  |  | ||||||
|  |     def print(self, format: OutputFormat = OutputFormat.CONSOLE): | ||||||
|  |         match format: | ||||||
|  |             case OutputFormat.CONSOLE: | ||||||
|  |                 console = Console() | ||||||
|  |                 for pr in self.prs: | ||||||
|  |                     console.print(f"{pr.pr}: {pr.title}") | ||||||
|  |             case OutputFormat.JSON: | ||||||
|  |                 print(self.model_dump_json()) | ||||||
|  |             case _: | ||||||
|  |                 raise ValueError(f"Unknown format: {format}") | ||||||
|  |  | ||||||
|  |     def pr(self, pr: int) -> PRInfo | None: | ||||||
|  |         for p in self.prs: | ||||||
|  |             if p.pr == pr: | ||||||
|  |                 return p | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     def __contains__(self, item: PRInfo | int): | ||||||
|  |         match item: | ||||||
|  |             case PRInfo(): | ||||||
|  |                 return any([x == item for x in self.prs]) | ||||||
|  |             case int(): | ||||||
|  |                 return any([x.pr == item for x in self.prs]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _default_path() -> str: | ||||||
|  |     if "XDG_STATE_HOME" in os.environ: | ||||||
|  |         return f"{os.environ['XDG_STATE_HOME']}/nixprstatus/watchlist.json" | ||||||
|  |     return "~/.config/nixprstatus/watchlist.json" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _ensure_default_path(): | ||||||
|  |     p = Path(_default_path()).expanduser() | ||||||
|  |     p.parent.mkdir(parents=True, exist_ok=True) | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| [tool.poetry] | [tool.poetry] | ||||||
| name = "nixprstatus" | name = "nixprstatus" | ||||||
| version = "0.1.1" | version = "0.1.5" | ||||||
| description = "Nixpkgs PR status checker" | description = "Nixpkgs PR status checker" | ||||||
| authors = ["Torjus Håkestad <torjus@usit.uio.no>"] | authors = ["Torjus Håkestad <torjus@usit.uio.no>"] | ||||||
| license = "MIT" | license = "MIT" | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										32
									
								
								tests/helpers/mocks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/helpers/mocks.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | import requests | ||||||
|  | import json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def mocked_requests_get(*args, **kwargs): | ||||||
|  |     class MockedResponse: | ||||||
|  |         def __init__(self, json_data, status_code): | ||||||
|  |             self.json_data = json_data | ||||||
|  |             self.status_code = status_code | ||||||
|  |  | ||||||
|  |         def json(self): | ||||||
|  |             return json.loads(self.json_data) | ||||||
|  |  | ||||||
|  |         def raise_for_status(self): | ||||||
|  |             if self.status_code not in [200, 201]: | ||||||
|  |                 raise requests.exceptions.HTTPError() | ||||||
|  |  | ||||||
|  |     if "pulls" in args[0]: | ||||||
|  |         pr = args[0].split("/")[-1] | ||||||
|  |         with open(f"tests/fixtures/pulls_{pr}.json") as f: | ||||||
|  |             data = f.read() | ||||||
|  |         return MockedResponse(data, 200) | ||||||
|  |     elif "compare" in args[0]: | ||||||
|  |         branch, commit_sha = args[0].split("/")[-1].split("...") | ||||||
|  |         with open(f"tests/fixtures/compare_{branch}_{commit_sha}.json") as f: | ||||||
|  |             data = f.read() | ||||||
|  |         return MockedResponse(data, 200) | ||||||
|  |     elif "comments" in args[0]: | ||||||
|  |         pr = args[0].split("/")[-2] | ||||||
|  |         with open(f"tests/fixtures/comments_{pr}.json") as f: | ||||||
|  |             data = f.read() | ||||||
|  |         return MockedResponse(data, 200) | ||||||
| @@ -1,39 +1,8 @@ | |||||||
| import unittest | import unittest | ||||||
| import unittest.mock | import unittest.mock | ||||||
| import requests |  | ||||||
| import json |  | ||||||
|  |  | ||||||
| from nixprstatus.pr import commit_in_branch, pr_merge_status, commits_since | from nixprstatus.pr import commit_in_branch, pr_merge_status, commits_since | ||||||
|  | from tests.helpers.mocks import mocked_requests_get | ||||||
|  |  | ||||||
| def mocked_requests_get(*args, **kwargs): |  | ||||||
|     class MockedResponse: |  | ||||||
|         def __init__(self, json_data, status_code): |  | ||||||
|             self.json_data = json_data |  | ||||||
|             self.status_code = status_code |  | ||||||
|  |  | ||||||
|         def json(self): |  | ||||||
|             return json.loads(self.json_data) |  | ||||||
|  |  | ||||||
|         def raise_for_status(self): |  | ||||||
|             if self.status_code not in [200, 201]: |  | ||||||
|                 raise requests.exceptions.HTTPError() |  | ||||||
|  |  | ||||||
|     if "pulls" in args[0]: |  | ||||||
|         pr = args[0].split("/")[-1] |  | ||||||
|         with open(f"tests/fixtures/pulls_{pr}.json") as f: |  | ||||||
|             data = f.read() |  | ||||||
|         return MockedResponse(data, 200) |  | ||||||
|     elif "compare" in args[0]: |  | ||||||
|         branch, commit_sha = args[0].split("/")[-1].split("...") |  | ||||||
|         with open(f"tests/fixtures/compare_{branch}_{commit_sha}.json") as f: |  | ||||||
|             data = f.read() |  | ||||||
|         return MockedResponse(data, 200) |  | ||||||
|     elif "comments" in args[0]: |  | ||||||
|         pr = args[0].split("/")[-2] |  | ||||||
|         with open(f"tests/fixtures/comments_{pr}.json") as f: |  | ||||||
|             data = f.read() |  | ||||||
|         return MockedResponse(data, 200) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestPRMergeStatus(unittest.TestCase): | class TestPRMergeStatus(unittest.TestCase): | ||||||
| @@ -57,6 +26,28 @@ class TestPRMergeStatus(unittest.TestCase): | |||||||
|         self.assertTrue(res.merged) |         self.assertTrue(res.merged) | ||||||
|         self.assertTrue(res.branches["nixos-24.05 (#346022)"]) |         self.assertTrue(res.branches["nixos-24.05 (#346022)"]) | ||||||
|  |  | ||||||
|  |     @unittest.mock.patch("requests.get", side_effect=mocked_requests_get) | ||||||
|  |     def test_pr_merge_status_title_345769(self, mock_get): | ||||||
|  |         pr = 345769 | ||||||
|  |         branches = ["nixos-24.05"] | ||||||
|  |         expected_title = "Firefox: 130.0.1 -> 131.0; 128.2.0esr -> 128.3.0esr; 115.15.0esr -> 115.16.0esr" | ||||||
|  |  | ||||||
|  |         res = pr_merge_status(pr, branches, check_backport=True) | ||||||
|  |         self.assertEqual(res.title, expected_title) | ||||||
|  |  | ||||||
|  |     @unittest.mock.patch("requests.get", side_effect=mocked_requests_get) | ||||||
|  |     def test_pr_merge_status_no_check_master_345583(self, mock_get): | ||||||
|  |         pr = 345583 | ||||||
|  |         branches = ["master", "nixos-unstable", "nixos-24.05"] | ||||||
|  |         master_compare_url = "https://api.github.com/repos/NixOS/nixpkgs/compare/master...2c5fac3edf2d00d948253e392ec1604b29b38f14" | ||||||
|  |  | ||||||
|  |         res = pr_merge_status(pr, branches, check_backport=False) | ||||||
|  |         self.assertTrue(res.merged) | ||||||
|  |         self.assertTrue(res.branches["master"]) | ||||||
|  |  | ||||||
|  |         urls_called = [call[0][0] for call in mock_get.call_args_list] | ||||||
|  |         self.assertFalse(master_compare_url in urls_called) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestCommitInBranch(unittest.TestCase): | class TestCommitInBranch(unittest.TestCase): | ||||||
|     @unittest.mock.patch("requests.get", side_effect=mocked_requests_get) |     @unittest.mock.patch("requests.get", side_effect=mocked_requests_get) | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								tests/test_watchlist.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/test_watchlist.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | from nixprstatus.watchlist import Watchlist, PRInfo | ||||||
|  | from tempfile import TemporaryDirectory | ||||||
|  | import unittest | ||||||
|  |  | ||||||
|  | from tests.helpers.mocks import mocked_requests_get | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestWatchlist(unittest.TestCase): | ||||||
|  |     def test_save_load(self): | ||||||
|  |         with TemporaryDirectory() as d: | ||||||
|  |             filename = f"{d}/test.json" | ||||||
|  |  | ||||||
|  |             watchlist = Watchlist(prs=[PRInfo(pr=1, title="PR 1")]) | ||||||
|  |             watchlist.to_file(filename) | ||||||
|  |  | ||||||
|  |             # Check that the file was written correctly | ||||||
|  |             with open(filename, "r") as f: | ||||||
|  |                 self.assertEqual(watchlist.model_dump_json(), f.read()) | ||||||
|  |  | ||||||
|  |             # Check that the file can be read back | ||||||
|  |             loaded = Watchlist.from_file(filename) | ||||||
|  |             self.assertEqual(watchlist, loaded) | ||||||
|  |  | ||||||
|  |     @unittest.mock.patch("requests.get", side_effect=mocked_requests_get) | ||||||
|  |     def test_add_pr(self, mock_get): | ||||||
|  |         w = Watchlist(prs=[]) | ||||||
|  |         w.add_pr(345583) | ||||||
|  |         self.assertEqual(len(w.prs), 1) | ||||||
|  |         self.assertEqual(w.prs[0].title, "wireshark: 4.2.6 -> 4.2.7") | ||||||
|  |  | ||||||
|  |     def test_get_pr(self): | ||||||
|  |         w = Watchlist(prs=[PRInfo(pr=1, title="PR 1")]) | ||||||
|  |         self.assertEqual(w.pr(1), PRInfo(pr=1, title="PR 1")) | ||||||
|  |         self.assertEqual(w.pr(2), None) | ||||||
|  |  | ||||||
|  |     def test_contains(self): | ||||||
|  |         w = Watchlist(prs=[PRInfo(pr=1, title="PR 1")]) | ||||||
|  |         self.assertIn(PRInfo(pr=1, title="PR 1"), w) | ||||||
|  |         self.assertIn(1, w) | ||||||
|  |         self.assertNotIn(2, w) | ||||||
		Reference in New Issue
	
	Block a user