Skip to content

Commit f6f8e14

Browse files
author
Douglas
committed
Initial Commit
1 parent 6100797 commit f6f8e14

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,4 @@ cython_debug/
172172

173173
# PyPI configuration file
174174
.pypirc
175+
/config.json

main.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import hashlib
2+
import requests
3+
import json
4+
import traceback
5+
import os
6+
import sys
7+
import inspect
8+
9+
GITHUB_TOKEN = None
10+
11+
# Define the current version of the app
12+
APP_VERSION = "1.0.0a"
13+
14+
# Hardcoded repository name
15+
REPO_NAME = "RedNeckSnailSpit/IssueAutomationTest"
16+
17+
# Path to the config file
18+
CONFIG_FILE = "config.json"
19+
20+
def setup():
21+
"""
22+
Sets up the application by checking for or creating a valid config.json file.
23+
"""
24+
if os.path.exists(CONFIG_FILE):
25+
print("Config file already exists. Skipping setup.")
26+
return
27+
28+
print("Config file not found. Starting setup process.")
29+
print(
30+
"You need to provide a Personal Access Token (PAT) from GitHub to use this script.\n"
31+
"1. Go to https://github.com/settings/tokens\n"
32+
"2. Generate a new token with the following required access:\n"
33+
" - repo\n"
34+
"3. Copy the token and paste it below."
35+
)
36+
37+
pat = input("Enter your GitHub Personal Access Token (PAT): ").strip()
38+
39+
if not validate_token(pat):
40+
print("Exiting setup due to invalid or insecure token.")
41+
sys.exit(1)
42+
43+
# Save the token to config.json
44+
config_data = {"github_token": pat}
45+
with open(CONFIG_FILE, "w", encoding="utf-8") as config_file:
46+
json.dump(config_data, config_file, ensure_ascii=False)
47+
print("Setup complete. Your PAT has been saved securely to config.json.")
48+
49+
def validate_token(pat):
50+
"""
51+
Validates the GitHub PAT for required access scopes.
52+
"""
53+
url = "https://api.github.com/user"
54+
headers = {"Authorization": f"Bearer {pat}"}
55+
56+
response = requests.get(url, headers=headers)
57+
if response.status_code != 200:
58+
print("Error: Unable to validate token. Please check if it's valid.")
59+
return False
60+
61+
scopes = response.headers.get("x-oauth-scopes", "").split(", ")
62+
if "repo" not in scopes:
63+
print("Error: Token is missing the required 'repo' scope.")
64+
return False
65+
66+
print("Token validation successful.")
67+
return True
68+
69+
def load_config():
70+
"""
71+
Loads the configuration from config.json.
72+
"""
73+
if not os.path.exists(CONFIG_FILE):
74+
print("Config file not found. Please run the setup process.")
75+
sys.exit(1)
76+
77+
with open(CONFIG_FILE) as config_file:
78+
return json.load(config_file)
79+
80+
81+
def generate_exception_hash(traceback_details):
82+
"""
83+
Generates a unique hash for an exception based on its traceback details.
84+
"""
85+
return hashlib.md5(traceback_details.encode()).hexdigest()
86+
87+
def check_for_existing_issue(exception_hash):
88+
"""
89+
Checks if an issue with the same hash already exists in the GitHub repository.
90+
"""
91+
url = f"https://api.github.com/repos/{REPO_NAME}/issues"
92+
headers = {
93+
"Authorization": f"Bearer {GITHUB_TOKEN}",
94+
"Accept": "application/vnd.github.v3+json",
95+
}
96+
97+
response = requests.get(url, headers=headers)
98+
99+
if response.status_code == 200:
100+
issues = response.json()
101+
for issue in issues:
102+
# Look for the hash in the issue body
103+
if exception_hash in issue["body"]:
104+
print(f"Duplicate issue found: {issue['html_url']}")
105+
return True # Duplicate found
106+
return False # No duplicates found
107+
else:
108+
print(f"Failed to fetch issues: {response.status_code}")
109+
print(response.text)
110+
return False
111+
112+
def report_issue(exception_title, exception_body, traceback_details):
113+
"""
114+
Reports an issue to the specified GitHub repository.
115+
"""
116+
exception_hash = generate_exception_hash(traceback_details)
117+
118+
if check_for_existing_issue(exception_hash):
119+
print("Duplicate issue detected. Skipping issue creation.")
120+
return
121+
122+
url = f"https://api.github.com/repos/{REPO_NAME}/issues"
123+
headers = {
124+
"Authorization": f"Bearer {GITHUB_TOKEN}",
125+
"Accept": "application/vnd.github.v3+json",
126+
}
127+
payload = {
128+
"title": f"[{APP_VERSION}] {exception_title}",
129+
"body": (
130+
f"**Version:** {APP_VERSION}\n\n{exception_body}\n\n"
131+
f"**Exception Hash:** `{exception_hash}`\n\n"
132+
f"**Stack Trace:**\n```\n{traceback_details}\n```"
133+
),
134+
"labels": ["bug", "automatic", "Automatic Bug Report", f"version:{APP_VERSION}"]
135+
}
136+
137+
response = requests.post(url, json=payload, headers=headers)
138+
139+
if response.status_code == 201:
140+
print("Bug report successfully created on GitHub!")
141+
else:
142+
print(f"Failed to create bug report: {response.status_code}")
143+
print(response.text)
144+
145+
def simulate_and_report_exception():
146+
"""
147+
Simulates an exception and reports it to GitHub.
148+
"""
149+
try:
150+
# Simulating an error
151+
sample_list2 = [1, 2, 3]
152+
print(sample_list2[5]) # This will raise an IndexError
153+
except Exception as e:
154+
# Prepare exception details
155+
exception_title = f"{inspect.currentframe().f_code.co_name} - {type(e).__name__} - {str(e)}"
156+
exception_body = f"An exception occurred:\n\n- **Type:** {type(e).__name__}\n- **Message:** {str(e)}"
157+
traceback_details = "".join(traceback.format_exception(type(e), e, e.__traceback__))
158+
159+
# Call report_issue to create the GitHub issue
160+
report_issue(exception_title, exception_body, traceback_details)
161+
162+
# Run the test
163+
if __name__ == "__main__":
164+
setup()
165+
config = load_config()
166+
GITHUB_TOKEN = config.get("github_token")
167+
if GITHUB_TOKEN is None:
168+
print("GitHub token not found in config.json. Please run the setup process.")
169+
sys.exit(1)
170+
simulate_and_report_exception()

0 commit comments

Comments
 (0)