Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-35149: Integrate GitHub Checks API for validating YAML configs in repositories #40

Merged
merged 9 commits into from
Jun 23, 2022
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Change log
==========

Unreleased
----------

Times Square now implements GitHub Checks for pull requests for notebook repositories.
Initially, Times Square validates the structure of YAML configuration files, specifically the ``times-square.yaml`` repository settings as well as the YAML sidecar files that describe each notebook.

0.4.0 (2022-05-14)
------------------

Expand Down
113 changes: 113 additions & 0 deletions src/timessquare/domain/githubapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from __future__ import annotations

from base64 import b64decode
from enum import Enum
from typing import Optional

from pydantic import BaseModel, Field, HttpUrl

Expand Down Expand Up @@ -144,3 +146,114 @@ def decode(self) -> str:
f"GitHub blob content encoding {self.encoding} "
f"is unknown by GitHubBlobModel for url {self.url}"
)


class GitHubCheckSuiteStatus(str, Enum):

queued = "queued"
in_progress = "in_progress"
completed = "completed"


class GitHubCheckSuiteConclusion(str, Enum):

success = "success"
failure = "failure"
neutral = "neutral"
cancelled = "cancelled"
timed_out = "timed_out"
action_required = "action_required"
stale = "stale"


class GitHubCheckSuiteModel(BaseModel):
"""A Pydantic model for the "check_suite" field in a check_suite webhook
(`GitHubCheckSuiteRequestModel`).
"""

id: str = Field(description="Identifier for this check run")

head_branch: str = Field(
title="Head branch",
description="Name of the branch the changes are on.",
)

head_sha: str = Field(
title="Head sha",
description="The SHA of the most recent commit for this check suite.",
)

url: HttpUrl = Field(
description="GitHub API URL for the check suite resource."
)

status: GitHubCheckSuiteStatus

conclusion: Optional[GitHubCheckSuiteConclusion]


class GitHubCheckRunStatus(str, Enum):
"""The check run status."""

queued = "queued"
in_progress = "in_progress"
completed = "completed"


class GitHubCheckRunConclusion(str, Enum):
"""The check run conclusion state."""

success = "success"
failure = "failure"
neutral = "neutral"
cancelled = "cancelled"
timed_out = "timed_out"
action_required = "action_required"
stale = "stale"


class GitHubCheckRunAnnotationLevel(str, Enum):
"""The level of a check run output annotation."""

notice = "notice"
warning = "warning"
failure = "failure"


class GitHubCheckSuiteId(BaseModel):
"""Brief information about a check suite in the `GitHubCheckRunModel`."""

id: str = Field(description="Check suite ID")


class GitHubCheckRunModel(BaseModel):
"""A Pydantic model for the "check_run" field in a check_run webhook
payload (`GitHubCheckRunPayloadModel`).
"""

id: str = Field(description="Identifier for this check run")

external_id: Optional[str] = Field(
description="Identifier set by the check runner."
)

head_sha: str = Field(
title="Head sha",
description="The SHA of the most recent commit for this check suite.",
)

status: GitHubCheckRunStatus = Field(
description="Status of the check run."
)

conclusion: Optional[GitHubCheckRunConclusion] = Field(
description="Conclusion status, if completed."
)

name: str = Field(description="Name of the check run.")

url: HttpUrl = Field(description="URL of the check run API resource.")

html_url: HttpUrl = Field(description="URL of the check run webpage.")

check_suite: GitHubCheckSuiteId
33 changes: 30 additions & 3 deletions src/timessquare/domain/githubcheckout.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from gidgethub.httpx import GitHubAPI
from pydantic import BaseModel, EmailStr, Field, HttpUrl, root_validator

from .githubapi import GitHubBlobModel
from .githubapi import GitHubBlobModel, GitHubRepositoryModel
from .page import PageParameterSchema, PersonModel


Expand Down Expand Up @@ -43,8 +43,9 @@ class GitHubRepositoryCheckout:
settings: RepositorySettingsFile
"""Repository settings, read from times-square.yaml."""

git_ref: str
"""The "checked-out" full git ref.
git_ref: Optional[str]
"""The "checked-out" full git ref, or `None` if a checkout of a bare
commit.

Examples:

Expand All @@ -68,6 +69,32 @@ class GitHubRepositoryCheckout:
URL variable is ``sha``.
"""

@classmethod
async def create(
cls,
*,
github_client: GitHubAPI,
repo: GitHubRepositoryModel,
head_sha: str,
git_ref: Optional[str] = None,
) -> GitHubRepositoryCheckout:
uri = repo.contents_url + "{?ref}"
data = await github_client.getitem(
uri, url_vars={"path": "times-square.yaml", "ref": head_sha}
)
content_data = GitHubBlobModel.parse_obj(data)
file_content = content_data.decode()
settings = RepositorySettingsFile.parse_yaml(file_content)
return cls(
owner_name=repo.owner.login,
name=repo.name,
settings=settings,
git_ref=git_ref,
head_sha=head_sha,
trees_url=repo.trees_url,
blobs_url=repo.blobs_url,
)

@property
def full_name(self) -> str:
"""The full repository name (owner/repo format)."""
Expand Down
Loading