From f0a74c112201afeb46bed1beeedd115f04942c7a Mon Sep 17 00:00:00 2001 From: "ry.yamafuji" Date: Fri, 5 Dec 2025 00:44:16 +0900 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pyruff.yml | 21 +++++++++++++---- .gitignore | 2 ++ examples/example.py | 2 +- lint-result.md | 15 ------------ ruff.toml | 8 ++++++- scripts/generate_coverage.py | 42 ++++++++++++++++++--------------- scripts/generate_linter.py | 45 +++++++++++++++++++++++++----------- src/utils/singleton.py | 1 + 8 files changed, 83 insertions(+), 53 deletions(-) delete mode 100644 lint-result.md diff --git a/.github/workflows/pyruff.yml b/.github/workflows/pyruff.yml index 6a11a11..0945342 100644 --- a/.github/workflows/pyruff.yml +++ b/.github/workflows/pyruff.yml @@ -48,8 +48,19 @@ jobs: - name: pull_request message with Ruff Lint results id: prMessageRuffLint run: | - curl -v -X POST \ - -H "Content-Type: application/json" \ - -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ - -d @lint-result.json \ - ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/issues/8/comments + # イベントがプルリクエストの場合はPRにコメントを追加する + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "Posting Ruff Lint results to Pull Request..." + curl -v -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -d @lint-result.json \ + ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/issues/${{ github.event.pull_request.number }}/comments + else + echo "Not a pull request event." + echo "Ruff Lint results:" + echo "-------------------" + cat lint-result.md + echo "-------------------" + echo "No PR detected. Skipping API comment." + fi diff --git a/.gitignore b/.gitignore index 139d1f8..00b439c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,9 @@ __pycache__/ *.py[cod] *$py.class ruff-report.* +lint-result.md lint-result.json + # C extensions *.so diff --git a/examples/example.py b/examples/example.py index 029edea..0976ae4 100644 --- a/examples/example.py +++ b/examples/example.py @@ -11,7 +11,7 @@ logger = get_logger(__name__) def example(): logger.info("Application started") - print("Hello, World!") + print("Hello, World!") example() diff --git a/lint-result.md b/lint-result.md deleted file mode 100644 index c292e80..0000000 --- a/lint-result.md +++ /dev/null @@ -1,15 +0,0 @@ -## Linter(リンタ)レビュー - -以下の指摘事項があります。コードを見直してください。 - -総数:6個 - -### 指摘事項一覧 -|コード|重要性|項目|ファイル名|行数| -|---|---|---|---|---| -|W291|🟢低|行末に不要な空白があります。|examples/example.py|14行目27列 〜 14行目28列| -|W291|🟢低|行末に不要な空白があります。|scripts/generate_coverage.py|5行目23列 〜 5行目24列| -|E501|🟢低|行が長すぎます。79文字以内にしてください。|scripts/generate_coverage.py|38行目89列 〜 38行目107列| -|W291|🟢低|行末に不要な空白があります。|scripts/generate_linter_from_json.py|4行目23列 〜 4行目24列| -|W291|🟢低|行末に不要な空白があります。|scripts/generate_linter_from_json.py|25行目31列 〜 25行目39列| -|W292|🟢低|ファイルの最後に改行がありません。|scripts/generate_linter_from_json.py|53行目42列 〜 53行目42列| diff --git a/ruff.toml b/ruff.toml index d2b3aac..bafe49b 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,6 +1,12 @@ line-length = 88 # 末尾スペース・空行まわりをチェックするのは E と W系のルール +# E7xx/E9xx(構文/実行時エラーの可能性) +# W1xx/W5xx(スタイル・フォーマット関連) +# DXXX(ドキュメンテーション文字列関連) +# F (未使用インポートなどのエラー) +# BXX(バグの可能性) + [lint] -select = ["E", "W"] +select = ["F", "E", "W", "D101", "B"] ignore = [] \ No newline at end of file diff --git a/scripts/generate_coverage.py b/scripts/generate_coverage.py index 00a31df..a2e57d6 100644 --- a/scripts/generate_coverage.py +++ b/scripts/generate_coverage.py @@ -2,9 +2,11 @@ import re class GenerateCoverage: - def __init__(self, - coverage_file="pytest-coverage.txt", - output_file="coverage_table.md"): + """カバレッジ結果を解析して Markdown テーブルを生成""" + + def __init__( + self, coverage_file="pytest-coverage.txt", output_file="coverage_table.md" + ): """ 初期化 @@ -35,26 +37,28 @@ class GenerateCoverage: if in_coverage_section and line.strip().startswith("---"): continue # Coverage セクションの終わりを検出(TOTAL行の次の空行) - if in_coverage_section and (line.strip().startswith("TOTAL") or line.strip().startswith("=")): + if in_coverage_section and ( + line.strip().startswith("TOTAL") or line.strip().startswith("=") + ): break # Coverage データを抽出 if in_coverage_section: - match = re.match( - r"(.+?)\s+(\d+)\s+(\d+)\s+(\d+%)\s*(.*)", line) + match = re.match(r"(.+?)\s+(\d+)\s+(\d+)\s+(\d+%)\s*(.*)", line) if match: filename = match.group(1).strip() statements = match.group(2).strip() missed = match.group(3).strip() coverage = match.group(4).strip() - missing_lines = match.group( - 5).strip() if match.group(5) else "-" - coverage_info.append({ - "filename": filename, - "statements": statements, - "missed": missed, - "coverage": coverage, - "missing_lines": missing_lines - }) + missing_lines = match.group(5).strip() if match.group(5) else "-" + coverage_info.append( + { + "filename": filename, + "statements": statements, + "missed": missed, + "coverage": coverage, + "missing_lines": missing_lines, + } + ) self.coverage_data = coverage_info @@ -72,9 +76,11 @@ class GenerateCoverage: # テーブル行を生成 table_rows = [ - (f"| {data['filename']} | {data['statements']} | " - f"{data['missed']} | {data['coverage']} | " - f"{data['missing_lines']} |") + ( + f"| {data['filename']} | {data['statements']} | " + f"{data['missed']} | {data['coverage']} | " + f"{data['missing_lines']} |" + ) for data in self.coverage_data ] diff --git a/scripts/generate_linter.py b/scripts/generate_linter.py index 2d706b2..0e9917a 100644 --- a/scripts/generate_linter.py +++ b/scripts/generate_linter.py @@ -7,13 +7,18 @@ print(f"Project Name: {PROJECT_NAME}") CODE_MAP = { "W291": {"message": "行末に不要な空白があります。", "severity": "🟢低"}, - "W292": {"message": "ファイルの最後に改行がありません。", "severity": "🟢低"} , + "W292": {"message": "ファイルの最後に改行がありません。", "severity": "🟢低"}, "E501": { "message": "行が長すぎます。79文字以内にしてください。", "severity": "🟢低", }, + "D101": { + "message": "クラスにドキュメンテーション文字列がありません。", + "severity": "⚪️無害", + }, } + def get_relative_path(absolute_path: str) -> str: """ 絶対パスからプロジェクトルートからの相対パスを取得 @@ -26,7 +31,8 @@ def get_relative_path(absolute_path: str) -> str: class GenerateLinter: - def __init__(self, json_file="ruff-report.json", output_file="lint-result.json"): + """Linterレポートを生成するクラス""" + def __init__(self, json_file="ruff-report.json", output_file="lint-result"): """ 初期化 """ @@ -46,43 +52,56 @@ class GenerateLinter: _str += f"総数:{len(data)}個\n" _str += "### 指摘事項一覧\n" - _str += "|コード|重要性|項目|ファイル名|行数|\n" - _str += "|---|---|---|---|---|\n" + _str += "|コード|重要性|項目|ファイル名|行数|自動修正|\n" + _str += "|---|---|---|---|---|---|\n" for issue in data: code = issue.get("code", "-") severity = ( - CODE_MAP.get(code, {}).get("severity", "❓不明") - if code != "-" - else "-" + CODE_MAP.get(code, {}).get("severity", "❓不明") if code != "-" else "-" ) message = CODE_MAP.get(code, {}).get("message", issue.get("message", "-")) filename = get_relative_path(issue.get("filename", "-")) + file_link = f"./{filename}" + line = "" if issue.get("location") and issue["location"].get("row"): line = f"{issue['location']['row']}行目" if issue["location"].get("column"): line += f"{issue['location']['column']}列" - if issue.get("end_location"): if issue["end_location"].get("row"): line += f" 〜 {issue['end_location']['row']}行目" if issue["end_location"].get("column"): line += f"{issue['end_location']['column']}列" + auto_fix = "✅" if issue.get("fix") else "❌" + + _str += f"|{code}|{severity}|{message}|" + _str += f"[{filename}]({file_link})|{line}|{auto_fix}|\n" + + _str += "\n\n" + _str += "### 自動修正コマンド\n" + _str += ("自動修正が可能な指摘事項については、" + "以下のコマンドで自動修正を試みることができます。\n\n" + ) + _str += "```bash\n" + _str += "ruff check --fix .\n" + _str += "```\n\n" - _str += f"|{code}|{severity}|{message}|{filename}|{line}|\n" return _str def generate_lint_report_json(self): with open(self.json_file, "r") as f: data = json.load(f) - with open(self.output_file, "w") as f: - # report_body = self._genarate_lint_report(data) - # f.write(report_body) + with open(f"{self.output_file}.md", "w") as f: + report_body = self._genarate_lint_report(data) + f.write(report_body) + + with open(f"{self.output_file}.json", "w") as f: report = {"body": self._genarate_lint_report(data)} json.dump(report, f, ensure_ascii=False, indent=4) - print(f"Linter report generated: {self.output_file}") + print(f"Linter report generated: {self.output_file}.md, {self.output_file}.json") if __name__ == "__main__": diff --git a/src/utils/singleton.py b/src/utils/singleton.py index 8ac3278..54385f0 100644 --- a/src/utils/singleton.py +++ b/src/utils/singleton.py @@ -11,6 +11,7 @@ import threading class Singleton(object): + """シングルトンパターンの基底クラス""" _instances = {} _lock = threading.Lock()