mirror of
https://github.com/block/goose.git
synced 2026-06-02 06:19:33 +02:00
[recipe cookbook] Update url build (#4427)
This commit is contained in:
+28
-74
@@ -20,29 +20,19 @@ def fetch_pr_body(pr_url, github_token):
|
||||
return pr_resp.json()
|
||||
|
||||
def extract_email_from_text(text):
|
||||
"""Extract email from text using various patterns"""
|
||||
# Try PR template format: "**Email**: email@example.com"
|
||||
email_match = re.search(r"\*\*Email\*\*:\s*([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})", text)
|
||||
if email_match:
|
||||
return email_match.group(1)
|
||||
|
||||
# Try other common email patterns
|
||||
email_match = re.search(r"[Ee]mail:\s*([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})", text)
|
||||
if email_match:
|
||||
return email_match.group(1)
|
||||
|
||||
# Try general email pattern
|
||||
email_match = re.search(r"\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})\b", text)
|
||||
if email_match:
|
||||
return email_match.group(1)
|
||||
|
||||
return None
|
||||
|
||||
def fetch_pr_comments(pr_url, github_token):
|
||||
"""Fetch all comments on the PR"""
|
||||
# Convert PR URL to comments URL
|
||||
comments_url = pr_url.replace("/pulls/", "/issues/") + "/comments"
|
||||
|
||||
try:
|
||||
comments_resp = requests.get(
|
||||
comments_url,
|
||||
@@ -55,9 +45,7 @@ def fetch_pr_comments(pr_url, github_token):
|
||||
return []
|
||||
|
||||
def validate_email_address(email):
|
||||
"""Validate email address format and deliverability"""
|
||||
try:
|
||||
# Validate and get normalized email
|
||||
valid_email = email_validator.validate_email(email)
|
||||
normalized_email = valid_email.email
|
||||
print(f"✅ Email validation passed: {normalized_email}")
|
||||
@@ -67,10 +55,7 @@ def validate_email_address(email):
|
||||
return None
|
||||
|
||||
def extract_email(pr_body, pr_url, github_token):
|
||||
"""Extract and validate email from PR body and comments"""
|
||||
print("🔍 Searching for email in PR body...")
|
||||
|
||||
# First check PR body
|
||||
email = extract_email_from_text(pr_body)
|
||||
if email:
|
||||
print(f"📧 Found email in PR body: {email}")
|
||||
@@ -79,10 +64,8 @@ def extract_email(pr_body, pr_url, github_token):
|
||||
return validated_email
|
||||
else:
|
||||
print("⚠️ Email in PR body is invalid, checking comments...")
|
||||
|
||||
|
||||
print("🔍 No valid email found in PR body, checking comments...")
|
||||
|
||||
# Check PR comments
|
||||
comments = fetch_pr_comments(pr_url, github_token)
|
||||
for comment in comments:
|
||||
comment_body = comment.get("body", "")
|
||||
@@ -94,10 +77,9 @@ def extract_email(pr_body, pr_url, github_token):
|
||||
return validated_email
|
||||
else:
|
||||
print("⚠️ Email in comment is invalid, continuing search...")
|
||||
|
||||
# No valid email found anywhere
|
||||
|
||||
print("❌ No valid email found in PR body or comments. Skipping key issuance.")
|
||||
exit(0)
|
||||
exit(2)
|
||||
|
||||
def provision_api_key(provisioning_api_key):
|
||||
print("🔐 Creating OpenRouter key...")
|
||||
@@ -118,11 +100,14 @@ def provision_api_key(provisioning_api_key):
|
||||
except requests.exceptions.RequestException as e:
|
||||
print("❌ Failed to provision API key:", str(e))
|
||||
raise
|
||||
return key_resp.json()["key"]
|
||||
key = key_resp.json().get("key")
|
||||
if not key:
|
||||
print("❌ API response did not include a key.")
|
||||
exit(2)
|
||||
return key
|
||||
|
||||
def send_email(email, api_key, sendgrid_api_key):
|
||||
print("📤 Sending email via SendGrid...")
|
||||
|
||||
try:
|
||||
sg = SendGridAPIClient(sendgrid_api_key)
|
||||
from_email = "Goose Team <goose@opensource.block.xyz>"
|
||||
@@ -139,43 +124,17 @@ def send_email(email, api_key, sendgrid_api_key):
|
||||
subject=subject,
|
||||
html_content=html_content
|
||||
)
|
||||
|
||||
response = sg.send(message)
|
||||
print(f"✅ Email sent successfully! Status code: {response.status_code}")
|
||||
|
||||
# Check for potential issues even on "success"
|
||||
if response.status_code >= 300:
|
||||
print(f"⚠️ Warning: Unexpected status code {response.status_code}")
|
||||
print(f"Response body: {response.body}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
except HTTPError as e:
|
||||
# Specific SendGrid HTTP errors
|
||||
status_code = e.status_code
|
||||
error_body = e.body
|
||||
|
||||
if status_code == 401:
|
||||
print("❌ SendGrid authentication failed - invalid API key")
|
||||
elif status_code == 403:
|
||||
print("❌ SendGrid authorization failed - API key lacks permissions")
|
||||
elif status_code == 429:
|
||||
print("❌ SendGrid rate limit exceeded - too many requests")
|
||||
elif status_code == 400:
|
||||
print(f"❌ SendGrid bad request - invalid email data: {error_body}")
|
||||
elif status_code >= 500:
|
||||
print(f"❌ SendGrid server error ({status_code}) - try again later")
|
||||
else:
|
||||
print(f"❌ SendGrid HTTP error {status_code}: {error_body}")
|
||||
|
||||
print(f"Full error details: {e}")
|
||||
print(f"❌ SendGrid HTTP error {e.status_code}: {e.body}")
|
||||
return False
|
||||
|
||||
except ValueError as e:
|
||||
print(f"❌ Invalid email format or API key: {e}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Unexpected error sending email: {type(e).__name__}: {e}")
|
||||
return False
|
||||
@@ -201,7 +160,13 @@ def comment_on_pr(github_token, repo_full_name, pr_number, email):
|
||||
raise
|
||||
|
||||
def main():
|
||||
# Load environment variables
|
||||
# ✅ Environment variable validation
|
||||
required_envs = ["GITHUB_TOKEN", "GITHUB_API_URL", "PROVISIONING_API_KEY", "EMAIL_API_KEY"]
|
||||
missing = [env for env in required_envs if env not in os.environ]
|
||||
if missing:
|
||||
print(f"❌ Missing environment variables: {', '.join(missing)}")
|
||||
exit(2)
|
||||
|
||||
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
|
||||
PR_URL = os.environ["GITHUB_API_URL"]
|
||||
PROVISIONING_API_KEY = os.environ["PROVISIONING_API_KEY"]
|
||||
@@ -209,35 +174,19 @@ def main():
|
||||
|
||||
pr_data = fetch_pr_body(PR_URL, GITHUB_TOKEN)
|
||||
pr_body = pr_data.get("body", "")
|
||||
|
||||
# Handle cases where pr_data might be missing expected fields
|
||||
pr_number = pr_data.get("number")
|
||||
|
||||
if not pr_number:
|
||||
print("❌ Unable to get PR number from GitHub API response")
|
||||
print(f"Available keys in response: {list(pr_data.keys())}")
|
||||
# Try to extract number from URL if available
|
||||
if "html_url" in pr_data:
|
||||
import re
|
||||
match = re.search(r'/pull/(\d+)', pr_data["html_url"])
|
||||
if match:
|
||||
pr_number = int(match.group(1))
|
||||
print(f"✅ Extracted PR number from URL: {pr_number}")
|
||||
else:
|
||||
print("❌ Could not extract PR number from URL either")
|
||||
exit(1)
|
||||
else:
|
||||
print("❌ No html_url available to extract PR number")
|
||||
exit(1)
|
||||
|
||||
# Get repo info
|
||||
exit(2)
|
||||
|
||||
if "base" in pr_data and "repo" in pr_data["base"]:
|
||||
repo_full_name = pr_data["base"]["repo"]["full_name"]
|
||||
elif "repository" in pr_data:
|
||||
repo_full_name = pr_data["repository"]["full_name"]
|
||||
else:
|
||||
print("❌ Unable to get repository name from GitHub API response")
|
||||
print(f"Available keys in response: {list(pr_data.keys())}")
|
||||
exit(1)
|
||||
exit(2)
|
||||
|
||||
email = extract_email(pr_body, PR_URL, GITHUB_TOKEN)
|
||||
print(f"📬 Found email: {email}")
|
||||
@@ -246,10 +195,15 @@ def main():
|
||||
api_key = provision_api_key(PROVISIONING_API_KEY)
|
||||
print("✅ API key generated!")
|
||||
|
||||
if send_email(email, api_key, SENDGRID_API_KEY):
|
||||
comment_on_pr(GITHUB_TOKEN, repo_full_name, pr_number, email)
|
||||
if not send_email(email, api_key, SENDGRID_API_KEY):
|
||||
print("❌ Email failed to send. Exiting without PR comment.")
|
||||
exit(2)
|
||||
|
||||
comment_on_pr(GITHUB_TOKEN, repo_full_name, pr_number, email)
|
||||
|
||||
except Exception as err:
|
||||
print(f"❌ An error occurred: {err}")
|
||||
exit(2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -24,9 +24,11 @@ jobs:
|
||||
- name: Install dependencies and run email script
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_URL: ${{ github.event.pull_request.url }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
REPO_NAME: ${{ github.repository }}
|
||||
PROVISIONING_API_KEY: ${{ secrets.PROVISIONING_API_KEY }}
|
||||
EMAIL_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
|
||||
run: |
|
||||
pip install requests sendgrid email-validator
|
||||
python .github/scripts/send_key.py
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
version: 1.0.0
|
||||
title: Test Recipe
|
||||
author:
|
||||
contact: EbonyLouis
|
||||
description: Analyzes code files for syntax and layout issues using available linting tools
|
||||
instructions: You are a code quality expert that helps identify syntax and layout issues in code files
|
||||
activities:
|
||||
- Detect file type and programming language
|
||||
- Check for available linting tools in the project
|
||||
- Run appropriate linters for syntax and layout checking
|
||||
- Provide recommendations if no linters are found
|
||||
parameters:
|
||||
- key: file_path
|
||||
input_type: string
|
||||
requirement: required
|
||||
description: Path to the file you want to lint
|
||||
extensions:
|
||||
- type: builtin
|
||||
name: developer
|
||||
display_name: Developer
|
||||
timeout: 300
|
||||
bundled: true
|
||||
prompt: |
|
||||
I need you to lint the file at {{ file_path }} for syntax and layout issues only. Do not modify the file - just report any problems you find.
|
||||
Here's what to do step by step:
|
||||
1. **Verify the file exists and determine its type:**
|
||||
- Check if {{ file_path }} exists
|
||||
- Examine the file extension and content to determine the programming language/file type
|
||||
- Focus on: Python (.py), JavaScript (.js, .jsx, .ts, .tsx), YAML (.yaml, .yml), HTML (.html, .htm), and CSS (.css)
|
||||
2. **Check for available linting tools in the project:**
|
||||
- Look for common linting tools and configurations in the current project:
|
||||
- Python: flake8, pylint, black, ruff, pycodestyle, autopep8
|
||||
- JavaScript/TypeScript: eslint, prettier, jshint, tslint
|
||||
- YAML: yamllint, yq
|
||||
- HTML: htmlhint, tidy
|
||||
- CSS: stylelint, csslint
|
||||
- Check for configuration files like .eslintrc, .flake8, pyproject.toml, .yamllint, etc.
|
||||
- Look in package.json, requirements.txt, or other dependency files
|
||||
3. **Run appropriate linting tools:**
|
||||
- If linting tools are found, run them only on the specified file
|
||||
- Use syntax-only or layout-only flags where available (e.g., `flake8 --select=E,W` for Python)
|
||||
- Capture and report the output clearly
|
||||
4. **If no linters are found, provide recommendations:**
|
||||
- For Python files: Suggest flake8, black, or ruff
|
||||
- For JavaScript/TypeScript: Suggest ESLint and Prettier
|
||||
- For YAML: Suggest yamllint
|
||||
- For HTML: Suggest htmlhint or W3C validator
|
||||
- For CSS: Suggest stylelint
|
||||
- Provide installation commands and basic usage examples
|
||||
5. **Report results:**
|
||||
- Clearly summarize any syntax or layout issues found
|
||||
- If no issues are found, confirm the file appears to be clean
|
||||
- If linting tools weren't available, explain what you checked manually and provide tool recommendations
|
||||
Remember:
|
||||
- Only check for syntax and layout issues, don't suggest code changes
|
||||
- Do not change the file on behalf of the user
|
||||
- Use tools that are already available in the project when possible
|
||||
- Be helpful by suggesting appropriate tools if none are found
|
||||
- Focus on the file types specified: Python, JavaScript, YAML, HTML, and CSS
|
||||
Reference in New Issue
Block a user