Skip to content

Commit

Permalink
Add skeleton of issue actions
Browse files Browse the repository at this point in the history
  • Loading branch information
happz committed Feb 15, 2024
1 parent e9802b4 commit 0575770
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 11 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ repos:
- "click>=8.0.3,!=8.1.4"
- "attrs>=20.3.0"
- "ruamel.yaml>=0.16.6"
- "jinja2>=2.11.3"
pass_filenames: false
args: [--config-file=pyproject.toml]

Expand Down
39 changes: 39 additions & 0 deletions component-config.yaml.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
issues:
- summary: "Errata respin {{ ERRATUM.respin_count }}"
description: "{{ ERRATUM.srpms }}"
assignee: '{{ ERRATUM.people_assigned_to }}'
type: task
id: errata_task
parent: errata_epic
on_respin: close

- summary: "Testing ER#{{ ERRATUM.event.id }} {{ ERRATUM.summary }}"
description: "{{ ERRATUM.url }}"
assignee: '{{ ERRATUM.people_assigned_to }}'
type: epic
id: errata_epic
on_respin: keep

- summary: "Errata filelist check"
description: "Compare errata filelist with a previously released advisory"
assignee: '{{ ERRATUM.people_assigned_to }}'
type: subtask
id: subtask_filelist
parent: errata_task
on_respin: close

- summary: "SPEC file review"
description: "Review changes made in the SPEC file"
assignee: '{{ ERRATUM.people_assigned_to }}'
type: subtask
id: subtask_spec
parent: errata_task
on_respin: close

- summary: "rpminspect review"
description: "Review rpminspect results in the CI Dashboard for all builds"
assignee: '{{ ERRATUM.people_assigned_to }}'
type: subtask
id: subtask_rpminspect
parent: errata_task
on_respin: close
78 changes: 77 additions & 1 deletion newa/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import io
from enum import Enum
from pathlib import Path
from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING, Any, Optional, TypeVar

import attrs
import jinja2
import ruamel.yaml
import ruamel.yaml.nodes
import ruamel.yaml.representer
Expand Down Expand Up @@ -40,6 +41,47 @@ def _represent_enum(
return yaml


def default_template_environment() -> jinja2.Environment:
"""
Create a Jinja2 environment with default settings.
Adds common filters, and enables block trimming and left strip.
"""

environment = jinja2.Environment()

environment.trim_blocks = True
environment.lstrip_blocks = True

return environment


def render_template(
template: str,
environment: Optional[jinja2.Environment] = None,
**variables: Any,
) -> str:
"""
Render a template.
:param template: template to render.
:param environment: Jinja2 environment to use.
:param variables: variables to pass to the template.
"""

environment = environment or default_template_environment()

try:
return environment.from_string(template).render(**variables).strip()

except jinja2.exceptions.TemplateSyntaxError as exc:
raise Exception(
f"Could not parse template at line {exc.lineno}.") from exc

except jinja2.exceptions.TemplateError as exc:
raise Exception("Could not render template.") from exc


class EventType(Enum):
""" Event types """

Expand Down Expand Up @@ -127,3 +169,37 @@ class ErratumJob(Job):
@property
def id(self) -> str:
return f'{self.event.id} @ {self.erratum.release}'


#
# Component configuration
#
class IssueType(Enum):
EPIC = 'epic'
TASK = 'task'
SUBTASK = 'subtask'


class OnRespinAction(Enum):
# TODO: what's the default? It would simplify the class a bit.
KEEP = 'keep'
CLOSE = 'close'


@define
class IssueAction: # type: ignore[no-untyped-def]
summary: str
description: str
assignee: str
id: str
on_respin: Optional[OnRespinAction] = field( # type: ignore[var-annotated]
converter=lambda value: OnRespinAction(value) if value else None)
type: IssueType = field(converter=IssueType)
parent: Optional[str] = None


@define
class ErratumConfig(Serializable):
issues: list[IssueAction] = field( # type: ignore[var-annotated]
factory=list, converter=lambda issues: [
IssueAction(**issue) for issue in issues])
47 changes: 38 additions & 9 deletions newa/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
import os.path
from collections.abc import Iterable, Iterator
from pathlib import Path
from typing import Any

import click
from attrs import define

from . import ErratumJob
from . import ErratumConfig, ErratumJob, render_template

logging.basicConfig(
format='%(asctime)s %(message)s',
Expand Down Expand Up @@ -94,14 +95,42 @@ def cmd_jira(ctx: CLIContext) -> None:

for erratum_job in ctx.load_erratum_jobs('event-'):
# read Jira issue configuration
# get list of matching actions

# for action in actions:
# create epic
# or create task
# or create sutask
# if subtask assoc. with recipes
# clone object with yaml
config = ErratumConfig.from_yaml_file(Path('component-config.yaml.sample'))

# TODO: record created/existing issues. Instead of `Any`, maybe something
# from the Jira library would be stored. Or just a Jira ticket ID.
known_issues: dict[str, Any] = {}

# Iterate over issue actions. Take one, if it's not possible to finish it,
# put it back at the end of the queue.
issue_actions = config.issues[:]

while issue_actions:
action = issue_actions.pop(0)

print(f'* Would create a {action.type.name} issue:')
print(f' summary: {action.summary}')
print(f' summary: {action.description}')

if action.id in known_issues:
raise Exception(f'Issue "{action.id}" is already created!')

if action.parent and action.parent not in known_issues:
print(f' !! Parent issue, "{action.parent}", is unknown, will try later')
print()

issue_actions.append(action)
continue

print()
print(f' Issue would be assigned to {action.assignee}.')
print(f' rendered: >>{render_template(action.assignee, ERRATUM=erratum_job)}<<')
print(f' Will remember the issue as `{action.id}`.')
if action.parent:
print(f' Issue would have issue `{action.parent}` as its parent.')
print()

known_issues[action.id] = True

# erratum_job.issue = ...
# what's recipe? doesn't it belong to "schedule"?
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ keywords = [
dependencies = [
"click>=8.0.3,!=8.1.4",
"attrs>=20.3.0",
"ruamel.yaml>=0.16.6"
"ruamel.yaml>=0.16.6",
"jinja2>=2.11.3"
]

[project.optional-dependencies]
Expand Down

0 comments on commit 0575770

Please sign in to comment.