Compare commits
110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 213b89a399 | |||
| f511b701ee | |||
| f597aea758 | |||
| 48f90c02fa | |||
| b5d312e840 | |||
| 3d6e11166d | |||
| 18fe66bd7a | |||
| 643e8280f7 | |||
| 98fe60d69b | |||
| 2eda7f9730 | |||
| bb1360ee33 | |||
| 2bc2c33257 | |||
| 80220b0c57 | |||
| 46d984a7a6 | |||
| 4b58460f3c | |||
| ba6ab05c19 | |||
| 5d985da6e6 | |||
| 3791e394b4 | |||
| df23c30855 | |||
| 7ef5e6654c | |||
| 46eb192ced | |||
| 14567f63e3 | |||
| d9955f358b | |||
| 74eb12d687 | |||
| 83d67e9c2f | |||
| 1e07859f76 | |||
| f4291aef42 | |||
| 4958e49ed5 | |||
| 33e80ab384 | |||
| 3a0ea5f698 | |||
| d283a08555 | |||
| 63e288d5f0 | |||
| 80499584bd | |||
| 6f55f05e88 | |||
| 5adf571e0a | |||
| 7527b6185e | |||
| e52c2875f1 | |||
| 00a1d71bf2 | |||
| 3de153452a | |||
| b2a6c3acff | |||
| 3706f8270f | |||
| d5b38771c8 | |||
| a456034ce2 | |||
| 53f26a2540 | |||
| 5e1cda791b | |||
| 8def1cd9cb | |||
| 5661ba2501 | |||
| 8d6f166b25 | |||
| 3aa07b1dc2 | |||
| 37d042ece1 | |||
| 50b30a7826 | |||
| f61cab825c | |||
| 53c3f528b7 | |||
| b38cd20e93 | |||
| b2200dfa79 | |||
| 133db3ed0d | |||
| 269010b78e | |||
| 709b0a62d6 | |||
| 25d91ba94f | |||
| 0a0a410031 | |||
| ca4047cb2a | |||
| 5cb61bcd6c | |||
| a03bf9954a | |||
| fc44f186d5 | |||
| 65e5d4d422 | |||
| ed0b86d472 | |||
| 7bd5b48a99 | |||
| 1fad6088a8 | |||
| 9d3957efce | |||
| e2eec6b831 | |||
| 4af4fc13d6 | |||
| 4b422d8f5e | |||
| 55e77f021c | |||
| 4dcc7993be | |||
| 8d9d835d5e | |||
| 11da421ece | |||
| dc1ad56b0c | |||
| b1337337ef | |||
| bd4da9d8a5 | |||
| acaaa47f39 | |||
| 5a882fcd52 | |||
| 1ebe3552e7 | |||
| 9f342c2c40 | |||
| cffa834dea | |||
| 331aabb298 | |||
| a371edf54b | |||
| 598bd9a7ed | |||
| 453b481dd5 | |||
| 22613b7898 | |||
| 5eb78c16cb | |||
| 92b2255a51 | |||
| 7f47ce1876 | |||
| 2caac04c2a | |||
| ef61262178 | |||
| 67c1f51422 | |||
| eec25e9bee | |||
| bef29ed0f1 | |||
| 0210e53008 | |||
| 5f7e1f4fd2 | |||
| 9714c47ab7 | |||
| 91c542b82e | |||
| ab9a769d4a | |||
| 8c4d81d3e0 | |||
| a6c38b5839 | |||
| b3c1531622 | |||
| 3886be8c31 | |||
| dfdfb43457 | |||
| c4fac43857 | |||
| 349acfb1c8 | |||
| c971365f0f |
22
.editorconfig
Normal file
22
.editorconfig
Normal file
@ -0,0 +1,22 @@
|
||||
#https://editorconfig.org/
|
||||
#INI format
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
#EditorConfig for VS Code v0.16.4
|
||||
#Known Issues
|
||||
#trim_trailing_whitespace = false is not applied when user/workspace setting of files.trimTrailingWhitespace is set to true.
|
||||
trim_trailing_whitespace = false
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
.env
|
||||
.env
|
||||
.env.local
|
||||
102
.woodpecker.yml
Normal file
102
.woodpecker.yml
Normal file
@ -0,0 +1,102 @@
|
||||
# 全体像
|
||||
# PR と push で 別の処理 が走ります。
|
||||
#NOTE depends_on なし → 並列実行
|
||||
#WARN failure: ignore がないため、Drep が失敗すると パイプライン全体が ❌ になり、マージが止まる可能性があります。
|
||||
# pull_request イベント
|
||||
# ├─ php-lint … PHP 構文チェック(マージ前の CI)
|
||||
# └─ ai-review … Drep による AI コードレビュー
|
||||
# ↑
|
||||
# depends_on なし → 並列実行
|
||||
# push イベント(develop ブランチのみ)
|
||||
# └─ deploy … EC2 へ SSH してデプロイ確認
|
||||
|
||||
steps:
|
||||
# 疎通テスト
|
||||
# hello:
|
||||
# image: alpine:latest
|
||||
# commands:
|
||||
# - echo "Woodpecker is working!"
|
||||
|
||||
# PHP構文チェック(merge前)
|
||||
php-lint:
|
||||
image: php:8.3-cli
|
||||
commands:
|
||||
- find . -name "*.php" -print0 | xargs -0 -n1 php -l
|
||||
when:
|
||||
event:
|
||||
- pull_request
|
||||
|
||||
# AI コードレビュー(skip-ai-review ラベル付き PR はスキップ)
|
||||
# 成功時に ai-reviewed ラベルを Gitea API で付与
|
||||
ai-review:
|
||||
image: ghcr.io/slb350/drep:latest
|
||||
environment:
|
||||
GITEA_TOKEN:
|
||||
from_secret: gitea_token
|
||||
DREP_LLM_API_KEY:
|
||||
from_secret: drep_llm_api_key
|
||||
OPENAI_API_KEY:
|
||||
from_secret: drep_llm_api_key
|
||||
DREP_LLM_ENDPOINT: https://openrouter.ai/api/v1
|
||||
DREP_LLM_MODEL: nvidia/nemotron-3-ultra-550b-a55b:free
|
||||
commands:
|
||||
- |
|
||||
case ",${CI_COMMIT_PULL_REQUEST_LABELS}," in
|
||||
*",skip-ai-review,"*)
|
||||
echo "★ skip-ai-review label detected — skipping AI review"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
cat > /tmp/config.yaml <<EOF
|
||||
gitea:
|
||||
url: https://gitea.git.mitchecp.com
|
||||
token: $${GITEA_TOKEN}
|
||||
repositories:
|
||||
- ${CI_REPO_OWNER}/*
|
||||
llm:
|
||||
enabled: true
|
||||
endpoint: $${DREP_LLM_ENDPOINT}
|
||||
api_key: $${DREP_LLM_API_KEY}
|
||||
model: $${DREP_LLM_MODEL}
|
||||
temperature: 0.2
|
||||
timeout: 120
|
||||
max_tokens: 4096
|
||||
database_url: sqlite:////tmp/drep.db
|
||||
documentation:
|
||||
enabled: true
|
||||
markdown_checks: false
|
||||
EOF
|
||||
export DREP_CONFIG=/tmp/config.yaml
|
||||
|
||||
echo "★ Running drep review for ${CI_REPO} PR #${CI_COMMIT_PULL_REQUEST}"
|
||||
drep review "${CI_REPO}" "${CI_COMMIT_PULL_REQUEST}"
|
||||
|
||||
echo "★ Adding ai-reviewed label to PR #${CI_COMMIT_PULL_REQUEST}"
|
||||
python3 ci/add-ai-reviewed-label.py
|
||||
when:
|
||||
event:
|
||||
- pull_request
|
||||
|
||||
# 本番デプロイ
|
||||
deploy:
|
||||
image: alpine:latest
|
||||
|
||||
environment:
|
||||
SSH_KEY:
|
||||
from_secret: mitchecp_ssh_key
|
||||
|
||||
#WARN secret key(.pem) の追加は gitea ではなく woodpecker 側に必要。
|
||||
#NOTE $$SSH_KEY は Woodpecker が $$ → $ に変換してから shell 実行(PID 展開ではない)
|
||||
commands:
|
||||
- apk add --no-cache openssh-client
|
||||
- mkdir -p ~/.ssh
|
||||
- echo "$$SSH_KEY" > ~/.ssh/mitchecp.pem
|
||||
- chmod 600 ~/.ssh/mitchecp.pem
|
||||
- ssh-keyscan gitea.git.mitchecp.com >> ~/.ssh/known_hosts
|
||||
- ssh -i ~/.ssh/mitchecp.pem ec2-user@gitea.git.mitchecp.com "cd /home/ec2-user && touch woodpecker.created.develop.txt"
|
||||
when:
|
||||
branch:
|
||||
- develop
|
||||
event:
|
||||
- push
|
||||
82
ci/add-ai-reviewed-label.py
Normal file
82
ci/add-ai-reviewed-label.py
Normal file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Add ai-reviewed label to a Gitea PR after successful Drep review."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
GITEA_URL = "https://gitea.git.mitchecp.com"
|
||||
LABEL_NAME = "ai-reviewed"
|
||||
REQUEST_TIMEOUT = 30
|
||||
|
||||
|
||||
def require_env(name: str) -> str:
|
||||
value = os.environ.get(name, "").strip()
|
||||
if not value:
|
||||
print(f"ERROR: required environment variable {name!r} is not set", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return value
|
||||
|
||||
|
||||
def api_request(token: str, method: str, url: str, data: dict | None = None) -> dict | list:
|
||||
headers = {"Authorization": f"token {token}"}
|
||||
body = None
|
||||
if data is not None:
|
||||
headers["Content-Type"] = "application/json"
|
||||
body = json.dumps(data).encode()
|
||||
|
||||
req = urllib.request.Request(url, data=body, headers=headers, method=method)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as resp:
|
||||
raw = resp.read().decode()
|
||||
return json.loads(raw) if raw else {}
|
||||
except urllib.error.HTTPError as exc:
|
||||
detail = exc.read().decode(errors="replace")
|
||||
print(f"ERROR: Gitea API {method} {url} failed ({exc.code}): {detail}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except urllib.error.URLError as exc:
|
||||
print(f"ERROR: Gitea API {method} {url} failed: {exc.reason}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
token = require_env("GITEA_TOKEN")
|
||||
owner = require_env("CI_REPO_OWNER")
|
||||
repo = require_env("CI_REPO_NAME")
|
||||
pr = require_env("CI_COMMIT_PULL_REQUEST")
|
||||
base = f"{GITEA_URL}/api/v1/repos/{owner}/{repo}"
|
||||
|
||||
issue = api_request(token, "GET", f"{base}/issues/{pr}")
|
||||
labels_on_pr = issue.get("labels", [])
|
||||
if any(label.get("name") == LABEL_NAME for label in labels_on_pr):
|
||||
print(f"Label {LABEL_NAME!r} already present on PR #{pr}")
|
||||
return
|
||||
|
||||
repo_labels = api_request(token, "GET", f"{base}/labels")
|
||||
label_id = next(
|
||||
(label["id"] for label in repo_labels if label.get("name") == LABEL_NAME),
|
||||
None,
|
||||
)
|
||||
if label_id is None:
|
||||
created = api_request(
|
||||
token,
|
||||
"POST",
|
||||
f"{base}/labels",
|
||||
{
|
||||
"name": LABEL_NAME,
|
||||
"color": "0e8a16",
|
||||
"description": "Drep AI review completed by Woodpecker",
|
||||
},
|
||||
)
|
||||
label_id = created["id"]
|
||||
|
||||
api_request(token, "POST", f"{base}/issues/{pr}/labels", {"labels": [label_id]})
|
||||
print(f"Added label {LABEL_NAME!r} to PR #{pr}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
x
Reference in New Issue
Block a user