mirror of
https://github.com/konpa/devicon.git
synced 2025-08-12 09:34:36 +02:00
Script upgrades and updated CONTRIBUTING.md and README.md (#576)
* Updated README and CONTRIBUTING * Added check for devicon object when peeking * Added PR template * Added a script to create release messages * Updated CONTRIBUTING about new script * Update .github/PULL_REQUEST_TEMPLATE/new_icon.md Co-authored-by: David Leal <halfpacho@gmail.com> * Update .github/scripts/build_assets/arg_getters.py Co-authored-by: David Leal <halfpacho@gmail.com> * Update .github/workflows/get_release_message.yml Co-authored-by: David Leal <halfpacho@gmail.com> * Update gulpfile.js Co-authored-by: David Leal <halfpacho@gmail.com> * Update .github/PULL_REQUEST_TEMPLATE/new_feature.md Co-authored-by: David Leal <halfpacho@gmail.com> * Update .github/PULL_REQUEST_TEMPLATE/new_feature.md Co-authored-by: David Leal <halfpacho@gmail.com> * Added a way for peek bot to comment error * Update CONTRIBUTING.md Co-authored-by: Clemens Bastian <8781699+amacado@users.noreply.github.com> * Update .github/scripts/get_release_message.py Co-authored-by: Malte Jürgens <maltejur@web.de> * Update .github/scripts/get_release_message.py Co-authored-by: Malte Jürgens <maltejur@web.de> * Update .github/PULL_REQUEST_TEMPLATE/new_feature.md Co-authored-by: David Leal <halfpacho@gmail.com> * Clean up and updated CONTRIBUTING * Updated CONTRIBUTING * Add set up steps for release message workflow * Refactored peek workflow * Added requests library * Reformat devicon object error messages Co-authored-by: David Leal <halfpacho@gmail.com> Co-authored-by: Clemens Bastian <8781699+amacado@users.noreply.github.com> Co-authored-by: Malte Jürgens <maltejur@web.de>
This commit is contained in:
13
.github/scripts/build_assets/arg_getters.py
vendored
13
.github/scripts/build_assets/arg_getters.py
vendored
@@ -67,4 +67,15 @@ def get_check_svgs_monthly_args():
|
||||
parser.add_argument("icons_folder_path",
|
||||
help="The path to the icons folder",
|
||||
action=PathResolverAction)
|
||||
return parser.parse_args()
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def get_release_message_args():
|
||||
"""
|
||||
Get the commandline arguments for get_release_message.py.
|
||||
"""
|
||||
parser = ArgumentParser(description="Create a text containing the icons and features added since last release.")
|
||||
parser.add_argument("token",
|
||||
help="The GitHub token to access the GitHub REST API.",
|
||||
type=str)
|
||||
return parser.parse_args()
|
||||
|
75
.github/scripts/get_release_message.py
vendored
Normal file
75
.github/scripts/get_release_message.py
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
import requests
|
||||
from build_assets import arg_getters
|
||||
import re
|
||||
|
||||
def main():
|
||||
print("Please wait a few seconds...")
|
||||
args = arg_getters.get_release_message_args()
|
||||
queryPath = "https://api.github.com/repos/devicons/devicon/pulls?accept=application/vnd.github.v3+json&state=closed&per_page=100"
|
||||
stopPattern = r"^(r|R)elease v"
|
||||
headers = {
|
||||
"Authorization": f"token {args.token}"
|
||||
}
|
||||
|
||||
response = requests.get(queryPath, headers=headers)
|
||||
if not response:
|
||||
print(f"Can't query the GitHub API. Status code is {response.status_code}. Message is {response.text}")
|
||||
return
|
||||
|
||||
data = response.json()
|
||||
newIcons = []
|
||||
features = []
|
||||
|
||||
for pullData in data:
|
||||
if re.search(stopPattern, pullData["title"]):
|
||||
break
|
||||
|
||||
authors = findAllAuthors(pullData, headers)
|
||||
markdown = f"- [{pullData['title']}]({pullData['html_url']}) by {authors}."
|
||||
|
||||
if isFeatureIcon(pullData):
|
||||
newIcons.append(markdown)
|
||||
else:
|
||||
features.append(markdown)
|
||||
|
||||
thankYou = "A huge thanks to all our maintainers and contributors for making this release possible!"
|
||||
iconTitle = "**{} New Icons**\n".format(len(newIcons))
|
||||
featureTitle = "**{} New Features**\n".format(len(features))
|
||||
finalString = "{0}\n\n {1}{2}\n\n {3}{4}".format(thankYou,
|
||||
iconTitle, "\n".join(newIcons), featureTitle, "\n".join(features))
|
||||
|
||||
print("--------------Here is the build message--------------\n", finalString)
|
||||
|
||||
|
||||
"""
|
||||
Check whether the pullData is a feature:icon PR.
|
||||
:param pullData
|
||||
:return true if the pullData has a label named "feature:icon"
|
||||
"""
|
||||
def isFeatureIcon(pullData):
|
||||
for label in pullData["labels"]:
|
||||
if label["name"] == "feature:icon":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
"""
|
||||
Find all the authors of a PR based on its commits.
|
||||
:param pullData - the data of a pull request.
|
||||
"""
|
||||
def findAllAuthors(pullData, authHeader):
|
||||
response = requests.get(pullData["commits_url"], headers=authHeader)
|
||||
if not response:
|
||||
print(f"Can't query the GitHub API. Status code is {response.status_code}")
|
||||
print("Response is: ", response.text)
|
||||
return
|
||||
|
||||
commits = response.json()
|
||||
authors = set() # want unique authors only
|
||||
for commit in commits:
|
||||
authors.add("@" + commit["author"]["login"])
|
||||
return ", ".join(list(authors))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
105
.github/scripts/icomoon_peek.py
vendored
105
.github/scripts/icomoon_peek.py
vendored
@@ -2,7 +2,6 @@ from typing import List
|
||||
import re
|
||||
import sys
|
||||
from selenium.common.exceptions import TimeoutException
|
||||
import xml.etree.ElementTree as et
|
||||
|
||||
# pycharm complains that build_assets is an unresolved ref
|
||||
# don't worry about it, the script still runs
|
||||
@@ -12,36 +11,28 @@ from build_assets import util
|
||||
|
||||
|
||||
def main():
|
||||
args = arg_getters.get_selenium_runner_args(True)
|
||||
new_icons = filehandler.find_new_icons(args.devicon_json_path, args.icomoon_json_path)
|
||||
|
||||
# get only the icon object that has the name matching the pr title
|
||||
filtered_icons = find_object_added_in_this_pr(new_icons, args.pr_title)
|
||||
|
||||
if len(new_icons) == 0:
|
||||
sys.exit("No files need to be uploaded. Ending script...")
|
||||
|
||||
if len(filtered_icons) == 0:
|
||||
message = "No icons found matching the icon name in the PR's title.\n" \
|
||||
"Ensure that a new icon entry is added in the devicon.json and the PR title matches the convention here: \n" \
|
||||
"https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#overview\n" \
|
||||
"Ending script...\n"
|
||||
sys.exit(message)
|
||||
|
||||
# print list of new icons
|
||||
print("List of new icons:", *new_icons, sep = "\n")
|
||||
print("Icons being uploaded:", *filtered_icons, sep = "\n", end='\n\n')
|
||||
|
||||
runner = None
|
||||
try:
|
||||
args = arg_getters.get_selenium_runner_args(True)
|
||||
new_icons = filehandler.find_new_icons(args.devicon_json_path, args.icomoon_json_path)
|
||||
|
||||
if len(new_icons) == 0:
|
||||
raise Exception("No files need to be uploaded. Ending script...")
|
||||
|
||||
# get only the icon object that has the name matching the pr title
|
||||
filtered_icon = find_object_added_in_this_pr(new_icons, args.pr_title)
|
||||
print("Icon being checked:", filtered_icon, sep = "\n", end='\n\n')
|
||||
|
||||
runner = SeleniumRunner(args.download_path, args.geckodriver_path, args.headless)
|
||||
svgs = filehandler.get_svgs_paths(filtered_icons, args.icons_folder_path, True)
|
||||
svgs = filehandler.get_svgs_paths([filtered_icon], args.icons_folder_path, True)
|
||||
screenshot_folder = filehandler.create_screenshot_folder("./")
|
||||
runner.upload_svgs(svgs, screenshot_folder)
|
||||
print("Task completed.")
|
||||
except TimeoutException as e:
|
||||
util.exit_with_err("Selenium Time Out Error: \n" + str(e))
|
||||
|
||||
# no errors, do this so upload-artifact won't fail
|
||||
filehandler.write_to_file("./err_messages.txt", "0")
|
||||
except Exception as e:
|
||||
filehandler.write_to_file("./err_messages.txt", str(e))
|
||||
util.exit_with_err(e)
|
||||
finally:
|
||||
runner.close()
|
||||
@@ -52,19 +43,77 @@ def find_object_added_in_this_pr(icons: List[dict], pr_title: str):
|
||||
Find the icon name from the PR title.
|
||||
:param icons, a list of the font objects found in the devicon.json.
|
||||
:pr_title, the title of the PR that this workflow was called on.
|
||||
:return a list containing the dictionary with the "name"
|
||||
:return a dictionary with the "name"
|
||||
entry's value matching the name in the pr_title.
|
||||
If none can be found, return an empty list.
|
||||
:raise If no object can be found, raise an Exception.
|
||||
"""
|
||||
try:
|
||||
pattern = re.compile(r"(?<=^new icon: )\w+ (?=\(.+\))", re.I)
|
||||
icon_name = pattern.findall(pr_title)[0].lower().strip() # should only have one match
|
||||
return [icon for icon in icons if icon["name"] == icon_name]
|
||||
icon = [icon for icon in icons if icon["name"] == icon_name][0]
|
||||
check_devicon_object(icon, icon_name)
|
||||
return icon
|
||||
except IndexError: # there are no match in the findall()
|
||||
return []
|
||||
raise Exception("Couldn't find an icon matching the name in the PR title.")
|
||||
except ValueError as e:
|
||||
raise Exception(str(e))
|
||||
|
||||
|
||||
def check_devicon_object(icon: dict, icon_name: str):
|
||||
"""
|
||||
Check that the devicon object added is up to standard.
|
||||
:return a string containing the error messages if any.
|
||||
"""
|
||||
err_msgs = []
|
||||
try:
|
||||
if icon["name"] != icon_name:
|
||||
err_msgs.append("- 'name' value is not: " + icon_name)
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'name'.")
|
||||
|
||||
try:
|
||||
for tag in icon["tags"]:
|
||||
if type(tag) != str:
|
||||
raise TypeError()
|
||||
except TypeError:
|
||||
err_msgs.append("- 'tags' must be an array of strings, not: " + str(icon["tags"]))
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'tags'.")
|
||||
|
||||
try:
|
||||
if type(icon["versions"]) != dict:
|
||||
err_msgs.append("- 'versions' must be an object.")
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'versions'.")
|
||||
|
||||
try:
|
||||
if type(icon["versions"]["svg"]) != list or len(icon["versions"]["svg"]) == 0:
|
||||
err_msgs.append("- must contain at least 1 svg version in a list.")
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'svg' in 'versions'.")
|
||||
|
||||
try:
|
||||
if type(icon["versions"]["font"]) != list or len(icon["versions"]["svg"]) == 0:
|
||||
err_msgs.append("- must contain at least 1 font version in a list.")
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'font' in 'versions'.")
|
||||
|
||||
try:
|
||||
if type(icon["color"]) != str or "#" not in icon["color"]:
|
||||
err_msgs.append("- 'color' must be a string in the format '#abcdef'")
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'color'.")
|
||||
|
||||
try:
|
||||
if type(icon["aliases"]) != list:
|
||||
err_msgs.append("- 'aliases' must be an array.")
|
||||
except KeyError:
|
||||
err_msgs.append("- missing key: 'aliases'.")
|
||||
|
||||
if len(err_msgs) > 0:
|
||||
message = "Error found in 'devicon.json' for '{}' entry: \n{}".format(icon_name, "\n".join(err_msgs))
|
||||
raise ValueError(message)
|
||||
return ""
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
3
.github/scripts/requirements.txt
vendored
3
.github/scripts/requirements.txt
vendored
@@ -1 +1,2 @@
|
||||
selenium==3.141.0
|
||||
selenium==3.141.0
|
||||
requests==2.25.1
|
Reference in New Issue
Block a user