Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the peek script (bot:peek) take screenshot of individual files #412

Merged
merged 7 commits into from
Dec 30, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 38 additions & 27 deletions .github/scripts/build_assets/SeleniumRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,13 @@ def upload_icomoon(self, icomoon_json_path: str):

print("JSON file uploaded.")

def upload_svgs(self, svgs: List[str]):
def upload_svgs(self, svgs: List[str], screenshot_folder: str=""):
"""
Upload the SVGs provided in folder_info
:param svgs: a list of svg Paths that we'll upload to icomoon.
:param screenshot_folder: the name of the screenshot_folder. If
the value is provided, it means the user want to take a screenshot
of each icon.
"""
try:
print("Uploading SVGs...")
Expand All @@ -133,17 +136,20 @@ def upload_svgs(self, svgs: List[str]):

self.click_hamburger_input()

for svg in svgs:
for i in range(len(svgs)):
import_btn = self.driver.find_element_by_css_selector(
"li.file input[type=file]"
)
import_btn.send_keys(svg)
print(f"Uploaded {svg}")
import_btn.send_keys(svgs[i])
print(f"Uploaded {svgs[i]}")
self.test_for_possible_alert(self.SHORT_WAIT_IN_SEC, "Dismiss")
self.remove_color_from_icon()
self.click_on_just_added_icon(screenshot_folder, i)

# take a screenshot of the icons that were just added
self.driver.save_screenshot("new_icons.png");
new_icons_path = str(Path(screenshot_folder, "new_icons.png").resolve())
self.driver.save_screenshot(new_icons_path);

# select all the svgs so that the newly added svg are part of the collection
self.click_hamburger_input()
select_all_button = WebDriverWait(self.driver, self.LONG_WAIT_IN_SEC).until(
ec.element_to_be_clickable((By.XPATH, "//button[text()='Select All']"))
Expand Down Expand Up @@ -191,45 +197,50 @@ def test_for_possible_alert(self, wait_period: float, btn_text: str):
)
dismiss_btn.click()
except SeleniumTimeoutException:
pass
pass # nothing found => everything is good

def remove_color_from_icon(self):
def click_on_just_added_icon(self, screenshot_folder: str, index: int):
"""
Remove the color from the most recent uploaded icon.
:return: None.
Click on the most recently added icon so we can remove the colors
and take a snapshot if needed.
"""
try:
recently_uploaded_icon = WebDriverWait(self.driver, self.LONG_WAIT_IN_SEC).until(
ec.element_to_be_clickable((By.XPATH, "//div[@id='set0']//mi-box[1]//div"))
)
recently_uploaded_icon.click()
except Exception as e:
self.close()
raise e

try:
color_tab = WebDriverWait(self.driver, self.SHORT_WAIT_IN_SEC).until(
ec.element_to_be_clickable((By.CSS_SELECTOR, "div.overlayWindow i.icon-droplet"))
)
color_tab.click()
self.remove_color_from_icon()

remove_color_btn = self.driver \
.find_element_by_css_selector("div.overlayWindow i.icon-droplet-cross")
remove_color_btn.click()
except SeleniumTimeoutException:
pass
except Exception as e:
self.close()
raise e
if screenshot_folder:
screenshot_path = str(Path(screenshot_folder, f"screenshot_{index}.png").resolve())
self.driver.save_screenshot(screenshot_path)
print("Took screenshot and saved it at " + screenshot_path)

try:
close_btn = self.driver \
.find_element_by_css_selector("div.overlayWindow i.icon-close")
close_btn.click()
except Exception as e:
self.close()
raise e

def remove_color_from_icon(self):
amacado marked this conversation as resolved.
Show resolved Hide resolved
"""
Remove the color from the most recent uploaded icon.
This is because some SVG have colors in them and we don't want to
force contributors to remove them in case people want the colored SVGs.
The color removal is also necessary so that the Icomoon-generated
icons fit within one font symbol/ligiature.
"""
color_tab = WebDriverWait(self.driver, self.SHORT_WAIT_IN_SEC).until(
ec.element_to_be_clickable((By.CSS_SELECTOR, "div.overlayWindow i.icon-droplet"))
)
color_tab.click()

remove_color_btn = self.driver \
.find_element_by_css_selector("div.overlayWindow i.icon-droplet-cross")
remove_color_btn.click()

def download_icomoon_fonts(self, zip_path: Path):
"""
Download the icomoon.zip from icomoon.io.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pathlib import Path
from argparse import ArgumentParser
from build_assets.PathResolverAction import PathResolverAction

def get_commandline_args():

def get_selenium_runner_args(peek_mode=False):
parser = ArgumentParser(description="Upload svgs to Icomoon to create icon files.")

parser.add_argument("--headless",
Expand All @@ -26,8 +26,11 @@ def get_commandline_args():
action=PathResolverAction)

parser.add_argument("download_path",
help="The path where you'd like to download the Icomoon files to",
help="The download destination of the Icomoon files",
action=PathResolverAction)

if peek_mode:
parser.add_argument("--pr_title",
help="The title of the PR that we are peeking at")

return parser.parse_args()
21 changes: 21 additions & 0 deletions .github/scripts/build_assets/filehandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,24 @@ def rename_extracted_files(extract_path: str):
os.replace(dict_["old"], dict_["new"])

print("Files renamed")


def create_screenshot_folder(dir, screenshot_name: str="screenshots/"):
"""
Create a screenshots folder in the dir.
:param dir, the dir where we want to create the folder.
:param screenshot_name, the name of the screenshot folder.
:raise Exception if the dir provided is not a directory.
:return the string name of the screenshot folder.
"""
folder = Path(dir).resolve()
if not folder.is_dir():
raise Exception(f"This is not a dir: {str(folder)}. \ndir must be a valid directory")

screenshot_folder = Path(folder, screenshot_name)
try:
os.mkdir(screenshot_folder)
except FileExistsError:
print(f"{screenshot_folder} already exist. Script will do nothing.")
finally:
return str(screenshot_folder)
10 changes: 10 additions & 0 deletions .github/scripts/generate_screenshot_markdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import json
import os


if __name__ == "__main__":
img_urls_list = json.loads(os.environ["IMG_URLS"])
template = "![Detailed Screenshot]({})"
markdown = [template.format(img_url) for img_url in img_urls_list]
print("\n\n".join(markdown))

4 changes: 2 additions & 2 deletions .github/scripts/icomoon_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
# pycharm complains that build_assets is an unresolved ref
# don't worry about it, the script still runs
from build_assets.SeleniumRunner import SeleniumRunner
from build_assets import filehandler, util
from build_assets import filehandler, arg_getters


def main():
args = util.get_commandline_args()
args = arg_getters.get_selenium_runner_args()
new_icons = filehandler.find_new_icons(args.devicon_json_path, args.icomoon_json_path)
if len(new_icons) == 0:
print("No files need to be uploaded. Ending script...")
Expand Down
47 changes: 40 additions & 7 deletions .github/scripts/icomoon_peek.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,66 @@
from typing import List
import re
import sys
from selenium.common.exceptions import TimeoutException

# pycharm complains that build_assets is an unresolved ref
# don't worry about it, the script still runs
from build_assets.SeleniumRunner import SeleniumRunner
from build_assets import filehandler, util
from build_assets import filehandler, arg_getters


def main():
args = util.get_commandline_args()
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:
print("No files need to be uploaded. Ending script...")
return
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 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:
runner = SeleniumRunner(args.download_path, args.geckodriver_path, args.headless)
svgs = filehandler.get_svgs_paths(new_icons, args.icons_folder_path)
runner.upload_svgs(svgs)
svgs = filehandler.get_svgs_paths(filtered_icons, args.icons_folder_path)
screenshot_folder = filehandler.create_screenshot_folder("./")
runner.upload_svgs(svgs, screenshot_folder)
print("Task completed.")
except TimeoutException as e:
print("Selenium Time Out Error: ", e.stacktrace, sep='\n')
except Exception as e:
print(e)
print(e.stacktrace)
finally:
runner.close()


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"
entry's value matching the name in the pr_title.
If none can be found, return an empty list.
"""
try:
pattern = re.compile(r"(?<=^new icon: )\w+ (?=\(.+\))", re.I)
icon_name = pattern.findall(pr_title)[0].lower().strip() # should only have one match
amacado marked this conversation as resolved.
Show resolved Hide resolved
return [icon for icon in icons if icon["name"] == icon_name]
except IndexError: # there are no match in the findall()
return []


if __name__ == "__main__":
main()
17 changes: 10 additions & 7 deletions .github/workflows/build_icons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,28 @@ jobs:
pip install -r ./.github/scripts/requirements.txt
npm install
- name: Executing build and create fonts via icomoon
run: npm run build
run: >
python ./.github/scripts/icomoon_build.py
./.github/scripts/build_assets/geckodriver-v0.27.0-win64/geckodriver.exe ./icomoon.json
./devicon.json ./icons ./ --headless
- name: Upload geckodriver.log for debugging purposes
uses: actions/upload-artifact@v2
if: ${{failure()}}
if: failure()
with:
name: geckodriver-log
path: ./geckodriver.log
- name: Build devicon.min.css
if: ${{ success() }}
if: success()
run: npm run build-css
- name: Upload screenshot of the newly made icons
id: imgur_step
uses: devicons/public-upload-to-imgur@v1
if: ${{success()}}
uses: devicons/public-upload-to-imgur@v2
if: success()
with:
img_path: ./new_icons.png
path: ./new_icons.png
client_id: ${{secrets.IMGUR_CLIENT_ID}}
- name: Create Pull Request
if: ${{ success() }}
if: success()
uses: peter-evans/create-pull-request@v3
env:
MESSAGE: |
Expand Down
71 changes: 62 additions & 9 deletions .github/workflows/peek_icons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,47 @@ jobs:
python -m pip install --upgrade pip
pip install -r ./.github/scripts/requirements.txt
- name: Run icomoon_peek.py
run: npm run peek
env:
PR_TITLE: ${{ github.event.pull_request.title }}
shell: cmd
run: >
python ./.github/scripts/icomoon_peek.py
./.github/scripts/build_assets/geckodriver-v0.27.0-win64/geckodriver.exe ./icomoon.json
./devicon.json ./icons ./ --headless --pr_title "%PR_TITLE%"
- name: Upload geckodriver.log for debugging purposes
uses: actions/upload-artifact@v2
if: ${{failure()}}
if: failure()
with:
name: geckodriver-log
path: ./geckodriver.log
- name: Upload screenshot of the newly made icons
id: imgur_step
uses: devicons/public-upload-to-imgur@v1
if: ${{success()}}
id: icons_overview_img_step
uses: devicons/public-upload-to-imgur@v2
if: success()
with:
path: ./screenshots/new_icons.png
client_id: ${{secrets.IMGUR_CLIENT_ID}}
- name: Upload zoomed in screenshot of the newly made icons
id: icons_detailed_img_step
uses: devicons/public-upload-to-imgur@v2
if: success()
with:
img_path: ./new_icons.png
path: ./screenshots/screenshot_*.png
client_id: ${{secrets.IMGUR_CLIENT_ID}}
- name: Generate the markdowns for the screenshot and put it in the DETAILED_IMGS_MARKDOWN env var
if: success()
env:
IMG_URLS: ${{ steps.icons_detailed_img_step.outputs.imgur_urls }}
run: |
echo 'DETAILED_IMGS_MARKDOWN<<EOF' >> $GITHUB_ENV
python ./.github/scripts/generate_screenshot_markdown.py >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
shell: bash
- name: Comment on the PR about the result
if: success()
uses: github-actions-up-and-running/pr-comment@v1.0.1
env:
IMG_URL: ${{ steps.imgur_step.outputs.imgur_url }}
OVERVIEW_IMG_URL: ${{ fromJSON(steps.icons_overview_img_step.outputs.imgur_urls)[0] }}
MESSAGE: |
Hi!

Expand All @@ -47,13 +70,43 @@ jobs:

![Peeked Icons (top left)]({0})

Note: If the image doesn't show up, it's probably because it has been autodeleted by Imgur after 6 months due to our API choice.
Here are the zoomed-in screenshots of the added icons:
{1}

Note: If the images don't show up, it's probably because it has been autodeleted by Imgur after 6 months due to our API choice.

The maintainers will now take a look at it and decide whether to merge your PR.

Thank you for contributing to Devicon! I hope everything works out and your icons are accepted into the repo.

Cheers :),

Peek Bot
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
message: ${{format(env.MESSAGE, env.OVERVIEW_IMG_URL, env.DETAILED_IMGS_MARKDOWN)}}
- name: Comment on the PR about the result
if: failure()
uses: github-actions-up-and-running/pr-comment@v1.0.1
env:
MESSAGE: |
Hi!

I'm Devicons' Peek Bot and it seems we've ran into a problem. I'm supposed to check your svgs but I couldn't do my task due to an issue.

Can you please double check and fix the possible issues below:

- Your svgs are named and added correctly to the /icons folder as seen [here](https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#orgGuidelines).
- Your icon information has been added to the `devicon.json` as seen [here](https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#updateDevicon)
- Your PR title follows the format seen [here](https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#overview)

Once everything is fixed, the maintainers will try again. If I still fail, the maintainers will investigate what cause this problem.

Thank you for your help :smile:

Cheers :),

Peek Bot
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
message: ${{format(env.MESSAGE, env.IMG_URL, env.IMG_URL)}}
message: ${{env.MESSAGE}}
Loading