Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/contribute.rst
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,38 @@ prioritized issues.
.. _backlog: https://github.com/orgs/teemtee/projects/1/views/1


Sync
------------------------------------------------------------------

The ``scripts/sprint-overview`` script lists all issues and pull
requests in a GitHub Project sprint together with their story
points. It can also output the data in YAML format for further
processing:

.. code-block:: bash

./scripts/sprint-overview --sprint 'Sprint 11'
./scripts/sprint-overview --sprint 'Sprint 11' --yaml

The ``scripts/sprint-sync`` script synchronizes a Jira sprint
with GitHub sprint items. It reads the YAML output from
``sprint-overview``, removes Jira items not present in the
GitHub sprint and adds missing items into the Jira sprint:

.. code-block:: bash

./scripts/sprint-overview --sprint 'Sprint 11' --yaml \
| ./scripts/sprint-sync --sprint 'Sprint 11'

Use ``--dry`` to preview changes without modifying the Jira
sprint:

.. code-block:: bash

./scripts/sprint-overview --sprint 'Sprint 11' --yaml \
| ./scripts/sprint-sync --sprint 'Sprint 11' --dry


Release
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
26 changes: 26 additions & 0 deletions scripts/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Common data structures shared between sprint scripts.
"""

import dataclasses
from typing import Optional


@dataclasses.dataclass
class Item:
"""
A sprint item (issue or pull request).
"""

id: int
type: str
repo: str
status: str
size: Optional[int]
url: str
title: str

def __str__(self) -> str:
size_str = f"[{self.size}]" if self.size is not None else "[-]"
identifier = f"{self.repo}#{self.id}"
return f"{identifier:<10} {size_str:>4} {self.title}"
32 changes: 7 additions & 25 deletions scripts/sprint-overview
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import jinja2
import requests
from ruamel.yaml import YAML

from common import Item # isort: skip

# https://docs.github.com/en/rest/about-the-rest-api/breaking-changes
GITHUB_API_URL = "https://api.github.com"
GITHUB_API_VERSION = "2026-03-10"
Expand Down Expand Up @@ -75,26 +77,6 @@ DISPLAY_TEMPLATE = jinja2.Template(
)


@dataclasses.dataclass
class Item:
"""
A sprint item (issue or pull request).
"""

id: int
type: str
repo: str
status: str
size: Optional[int]
url: str
title: str

def __str__(self) -> str:
size_str = f"[{self.size}]" if self.size is not None else "[-]"
identifier = f"{self.repo}#{self.id}"
return f"{identifier:<10} {size_str:>4} {self.title}"


def github_api_get(
path: str,
params: Optional[dict[str, str]] = None,
Expand Down Expand Up @@ -253,14 +235,14 @@ def main(sprint: str, output_yaml: bool) -> None:
"""
items = fetch_sprint_items(sprint)

if not items:
click.echo(f"No items found in sprint '{sprint}'.")
return

if output_yaml:
YAML().dump([dataclasses.asdict(item) for item in items], sys.stdout)
else:
return

if items:
display_items(sprint, items)
else:
click.echo(f"No items found in sprint '{sprint}'.", err=True)


if __name__ == "__main__":
Expand Down
Loading
Loading