Skip to content

Commit 39141ae

Browse files
implement support for forgejo commit statuses
Signed-off-by: Olamidepeterojo <[email protected]>
1 parent e0498a6 commit 39141ae

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright Contributors to the Packit project.
2+
# SPDX-License-Identifier: MIT
3+
4+
import requests
5+
6+
from datetime import datetime
7+
from typing import Any, List, Optional
8+
from ogr.abstract import CommitFlag, CommitStatus
9+
10+
class ForgejoCommitFlag(CommitFlag):
11+
"""
12+
CommitFlag implementation for Forgejo.
13+
"""
14+
15+
@classmethod
16+
def _state_from_str(cls, state: str) -> CommitStatus:
17+
# Convert a status string returned by Forgejo API into CommitStatus enum.
18+
state = state.lower()
19+
if state == "success":
20+
return CommitStatus.success
21+
elif state == "failure":
22+
return CommitStatus.failure
23+
elif state == "pending":
24+
return CommitStatus.pending
25+
else:
26+
raise ValueError(f"Unknown commit state from Forgejo: {state}")
27+
28+
@classmethod
29+
def _validate_state(cls, state: CommitStatus) -> CommitStatus:
30+
# Validate that the provided state is acceptable for Forgejo.
31+
valid_states = {CommitStatus.success, CommitStatus.failure, CommitStatus.pending}
32+
if state in valid_states:
33+
return state
34+
raise ValueError(f"Invalid commit state for Forgejo: {state}")
35+
36+
def _from_raw_commit_flag(self) -> None:
37+
"""
38+
Populate attributes from the raw commit flag data obtained from Forgejo's API.
39+
Expected keys in self._raw_commit_flag: 'commit', 'state', 'context', 'comment', 'id',
40+
'created', and 'updated'.
41+
"""
42+
raw = self._raw_commit_flag
43+
self.commit = raw.get("commit")
44+
self.state = self._state_from_str(raw.get("state", "pending"))
45+
self.context = raw.get("context")
46+
self.comment = raw.get("comment")
47+
self.uid = raw.get("id")
48+
self.url = raw.get("url")
49+
# Parse timestamps in ISO8601 format (adjust format if needed)
50+
self._created = datetime.strptime(raw.get("created"), "%Y-%m-%dT%H:%M:%SZ")
51+
self._edited = datetime.strptime(raw.get("updated"), "%Y-%m-%dT%H:%M:%SZ")
52+
53+
@staticmethod
54+
def get(project: Any, commit: str) -> List["CommitFlag"]:
55+
"""
56+
Retrieve commit statuses for the given commit from Forgejo.
57+
This method should use Forgejo's API to fetch statuses.
58+
"""
59+
# Construct the URL using the project's forge_api_url, owner, repo, and commit hash.
60+
url = f"{project.forge_api_url}/repos/{project.owner}/{project.repo}/commits/{commit}/statuses"
61+
headers = project.get_auth_header() # Get auth headers from project config
62+
response = requests.get(url, headers=headers)
63+
flags = []
64+
for raw_flag in response.json():
65+
flags.append(ForgejoCommitFlag(raw_commit_flag=raw_flag, project=project, commit=commit))
66+
return flags
67+
68+
@staticmethod
69+
def set(
70+
project: Any,
71+
commit: str,
72+
state: CommitStatus,
73+
target_url: str,
74+
description: str,
75+
context: str,
76+
) -> "CommitFlag":
77+
"""
78+
Set a new commit status on Forgejo via its API.
79+
"""
80+
url = f"{project.forge_api_url}/repos/{project.owner}/{project.repo}/commits/{commit}/statuses"
81+
payload = {
82+
"state": state.name.lower(),
83+
"target_url": target_url,
84+
"description": description,
85+
"context": context,
86+
}
87+
headers = project.get_auth_header()
88+
response = requests.post(url, json=payload, headers=headers)
89+
return ForgejoCommitFlag(raw_commit_flag=response.json(), project=project, commit=commit)
90+
91+
@property
92+
def created(self) -> datetime:
93+
return self._created
94+
95+
@property
96+
def edited(self) -> datetime:
97+
return self._edited
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Copyright Contributors to the Packit project.
2+
# SPDX-License-Identifier: MIT
3+
4+
import datetime
5+
import responses
6+
import pytest
7+
from typing import Any, Dict, List, Optional
8+
import requests
9+
10+
from ogr.abstract import CommitStatus, CommitFlag
11+
from ogr.services.forgejo.commit_flag import ForgejoCommitFlag
12+
13+
class MockProject:
14+
forge_api_url = "http://dummy-forgejo/api/v1"
15+
owner = "dummy_owner"
16+
repo = "dummy_repo"
17+
18+
def get_auth_header(self) -> Dict[str, str]:
19+
return {"Authorization": "Bearer dummy_token"}
20+
21+
@responses.activate
22+
def test_get_commit_flag_integration():
23+
project = MockProject()
24+
commit = "abcdef123456"
25+
url = f"{project.forge_api_url}/repos/{project.owner}/{project.repo}/commits/{commit}/statuses"
26+
27+
# Dummy response data simulating Forgejo API output.
28+
dummy_response = [{
29+
"commit": commit,
30+
"state": "success",
31+
"context": "CI",
32+
"comment": "All tests passed",
33+
"id": "123",
34+
"url": "http://dummy-forgejo/commit/abcdef123456/status",
35+
"created": "2023-01-01T12:00:00Z",
36+
"updated": "2023-01-01T12:30:00Z"
37+
}]
38+
responses.add(responses.GET, url, json=dummy_response, status=200)
39+
40+
# Call the method under test.
41+
flags: List[CommitFlag] = ForgejoCommitFlag.get(project, commit)
42+
43+
# Assertions using CommitStatus from packit.ogr.abstract.
44+
assert len(flags) == 1
45+
flag = flags[0]
46+
assert flag.commit == commit
47+
assert flag.state == CommitStatus.success
48+
assert flag.context == "CI"
49+
assert flag.comment == "All tests passed"
50+
assert flag.uid == "123"
51+
52+
expected_created = datetime.datetime.strptime("2023-01-01T12:00:00Z", "%Y-%m-%dT%H:%M:%SZ")
53+
expected_updated = datetime.datetime.strptime("2023-01-01T12:30:00Z", "%Y-%m-%dT%H:%M:%SZ")
54+
assert flag.created == expected_created
55+
assert flag.edited == expected_updated
56+
57+
@responses.activate
58+
def test_set_commit_flag_integration():
59+
project = MockProject()
60+
commit = "abcdef123456"
61+
url = f"{project.forge_api_url}/repos/{project.owner}/{project.repo}/commits/{commit}/statuses"
62+
63+
# Dummy response for setting a commit status.
64+
dummy_response = {
65+
"commit": commit,
66+
"state": "success",
67+
"context": "CI",
68+
"comment": "Build succeeded",
69+
"id": "456",
70+
"url": "http://dummy-forgejo/commit/abcdef123456/status",
71+
"created": "2023-02-01T12:00:00Z",
72+
"updated": "2023-02-01T12:30:00Z"
73+
}
74+
responses.add(responses.POST, url, json=dummy_response, status=200)
75+
76+
# Call the set method to create a new commit flag.
77+
flag = ForgejoCommitFlag.set(
78+
project=project,
79+
commit=commit,
80+
state=CommitStatus.success,
81+
target_url="http://dummy-target",
82+
description="Build succeeded",
83+
context="CI"
84+
)
85+
86+
# Assertions to verify correct mapping using CommitStatus.
87+
assert flag.commit == commit
88+
assert flag.state == CommitStatus.success
89+
assert flag.context == "CI"
90+
assert flag.comment == "Build succeeded"
91+
assert flag.uid == "456"
92+
93+
expected_created = datetime.datetime.strptime("2023-02-01T12:00:00Z", "%Y-%m-%dT%H:%M:%SZ")
94+
expected_updated = datetime.datetime.strptime("2023-02-01T12:30:00Z", "%Y-%m-%dT%H:%M:%SZ")
95+
assert flag.created == expected_created
96+
assert flag.edited == expected_updated

0 commit comments

Comments
 (0)