From 769b20a888a7f693f5ef5edb9912946bae07156c Mon Sep 17 00:00:00 2001 From: Karel Srot Date: Fri, 15 Mar 2024 12:08:51 +0100 Subject: [PATCH 1/3] Add initial JiraJob implementation --- component-config.yaml.sample | 9 +++++++ newa/__init__.py | 44 +++++++++++++++++++++++++++++++-- newa/cli.py | 47 +++++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/component-config.yaml.sample b/component-config.yaml.sample index 8afc90a..205149b 100644 --- a/component-config.yaml.sample +++ b/component-config.yaml.sample @@ -38,3 +38,12 @@ issues: id: subtask_rpminspect parent_id: errata_task on_respin: close + + - summary: "regression testing" + description: "Run automated tests" + assignee: '{{ ERRATUM.people_assigned_to }}' + type: subtask + id: subtask_regression + parent: errata_task + on_respin: close + job_recipe: https://path/to/recipe.yaml diff --git a/newa/__init__.py b/newa/__init__.py index b2a0da4..0d3e636 100644 --- a/newa/__init__.py +++ b/newa/__init__.py @@ -148,7 +148,27 @@ class Erratum(Cloneable, Serializable): """ An eratum """ release: str - # builds: list[...] = ... + builds: list[str] = [] + + def fetch_details(self) -> None: + raise NotImplementedError + + +@define +class Issue(Cloneable, Serializable): + """ A Jira issue """ + + issue: str + + def fetch_details(self) -> None: + raise NotImplementedError + + +@define +class Recipe(Cloneable, Serializable): + """ A job recipe """ + + url: str def fetch_details(self) -> None: raise NotImplementedError @@ -162,7 +182,7 @@ class Job(Cloneable, Serializable): converter=lambda x: x if isinstance(x, Event) else Event(**x), ) - # issue: ... + # jira: ... # recipe: ... # test_job: ... # job_result: ... @@ -185,9 +205,28 @@ def id(self) -> str: return f'{self.event.id} @ {self.erratum.release}' +@define +class JiraJob(ErratumJob): + """ A single *jira* job """ + + jira: Issue = field( # type: ignore[var-annotated] + converter=lambda x: x if isinstance(x, Issue) else Issue(**x), + ) + + recipe: Recipe = field( # type: ignore[var-annotated] + converter=lambda x: x if isinstance(x, Recipe) else Recipe(**x), + ) + + @property + def id(self) -> str: + return f'{self.event.id} @ {self.erratum.release}' + + # # Component configuration # + + class IssueType(Enum): EPIC = 'epic' TASK = 'task' @@ -210,6 +249,7 @@ class IssueAction: # type: ignore[no-untyped-def] converter=lambda value: OnRespinAction(value) if value else None) type: IssueType = field(converter=IssueType) parent_id: Optional[str] = None + job_recipe: Optional[str] = None @define diff --git a/newa/cli.py b/newa/cli.py index 771f81f..fd56b47 100644 --- a/newa/cli.py +++ b/newa/cli.py @@ -7,7 +7,18 @@ import click from attrs import define -from . import Erratum, ErratumConfig, ErratumJob, Event, EventType, InitialErratum, render_template +from . import ( + Erratum, + ErratumConfig, + ErratumJob, + Event, + EventType, + InitialErratum, + Issue, + JiraJob, + Recipe, + render_template +) logging.basicConfig( format='%(asctime)s %(message)s', @@ -68,6 +79,13 @@ def save_erratum_jobs(self, filename_prefix: str, jobs: Iterable[ErratumJob]) -> for job in jobs: self.save_erratum_job(filename_prefix, job) + def save_jira_job(self, filename_prefix: str, job: JiraJob) -> None: + filepath = self.state_dirpath / \ + f'{filename_prefix}{job.event.id}-{job.erratum.release}-{job.jira.issue}.yaml' + + job.to_yaml_file(filepath) + self.logger.info(f'Jira job {job.id} written to {filepath}') + @click.group(chain=True) @click.option( @@ -124,6 +142,15 @@ def cmd_event(ctx: CLIContext, errata_ids: tuple[str, ...]) -> None: def cmd_jira(ctx: CLIContext) -> None: ctx.enter_command('jira') + # This is just to provide fake Jira IDs until we can obtain real ones + def jira_issue_identifier() -> str: + num = 1 + while True: + yield f'NEWA-{num}' + num += 1 + + jira_id_gen = jira_issue_identifier() + for erratum_job in ctx.load_erratum_jobs('event-'): # read Jira issue configuration config = ErratumConfig.from_yaml_file(Path('component-config.yaml.sample')) @@ -142,6 +169,7 @@ def cmd_jira(ctx: CLIContext) -> None: print(f'* Would create a {action.type.name} issue:') print(f' summary: {action.summary}') print(f' summary: {action.description}') + print() if action.id in known_issues: raise Exception(f'Issue "{action.id}" is already created!') @@ -153,7 +181,6 @@ def cmd_jira(ctx: CLIContext) -> None: 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}`.') @@ -163,11 +190,19 @@ def cmd_jira(ctx: CLIContext) -> None: known_issues[action.id] = True - # erratum_job.issue = ... - # what's recipe? doesn't it belong to "schedule"? - # recipe = new JobRecipe(url) + # create a fake Issue object for now + issue = Issue(issue=next(jira_id_gen)) + + if action.job_recipe: + print( + f'* Would kick automated job for issue {action.type.name} based on recipe from {action.job_recipe}:') + print() - ctx.save_erratum_job('jira-', erratum_job) + jira_job = JiraJob(event=erratum_job.event, + erratum=erratum_job.erratum, + jira=issue, + recipe=Recipe(url=action.job_recipe)) + ctx.save_jira_job('jira-', jira_job) @main.command(name='schedule') From d823d25d7532d5969ce5b31ed06e48d2bd725f05 Mon Sep 17 00:00:00 2001 From: Karel Srot Date: Fri, 15 Mar 2024 14:46:31 +0100 Subject: [PATCH 2/3] Incorporate fixes from review --- component-config.yaml.sample | 2 +- newa/__init__.py | 4 ++-- newa/cli.py | 15 +++++---------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/component-config.yaml.sample b/component-config.yaml.sample index 205149b..9f7562b 100644 --- a/component-config.yaml.sample +++ b/component-config.yaml.sample @@ -44,6 +44,6 @@ issues: assignee: '{{ ERRATUM.people_assigned_to }}' type: subtask id: subtask_regression - parent: errata_task + parent_id: errata_task on_respin: close job_recipe: https://path/to/recipe.yaml diff --git a/newa/__init__.py b/newa/__init__.py index 0d3e636..75936af 100644 --- a/newa/__init__.py +++ b/newa/__init__.py @@ -148,7 +148,7 @@ class Erratum(Cloneable, Serializable): """ An eratum """ release: str - builds: list[str] = [] + builds: list[str] = field(factory=list) def fetch_details(self) -> None: raise NotImplementedError @@ -158,7 +158,7 @@ def fetch_details(self) -> None: class Issue(Cloneable, Serializable): """ A Jira issue """ - issue: str + id: str def fetch_details(self) -> None: raise NotImplementedError diff --git a/newa/cli.py b/newa/cli.py index fd56b47..b2d232d 100644 --- a/newa/cli.py +++ b/newa/cli.py @@ -1,3 +1,4 @@ +import itertools import logging import os.path from collections.abc import Iterable, Iterator @@ -81,7 +82,7 @@ def save_erratum_jobs(self, filename_prefix: str, jobs: Iterable[ErratumJob]) -> def save_jira_job(self, filename_prefix: str, job: JiraJob) -> None: filepath = self.state_dirpath / \ - f'{filename_prefix}{job.event.id}-{job.erratum.release}-{job.jira.issue}.yaml' + f'{filename_prefix}{job.event.id}-{job.erratum.release}-{job.jira.id}.yaml' job.to_yaml_file(filepath) self.logger.info(f'Jira job {job.id} written to {filepath}') @@ -142,14 +143,8 @@ def cmd_event(ctx: CLIContext, errata_ids: tuple[str, ...]) -> None: def cmd_jira(ctx: CLIContext) -> None: ctx.enter_command('jira') - # This is just to provide fake Jira IDs until we can obtain real ones - def jira_issue_identifier() -> str: - num = 1 - while True: - yield f'NEWA-{num}' - num += 1 - - jira_id_gen = jira_issue_identifier() + # this is here temporarily so we generate fake Jira issue IDs + jira_id_gen = itertools.count(start=1) for erratum_job in ctx.load_erratum_jobs('event-'): # read Jira issue configuration @@ -191,7 +186,7 @@ def jira_issue_identifier() -> str: known_issues[action.id] = True # create a fake Issue object for now - issue = Issue(issue=next(jira_id_gen)) + issue = Issue(id=f'NEWA-{next(jira_id_gen)}') if action.job_recipe: print( From d79df7b8d1cec466a602b0f9444856a5fb0f8d0a Mon Sep 17 00:00:00 2001 From: Karel Srot Date: Fri, 15 Mar 2024 14:48:56 +0100 Subject: [PATCH 3/3] Please linters --- newa/cli.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/newa/cli.py b/newa/cli.py index b2d232d..9307626 100644 --- a/newa/cli.py +++ b/newa/cli.py @@ -18,8 +18,8 @@ Issue, JiraJob, Recipe, - render_template -) + render_template, + ) logging.basicConfig( format='%(asctime)s %(message)s', @@ -190,7 +190,8 @@ def cmd_jira(ctx: CLIContext) -> None: if action.job_recipe: print( - f'* Would kick automated job for issue {action.type.name} based on recipe from {action.job_recipe}:') + f'* Would kick automated job for issue {action.type.name}' + f'based on recipe from {action.job_recipe}:') print() jira_job = JiraJob(event=erratum_job.event,