Skip to content

Commit

Permalink
Merge pull request #34 from ivellios/main
Browse files Browse the repository at this point in the history
Automatyczne tworzenie Pull Requesta z nową organizacją
  • Loading branch information
ivellios authored Dec 19, 2024
2 parents 55396b6 + e1e3e1a commit 5280c8c
Show file tree
Hide file tree
Showing 18 changed files with 485 additions and 209 deletions.
16 changes: 8 additions & 8 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Usuwanie produktu
url: https://github.com/wyslijco/wyslijco.github.io/wiki
about: Zobacz, jak możesz usunąć produkt ze strony swojej organizacji w Wyślij.co
- name: Usuwanie organizacji
url: https://github.com/wyslijco/wyslijco.github.io/wiki
about: Zobacz, jak usunąć swoją organizację z Wyślij.co
blank_issues_enabled: true
contact_links:
- name: Usuwanie produktu
url: https://github.com/wyslijco/wyslijco.github.io/wiki
about: Zobacz, jak możesz usunąć produkt ze strony swojej organizacji w Wyślij.co
- name: Usuwanie organizacji
url: https://github.com/wyslijco/wyslijco.github.io/wiki
about: Zobacz, jak usunąć swoją organizację z Wyślij.co
76 changes: 38 additions & 38 deletions .github/ISSUE_TEMPLATE/dodanieproduktu.yaml
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
name: Dodanie produktu
description: Dodaj produkt do strony swojej organizacji.
title: "[Dodanie produktu]"
labels: ["organizacje", "nowy-produkt"]
assignees:
- ivellios

body:
- type: markdown
attributes:
value: |
Ten formularz pomoże Ci w dodaniu produktu do strony Twojej organizacji w Wyślij.co
- type: dropdown
id: nazwa_organizacji
attributes:
label: Twoja organizacja
options:
- Testowa
validations:
required: true
- type: input
id: nazwa
attributes:
label: Nazwa produktu
validations:
required: true
- type: input
id: opis
attributes:
label: Krótki opis produktu
validations:
required: false
- type: input
id: link
attributes:
label: Link do produktu w sklepie internetowym
validations:
required: true
name: Dodanie produktu
description: Dodaj produkt do strony swojej organizacji.
title: "[Dodanie produktu]"
labels: ["organizacje", "nowy-produkt"]
assignees:
- ivellios

body:
- type: markdown
attributes:
value: |
Ten formularz pomoże Ci w dodaniu produktu do strony Twojej organizacji w Wyślij.co
- type: dropdown
id: nazwa_organizacji
attributes:
label: Twoja organizacja
options:
- Testowa
validations:
required: true
- type: input
id: nazwa
attributes:
label: Nazwa produktu
validations:
required: true
- type: input
id: opis
attributes:
label: Krótki opis produktu
validations:
required: false
- type: input
id: link
attributes:
label: Link do produktu w sklepie internetowym
validations:
required: true
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/nowa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,8 @@ body:
placeholder: 000 000 000
validations:
required: true
- type: markdown
attributes:
value: |
# Następne kroki
Po wypełnieniu formularza, Twój wniosek zostanie zweryfikowany przez nasz zespół. W celu weryfikacji poprawności danych skontaktujemy się z Twoją organizacją poprzez oficjalne dane kontaktowe dostępne na stronie internetowej organizacji lub w rejestrze KRS. W przypadku pozytywnej weryfikacji, otrzymasz od nas informację o dalszych krokach w komentarzu do tego zgłoszenia (zakładka Issues).
95 changes: 95 additions & 0 deletions .github/scripts/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import json
import logging
import os

from github import Auth, Github, Issue

from consts import (
OrgFormSchemaIds,
NEW_ORG_ISSUE_DEFAULT_TITLE,
NEW_ORG_FORM_SCHEMA_FILENAME,
)
from exceptions import BranchModifiedError
from git_managers import create_organization_yaml_pr
from labels import Label
from parsers import GithubIssueFormDataParser
from pullers import KRSDataPuller
from utils import has_label
from validators import OrgValidator
from renderers import render_organization_yaml

logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__file__)

GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")

auth = Auth.Token(GITHUB_TOKEN)
g = Github(auth=auth)
repo = g.get_repo(GITHUB_REPOSITORY)


def process_new_org_issue(issue: Issue, data: GithubIssueFormDataParser):
validation_warnings = []

org_name = data.get(OrgFormSchemaIds.name)

if has_label(issue, Label.AUTO_VERIFIED):
issue.remove_from_labels(Label.AUTO_VERIFIED)

validator = OrgValidator(data, issue)
if not validator.validate():
logger.error("Validation failed - not continuing")
return

if not (org := KRSDataPuller.get_org_by_krs(issue, data.get(OrgFormSchemaIds.krs))):
logger.error("KRS db validation failed")
validation_warnings.append("Nie można zweryfikować KRS")
else:
org_name = org.name

# Update issue title
if issue.title == NEW_ORG_ISSUE_DEFAULT_TITLE:
logger.info("Updating issue title")
issue.edit(title=f"{NEW_ORG_ISSUE_DEFAULT_TITLE} {org_name}")

logger.info("Adding auto-verified label")
if not validation_warnings:
issue.add_to_labels(Label.AUTO_VERIFIED)

if not has_label(issue, Label.WAITING):
issue.add_to_labels(Label.WAITING)
issue.create_comment(
f"@{issue.user.login}, dziękujemy za podanie informacji. "
f"Przyjęliśmy zgłoszenie dodania nowej organizacji. "
f"Wkrótce skontaktujemy się celem weryfikacji zgłoszenia."
)

# create organization yaml file and add to the Pull Request
yaml_string = render_organization_yaml(data)

try:
create_organization_yaml_pr(issue, yaml_string, data)
except BranchModifiedError:
logger.error("Branch was modified by someone else")
issue.create_comment(
"Aktualizacja pliku organizacji na podstawie opisu zgłoszenia niemożliwa. "
"Plik organizacji został już zmodyfikowany przez innego użytkownika."
)


def main():
github_form_json = os.getenv("GITHUB_FORM_JSON")
github_issue_number = int(os.getenv("GITHUB_ISSUE_NUMBER"))

issue = repo.get_issue(github_issue_number)
data = GithubIssueFormDataParser(
json.loads(github_form_json), NEW_ORG_FORM_SCHEMA_FILENAME
)
process_new_org_issue(issue, data)


if __name__ == "__main__":
main()
7 changes: 4 additions & 3 deletions .github/scripts/consts.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import enum


class OrgSchemaIds(enum.StrEnum):
class OrgFormSchemaIds(enum.StrEnum):
name = "nazwa"
www = "www"
website = "www"
krs = "krs"
slug = "nazwa_strony"
street = "ulica"
postal_code = "kod_pocztowy"
city = "miasto"
phone_number = "telefon"


NEW_ORG_ISSUE_DEFAULT_TITLE = "[Nowa Organizacja]"
NEW_ORG_SCHEMA_FILENAME = "nowa.yaml"
NEW_ORG_FORM_SCHEMA_FILENAME = "nowa.yaml"


ORG_SCHEMA_SLUG_FIELD = "adres"
6 changes: 6 additions & 0 deletions .github/scripts/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class BranchModifiedError(ValueError):
pass


class KRSMaintenanceError(Exception):
pass
142 changes: 142 additions & 0 deletions .github/scripts/git_managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import logging
from dataclasses import dataclass

from github import GithubException, InputGitTreeElement
from github.GitCommit import GitCommit
from github.GitRef import GitRef
from github.Issue import Issue
from github.PullRequest import PullRequest
from github.Repository import Repository

from consts import OrgFormSchemaIds
from exceptions import BranchModifiedError
from parsers import GithubIssueFormDataParser


logger = logging.getLogger(__file__)


@dataclass
class GitManager:
"""Manager for creating a new branch and pull request with a file commit in the repo."""

repo: Repository

def commit_file_contents_to_branch(
self, branch_ref: GitRef, file_path: str, contents: str, commit_message: str
) -> GitCommit:
latest_commit = self.repo.get_commit(branch_ref.object.sha)
blob = self.repo.create_git_blob(contents, "utf-8")
tree_element = InputGitTreeElement(
path=file_path, mode="100644", type="blob", sha=blob.sha
)
base_tree = latest_commit.commit.tree
new_tree = self.repo.create_git_tree([tree_element], base_tree)
new_commit = self.repo.create_git_commit(
message=commit_message, tree=new_tree, parents=[latest_commit.commit]
)
return new_commit

def get_or_create_branch(self, source_branch: str, new_branch_name: str) -> GitRef:
source = self.repo.get_branch(source_branch)
try:
branch_ref = self.repo.get_git_ref(f"heads/{new_branch_name}")
logger.info(f"Found existing branch '{new_branch_name}'.")
except GithubException as e:
if e.status == 404:
# Branch does not exist, create it from the source branch
self.repo.create_git_ref(
ref=f"refs/heads/{new_branch_name}", sha=source.commit.sha
)
branch_ref = self.repo.get_git_ref(f"heads/{new_branch_name}")
logger.info(
f"Branch '{new_branch_name}' created from '{source_branch}'."
)
else:
raise e

latest_commit = self.repo.get_commit(branch_ref.object.sha)
if (
latest_commit.sha != source.commit.sha
and not latest_commit.commit.message.startswith("[auto] ")
):
logger.error(f"Branch was modified: {latest_commit.commit.message}")
raise BranchModifiedError()

return branch_ref

def get_or_create_pr(
self, target_branch: str, new_branch_name: str, pr_title: str, pr_body: str
) -> PullRequest:
pulls = self.repo.get_pulls(
state="open",
head=f"{self.repo.owner.login}:{new_branch_name}",
base=target_branch,
)
if pulls.totalCount > 0:
logger.warning(
f"Pull request already exists for branch '{new_branch_name}': {pulls[0].html_url}"
)
return pulls[0]

logger.info(f"Creating pull request for branch '{new_branch_name}'")
return self.repo.create_pull(
title=pr_title, body=pr_body, head=new_branch_name, base=target_branch
)

def create_or_update_remote_branch_with_file_commit(
self,
source_branch: str,
new_branch: str,
file_path: str,
file_contents: str,
commit_message: str,
) -> GitRef:
"""Create or update a remote branch with a file commit."""
branch = self.get_or_create_branch(source_branch, new_branch)
commit = self.commit_file_contents_to_branch(
branch, file_path, file_contents, commit_message
)
branch.edit(commit.sha)
return branch

def create_or_update_pr_with_file(
self,
source_branch: str,
new_branch: str,
pr_title: str,
pr_body: str,
file_path: str,
file_contents: str,
commit_message: str,
) -> PullRequest:
self.create_or_update_remote_branch_with_file_commit(
source_branch, new_branch, file_path, file_contents, commit_message
)
return self.get_or_create_pr(source_branch, new_branch, pr_title, pr_body)


def create_organization_yaml_pr(
issue: Issue, yaml_string: str, data: GithubIssueFormDataParser
):
repo = issue.repository

source_branch = "main"
new_branch_name = f"nowa-organizacja-zgloszenie-{issue.number}"

commit_message = f"[auto] Dodana nowa organizacja: {data.get(OrgFormSchemaIds.name)} | Zgłoszenie: #{issue.number}"
pr_title = f"Dodana nowa organizacja: {data.get(OrgFormSchemaIds.name)} | Zgłoszenie: #{issue.number}"
pr_body = f"Automatycznie dodana nowa organizacja na podstawie zgłoszenia z issue #{issue.number}.\n\n Closes #{issue.number}"

file_path = "organizations/organization.yaml"

manager = GitManager(repo)
manager.create_or_update_pr_with_file(
source_branch=source_branch,
new_branch=new_branch_name,
pr_title=pr_title,
pr_body=pr_body,
file_path=file_path,
file_contents=yaml_string,
commit_message=commit_message,
)
11 changes: 6 additions & 5 deletions .github/scripts/labels.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import enum

from consts import OrgSchemaIds
from consts import OrgFormSchemaIds


class Label(enum.StrEnum):
Expand All @@ -9,11 +9,12 @@ class Label(enum.StrEnum):
INVALID_PHONE = "niepoprawny numer telefonu"
INVALID_SLUG = "niepoprawna nazwa strony"
AUTO_VERIFIED = "zweryfikowana automatycznie"
WAITING = "oczekuje na akceptację"


INVALID_FIELD_TO_LABEL = {
OrgSchemaIds.krs: Label.INVALID_KRS,
OrgSchemaIds.postal_code: Label.INVALID_POSTAL_CODE,
OrgSchemaIds.phone_number: Label.INVALID_PHONE,
OrgSchemaIds.slug: Label.INVALID_SLUG,
OrgFormSchemaIds.krs: Label.INVALID_KRS,
OrgFormSchemaIds.postal_code: Label.INVALID_POSTAL_CODE,
OrgFormSchemaIds.phone_number: Label.INVALID_PHONE,
OrgFormSchemaIds.slug: Label.INVALID_SLUG,
}
Loading

0 comments on commit 5280c8c

Please sign in to comment.