adowu commited on
Commit
faa1e36
·
verified ·
1 Parent(s): 20dc0d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +746 -59
app.py CHANGED
@@ -4,6 +4,7 @@ import os
4
  import requests
5
  import re
6
  from collections import Counter
 
7
 
8
  # Load token. Best practice is to use environment variables.
9
  GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
@@ -11,20 +12,65 @@ if not GITHUB_TOKEN: # Good practice to have this check.
11
  raise ValueError("GITHUB_TOKEN environment variable not set!")
12
  g = Github(GITHUB_TOKEN)
13
 
14
- # Project templates (well-structured).
15
  PROJECT_TEMPLATES = {
16
  "flask": {
 
 
 
 
 
 
 
 
17
  "files": {
18
  "app.py": """from flask import Flask
 
 
 
 
 
19
  app = Flask(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  @app.route('/')
21
  def hello():
22
  return "Hello, Flask!"
 
 
 
 
 
 
 
 
 
 
23
  if __name__ == '__main__':
 
 
 
 
 
 
24
  app.run(debug=True)""",
25
- "requirements.txt": "Flask",
26
- ".gitignore": "__pycache__/\n*.pyc\nvenv/\ninstance/"
27
- }
 
 
 
28
  },
29
  "react": {
30
  "files": {
@@ -95,7 +141,538 @@ code {
95
  }""",
96
  ".gitignore": "node_modules/\ndist/"
97
  }
98
- }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
 
101
  def get_file_content(owner, repo_name, path, branch="main"):
@@ -148,11 +725,12 @@ def github_tool(
148
  file_url: str = None,
149
  repo_url: str = None,
150
  template_name: str = None,
 
151
  ):
152
  """Manages GitHub repositories."""
153
  user = g.get_user()
154
 
155
- try: # Single try block for ALL actions (Solution 1)
156
  if action == "import_repository":
157
  if not all([owner, repo_name, vcs_url]):
158
  raise ValueError("Missing parameters: owner, repo_name, vcs_url")
@@ -168,10 +746,9 @@ def github_tool(
168
  }
169
  import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
170
  response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
171
- response.raise_for_status() # Handle potential HTTP errors.
172
  return "Repository import started."
173
 
174
-
175
  elif action == "create_repository":
176
  if not repo_name:
177
  raise ValueError("Missing parameter: repo_name")
@@ -187,23 +764,82 @@ def github_tool(
187
  )
188
  repo = user.create_repo(name=repo_name)
189
  template = PROJECT_TEMPLATES[template_name]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  for file_path, file_content in template["files"].items():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  repo.create_file(
192
- file_path,
193
- f"Create {file_path} from template {template_name}",
194
- file_content,
195
  branch="main",
196
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
198
 
199
- elif action == "create_file":
200
  if not all([repo_name, path, content, message]):
201
  raise ValueError("Missing parameters: repo_name, path, content, message")
202
  repo = user.get_repo(repo_name)
203
  repo.create_file(path, message, content, branch=branch)
204
  return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
205
 
206
- elif action == "get_file":
207
  if not all([repo_name, path]):
208
  raise ValueError("Missing parameters: repo_name, path")
209
  repo = user.get_repo(repo_name)
@@ -212,13 +848,13 @@ def github_tool(
212
  f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
213
  )
214
 
215
- elif action == "get_file_content_by_url":
216
  if not file_url:
217
  raise ValueError("Missing parameter: file_url")
218
- file_content = get_file_content(None, None, None, None) # Dummy call to avoid UnboundLocalError. get_file_content changed!
219
  return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
220
 
221
- elif action == "delete_file":
222
  if not all([repo_name, path]):
223
  raise ValueError("Missing parameters: repo_name, path")
224
  repo = user.get_repo(repo_name)
@@ -226,7 +862,7 @@ def github_tool(
226
  repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
227
  return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
228
 
229
- elif action == "update_file":
230
  if not all([repo_name, path, content, message]):
231
  raise ValueError("Missing parameters: repo_name, path, content, message")
232
  repo = user.get_repo(repo_name)
@@ -234,7 +870,7 @@ def github_tool(
234
  repo.update_file(path, message, content, file_contents.sha, branch=branch)
235
  return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
236
 
237
- elif action == "list_branches":
238
  if not repo_name:
239
  raise ValueError("Missing parameter: repo_name")
240
  repo = user.get_repo(repo_name)
@@ -242,7 +878,7 @@ def github_tool(
242
  branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
243
  return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
244
 
245
- elif action == "create_branch":
246
  if not all([repo_name, base, head]):
247
  raise ValueError("Missing parameters: repo_name, base, head")
248
  repo = user.get_repo(repo_name)
@@ -250,21 +886,21 @@ def github_tool(
250
  repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
251
  return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
252
 
253
- elif action == "delete_branch":
254
  if not all([repo_name, branch]):
255
  raise ValueError("Missing parameters: repo_name, branch")
256
  repo = user.get_repo(repo_name)
257
  repo.get_git_ref(f"heads/{branch}").delete()
258
  return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
259
 
260
- elif action == "create_pull_request":
261
  if not all([repo_name, title, body, base, head]):
262
  raise ValueError("Missing parameters: repo_name, title, body, base, head")
263
  repo = user.get_repo(repo_name)
264
  pr = repo.create_pull(title=title, body=body, base=base, head=head)
265
  return f"Pull request created! [Open Pull Request]({pr.html_url})"
266
 
267
- elif action == "list_open_pull_requests":
268
  if not repo_name:
269
  raise ValueError("Missing parameter: repo_name")
270
  repo = user.get_repo(repo_name)
@@ -274,14 +910,14 @@ def github_tool(
274
  prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
275
  return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
276
 
277
- elif action == "create_issue":
278
  if not all([repo_name, title, body]):
279
  raise ValueError("Missing parameters: repo_name, title, body")
280
  repo = user.get_repo(repo_name)
281
  issue = repo.create_issue(title=title, body=body)
282
  return f"Issue created! [Open Issue]({issue.html_url})"
283
 
284
- elif action == "list_issues":
285
  if not repo_name:
286
  raise ValueError("Missing parameter: repo_name")
287
  repo = user.get_repo(repo_name)
@@ -291,7 +927,7 @@ def github_tool(
291
  issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
292
  return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
293
 
294
- elif action == "add_label_to_issue":
295
  if not all([repo_name, issue_number, labels]):
296
  raise ValueError("Missing parameters: repo_name, issue_number, labels")
297
  repo = user.get_repo(repo_name)
@@ -302,7 +938,7 @@ def github_tool(
302
  f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
303
  )
304
 
305
- elif action == "close_issue":
306
  if not all([repo_name, issue_number]):
307
  raise ValueError("Missing parameters: repo_name, issue_number")
308
  repo = user.get_repo(repo_name)
@@ -310,7 +946,7 @@ def github_tool(
310
  issue.edit(state='closed')
311
  return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
312
 
313
- elif action == "add_comment_to_issue":
314
  if not all([repo_name, issue_number, message]):
315
  raise ValueError("Missing parameters: repo_name, issue_number, message")
316
  repo = user.get_repo(repo_name)
@@ -318,7 +954,7 @@ def github_tool(
318
  issue.create_comment(body=message)
319
  return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
320
 
321
- elif action == "create_release":
322
  if not all([repo_name, tag, name, message]):
323
  raise ValueError("Missing parameters: repo_name, tag, name, message")
324
  repo = user.get_repo(repo_name)
@@ -327,7 +963,7 @@ def github_tool(
327
  f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
328
  )
329
 
330
- elif action == "list_releases":
331
  if not repo_name:
332
  raise ValueError("Missing parameter: repo_name")
333
  repo = user.get_repo(repo_name)
@@ -337,14 +973,14 @@ def github_tool(
337
  releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
338
  return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
339
 
340
- elif action == "fork_repository":
341
  if not repo_name:
342
  raise ValueError("Missing parameter: repo_name")
343
  repo = g.get_repo(repo_name)
344
  fork = user.create_fork(repo)
345
  return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
346
 
347
- elif action == "list_forks":
348
  if not repo_name:
349
  raise ValueError("Missing parameter: repo_name")
350
  repo = g.get_repo(repo_name)
@@ -354,7 +990,7 @@ def github_tool(
354
  forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
355
  return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
356
 
357
- elif action == "list_files":
358
  if not all([owner, repo_name]):
359
  raise ValueError("Missing parameters: owner, repo_name")
360
  repo = g.get_repo(f"{owner}/{repo_name}")
@@ -364,7 +1000,7 @@ def github_tool(
364
  files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
365
  return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
366
 
367
- elif action == "get_repository_info":
368
  if not all([owner, repo_name]):
369
  raise ValueError("Missing parameters: owner, repo_name")
370
  repo = g.get_repo(f"{owner}/{repo_name}")
@@ -383,7 +1019,7 @@ def github_tool(
383
  info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
384
  return f"Repository info for **`{repo_name}`**:\n{info_md}"
385
 
386
- elif action == "get_file_content":
387
  if not all([owner, repo_name, path]):
388
  raise ValueError("Missing parameters: owner, repo_name, path")
389
  content_text = get_file_content(owner, repo_name, path, branch)
@@ -391,7 +1027,7 @@ def github_tool(
391
  f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
392
  )
393
 
394
- elif action == "analyze_repository_by_url":
395
  if not repo_url:
396
  raise ValueError("Missing parameter: repo_url")
397
  owner, repo_name = extract_repo_info(repo_url)
@@ -419,7 +1055,7 @@ def github_tool(
419
  ])
420
  return analysis_md
421
 
422
- elif action == "analyze_repository_content":
423
  if not all([owner, repo_name]):
424
  raise ValueError("Missing parameters: owner, repo_name")
425
  repo = g.get_repo(f"{owner}/{repo_name}")
@@ -454,7 +1090,7 @@ def github_tool(
454
  except requests.exceptions.RequestException as e:
455
  return f"**Connection Error:** {e}"
456
  except Exception as e:
457
- return f"**Unexpected Error:** {e}" # Catch all.
458
 
459
 
460
  with gr.Blocks() as demo:
@@ -466,6 +1102,11 @@ with gr.Blocks() as demo:
466
  "import_repository",
467
  "create_repository",
468
  "create_project_from_template",
 
 
 
 
 
469
  "create_file",
470
  "get_file",
471
  "get_file_content_by_url",
@@ -497,9 +1138,29 @@ with gr.Blocks() as demo:
497
  template_name = gr.Dropdown(
498
  choices=[""] + list(PROJECT_TEMPLATES.keys()), # Add "" as a choice
499
  label="Project Template",
500
- value="", # Set default value to "" (no selection)
501
  allow_custom_value=True, # Use allow_custom_value instead of allow_none
502
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  branch = gr.Textbox(label="Branch", value="main")
504
  path = gr.Textbox(label="File Path")
505
  content = gr.Code(label="File Content", lines=5, language='python') # Larger code box
@@ -517,32 +1178,58 @@ with gr.Blocks() as demo:
517
  file_url = gr.Textbox(label="File URL")
518
  repo_url = gr.Textbox(label="Repository URL")
519
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  run_button = gr.Button("Execute")
521
  output = gr.Markdown(label="Result") # Use Markdown for richer output
522
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  run_button.click(
524
  github_tool,
525
- inputs=[
526
- action,
527
- repo_name,
528
- branch,
529
- path,
530
- content,
531
- message,
532
- owner,
533
- vcs_url,
534
- title,
535
- body,
536
- base,
537
- head,
538
- issue_number,
539
- labels,
540
- tag,
541
- release_name,
542
- file_url,
543
- repo_url,
544
- template_name,
545
- ],
546
  outputs=output,
547
  api_name="github_tool"
548
  )
 
4
  import requests
5
  import re
6
  from collections import Counter
7
+ import jinja2 # Import Jinja2
8
 
9
  # Load token. Best practice is to use environment variables.
10
  GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
 
12
  raise ValueError("GITHUB_TOKEN environment variable not set!")
13
  g = Github(GITHUB_TOKEN)
14
 
15
+ # Project templates (parameterized with Jinja2) including shadcn.
16
  PROJECT_TEMPLATES = {
17
  "flask": {
18
+ "params": { # Define parameters for the template
19
+ "database_type": {
20
+ "type": "choice",
21
+ "default": "sqlite",
22
+ "choices": ["sqlite", "postgresql", "mysql"],
23
+ "description": "Type of database to configure for the Flask app."
24
+ }
25
+ },
26
  "files": {
27
  "app.py": """from flask import Flask
28
+ from flask_sqlalchemy import SQLAlchemy
29
+ import os
30
+
31
+ basedir = os.path.abspath(os.path.dirname(__file__))
32
+
33
  app = Flask(__name__)
34
+ app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or \\
35
+ '{{database_uri}}' # Placeholder for database URI
36
+ app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
37
+
38
+ db = SQLAlchemy(app)
39
+
40
+ class HelloWorld(db.Model):
41
+ id = db.Column(db.Integer, primary_key=True)
42
+ message = db.Column(db.String(128))
43
+
44
+ def __repr__(self):
45
+ return f'<HelloWorld {self.message}>'
46
+
47
  @app.route('/')
48
  def hello():
49
  return "Hello, Flask!"
50
+
51
+ @app.route('/db_test')
52
+ def db_test():
53
+ try:
54
+ HelloWorld.query.first() # Simple DB query to test connection
55
+ return "Database connection successful!"
56
+ except Exception as e:
57
+ return f"Database connection failed: {e}"
58
+
59
+
60
  if __name__ == '__main__':
61
+ with app.app_context(): # Create application context for DB operations
62
+ db.create_all()
63
+ if not HelloWorld.query.first(): # Initialize DB with a default entry if empty
64
+ default_hello = HelloWorld(message="Hello, Database!")
65
+ db.session.add(default_hello)
66
+ db.session.commit()
67
  app.run(debug=True)""",
68
+ "requirements.txt": """Flask
69
+ Flask-SQLAlchemy
70
+ {{sqlalchemy_dependency}} # Placeholder for SQLAlchemy dependency""", # Conditional dependency
71
+ ".gitignore": "__pycache__/\n*.pyc\nvenv/\ninstance/\n*.db"
72
+ },
73
+ "post_process": "install_dependencies" # Define a post-processing action
74
  },
75
  "react": {
76
  "files": {
 
141
  }""",
142
  ".gitignore": "node_modules/\ndist/"
143
  }
144
+ },
145
+ "django": {
146
+ "files": {
147
+ "manage.py": """#!/usr/bin/env python
148
+ import os
149
+ import sys
150
+
151
+ if __name__ == "__main__":
152
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
153
+ try:
154
+ from django.core.management import execute_from_command_line
155
+ except ImportError as exc:
156
+ raise ImportError(
157
+ "Couldn't import Django. Are you sure it is installed and "
158
+ "available on your PYTHONPATH environment variable? Did you "
159
+ "forget to activate a virtual environment?"
160
+ ) from exc
161
+ execute_from_command_line(sys.argv)""",
162
+ "myapp/settings.py": """import os
163
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
164
+ SECRET_KEY = 'your_secret_key_here'
165
+ DEBUG = True
166
+ ALLOWED_HOSTS = []
167
+ INSTALLED_APPS = [
168
+ 'django.contrib.admin',
169
+ 'django.contrib.auth',
170
+ 'django.contrib.contenttypes',
171
+ 'django.contrib.sessions',
172
+ 'django.contrib.messages',
173
+ 'django.contrib.staticfiles',
174
+ ]
175
+ MIDDLEWARE = [
176
+ 'django.middleware.security.SecurityMiddleware',
177
+ 'django.contrib.sessions.middleware.SessionMiddleware',
178
+ 'django.middleware.common.CommonMiddleware',
179
+ 'django.middleware.csrf.CsrfViewMiddleware',
180
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
181
+ 'django.contrib.messages.middleware.MessageMiddleware',
182
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
183
+ ]
184
+ ROOT_URLCONF = 'myapp.urls'
185
+ TEMPLATES = [
186
+ {
187
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
188
+ 'DIRS': [],
189
+ 'APP_DIRS': True,
190
+ 'OPTIONS': {
191
+ 'context_processors': [
192
+ 'django.template.context_processors.debug',
193
+ 'django.template.context_processors.request',
194
+ 'django.contrib.auth.context_processors.auth',
195
+ 'django.contrib.messages.context_processors.messages',
196
+ ],
197
+ },
198
+ },
199
+ ]
200
+ WSGI_APPLICATION = 'myapp.wsgi.application'
201
+ DATABASES = {
202
+ 'default': {
203
+ 'ENGINE': 'django.db.backends.sqlite3',
204
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
205
+ }
206
+ }
207
+ AUTH_PASSWORD_VALIDATORS = [
208
+ {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},
209
+ {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},
210
+ {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},
211
+ {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
212
+ ]
213
+ LANGUAGE_CODE = 'en-us'
214
+ TIME_ZONE = 'UTC'
215
+ USE_I18N = True
216
+ USE_L10N = True
217
+ USE_TZ = True
218
+ STATIC_URL = '/static/'
219
+ """,
220
+ "myapp/urls.py": """from django.contrib import admin
221
+ from django.urls import path
222
+ from django.http import HttpResponse
223
+
224
+ def home(request):
225
+ return HttpResponse("Hello, Django!")
226
+
227
+ urlpatterns = [
228
+ path('admin/', admin.site.urls),
229
+ path('', home, name='home'),
230
+ ]""",
231
+ "myapp/wsgi.py": """import os
232
+ from django.core.wsgi import get_wsgi_application
233
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
234
+ application = get_wsgi_application()""",
235
+ "requirements.txt": "Django",
236
+ ".gitignore": "__pycache__/\n*.pyc\nvenv/\ndb.sqlite3\n",
237
+ },
238
+ "rename_files": {"myapp": "{{repo_name_snake_case}}"} # Placeholder for repo name
239
+ },
240
+ "nodejs_express": {
241
+ "files": {
242
+ "server.js": """const express = require('express')
243
+ const app = express()
244
+ const port = 3000
245
+
246
+ app.get('/', (req, res) => {
247
+ res.send('Hello World from Express!')
248
+ })
249
+
250
+ app.listen(port, () => {
251
+ console.log(`Server listening on port ${port}`)
252
+ })""",
253
+ "package.json": """{
254
+ "name": "express-app",
255
+ "version": "1.0.0",
256
+ "description": "",
257
+ "main": "server.js",
258
+ "scripts": {
259
+ "start": "node server.js"
260
+ },
261
+ "dependencies": {
262
+ "express": "^4.17.1"
263
+ }
264
+ }""",
265
+ ".gitignore": "node_modules/\n"
266
+ }
267
+ },
268
+ "static_website": {
269
+ "files": {
270
+ "index.html": """<!DOCTYPE html>
271
+ <html>
272
+ <head>
273
+ <title>Simple Static Website</title>
274
+ </head>
275
+ <body>
276
+ <h1>Hello from Static Website!</h1>
277
+ <p>This is a basic HTML page.</p>
278
+ </body>
279
+ </html>""",
280
+ "style.css": """body {
281
+ font-family: sans-serif;
282
+ margin: 20px;
283
+ }""",
284
+ "script.js": """console.log("Hello from JavaScript!");""",
285
+ ".gitignore": ""
286
+ }
287
+ },
288
+ "python_script": {
289
+ "files": {
290
+ "main.py": """def main():
291
+ print("Hello from Python script!")
292
+
293
+ if __name__ == "__main__":
294
+ main()""",
295
+ "requirements.txt": "",
296
+ ".gitignore": "__pycache__/\n*.pyc\nvenv/\n"
297
+ }
298
+ },
299
+ "empty": {
300
+ "files": {
301
+ "README.md": "# {{repo_name}}", # Placeholder for repo name
302
+ ".gitignore": ""
303
+ },
304
+ "rename_files": {"README.md": "{{readme_filename}}"} # Placeholder for readme filename
305
+ },
306
+ "shadcn": {
307
+ "files": {
308
+ "package.json": """{
309
+ "name": "shadcn-react-app",
310
+ "private": true,
311
+ "version": "0.0.0",
312
+ "type": "module",
313
+ "scripts": {
314
+ "dev": "vite",
315
+ "build": "vite build",
316
+ "preview": "vite preview",
317
+ "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
318
+ "preview": "vite preview"
319
+ },
320
+ "dependencies": {
321
+ "@radix-ui/react-slot": "^1.0.2",
322
+ "class-variance-authority": "^0.7.0",
323
+ "clsx": "^2.1.0",
324
+ "lucide-react": "^0.303.0",
325
+ "react": "^18.2.0",
326
+ "react-dom": "^18.2.0",
327
+ "tailwind-merge": "^2.2.0",
328
+ "tailwindcss-animate": "^1.0.7"
329
+ },
330
+ "devDependencies": {
331
+ "@vitejs/plugin-react": "^4.2.1",
332
+ "autoprefixer": "^10.4.16",
333
+ "eslint": "^8.55.0",
334
+ "eslint-plugin-react": "^7.33.2",
335
+ "eslint-plugin-react-hooks": "^4.6.0",
336
+ "eslint-plugin-react-refresh": "^0.4.5",
337
+ "postcss": "^8.4.33",
338
+ "tailwindcss": "^3.4.1",
339
+ "vite": "^5.0.8"
340
+ }
341
+ }""",
342
+ "vite.config.js": """import { defineConfig } from 'vite'
343
+ import react from '@vitejs/plugin-react'
344
+
345
+ // https://vitejs.dev/config/
346
+ export default defineConfig({
347
+ plugins: [react()],
348
+ })""",
349
+ "index.html": """<!doctype html>
350
+ <html lang="en">
351
+ <head>
352
+ <meta charset="UTF-8" />
353
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
354
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
355
+ <title>Vite + React + Shadcn</title>
356
+ </head>
357
+ <body class="bg-background">
358
+ <div id="root"></div>
359
+ <script type="module" src="/src/main.jsx"></script>
360
+ </body>
361
+ </html>""",
362
+ "src/main.jsx": """import React from 'react'
363
+ import ReactDOM from 'react-dom/client'
364
+ import App from './App.jsx'
365
+ import './index.css'
366
+
367
+ ReactDOM.createRoot(document.getElementById('root')).render(
368
+ <React.StrictMode>
369
+ <App />
370
+ </React.StrictMode>,
371
+ )""",
372
+ "src/App.jsx": """import React from 'react'
373
+ import { Button } from "./components/ui/button"
374
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./components/ui/card"
375
+
376
+
377
+ function App() {
378
+ return (
379
+ <div className="container mx-auto py-10">
380
+ <h1 className="text-3xl font-bold text-center mb-5">
381
+ Witaj w aplikacji Shadcn UI!
382
+ </h1>
383
+
384
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
385
+ <Card>
386
+ <CardHeader>
387
+ <CardTitle>Karta 1</CardTitle>
388
+ <CardDescription>Prosta karta z Shadcn UI.</CardDescription>
389
+ </CardHeader>
390
+ <CardContent>
391
+ <p>Zawartość karty.</p>
392
+ <Button className="mt-4">Przycisk Akcji</Button>
393
+ </CardContent>
394
+ </Card>
395
+
396
+ <Card>
397
+ <CardHeader>
398
+ <CardTitle>Karta 2</CardTitle>
399
+ <CardDescription>Kolejna karta dla przykładu.</CardDescription>
400
+ </CardHeader>
401
+ <CardContent>
402
+ <p>Więcej zawartości.</p>
403
+ <Button variant="secondary" className="mt-4">Przycisk Wtórny</Button>
404
+ </CardContent>
405
+ </Card>
406
+
407
+ <Card className="lg:col-span-1 md:col-span-2">
408
+ <CardHeader>
409
+ <CardTitle>Dłuższa Karta</CardTitle>
410
+ <CardDescription>Karta zajmująca więcej miejsca.</CardDescription>
411
+ </CardHeader>
412
+ <CardContent>
413
+ <p>
414
+ Ta karta demonstruje jak karty mogą dostosowywać się do różnych
415
+ rozmiarów ekranów i układów. Shadcn UI i Tailwind CSS
416
+ dają dużą elastyczność w projektowaniu interfejsów.
417
+ </p>
418
+ <Button variant="destructive" className="mt-4">Przycisk Destrukcyjny</Button>
419
+ </CardContent>
420
+ </Card>
421
+ </div>
422
+ </div>
423
+ )
424
+ }
425
+
426
+ export default App""",
427
+ "src/index.css": """@tailwind base;
428
+ @tailwind components;
429
+ @tailwind utilities;
430
+
431
+ @layer base {
432
+ :root {
433
+ --background: 0 0% 100%;
434
+ --foreground: 222.2 84.9% 4.9%;
435
+
436
+ --card: 0 0% 100%;
437
+ --card-foreground: 222.2 84.9% 4.9%;
438
+
439
+ --popover: 0 0% 100%;
440
+ --popover-foreground: 222.2 84.9% 4.9%;
441
+
442
+ --primary: 221.2 83.2% 53.3%;
443
+ --primary-foreground: 210 40% 98%;
444
+
445
+ --secondary: 210 40% 96.1%;
446
+ --secondary-foreground: 222.2 47.4% 11.2%;
447
+
448
+ --muted: 210 40% 96.1%;
449
+ --muted-foreground: 215.4 16.3% 46.9%;
450
+
451
+ --accent: 210 40% 96.1%;
452
+ --accent-foreground: 222.2 47.4% 11.2%;
453
+
454
+ --destructive: 0 84.2% 60.2%;
455
+ --destructive-foreground: 210 40% 98%;
456
+
457
+ --border: 214.3 31.8% 91.4%;
458
+ --input: 214.3 31.8% 91.4%;
459
+ --ring: 221.2 83.2% 53.3%;
460
+
461
+ --radius: 0.5rem;
462
+ }
463
+
464
+ .dark {
465
+ --background: 222.2 84.9% 4.9%;
466
+ --foreground: 210 40% 98%;
467
+
468
+ --card: 222.2 84.9% 4.9%;
469
+ --card-foreground: 210 40% 98%;
470
+
471
+ --popover: 222.2 84.9% 4.9%;
472
+ --popover-foreground: 210 40% 98%;
473
+
474
+ --primary: 217.2 91.2% 59.8%;
475
+ --primary-foreground: 222.2 47.4% 11.2%;
476
+
477
+ --secondary: 217.2 32.6% 17.5%;
478
+ --secondary-foreground: 210 40% 98%;
479
+
480
+ --muted: 217.2 32.6% 17.5%;
481
+ --muted-foreground: 215 20.2% 65.1%;
482
+
483
+ --accent: 217.2 32.6% 17.5%;
484
+ --accent-foreground: 210 40% 98%;
485
+
486
+ --destructive: 0 62.8% 30.6%;
487
+ --destructive-foreground: 210 40% 98%;
488
+
489
+ --border: 217.2 32.6% 17.5%;
490
+ --input: 217.2 32.6% 17.5%;
491
+ --ring: 224.9 98.6% 67.3%;
492
+ }
493
+ }
494
+
495
+ @layer components {
496
+ .container {
497
+ @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
498
+ }
499
+ }
500
+ """,
501
+ "postcss.config.js": """module.exports = {
502
+ plugins: {
503
+ tailwindcss: {},
504
+ autoprefixer: {},
505
+ },
506
+ }""",
507
+ "tailwind.config.js": """/** @type {import('tailwindcss').Config} */
508
+ module.exports = {
509
+ darkMode: ["class"],
510
+ content: [
511
+ './pages/**/*.{js,jsx}',
512
+ './components/**/*.{js,jsx}',
513
+ './app/**/*.{js,jsx}',
514
+ './src/**/*.{js,jsx}',
515
+ ],
516
+ prefix: "",
517
+ theme: {
518
+ container: {
519
+ center: true,
520
+ padding: "2rem",
521
+ screens: {
522
+ "2xl": "1400px",
523
+ },
524
+ },
525
+ extend: {
526
+ colors: {
527
+ border: "hsl(var(--border))",
528
+ input: "hsl(var(--input))",
529
+ ring: "hsl(var(--ring))",
530
+ background: "hsl(var(--background))",
531
+ foreground: "hsl(var(--foreground))",
532
+ primary: {
533
+ DEFAULT: "hsl(var(--primary))",
534
+ foreground: "hsl(var(--primary-foreground))",
535
+ },
536
+ secondary: {
537
+ DEFAULT: "hsl(var(--secondary))",
538
+ foreground: "hsl(var(--secondary-foreground))",
539
+ },
540
+ destructive: {
541
+ DEFAULT: "hsl(var(--destructive))",
542
+ foreground: "hsl(var(--destructive-foreground))",
543
+ },
544
+ muted: {
545
+ DEFAULT: "hsl(var(--muted))",
546
+ foreground: "hsl(var(--muted-foreground))",
547
+ },
548
+ accent: {
549
+ DEFAULT: "hsl(var(--accent))",
550
+ foreground: "hsl(var(--accent-foreground))",
551
+ },
552
+ popover: {
553
+ DEFAULT: "hsl(var(--popover))",
554
+ foreground: "hsl(var(--popover-foreground))",
555
+ },
556
+ card: {
557
+ DEFAULT: "hsl(var(--card))",
558
+ foreground: "hsl(var(--card-foreground))",
559
+ },
560
+ },
561
+ borderRadius: {
562
+ lg: "var(--radius)",
563
+ md: "calc(var(--radius) - 2px)",
564
+ sm: "calc(var(--radius) - 4px)",
565
+ },
566
+ keyframes: {
567
+ "accordion-down": {
568
+ from: { height: "0" },
569
+ to: { height: "var(--radix-accordion-content-height)" },
570
+ },
571
+ "accordion-up": {
572
+ from: { height: "var(--radix-accordion-content-height)" },
573
+ },
574
+ },
575
+ animation: {
576
+ "accordion-down": "accordion-down 0.2s ease-out",
577
+ "accordion-up": "accordion-up 0.2s ease-out",
578
+ },
579
+ },
580
+ },
581
+ plugins: [require("tailwindcss-animate")],
582
+ }""",
583
+ "src/components/ui/button.jsx": """import * as React from "react"
584
+ import { cn } from "@/lib/utils"
585
+ import { Slot } from "@radix-ui/react-slot"
586
+ import { cva } from "class-variance-authority";
587
+
588
+ const buttonVariants = cva(
589
+ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
590
+ {
591
+ variants: {
592
+ variant: {
593
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
594
+ destructive:
595
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
596
+ outline:
597
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
598
+ secondary:
599
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
600
+ ghost: "hover:bg-accent hover:text-accent-foreground",
601
+ link: "underline-offset-4 hover:underline text-primary",
602
+ },
603
+ size: {
604
+ default: "h-10 px-4 py-2",
605
+ sm: "h-9 rounded-md px-3",
606
+ lg: "h-11 rounded-md px-8",
607
+ icon: "h-10 w-10",
608
+ },
609
+ },
610
+ defaultVariants: {
611
+ variant: "default",
612
+ size: "default",
613
+ },
614
+ }
615
+ )
616
+
617
+ const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
618
+ const Comp = asChild ? Slot : "button"
619
+ return (<Comp
620
+ className={cn(buttonVariants({ variant, size, className }))}
621
+ ref={ref} {...props} />)
622
+ })
623
+ Button.displayName = "Button"
624
+
625
+ export { Button, buttonVariants }""",
626
+ "src/components/ui/card.jsx": """import * as React from "react"
627
+ import { cn } from "@/lib/utils"
628
+
629
+ const Card = React.forwardRef(({ className, ...props }, ref) => (<div
630
+ className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
631
+ ref={ref}
632
+ {...props} />))
633
+ Card.displayName = "Card"
634
+
635
+ const CardHeader = React.forwardRef(({ className, ...props }, ref) => (<div
636
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
637
+ ref={ref}
638
+ {...props} />))
639
+ CardHeader.displayName = "CardHeader"
640
+
641
+ const CardTitle = React.forwardRef(({ className, ...props }, ref) => (<h3
642
+ className={cn("text-lg font-semibold leading-none tracking-tight", className)}
643
+ ref={ref}
644
+ {...props} />))
645
+ CardTitle.displayName = "CardTitle"
646
+
647
+ const CardDescription = React.forwardRef(({ className, ...props }, ref) => (<p
648
+ className={cn("text-sm text-muted-foreground", className)}
649
+ ref={ref}
650
+ {...props} />))
651
+ CardDescription.displayName = "CardDescription"
652
+
653
+ const CardContent = React.forwardRef(({ className, ...props }, ref) => (<div
654
+ className={cn("p-6 pt-0", className)}
655
+ ref={ref}
656
+ {...props} />))
657
+ CardContent.displayName = "CardContent"
658
+
659
+ const CardFooter = React.forwardRef(({ className, ...props }, ref) => (<div
660
+ className={cn("flex items-center p-6 pt-0", className)}
661
+ ref={ref}
662
+ {...props} />))
663
+ CardFooter.displayName = "CardFooter"
664
+
665
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }""",
666
+ "src/lib/utils.js": """import { clsx } from "clsx"
667
+ import { twMerge } from "tailwind-merge"
668
+
669
+ export function cn(...inputs) {
670
+ return twMerge(clsx(inputs))
671
+ }"""
672
+ },
673
+ "post_process": "shadcn_setup" # Now using a specific post_process action
674
+ },
675
+ }
676
 
677
 
678
  def get_file_content(owner, repo_name, path, branch="main"):
 
725
  file_url: str = None,
726
  repo_url: str = None,
727
  template_name: str = None,
728
+ template_params: dict = None # New parameter for template parameters
729
  ):
730
  """Manages GitHub repositories."""
731
  user = g.get_user()
732
 
733
+ try: # Single try block for ALL actions
734
  if action == "import_repository":
735
  if not all([owner, repo_name, vcs_url]):
736
  raise ValueError("Missing parameters: owner, repo_name, vcs_url")
 
746
  }
747
  import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
748
  response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
749
+ response.raise_for_status() # Handle potential HTTP errors.
750
  return "Repository import started."
751
 
 
752
  elif action == "create_repository":
753
  if not repo_name:
754
  raise ValueError("Missing parameter: repo_name")
 
764
  )
765
  repo = user.create_repo(name=repo_name)
766
  template = PROJECT_TEMPLATES[template_name]
767
+
768
+ # Prepare template parameters, use defaults if not provided
769
+ template_params_final = {}
770
+ if "params" in template:
771
+ for param_name, param_config in template["params"].items():
772
+ template_params_final[param_name] = template_params.get(param_name,
773
+ param_config.get("default")) if template_params else param_config.get(
774
+ "default")
775
+
776
+ # Handle file renaming and content templating
777
+ repo_name_snake_case = repo_name.replace("-", "_") # For django app names
778
+ readme_filename = "README.md" # Default readme name
779
+
780
+ env = jinja2.Environment() # Initialize Jinja2 environment
781
+
782
  for file_path, file_content in template["files"].items():
783
+ final_file_path = file_path
784
+ final_file_content = file_content
785
+
786
+ # Apply file renaming if defined in template
787
+ if "rename_files" in template:
788
+ for old_name, new_name_template in template["rename_files"].items():
789
+ if file_path == old_name:
790
+ final_file_path = new_name_template.replace("{{repo_name_snake_case}}",
791
+ repo_name_snake_case).replace("{{repo_name}}",
792
+ repo_name).replace(
793
+ "{{readme_filename}}", readme_filename)
794
+
795
+ # Render file content using Jinja2 template
796
+ template_render = env.from_string(final_file_content)
797
+ final_file_content = template_render.render(
798
+ repo_name=repo_name,
799
+ repo_name_snake_case=repo_name_snake_case,
800
+ readme_filename=readme_filename,
801
+ **template_params_final # Pass template parameters to Jinja2
802
+ )
803
+
804
  repo.create_file(
805
+ final_file_path,
806
+ f"Create {final_file_path} from template {template_name}",
807
+ final_file_content,
808
  branch="main",
809
  )
810
+
811
+ # Post-processing actions (example: install dependencies)
812
+ if "post_process" in template:
813
+ post_process_action = template["post_process"]
814
+ if post_process_action == "install_dependencies":
815
+ print(
816
+ f"Post-processing: install_dependencies for {repo_name} (Not fully implemented in this example).") # existing message
817
+ elif post_process_action == "shadcn_setup": # New post-process action
818
+ instructions = f"""
819
+ **Konfiguracja Shadcn UI wymaga dodatkowych kroków po stronie klienta!**
820
+
821
+ 1. **Sklonuj repozytorium:** `git clone https://github.com/{user.login}/{repo_name}.git`
822
+ 2. **Przejdź do katalogu projektu:** `cd {repo_name}`
823
+ 3. **Zainstaluj zależności:** `npm install` (lub `yarn install`, `pnpm install`)
824
+ 4. **Zainicjuj Shadcn UI:** `npx shadcn-ui@latest init`
825
+ 5. **Uruchom aplikację:** `npm run dev` (lub odpowiednia komenda dla Twojego menedżera pakietów)
826
+
827
+ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfigurowana i gotowa do rozwoju.
828
+ """
829
+ return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})\n\n{instructions}"
830
+ else:
831
+ print(f"Unknown post-process action: {post_process_action}") # Handle unknown actions
832
+
833
  return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
834
 
835
+ elif action == "create_file": # ... rest of actions - no changes needed in most of them ...
836
  if not all([repo_name, path, content, message]):
837
  raise ValueError("Missing parameters: repo_name, path, content, message")
838
  repo = user.get_repo(repo_name)
839
  repo.create_file(path, message, content, branch=branch)
840
  return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
841
 
842
+ elif action == "get_file": # ...
843
  if not all([repo_name, path]):
844
  raise ValueError("Missing parameters: repo_name, path")
845
  repo = user.get_repo(repo_name)
 
848
  f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
849
  )
850
 
851
+ elif action == "get_file_content_by_url": # ...
852
  if not file_url:
853
  raise ValueError("Missing parameter: file_url")
854
+ file_content = get_file_content(None, None, None, None) # Dummy call to avoid UnboundLocalError. get_file_content changed!
855
  return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
856
 
857
+ elif action == "delete_file": # ...
858
  if not all([repo_name, path]):
859
  raise ValueError("Missing parameters: repo_name, path")
860
  repo = user.get_repo(repo_name)
 
862
  repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
863
  return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
864
 
865
+ elif action == "update_file": # ...
866
  if not all([repo_name, path, content, message]):
867
  raise ValueError("Missing parameters: repo_name, path, content, message")
868
  repo = user.get_repo(repo_name)
 
870
  repo.update_file(path, message, content, file_contents.sha, branch=branch)
871
  return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
872
 
873
+ elif action == "list_branches": # ...
874
  if not repo_name:
875
  raise ValueError("Missing parameter: repo_name")
876
  repo = user.get_repo(repo_name)
 
878
  branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
879
  return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
880
 
881
+ elif action == "create_branch": # ...
882
  if not all([repo_name, base, head]):
883
  raise ValueError("Missing parameters: repo_name, base, head")
884
  repo = user.get_repo(repo_name)
 
886
  repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
887
  return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
888
 
889
+ elif action == "delete_branch": # ...
890
  if not all([repo_name, branch]):
891
  raise ValueError("Missing parameters: repo_name, branch")
892
  repo = user.get_repo(repo_name)
893
  repo.get_git_ref(f"heads/{branch}").delete()
894
  return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
895
 
896
+ elif action == "create_pull_request": # ...
897
  if not all([repo_name, title, body, base, head]):
898
  raise ValueError("Missing parameters: repo_name, title, body, base, head")
899
  repo = user.get_repo(repo_name)
900
  pr = repo.create_pull(title=title, body=body, base=base, head=head)
901
  return f"Pull request created! [Open Pull Request]({pr.html_url})"
902
 
903
+ elif action == "list_open_pull_requests": # ...
904
  if not repo_name:
905
  raise ValueError("Missing parameter: repo_name")
906
  repo = user.get_repo(repo_name)
 
910
  prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
911
  return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
912
 
913
+ elif action == "create_issue": # ...
914
  if not all([repo_name, title, body]):
915
  raise ValueError("Missing parameters: repo_name, title, body")
916
  repo = user.get_repo(repo_name)
917
  issue = repo.create_issue(title=title, body=body)
918
  return f"Issue created! [Open Issue]({issue.html_url})"
919
 
920
+ elif action == "list_issues": # ...
921
  if not repo_name:
922
  raise ValueError("Missing parameter: repo_name")
923
  repo = user.get_repo(repo_name)
 
927
  issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
928
  return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
929
 
930
+ elif action == "add_label_to_issue": # ...
931
  if not all([repo_name, issue_number, labels]):
932
  raise ValueError("Missing parameters: repo_name, issue_number, labels")
933
  repo = user.get_repo(repo_name)
 
938
  f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
939
  )
940
 
941
+ elif action == "close_issue": # ...
942
  if not all([repo_name, issue_number]):
943
  raise ValueError("Missing parameters: repo_name, issue_number")
944
  repo = user.get_repo(repo_name)
 
946
  issue.edit(state='closed')
947
  return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
948
 
949
+ elif action == "add_comment_to_issue": # ...
950
  if not all([repo_name, issue_number, message]):
951
  raise ValueError("Missing parameters: repo_name, issue_number, message")
952
  repo = user.get_repo(repo_name)
 
954
  issue.create_comment(body=message)
955
  return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
956
 
957
+ elif action == "create_release": # ...
958
  if not all([repo_name, tag, name, message]):
959
  raise ValueError("Missing parameters: repo_name, tag, name, message")
960
  repo = user.get_repo(repo_name)
 
963
  f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
964
  )
965
 
966
+ elif action == "list_releases": # ...
967
  if not repo_name:
968
  raise ValueError("Missing parameter: repo_name")
969
  repo = user.get_repo(repo_name)
 
973
  releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
974
  return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
975
 
976
+ elif action == "fork_repository": # ...
977
  if not repo_name:
978
  raise ValueError("Missing parameter: repo_name")
979
  repo = g.get_repo(repo_name)
980
  fork = user.create_fork(repo)
981
  return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
982
 
983
+ elif action == "list_forks": # ...
984
  if not repo_name:
985
  raise ValueError("Missing parameter: repo_name")
986
  repo = g.get_repo(repo_name)
 
990
  forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
991
  return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
992
 
993
+ elif action == "list_files": # ...
994
  if not all([owner, repo_name]):
995
  raise ValueError("Missing parameters: owner, repo_name")
996
  repo = g.get_repo(f"{owner}/{repo_name}")
 
1000
  files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
1001
  return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
1002
 
1003
+ elif action == "get_repository_info": # ...
1004
  if not all([owner, repo_name]):
1005
  raise ValueError("Missing parameters: owner, repo_name")
1006
  repo = g.get_repo(f"{owner}/{repo_name}")
 
1019
  info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
1020
  return f"Repository info for **`{repo_name}`**:\n{info_md}"
1021
 
1022
+ elif action == "get_file_content": # ...
1023
  if not all([owner, repo_name, path]):
1024
  raise ValueError("Missing parameters: owner, repo_name, path")
1025
  content_text = get_file_content(owner, repo_name, path, branch)
 
1027
  f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
1028
  )
1029
 
1030
+ elif action == "analyze_repository_by_url": # ...
1031
  if not repo_url:
1032
  raise ValueError("Missing parameter: repo_url")
1033
  owner, repo_name = extract_repo_info(repo_url)
 
1055
  ])
1056
  return analysis_md
1057
 
1058
+ elif action == "analyze_repository_content": # ...
1059
  if not all([owner, repo_name]):
1060
  raise ValueError("Missing parameters: owner, repo_name")
1061
  repo = g.get_repo(f"{owner}/{repo_name}")
 
1090
  except requests.exceptions.RequestException as e:
1091
  return f"**Connection Error:** {e}"
1092
  except Exception as e:
1093
+ return f"**Unexpected Error:** {e}" # Catch all.
1094
 
1095
 
1096
  with gr.Blocks() as demo:
 
1102
  "import_repository",
1103
  "create_repository",
1104
  "create_project_from_template",
1105
+ # Modular actions - to be added later in UI if needed
1106
+ # "create_repository_structure",
1107
+ # "add_dependencies",
1108
+ # "configure_database",
1109
+ # "add_authentication",
1110
  "create_file",
1111
  "get_file",
1112
  "get_file_content_by_url",
 
1138
  template_name = gr.Dropdown(
1139
  choices=[""] + list(PROJECT_TEMPLATES.keys()), # Add "" as a choice
1140
  label="Project Template",
1141
+ value="", # Set default value to "" (no selection)
1142
  allow_custom_value=True, # Use allow_custom_value instead of allow_none
1143
  )
1144
+ # Template parameters UI - dynamically generated based on template
1145
+ template_params_ui = {}
1146
+ with gr.Row(): # Display parameters in a row for better layout
1147
+ for template_key, template_config in PROJECT_TEMPLATES.items():
1148
+ if "params" in template_config:
1149
+ with gr.Column(visible=False, elem_classes=f"params_{template_key}") as params_section: # Hide initially
1150
+ for param_name, param_details in template_config["params"].items():
1151
+ if param_details["type"] == "choice":
1152
+ template_params_ui[param_name] = gr.Dropdown(
1153
+ choices=param_details["choices"],
1154
+ label=param_details["description"] or param_name,
1155
+ value=param_details["default"]
1156
+ )
1157
+ else: # Add other input types if needed (e.g., Textbox for string parameters)
1158
+ template_params_ui[param_name] = gr.Textbox(
1159
+ label=param_details["description"] or param_name,
1160
+ value=param_details["default"] if "default" in param_details else ""
1161
+ )
1162
+ template_params_ui[template_key] = params_section # Store the section itself for visibility control
1163
+
1164
  branch = gr.Textbox(label="Branch", value="main")
1165
  path = gr.Textbox(label="File Path")
1166
  content = gr.Code(label="File Content", lines=5, language='python') # Larger code box
 
1178
  file_url = gr.Textbox(label="File URL")
1179
  repo_url = gr.Textbox(label="Repository URL")
1180
 
1181
+ # Function to show/hide template parameters based on template selection
1182
+ def show_template_params(template_name):
1183
+ visibility_map = {key: gr.Column.update(visible=False) for key in PROJECT_TEMPLATES if
1184
+ "params" in PROJECT_TEMPLATES[key]} # Initially hide all
1185
+ if template_name and template_name in PROJECT_TEMPLATES and "params" in PROJECT_TEMPLATES[template_name]:
1186
+ visibility_map[template_name] = gr.Column.update(visible=True) # Show for selected template
1187
+ return [visibility_map.get(key, gr.Column.update(visible=False)) for key in PROJECT_TEMPLATES if
1188
+ "params" in PROJECT_TEMPLATES[key]] # Return list in consistent order
1189
+
1190
+ template_param_visibility_outputs = [template_params_ui[key] for key in PROJECT_TEMPLATES if
1191
+ "params" in PROJECT_TEMPLATES[key]] # Get list of output components for visibility
1192
+ template_name.change(
1193
+ show_template_params,
1194
+ inputs=[template_name],
1195
+ outputs=template_param_visibility_outputs
1196
+ )
1197
+
1198
  run_button = gr.Button("Execute")
1199
  output = gr.Markdown(label="Result") # Use Markdown for richer output
1200
 
1201
+ input_components = [
1202
+ action,
1203
+ repo_name,
1204
+ branch,
1205
+ path,
1206
+ content,
1207
+ message,
1208
+ owner,
1209
+ vcs_url,
1210
+ title,
1211
+ body,
1212
+ base,
1213
+ head,
1214
+ issue_number,
1215
+ labels,
1216
+ tag,
1217
+ release_name,
1218
+ file_url,
1219
+ repo_url,
1220
+ template_name,
1221
+ ]
1222
+
1223
+ # Add template parameters dynamically to input components
1224
+ for template_key in PROJECT_TEMPLATES:
1225
+ if "params" in PROJECT_TEMPLATES[template_key]:
1226
+ for param_name in template_params_ui: # Use keys from template_params_ui which are param names
1227
+ if param_name in PROJECT_TEMPLATES[template_key]["params"]: # Check if parameter belongs to template
1228
+ input_components.append(template_params_ui[param_name]) # Append parameter component
1229
+
1230
  run_button.click(
1231
  github_tool,
1232
+ inputs=input_components, # Use dynamically built input list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1233
  outputs=output,
1234
  api_name="github_tool"
1235
  )