mirror of
https://github.com/walkxcode/dashboard-icons.git
synced 2025-06-28 07:20:21 +08:00
feat: add issue_templates for creation of icons (#935)
Co-authored-by: Dashboard Icons Bot <homarr-labs@proton.me>
This commit is contained in:
parent
02aaf9bb7f
commit
d1e008be5f
73
.github/ISSUE_TEMPLATE/add_monochrome_icon.yml
vendored
Normal file
73
.github/ISSUE_TEMPLATE/add_monochrome_icon.yml
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
name: "Add light & dark icon"
|
||||
description: Use this template to add a new icon to the project. Monochrome icons need both light and dark versions.
|
||||
title: "feat(icons): add [NAME]"
|
||||
labels: ["monochrome-icon"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Hello and thank you for contributing to the project! Please fill out the following information to add a new icon to the project.
|
||||
Once you've submitted the issue, sombody from the team will review it, before adding a label which automatically creates a pull request with the other filetypes.
|
||||
If you submit a PNG icon, please note, that the SVG can not be generated from it.
|
||||
- type: input
|
||||
attributes:
|
||||
label: Icon name
|
||||
description: The name has to be unique and should be kebab-case.
|
||||
placeholder: e.g. "icon-name"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Paste light mode icon
|
||||
description: |
|
||||
Please paste the icon here. It will automatically upload it to github. This icon should be visible on a light background.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Paste dark mode icon
|
||||
description: |
|
||||
Please paste the icon here. It will automatically upload it to github. This icon should be visible on a dark background.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Icon type
|
||||
options:
|
||||
- SVG
|
||||
- PNG
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Categories
|
||||
multiple: true
|
||||
options:
|
||||
- Animal
|
||||
- Cloud
|
||||
- Communication
|
||||
- Design
|
||||
- Development
|
||||
- E-Commerce
|
||||
- Education
|
||||
- File
|
||||
- Finance
|
||||
- Food
|
||||
- Gaming
|
||||
- Hardware
|
||||
- Health
|
||||
- Location
|
||||
- Logistics
|
||||
- Media
|
||||
- Music
|
||||
- Nature
|
||||
- News
|
||||
- Organization
|
||||
- Search
|
||||
- Security
|
||||
- SocialMedia
|
||||
- Streaming
|
||||
- Travel
|
||||
- Video
|
||||
- type: input
|
||||
attributes:
|
||||
label: Aliases
|
||||
description: A comma separated list of aliases
|
||||
placeholder: e.g. "icon-alias, icon-alias-2"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
Add additional informations like a link to the application.
|
68
.github/ISSUE_TEMPLATE/add_normal_icon.yml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/add_normal_icon.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: "Add normal icon"
|
||||
description: Use this template to add a new icon to the project. Normal icons work for both light and dark themes.
|
||||
title: "feat(icons): add [NAME]"
|
||||
labels: ["normal-icon"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Hello and thank you for contributing to the project! Please fill out the following information to add a new icon to the project.
|
||||
Once you've submitted the issue, sombody from the team will review it, before adding a label which automatically creates a pull request with the other filetypes.
|
||||
If you submit a PNG icon, please note, that the SVG can not be generated from it.
|
||||
- type: input
|
||||
attributes:
|
||||
label: Icon name
|
||||
description: The name has to be unique and should be kebab-case.
|
||||
placeholder: e.g. "icon-name"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Paste icon
|
||||
description: |
|
||||
Please paste the icon here. It will automatically upload it to github.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Icon type
|
||||
options:
|
||||
- SVG
|
||||
- PNG
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Categories
|
||||
multiple: true
|
||||
options:
|
||||
- Animal
|
||||
- Cloud
|
||||
- Communication
|
||||
- Design
|
||||
- Development
|
||||
- E-Commerce
|
||||
- Education
|
||||
- File
|
||||
- Finance
|
||||
- Food
|
||||
- Gaming
|
||||
- Hardware
|
||||
- Health
|
||||
- Location
|
||||
- Logistics
|
||||
- Media
|
||||
- Music
|
||||
- Nature
|
||||
- News
|
||||
- Organization
|
||||
- Search
|
||||
- Security
|
||||
- SocialMedia
|
||||
- Streaming
|
||||
- Travel
|
||||
- Video
|
||||
- type: input
|
||||
attributes:
|
||||
label: Aliases
|
||||
description: A comma separated list of aliases
|
||||
placeholder: e.g. "icon-alias, icon-alias-2"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
Add additional informations like a link to the application.
|
35
.github/ISSUE_TEMPLATE/update_monochrome_icon.yml
vendored
Normal file
35
.github/ISSUE_TEMPLATE/update_monochrome_icon.yml
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
name: "Update light & dark icon"
|
||||
description: Use this template to update an existing icon. Monochrome icons need both light and dark versions.
|
||||
title: "feat(icons): update [NAME]"
|
||||
labels: ["monochrome-icon"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Hello and thank you for contributing to the project! Please fill out the following informations to update an existing icon in the project.
|
||||
- type: input
|
||||
attributes:
|
||||
label: Icon name
|
||||
description: The name has to be unique and should be kebab-case.
|
||||
placeholder: e.g. "icon-name"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Paste light mode icon
|
||||
description: |
|
||||
Please paste the icon here. It will automatically upload it to github. This icon should be visible on a light background.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Paste dark mode icon
|
||||
description: |
|
||||
Please paste the icon here. It will automatically upload it to github. This icon should be visible on a dark background.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Icon type
|
||||
options:
|
||||
- SVG
|
||||
- PNG
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
Add additional informations like, the reason for the update, or what has been changed.
|
30
.github/ISSUE_TEMPLATE/update_normal_icon.yml
vendored
Normal file
30
.github/ISSUE_TEMPLATE/update_normal_icon.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: "Update normal icon"
|
||||
description: Use this template to update an existing icon. Normal icons work for both light and dark themes.
|
||||
title: "feat(icons): update [NAME]"
|
||||
labels: ["normal-icon"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Hello and thank you for contributing to the project! Please fill out the following informations to update an existing icon in the project.
|
||||
- type: input
|
||||
attributes:
|
||||
label: Icon name
|
||||
description: The name has to match the existing icon name.
|
||||
placeholder: e.g. "icon-name"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Paste icon
|
||||
description: |
|
||||
Please paste the icon here. It will automatically upload it to github.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Icon type
|
||||
options:
|
||||
- SVG
|
||||
- PNG
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
Add additional informations like, the reason for the update, or what has been changed.
|
2
.github/workflows/compress_icons.yml
vendored
2
.github/workflows/compress_icons.yml
vendored
@ -1,8 +1,6 @@
|
||||
name: Compress Icons
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * 0"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
69
.github/workflows/on_icon_addition_approved.yml
vendored
Normal file
69
.github/workflows/on_icon_addition_approved.yml
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
name: "[Icon] Icon addition approved"
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
add-icon:
|
||||
runs-on: ubuntu-latest
|
||||
# This condition ensures the job only runs when the 'approved' label is added and the issue title starts with 'feat(icons): add '
|
||||
if: |
|
||||
contains(github.event.issue.labels.*.name, 'approved') &&
|
||||
startsWith(github.event.issue.title, 'feat(icons): add ')
|
||||
env:
|
||||
ICON_TYPE: ${{ contains(github.event.issue.labels.*.name, 'normal-icon') && 'normal' || 'monochrome' }}
|
||||
steps:
|
||||
- name: Obtain token
|
||||
id: obtainToken
|
||||
uses: tibdex/github-app-token@v2
|
||||
with:
|
||||
private_key: ${{ secrets.DASHBOARD_ICONS_MANAGER_APP_PRIVATE_KEY }}
|
||||
app_id: ${{ vars.DASHBOARD_ICONS_MANAGER_APP_ID }}
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||
- name: Set Up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
pip install cairosvg pillow requests
|
||||
- name: Parse issue form
|
||||
id: parse_issue_form
|
||||
run: echo "ISSUE_FORM=$(python scripts/parse_issue_form.py)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
INPUT_ISSUE_BODY: ${{ github.event.issue.body }}
|
||||
- name: Create metadata file
|
||||
run: python scripts/generate_metadata_file.py ${{ env.ICON_TYPE }} addition
|
||||
env:
|
||||
INPUT_ISSUE_FORM: ${{ steps.parse_issue_form.outputs.ISSUE_FORM }}
|
||||
INPUT_ISSUE_AUTHOR_ID: ${{ github.event.issue.user.id }}
|
||||
INPUT_ISSUE_AUTHOR_LOGIN: ${{ github.event.issue.user.login }}
|
||||
- name: Generate icons
|
||||
run: python scripts/generate_icons.py ${{ env.ICON_TYPE }} addition
|
||||
env:
|
||||
INPUT_ISSUE_FORM: ${{ steps.parse_issue_form.outputs.ISSUE_FORM }}
|
||||
- name: Extract icon name
|
||||
id: extract_icon_name
|
||||
run: echo "ICON_NAME=$(python scripts/print_icon_name.py ${{ env.ICON_TYPE }} addition)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
INPUT_ISSUE_FORM: ${{ steps.parse_issue_form.outputs.ISSUE_FORM }}
|
||||
- name: Commit changes
|
||||
run: |
|
||||
git config --global user.email "193821040+dashboard-icons-manager[bot]@users.noreply.github.com"
|
||||
git config --global user.name "Dashboard Icons Manager"
|
||||
git add .
|
||||
git commit -m "feat(icons): add ${{ steps.extract_icon_name.outputs.ICON_NAME }}"
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ steps.obtainToken.outputs.token }}
|
||||
branch: icons/add-${{steps.extract_icon_name.outputs.ICON_NAME}}
|
||||
base: main
|
||||
title: "feat(icons): add ${{steps.extract_icon_name.outputs.ICON_NAME}}"
|
||||
delete-branch: true
|
||||
body: |
|
||||
This PR adds the icon ${{steps.extract_icon_name.outputs.ICON_NAME}} added in #${{github.event.issue.number}} to the project.
|
69
.github/workflows/on_icon_update_approved.yml
vendored
Normal file
69
.github/workflows/on_icon_update_approved.yml
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
name: "[Icon] Icon update approved"
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
update-icon:
|
||||
runs-on: ubuntu-latest
|
||||
# This condition ensures the job only runs when the 'approved' label is updated and the issue title starts with 'feat(icons): update '
|
||||
if: |
|
||||
contains(github.event.issue.labels.*.name, 'approved') &&
|
||||
startsWith(github.event.issue.title, 'feat(icons): update ')
|
||||
env:
|
||||
ICON_TYPE: ${{ contains(github.event.issue.labels.*.name, 'normal-icon') && 'normal' || 'monochrome' }}
|
||||
steps:
|
||||
- name: Obtain token
|
||||
id: obtainToken
|
||||
uses: tibdex/github-app-token@v2
|
||||
with:
|
||||
private_key: ${{ secrets.DASHBOARD_ICONS_MANAGER_APP_PRIVATE_KEY }}
|
||||
app_id: ${{ vars.DASHBOARD_ICONS_MANAGER_APP_ID }}
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||
- name: Set Up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
pip install cairosvg pillow requests
|
||||
- name: Parse issue form
|
||||
id: parse_issue_form
|
||||
run: echo "ISSUE_FORM=$(python scripts/parse_issue_form.py)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
INPUT_ISSUE_BODY: ${{ github.event.issue.body }}
|
||||
- name: Update metadata file
|
||||
run: python scripts/generate_metadata_file.py ${{ env.ICON_TYPE }} update
|
||||
env:
|
||||
INPUT_ISSUE_FORM: ${{ steps.parse_issue_form.outputs.ISSUE_FORM }}
|
||||
INPUT_ISSUE_AUTHOR_ID: ${{ github.event.issue.user.id }}
|
||||
INPUT_ISSUE_AUTHOR_LOGIN: ${{ github.event.issue.user.login }}
|
||||
- name: Generate icons
|
||||
run: python scripts/generate_icons.py ${{ env.ICON_TYPE }} update
|
||||
env:
|
||||
INPUT_ISSUE_FORM: ${{ steps.parse_issue_form.outputs.ISSUE_FORM }}
|
||||
- name: Extract icon name
|
||||
id: extract_icon_name
|
||||
run: echo "ICON_NAME=$(python scripts/print_icon_name.py ${{ env.ICON_TYPE }} update)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
INPUT_ISSUE_FORM: ${{ steps.parse_issue_form.outputs.ISSUE_FORM }}
|
||||
- name: Commit changes
|
||||
run: |
|
||||
git config --global user.email "193821040+dashboard-icons-manager[bot]@users.noreply.github.com"
|
||||
git config --global user.name "Dashboard Icons Manager"
|
||||
git add .
|
||||
git commit -m "feat(icons): update ${{ steps.extract_icon_name.outputs.ICON_NAME }}"
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ steps.obtainToken.outputs.token }}
|
||||
branch: icons/update-${{steps.extract_icon_name.outputs.ICON_NAME}}
|
||||
base: main
|
||||
title: "feat(icons): update ${{steps.extract_icon_name.outputs.ICON_NAME}}"
|
||||
delete-branch: true
|
||||
body: |
|
||||
This PR updates the icon ${{steps.extract_icon_name.outputs.ICON_NAME}} like requested in #${{github.event.issue.number}} to the project.
|
@ -10,7 +10,7 @@
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
"dark": "apple",
|
||||
"light": "apple-light"
|
||||
"light": "apple",
|
||||
"dark": "apple-light"
|
||||
}
|
||||
}
|
17694
metadata.json
Normal file
17694
metadata.json
Normal file
File diff suppressed because it is too large
Load Diff
7
scripts/common.py
Normal file
7
scripts/common.py
Normal file
@ -0,0 +1,7 @@
|
||||
import re
|
||||
|
||||
def convert_to_kebab_case(name: str) -> str:
|
||||
"""Convert a filename to kebab-case."""
|
||||
cleaned = re.sub(r'[^a-zA-Z0-9\s-]', '', name)
|
||||
kebab_case_name = re.sub(r'[\s_]+', '-', cleaned).lower()
|
||||
return kebab_case_name
|
83
scripts/generate_icons.py
Normal file
83
scripts/generate_icons.py
Normal file
@ -0,0 +1,83 @@
|
||||
from icons import IssueFormType, checkAction, iconFactory, checkType
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import requests
|
||||
from PIL import Image
|
||||
import cairosvg
|
||||
|
||||
ISSUE_FORM_ENV_VAR = "INPUT_ISSUE_FORM"
|
||||
|
||||
ROOT_DIR = Path(__file__).resolve().parent.parent
|
||||
SVG_DIR = ROOT_DIR / "svg"
|
||||
PNG_DIR = ROOT_DIR / "png"
|
||||
WEBP_DIR = ROOT_DIR / "webp"
|
||||
|
||||
# Ensure the output folders exist
|
||||
PNG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
WEBP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def request_image(url: str) -> bytes:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
return response.content
|
||||
|
||||
def save_image(image: bytes, path: Path):
|
||||
with open(path, 'wb') as f:
|
||||
f.write(image)
|
||||
|
||||
def convert_svg_to_png(svg_path: Path) -> bytes:
|
||||
"""Convert SVG to PNG."""
|
||||
try:
|
||||
return cairosvg.svg2png(url=str(svg_path), output_height=512)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to convert {svg_path} to PNG: {e}")
|
||||
raise e
|
||||
|
||||
def save_image_as_webp(image_path: Path, webp_path: Path):
|
||||
"""Convert an image (PNG or other) to WEBP."""
|
||||
try:
|
||||
image = Image.open(image_path).convert("RGBA")
|
||||
image.save(webp_path, format='WEBP')
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to convert {image_path} to WEBP: {e}")
|
||||
raise e
|
||||
|
||||
def main(type: str, action: IssueFormType, issue_form: str):
|
||||
icon = iconFactory(type, issue_form, action)
|
||||
convertions = icon.convertions()
|
||||
|
||||
for convertion in convertions:
|
||||
svg_path = SVG_DIR / f"{convertion.name}.svg"
|
||||
png_path = PNG_DIR / f"{convertion.name}.png"
|
||||
webp_path = WEBP_DIR / f"{convertion.name}.webp"
|
||||
|
||||
imageBytes = request_image(convertion.source)
|
||||
|
||||
if icon.type == "svg":
|
||||
save_image(imageBytes, svg_path)
|
||||
print(f"Downloaded SVG: {svg_path}")
|
||||
|
||||
png_data = convert_svg_to_png(svg_path)
|
||||
save_image(png_data, png_path)
|
||||
print(f"Converted PNG: {png_path}")
|
||||
|
||||
if icon.type == "png":
|
||||
save_image(imageBytes, png_path)
|
||||
print(f"Downloaded PNG: {png_path}")
|
||||
|
||||
|
||||
save_image_as_webp(png_path, webp_path)
|
||||
print(f"Converted WEBP: {webp_path}")
|
||||
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
type = checkType(sys.argv[1])
|
||||
action = checkAction(sys.argv[2])
|
||||
main(
|
||||
type,
|
||||
action,
|
||||
os.getenv(ISSUE_FORM_ENV_VAR)
|
||||
)
|
33
scripts/generate_metadata.py
Normal file
33
scripts/generate_metadata.py
Normal file
@ -0,0 +1,33 @@
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
ROOT_DIR = Path(__file__).resolve().parent.parent
|
||||
META_DIR = ROOT_DIR / "meta"
|
||||
|
||||
# Ensure the output folders exist
|
||||
META_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def get_icon_names():
|
||||
return [path.stem for path in META_DIR.glob("*.json")]
|
||||
|
||||
def read_meta_for(icon_name):
|
||||
meta_file = META_DIR / f"{icon_name}.json"
|
||||
if meta_file.exists():
|
||||
with open(meta_file, 'r', encoding='UTF-8') as f:
|
||||
return json.load(f)
|
||||
return None
|
||||
|
||||
def generate_meta_json():
|
||||
icon_names = get_icon_names()
|
||||
fullMeta = dict()
|
||||
for icon_name in icon_names:
|
||||
meta = read_meta_for(icon_name)
|
||||
if meta is None:
|
||||
print(f"Missing metadata for {icon_name}")
|
||||
continue
|
||||
fullMeta[icon_name] = meta
|
||||
with open(ROOT_DIR / "metadata.json", 'w', encoding='UTF-8') as f:
|
||||
json.dump(fullMeta, f, indent=4)
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
generate_meta_json()
|
51
scripts/generate_metadata_file.py
Normal file
51
scripts/generate_metadata_file.py
Normal file
@ -0,0 +1,51 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from icons import IssueFormType, checkAction, iconFactory, checkType
|
||||
from pathlib import Path
|
||||
|
||||
from metadata import load_metadata
|
||||
|
||||
|
||||
|
||||
ISSUE_FORM_ENV_VAR = "INPUT_ISSUE_FORM"
|
||||
AUTHOR_ID_ENV_VAR = "INPUT_ISSUE_AUTHOR_ID"
|
||||
AUTHOR_LOGIN_ENV_VAR = "INPUT_ISSUE_AUTHOR_LOGIN"
|
||||
|
||||
ROOT_DIR = Path(__file__).resolve().parent.parent
|
||||
META_DIR = ROOT_DIR / "meta"
|
||||
|
||||
# Ensure the output folders exist
|
||||
META_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def main(type: str, action: IssueFormType, issue_form: str, author_id: int, author_login: str):
|
||||
icon = iconFactory(type, issue_form, action)
|
||||
if (action == IssueFormType.METADATA_UPDATE):
|
||||
existing_metadata = load_metadata(icon.name)
|
||||
author_id = existing_metadata["author"]["id"]
|
||||
author_login = existing_metadata["author"]["login"]
|
||||
metadata = icon.to_metadata({"id": author_id, "login": author_login})
|
||||
|
||||
FILE_PATH = META_DIR / f"{icon.name}.json"
|
||||
|
||||
with open(FILE_PATH, 'w', encoding='UTF-8') as f:
|
||||
json.dump(metadata, f, indent=2)
|
||||
|
||||
|
||||
def parse_author_id():
|
||||
author_id_string = os.getenv(AUTHOR_ID_ENV_VAR)
|
||||
if author_id_string != None:
|
||||
return int(author_id_string)
|
||||
return None
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
type = checkType(sys.argv[1])
|
||||
action = checkAction(sys.argv[2])
|
||||
main(
|
||||
type,
|
||||
action,
|
||||
os.getenv(ISSUE_FORM_ENV_VAR),
|
||||
parse_author_id(),
|
||||
os.getenv(AUTHOR_LOGIN_ENV_VAR)
|
||||
)
|
||||
|
222
scripts/icons.py
Normal file
222
scripts/icons.py
Normal file
@ -0,0 +1,222 @@
|
||||
import re
|
||||
from common import convert_to_kebab_case
|
||||
from datetime import datetime
|
||||
import json
|
||||
from enum import Enum
|
||||
|
||||
from metadata import load_metadata
|
||||
|
||||
class IconConvertion:
|
||||
def __init__(self, name: str, source: str):
|
||||
self.name = name
|
||||
self.source = source
|
||||
|
||||
class Icon:
|
||||
def __init__(self, name: str, type: str, categories: list, aliases: list):
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.categories = categories
|
||||
self.aliases = aliases
|
||||
|
||||
def to_metadata(self, author: dict) -> dict:
|
||||
return {
|
||||
"base": self.type,
|
||||
"aliases": self.aliases,
|
||||
"categories": self.categories,
|
||||
"update": {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"author": author
|
||||
}
|
||||
}
|
||||
|
||||
def convertions(self) -> list[IconConvertion]:
|
||||
raise NotImplementedError("Method 'files' must be implemented in subclass")
|
||||
|
||||
|
||||
class NormalIcon(Icon):
|
||||
def __init__(self, icon: str, name: str, type: str, categories: list, aliases: list):
|
||||
super().__init__(name, type, categories, aliases)
|
||||
self.icon = icon
|
||||
|
||||
def convertions(self) -> list[IconConvertion]:
|
||||
return [
|
||||
IconConvertion(self.name, self.icon)
|
||||
]
|
||||
|
||||
def from_addition_issue_form(input: dict):
|
||||
return NormalIcon(
|
||||
mapUrlFromMarkdownImage(input, "Paste icon"),
|
||||
convert_to_kebab_case(mapFromRequired(input, "Icon name")),
|
||||
mapFileTypeFrom(input, "Icon type"),
|
||||
mapListFrom(input, "Categories"),
|
||||
mapListFrom(input, "Aliases")
|
||||
)
|
||||
|
||||
def from_update_issue_form(input: dict):
|
||||
try:
|
||||
name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
|
||||
metadata = load_metadata(name)
|
||||
|
||||
|
||||
return NormalIcon(
|
||||
mapUrlFromMarkdownImage(input, "Paste icon"),
|
||||
mapFromRequired(input, "Icon name"),
|
||||
mapFileTypeFrom(input, "Icon type"),
|
||||
metadata["categories"],
|
||||
metadata["aliases"]
|
||||
)
|
||||
except Exception as exeption:
|
||||
raise ValueError(f"Icon '{name}' does not exist", exeption)
|
||||
|
||||
def from_metadata_update_issue_form(input: dict):
|
||||
name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
|
||||
metadata = load_metadata(name)
|
||||
|
||||
return NormalIcon(
|
||||
None,
|
||||
name,
|
||||
metadata["base"],
|
||||
mapListFrom(input, "Categories"),
|
||||
mapListFrom(input, "Aliases")
|
||||
)
|
||||
|
||||
|
||||
|
||||
class MonochromeIcon(Icon):
|
||||
def __init__(self, lightIcon: str, darkIcon: str, name: str, type: str, categories: list, aliases: list):
|
||||
super().__init__(name, type, categories, aliases)
|
||||
self.lightIcon = lightIcon
|
||||
self.darkIcon = darkIcon
|
||||
|
||||
def to_colors(self) -> dict:
|
||||
try:
|
||||
metadata = load_metadata(self.name)
|
||||
return {
|
||||
"light": f"{metadata['colors']['light']}",
|
||||
"dark": f"{metadata['colors']['dark']}"
|
||||
}
|
||||
except:
|
||||
return {
|
||||
"light": f"{self.name}",
|
||||
"dark": f"{self.name}-dark"
|
||||
}
|
||||
|
||||
def to_metadata(self, author: dict) -> dict:
|
||||
metadata = super().to_metadata(author)
|
||||
metadata["colors"] = self.to_colors()
|
||||
return metadata
|
||||
|
||||
def convertions(self) -> list[IconConvertion]:
|
||||
colorNames = self.to_colors()
|
||||
return [
|
||||
IconConvertion(colorNames["light"], self.lightIcon),
|
||||
IconConvertion(colorNames["dark"], self.darkIcon),
|
||||
]
|
||||
|
||||
def from_addition_issue_form(input: dict):
|
||||
return MonochromeIcon(
|
||||
mapUrlFromMarkdownImage(input, "Paste light mode icon"),
|
||||
mapUrlFromMarkdownImage(input, "Paste dark mode icon"),
|
||||
convert_to_kebab_case(mapFromRequired(input, "Icon name")),
|
||||
mapFileTypeFrom(input, "Icon type"),
|
||||
mapListFrom(input, "Categories"),
|
||||
mapListFrom(input, "Aliases")
|
||||
)
|
||||
|
||||
def from_update_issue_form(input: dict):
|
||||
try:
|
||||
name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
|
||||
metadata = load_metadata(name)
|
||||
|
||||
return MonochromeIcon(
|
||||
mapUrlFromMarkdownImage(input, "Paste light mode icon"),
|
||||
mapUrlFromMarkdownImage(input, "Paste dark mode icon"),
|
||||
mapFromRequired(input, "Icon name"),
|
||||
mapFileTypeFrom(input, "Icon type"),
|
||||
metadata["categories"],
|
||||
metadata["aliases"]
|
||||
)
|
||||
except Exception as exeption:
|
||||
raise ValueError(f"Icon '{name}' does not exist", exeption)
|
||||
|
||||
def from_metadata_update_issue_form(input: dict):
|
||||
name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
|
||||
metadata = load_metadata(name)
|
||||
|
||||
return MonochromeIcon(
|
||||
None,
|
||||
None,
|
||||
name,
|
||||
metadata["base"],
|
||||
mapListFrom(input, "Categories"),
|
||||
mapListFrom(input, "Aliases")
|
||||
)
|
||||
|
||||
def checkType(type: str):
|
||||
if type not in ["normal", "monochrome"]:
|
||||
raise ValueError(f"Invalid icon type: '{type}'")
|
||||
return type
|
||||
|
||||
def checkAction(action: str):
|
||||
if action == "addition":
|
||||
return IssueFormType.ADDITION
|
||||
elif action == "update":
|
||||
return IssueFormType.UPDATE
|
||||
elif action == "metadata_update":
|
||||
return IssueFormType.METADATA_UPDATE
|
||||
raise ValueError(f"Invalid action: '{action}'")
|
||||
|
||||
class IssueFormType(Enum):
|
||||
ADDITION = "addition"
|
||||
UPDATE = "update"
|
||||
METADATA_UPDATE = "metadata_update"
|
||||
|
||||
def iconFactory(type: str, issue_form: str, issue_form_type: IssueFormType):
|
||||
if type == "normal":
|
||||
if (issue_form_type == IssueFormType.ADDITION):
|
||||
return NormalIcon.from_addition_issue_form(json.loads(issue_form))
|
||||
elif (issue_form_type == IssueFormType.UPDATE):
|
||||
return NormalIcon.from_update_issue_form(json.loads(issue_form))
|
||||
elif (issue_form_type == IssueFormType.METADATA_UPDATE):
|
||||
return NormalIcon.from_metadata_update_issue_form(json.loads(issue_form))
|
||||
else:
|
||||
raise ValueError(f"Invalid issue form type: '{issue_form_type}'")
|
||||
elif type == "monochrome":
|
||||
if (issue_form_type == IssueFormType.ADDITION):
|
||||
return MonochromeIcon.from_addition_issue_form(json.loads(issue_form))
|
||||
elif (issue_form_type == IssueFormType.UPDATE):
|
||||
return MonochromeIcon.from_update_issue_form(json.loads(issue_form))
|
||||
elif (issue_form_type == IssueFormType.METADATA_UPDATE):
|
||||
return MonochromeIcon.from_metadata_update_issue_form(json.loads(issue_form))
|
||||
else:
|
||||
raise ValueError(f"Invalid issue form type: '{issue_form_type}'")
|
||||
raise ValueError(f"Invalid icon type: '{type}'")
|
||||
|
||||
def mapFrom(input: dict, label: str) -> str:
|
||||
return input.get(label, None)
|
||||
|
||||
def mapFromRequired(input: dict, label: str) -> str:
|
||||
value = mapFrom(input, label)
|
||||
if value is None:
|
||||
raise ValueError(f"Missing required field: '{label}'")
|
||||
return value
|
||||
|
||||
def mapFileTypeFrom(input: dict, label: str) -> str:
|
||||
fileType = mapFromRequired(input, label)
|
||||
if fileType not in ["SVG", "PNG"]:
|
||||
raise ValueError(f"Invalid file type: '{fileType}'")
|
||||
return fileType.lower()
|
||||
|
||||
def mapListFrom(input: dict, label: str) -> list:
|
||||
stringList = mapFrom(input, label)
|
||||
if stringList is None:
|
||||
return []
|
||||
return list(map(str.strip, stringList.split(",")))
|
||||
|
||||
def mapUrlFromMarkdownImage(input: dict, label: str) -> re.Match[str]:
|
||||
markdown = mapFromRequired(input, label)
|
||||
try:
|
||||
return re.match(r"!\[[^\]]+\]\((https:[^\)]+)\)", markdown)[1]
|
||||
except IndexError:
|
||||
raise ValueError(f"Invalid markdown image: '{markdown}'")
|
||||
|
9
scripts/metadata.py
Normal file
9
scripts/metadata.py
Normal file
@ -0,0 +1,9 @@
|
||||
import json
|
||||
|
||||
|
||||
def load_metadata(icon_name: str) -> dict:
|
||||
try:
|
||||
with open(f"meta/{icon_name}.json", "r") as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
raise ValueError(f"Icon '{icon_name}' does not exist")
|
28
scripts/parse_issue_form.py
Normal file
28
scripts/parse_issue_form.py
Normal file
@ -0,0 +1,28 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
ISSUE_FORM_ITEM_LABEL = "###"
|
||||
ISSUE_EMPTY_RESPONSE = "_No response_"
|
||||
INPUT_ENV_VAR_NAME = "INPUT_ISSUE_BODY"
|
||||
|
||||
def parse_issue_form(input: str) -> dict:
|
||||
splitItems = input.split(ISSUE_FORM_ITEM_LABEL)
|
||||
# Remove first empty item
|
||||
splitItems.pop(0)
|
||||
parsedForm = dict()
|
||||
for item in splitItems:
|
||||
item = item.strip()
|
||||
itemLines = item.split("\n")
|
||||
itemName = itemLines[0].strip()
|
||||
itemValue = "\n".join(itemLines[1:]).strip()
|
||||
if itemValue == ISSUE_EMPTY_RESPONSE:
|
||||
itemValue = None
|
||||
parsedForm[itemName] = itemValue
|
||||
return parsedForm
|
||||
|
||||
def main(input: str):
|
||||
parsedIssueForm = parse_issue_form(input)
|
||||
print(json.dumps(parsedIssueForm))
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
main(os.getenv(INPUT_ENV_VAR_NAME))
|
14
scripts/print_icon_name.py
Normal file
14
scripts/print_icon_name.py
Normal file
@ -0,0 +1,14 @@
|
||||
import os
|
||||
import sys
|
||||
from icons import IssueFormType, checkAction, iconFactory, checkType
|
||||
|
||||
ISSUE_FORM_ENV_VAR = "INPUT_ISSUE_FORM"
|
||||
|
||||
def main(type: str, action: IssueFormType, issue_form: str):
|
||||
icon = iconFactory(type, issue_form, action)
|
||||
print(icon.name)
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
type = checkType(sys.argv[1])
|
||||
action = checkAction(sys.argv[2])
|
||||
main(type, action, os.getenv(ISSUE_FORM_ENV_VAR))
|
0
svg/beszel.svg
Normal file → Executable file
0
svg/beszel.svg
Normal file → Executable file
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Loading…
x
Reference in New Issue
Block a user