File: bugfixer.py

package info (click to toggle)
parolottero-languages 9-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 4,368 kB
  • sloc: python: 351; makefile: 66
file content (133 lines) | stat: -rwxr-xr-x 3,858 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/python3

# parolottero-languages
# Copyright (C) 2020-2025 Salvo "LtWorf" Tomaselli
#
# parolottero-languages is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# author Salvo "LtWorf" Tomaselli <tiposchi@tiscali.it>


# This is copy pasted from typedload's example.py

from datetime import datetime
import json
from typing import *
import urllib.request
from pathlib import Path
import subprocess

import typedload.dataloader


def get_data() -> Any:
    """
    Use the github API to get issues information
    """
    url = 'https://codeberg.org/api/v1/repos/parolottero/parolottero-languages/issues?state=open'
    req = urllib.request.Request(url)
    req.add_header('accept', 'application/json')
    with urllib.request.urlopen(req) as f:
        return json.load(f)


class User(NamedTuple):
    login: str


class Issue(NamedTuple):
    number: int
    title: str
    body: str
    user: User
    created_at: datetime
    updated_at: datetime

    @property
    def autoissue(self) -> bool:
        return \
            self.title.startswith('User report for ') and \
            'id: ' in self.body and \
            'Item count: ' in self.body and \
            'Language: ' in self.body

    def _prefix(self, prefix: str) -> Iterable[str]:
        for l in self.body.split('\n'):
            if l.startswith(prefix):
                yield l.strip()

    def diff(self) -> Iterable[str]:
        yield from self._prefix('+')
        yield from self._prefix('-')

    @property
    def language(self) -> str:
        return next(self._prefix('Language: ')).split(' ', 1)[-1]

    @property
    def extrafile(self) -> str:
        a = {
            'Sicilianu': 'extralist/sicilian.extra',
            'Italiano': 'extralist/italian.extra',
            'English': 'extralist/english.extra',
            'Français': 'extralist/french.extra',
        }
        return Path(a[self.language])

    @property
    def machineid(self) -> str:
        return next(self._prefix('id: ')).split(' ', 1)[-1]

    def __str__(self) -> str:
        return f'#{self.number}: {self.language}\nAutomatic: {self.autoissue} From machine: {self.machineid}\n'


def interactive_fix_issue(issue: Issue) -> None:
    with issue.extrafile.open('rt') as f:
        extras = {i.strip() for i in f}

    print(f'===== Doing extra words for {issue.language}')
    for diff in issue.diff():
        reply = input(f'Is this valid "{diff}" [yN]? ')
        if reply in {'y', 'Y', 'YES', 'yes'}:
            extras.add(diff)

    with issue.extrafile.open('wt') as f:
        wlist = list(extras)
        wlist.sort()
        for l in extras:
            print(l, file=f)

    subprocess.check_call(['git', 'add', issue.extrafile])
    try:
        subprocess.check_call(['git', 'commit', '-m', f'Fix user reported mistakes\nCloses: #{issue.number}', issue.extrafile])
    except subprocess.CalledProcessError:
        pass
        # TODO close the issue via API


def main():
    data = get_data()

    loader = typedload.dataloader.Loader()

    # We know what the API returns so we can load the json into typed data
    issues = loader.load(data, List[Issue])
    for i in issues:
        if i.autoissue:
            interactive_fix_issue(i)


if __name__ == '__main__':
    main()