@@ -1266,64 +1266,172 @@ def create_github_issue(submission: schemas_submission.SubmissionMetadataSchema,
1266
1266
# If the settings for issue creation weren't supplied return, no need to do anything further
1267
1267
if gh_url is None or token is None :
1268
1268
return None
1269
-
1270
- # Gathering the fields we want to display in the issue
1269
+
1271
1270
headers = {"Authorization" : f"Bearer { token } " , "Content-Type" : "text/plain; charset=utf-8" }
1272
- study_form = submission .metadata_submission .studyForm
1273
- multiomics_form = submission .metadata_submission .multiOmicsForm
1274
- pi_name = study_form .piName
1275
- pi_orcid = study_form .piOrcid
1276
- data_generated = "Yes" if multiomics_form .dataGenerated else "No"
1277
- omics_processing_types = ", " .join (multiomics_form .omicsProcessingTypes )
1278
- sample_types = ", " .join (submission .metadata_submission .templates )
1279
- num_samples = submission .sample_count
1280
-
1281
- # some variable data to supply depending on if data has been generated or not
1282
- id_dict = {
1283
- "NCBI ID: " : study_form .NCBIBioProjectId ,
1284
- "GOLD ID: " : study_form .GOLDStudyId ,
1285
- "JGI ID: " : multiomics_form .JGIStudyId ,
1286
- "EMSL ID: " : multiomics_form .studyNumber ,
1287
- "Alternative IDs: " : ", " .join (study_form .alternativeNames ),
1288
- }
1289
- valid_ids = []
1290
- for key , value in id_dict .items ():
1291
- if str (value ) != "" :
1292
- valid_ids .append (key + value )
1293
-
1294
- # assemble the body of the API request
1295
- body_lis = [
1296
- f"Issue created from host: { settings .host } " ,
1297
- f"Submitter: { user .name } , { user .orcid } " ,
1298
- f"Submission ID: { submission .id } " ,
1299
- f"Has data been generated: { data_generated } " ,
1300
- f"PI name: { pi_name } " ,
1301
- f"PI orcid: { pi_orcid } " ,
1302
- f"Status: { SubmissionStatusEnum .SubmittedPendingReview .text } " ,
1303
- f"Data types: { omics_processing_types } " ,
1304
- f"Sample type: { sample_types } " ,
1305
- f"Number of samples: { num_samples } " ,
1306
- ] + valid_ids
1307
- body_string = " \n " .join (body_lis )
1308
- payload_dict = {
1309
- "title" : f"NMDC Submission: { submission .id } " ,
1310
- "body" : body_string ,
1311
- "assignees" : [assignee ],
1312
- }
1313
1271
1314
- payload = json .dumps (payload_dict )
1315
-
1316
- # make request and log an error or success depending on reply
1317
- res = requests .post (url = gh_url , data = payload , headers = headers )
1318
- if res .status_code != 201 :
1319
- logging .error (f"Github issue creation failed with code { res .status_code } " )
1320
- logging .error (res .reason )
1272
+ # Check for existing issues first
1273
+ existing_issue = check_existing_github_issue (submission .id , headers , gh_url , user )
1274
+ if existing_issue :
1275
+ logging .info (f"GitHub issue already exists for submission { submission .id } : { existing_issue ['html_url' ]} " )
1276
+ return existing_issue
1277
+
1321
1278
else :
1322
- logging .info (f"Github issue creation successful with code { res .status_code } " )
1323
- logging .info (res .reason )
1324
1279
1325
- return res
1280
+ # Gathering the fields we want to display in the issue
1281
+ study_form = submission .metadata_submission .studyForm
1282
+ multiomics_form = submission .metadata_submission .multiOmicsForm
1283
+ pi_name = study_form .piName
1284
+ pi_orcid = study_form .piOrcid
1285
+ data_generated = "Yes" if multiomics_form .dataGenerated else "No"
1286
+ omics_processing_types = ", " .join (multiomics_form .omicsProcessingTypes )
1287
+ sample_types = ", " .join (submission .metadata_submission .templates )
1288
+ num_samples = submission .sample_count
1289
+
1290
+ # some variable data to supply depending on if data has been generated or not
1291
+ id_dict = {
1292
+ "NCBI ID: " : study_form .NCBIBioProjectId ,
1293
+ "GOLD ID: " : study_form .GOLDStudyId ,
1294
+ "JGI ID: " : multiomics_form .JGIStudyId ,
1295
+ "EMSL ID: " : multiomics_form .studyNumber ,
1296
+ "Alternative IDs: " : ", " .join (study_form .alternativeNames ),
1297
+ }
1298
+ valid_ids = []
1299
+ for key , value in id_dict .items ():
1300
+ if str (value ) != "" :
1301
+ valid_ids .append (key + value )
1302
+
1303
+ # assemble the body of the API request
1304
+ body_lis = [
1305
+ f"Issue created from host: { settings .host } " ,
1306
+ f"Submitter: { user .name } , { user .orcid } " ,
1307
+ f"Submission ID: { submission .id } " ,
1308
+ f"Has data been generated: { data_generated } " ,
1309
+ f"PI name: { pi_name } " ,
1310
+ f"PI orcid: { pi_orcid } " ,
1311
+ f"Status: { SubmissionStatusEnum .SubmittedPendingReview .text } " ,
1312
+ f"Data types: { omics_processing_types } " ,
1313
+ f"Sample type: { sample_types } " ,
1314
+ f"Number of samples: { num_samples } " ,
1315
+ ] + valid_ids
1316
+ body_string = " \n " .join (body_lis )
1317
+ payload_dict = {
1318
+ "title" : f"NMDC Submission: { submission .id } " ,
1319
+ "body" : body_string ,
1320
+ "assignees" : [assignee ],
1321
+ }
1322
+
1323
+ payload = json .dumps (payload_dict )
1324
+
1325
+ # make request and log an error or success depending on reply
1326
+ res = requests .post (url = gh_url , data = payload , headers = headers )
1327
+ if res .status_code != 201 :
1328
+ logging .error (f"Github issue creation failed with code { res .status_code } " )
1329
+ logging .error (res .reason )
1330
+ else :
1331
+ logging .info (f"Github issue creation successful with code { res .status_code } " )
1332
+ logging .info (res .reason )
1326
1333
1334
+ return res
1335
+
1336
+ def update_github_issue_for_resubmission (existing_issue , user , headers ):
1337
+ """
1338
+ Update an existing GitHub issue to note that the submission was resubmitted.
1339
+ Adds a comment and optionally reopens the issue if it was closed.
1340
+ """
1341
+ try :
1342
+ issue_number = existing_issue .get ("number" )
1343
+ issue_url = existing_issue .get ("url" ) # API URL for the issue
1344
+
1345
+ if not issue_number or not issue_url :
1346
+ logging .error ("Could not find issue number or URL for existing GitHub issue" )
1347
+ return existing_issue
1348
+
1349
+ # Create a comment noting the resubmission
1350
+ from datetime import datetime
1351
+ timestamp = datetime .utcnow ().strftime ("%Y-%m-%d %H:%M:%S UTC" )
1352
+
1353
+ comment_body = f"""
1354
+ ## 🔄 Submission Resubmitted
1355
+
1356
+ **Resubmitted by:** { user .name } ({ user .orcid } )
1357
+ **Timestamp:** { timestamp }
1358
+ **Status:** { SubmissionStatusEnum .SubmittedPendingReview .text }
1359
+
1360
+ The submission has been updated and resubmitted for review.
1361
+ """ .strip ()
1362
+
1363
+ # Add comment to the issue
1364
+ comment_url = f"{ issue_url } /comments"
1365
+ comment_payload = {"body" : comment_body }
1366
+
1367
+ comment_response = requests .post (
1368
+ comment_url ,
1369
+ headers = headers ,
1370
+ data = json .dumps (comment_payload )
1371
+ )
1372
+
1373
+ if comment_response .status_code == 201 :
1374
+ logging .info (f"Successfully added resubmission comment to GitHub issue #{ issue_number } " )
1375
+ else :
1376
+ logging .error (f"Failed to add comment to GitHub issue: { comment_response .status_code } " )
1377
+
1378
+ # If the issue is closed, reopen it
1379
+ if existing_issue .get ("state" ) == "closed" :
1380
+ reopen_payload = {
1381
+ "state" : "open" ,
1382
+ "state_reason" : "reopened"
1383
+ }
1384
+
1385
+ reopen_response = requests .patch (
1386
+ issue_url ,
1387
+ headers = headers ,
1388
+ data = json .dumps (reopen_payload )
1389
+ )
1390
+
1391
+ if reopen_response .status_code == 200 :
1392
+ logging .info (f"Successfully reopened GitHub issue #{ issue_number } " )
1393
+ else :
1394
+ logging .error (f"Failed to reopen GitHub issue: { reopen_response .status_code } " )
1395
+
1396
+ return existing_issue
1397
+
1398
+ except Exception as e :
1399
+ logging .error (f"Error updating GitHub issue for resubmission: { str (e )} " )
1400
+ return existing_issue
1401
+
1402
+ def check_existing_github_issue (submission_id : str , headers : dict , gh_base_url :str , user ):
1403
+ """
1404
+ Check if a GitHub issue already exists for the given submission ID using GitHub's search API.
1405
+ """
1406
+ try :
1407
+ repo_url = gh_base_url .replace ('/issues' , '' )
1408
+ search_url = f"{ repo_url } /issues"
1409
+ expected_title = f"NMDC Submission: { submission_id } "
1410
+ params = {
1411
+ "state" : "all" ,
1412
+ "per_page" : 100 ,
1413
+ }
1414
+ response = requests .get (search_url , headers = headers , params = params )
1415
+
1416
+ if response .status_code == 200 :
1417
+ issues = response .json ()
1418
+
1419
+ # Look for an issue with matching title
1420
+ for issue in issues :
1421
+ if issue .get ("title" ) == expected_title :
1422
+ logging .info (f"Found existing GitHub issue for submission { submission_id } " )
1423
+ updated_issue = update_github_issue_for_resubmission (issue , user , headers )
1424
+ return updated_issue
1425
+ else :
1426
+ logging .info (f"No existing GitHub issue found for submission { submission_id } " )
1427
+ return None
1428
+ else :
1429
+ logging .warning (f"Failed to search GitHub issues: { response .status_code } " )
1430
+ return None
1431
+
1432
+ except Exception as e :
1433
+ logging .error (f"Error searching GitHub issues: { str (e )} " )
1434
+ return None
1327
1435
1328
1436
@router .delete (
1329
1437
"/metadata_submission/{id}" ,
0 commit comments