5656ERROR_MISSING_EXAMPLE_FOLDER = "Missing examples folder"
5757ERROR_EXAMPLE_MISSING_SENSORNAME = "Example file(s) missing sensor/library name"
5858ERROR_MISSING_EXAMPLE_SIMPLETEST = "Missing simpletest example."
59+ ERROR_MISSING_STANDARD_LABELS = "Missing one or more standard issue labels (bug, documentation, enhancement, good first issue)."
5960ERROR_MISSING_LIBRARIANS = "CircuitPythonLibrarians team missing or does not have write access"
6061ERROR_MISSING_LICENSE = "Missing license."
6162ERROR_MISSING_LINT = "Missing lint config"
133134 "Adafruit_CircuitPython_miniQR" ,
134135]
135136
137+ STD_REPO_LABELS = ("bug" , "documentation" , "enhancement" , "good first issue" )
138+
136139# Cache CircuitPython's subprojects on ReadTheDocs so its not fetched every repo check.
137140rtd_subprojects = None
138141
@@ -439,14 +442,24 @@ def validate_contents(self, repo):
439442 return []
440443
441444 content_list = github .get ("/repos/" + repo ["full_name" ] + "/contents/" )
442- # Empty repos return an object with a "message" that the repo is empty.
443- if not content_list .ok or "message" in content_list .json ():
444- if not self .validate_contents_quiet :
445- return [ERROR_UNABLE_PULL_REPO_CONTENTS ]
446- return []
445+ empty_repo = False
446+ if not content_list .ok :
447+ # Empty repos return:
448+ # - a 404 status code
449+ # - a "message" that the repo is empty.
450+ if "message" in content_list .json ():
451+ if "empty" in content_list .json ()["message" ]:
452+ empty_repo = True
453+ if not empty_repo :
454+ if not self .validate_contents_quiet :
455+ return [ERROR_UNABLE_PULL_REPO_CONTENTS ]
456+ return []
447457
448458 content_list = content_list .json ()
449- files = [x ["name" ] for x in content_list ]
459+ files = []
460+ # an empty repo will return a 'message'
461+ if not empty_repo :
462+ files = [x ["name" ] for x in content_list ]
450463
451464 # ignore new/in-work repos, which should have less than 8 files:
452465 # ___.py or folder, CoC, .travis.yml, .readthedocs.yml, docs/,
@@ -834,10 +847,17 @@ def gather_insights(self, repo, insights, since):
834847
835848 for issue in issues :
836849 created = datetime .datetime .strptime (issue ["created_at" ], "%Y-%m-%dT%H:%M:%SZ" )
850+ days_open = datetime .datetime .today () - created
851+ if days_open .days < 0 : # opened earlier today
852+ days_open += datetime .timedelta (days = (days_open .days * - 1 ))
837853 if "pull_request" in issue :
838- insights ["open_prs" ].append (issue ["pull_request" ]["html_url" ])
854+ pr_link = "{0} (Open {1} days)" .format (issue ["pull_request" ]["html_url" ],
855+ days_open .days )
856+ insights ["open_prs" ].append (pr_link )
839857 else :
840- insights ["open_issues" ].append (issue ["html_url" ])
858+ issue_link = "{0} (Open {1} days)" .format (issue ["html_url" ],
859+ days_open .days )
860+ insights ["open_issues" ].append (issue_link )
841861
842862 # get milestones for core repo
843863 if repo ["name" ] == "circuitpython" :
@@ -864,3 +884,22 @@ def validate_in_pypi(self, repo):
864884 if not common_funcs .repo_is_on_pypi (repo ):
865885 return [ERROR_NOT_ON_PYPI ]
866886 return []
887+
888+ def validate_labels (self , repo ):
889+ """ensures the repo has the standard labels available"""
890+ response = github .get ("/repos/" + repo ["full_name" ] + "/labels" )
891+ if not response .ok :
892+ # replace 'output_handler' with ERROR_OUTPUT_HANDLER
893+ self .output_file_data .append ("Labels request failed: {}" .format (repo ["full_name" ]))
894+ return [ERROR_OUTPUT_HANDLER ]
895+
896+ repo_labels = [label ["name" ] for label in response .json ()]
897+ has_all_labels = True
898+ for label in STD_REPO_LABELS :
899+ if not label in repo_labels :
900+ has_all_labels = False
901+
902+ if not has_all_labels :
903+ return [ERROR_MISSING_STANDARD_LABELS ]
904+ else :
905+ return []
0 commit comments