Skip to content

Commit

Permalink
Merge pull request #3 from merschformann/merschformann/fix-dependabot…
Browse files Browse the repository at this point in the history
…-alert-change-project-setup

Fix security issue in opencv dependency, rework project structure and workflows, fix overflow
  • Loading branch information
merschformann authored Sep 2, 2024
2 parents 16dbc23 + 67411fd commit 823bc56
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 121 deletions.
49 changes: 23 additions & 26 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,27 @@ name: build
on: [push]

jobs:
build:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]

runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install apt packages
run: sudo apt update && sudo apt-get install -y libgl1-mesa-glx
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff pytest
- name: Install project
run: pip install .
- name: lint with ruff
run: ruff check --output-format=github .
- name: Test with pytest
run: pytest
144 changes: 123 additions & 21 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,128 @@
name: publish

on:
release:
types: [created]
workflow_dispatch:
inputs:
VERSION:
description: "The version to release"
required: true
IS_PRE_RELEASE:
description: "It IS a pre-release"
required: true
default: false
type: boolean

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
bump: # This job is used to bump the version and create a release
runs-on: ubuntu-latest
env:
VERSION: ${{ inputs.VERSION }}
GH_TOKEN: ${{ github.token }}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
permissions:
contents: write
steps:
- name: set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: install dependencies
run: |
pip install --upgrade pip
pip install build hatch
- name: configure git with the bot credentials
run: |
mkdir -p ~/.ssh
ssh-keyscan github.com >> ~/.ssh/known_hosts
ssh-agent -a $SSH_AUTH_SOCK > /dev/null
ssh-add - <<< "${{ secrets.BOT_SSH_KEY }}"
echo "${{ secrets.BOT_SIGNING_KEY }}" > ~/.ssh/signing.key
chmod 600 ~/.ssh/signing.key
git config --global user.name "Merschbotmann"
git config --global user.email "bot.merschformann@gmail.com"
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/signing.key
git clone git@github.com:merschformann/brickmos.git
- name: upgrade version with hatch
run: hatch version ${{ env.VERSION }}
working-directory: ./brickmos

- name: commit new version
run: |
git add brickmos/__about__.py
git commit -S -m "Bump version to $VERSION"
git push
git tag $VERSION
git push origin $VERSION
working-directory: ./brickmos

- name: create release
run: |
PRERELEASE_FLAG=""
if [ ${{ inputs.IS_PRE_RELEASE }} = true ]; then
PRERELEASE_FLAG="--prerelease"
fi
gh release create $VERSION \
--verify-tag \
--generate-notes \
--title $VERSION $PRERELEASE_FLAG
working-directory: ./brickmos

- name: ensure passing build
run: python -m build
working-directory: ./brickmos

publish: # This job is used to publish the release to PyPI/TestPyPI
runs-on: ubuntu-latest
needs: bump
strategy:
matrix:
include:
- target-env: pypi
target-url: https://pypi.org/p/brickmos
- target-env: testpypi
target-url: https://test.pypi.org/p/brickmos
environment:
name: ${{ matrix.target-env }}
url: ${{ matrix.target-url }}
permissions:
contents: read
id-token: write # This is required for trusted publishing to PyPI
steps:
- name: git clone main
uses: actions/checkout@v4
with:
ref: main

- name: set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: install dependencies
run: |
pip install --upgrade pip
pip install build hatch
- name: build binary wheel and source tarball
run: python -m build

- name: Publish package distributions to PyPI
if: ${{ matrix.target-env == 'pypi' }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./dist

- name: Publish package distributions to TestPyPI
if: ${{ matrix.target-env == 'testpypi' }}
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: ./dist
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Ignore general python stuff
venv/
.venv/
__pycache__/
.pytest_cache/
*.egg-info/
Expand Down
1 change: 1 addition & 0 deletions brickmos/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "v0.0.4"
44 changes: 17 additions & 27 deletions brickmos/brickify.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from . import defaults
import argparse
import csv
import cv2
import math
import os
import sys
from typing import Tuple, List
import xml.etree.cElementTree as xmlET
import xml.etree.ElementTree as xmlET

import cv2

from . import defaults

# ===> Constants

Expand Down Expand Up @@ -111,24 +111,20 @@ def init_and_get_arguments():
sys.exit(-2)
# Get image size
try:
width, height = [int(a) for a in args.size.split("x")]
width, height = (int(a) for a in args.size.split("x"))
args.width = width
args.height = height
except Exception:
print(
f"Cannot parse --size argument. Got {args.size}, but wanted something like 48x48"
)
print(f"Cannot parse --size argument. Got {args.size}, but wanted something like 48x48")
sys.exit(-3)
# Get helper grid cell size
if args.grid_cell != NO_GRID:
try:
width, height = [int(a) for a in args.grid_cell.split("x")]
width, height = (int(a) for a in args.grid_cell.split("x"))
args.grid_cell_width = width
args.grid_cell_height = height
except Exception:
print(
f"Cannot parse --grid_cell argument. Got {args.grid_cell}, but wanted something like 8x8"
)
print(f"Cannot parse --grid_cell argument. Got {args.grid_cell}, but wanted something like 8x8")
sys.exit(-4)
# Get helper grid size
# Create output directory, if it does not exist
Expand All @@ -139,7 +135,7 @@ def init_and_get_arguments():
# ===> Functionality


def read_colors(color_csv: str) -> List[BrickColor]:
def read_colors(color_csv: str) -> list[BrickColor]:
"""
Reads the color CSV and returns the color definitions.
Expected CSV-format (with header, integer RGB): red,green,blue;color-name,bricklink-color-id,bricklink-brick-type
Expand All @@ -161,7 +157,7 @@ def read_colors(color_csv: str) -> List[BrickColor]:
return colors_read


def closest_color(rgb: Tuple[int, int, int], color_range: list) -> BrickColor:
def closest_color(rgb: tuple[int, int, int], color_range: list) -> BrickColor:
"""
Returns the color from the range which is closest to the given one.
:param rgb: The given color to fine the closest one for.
Expand All @@ -170,10 +166,12 @@ def closest_color(rgb: Tuple[int, int, int], color_range: list) -> BrickColor:
"""
# Get rgb values of color while adhering to cv2 BGR representation
r, g, b = rgb
r, g, b = float(r), float(g), float(b)
# Assess euclidean distance of color to all brick colors given
color_diffs = []
for color in color_range:
cr, cg, cb = color.rgb
cr, cg, cb = float(cr), float(cg), float(cb)
color_diff = math.sqrt(abs(r - cr) ** 2 + abs(g - cg) ** 2 + abs(b - cb) ** 2)
color_diffs.append((color_diff, color))
# Get color closest to the given one and update its stats
Expand Down Expand Up @@ -245,7 +243,7 @@ def main():
if args.color_file == "":
color_info = defaults.get_default_colors()
else:
with open(args.color_file, "r") as f:
with open(args.color_file) as f:
color_info = f.read()
colors = read_colors(color_info)

Expand All @@ -265,32 +263,24 @@ def main():
statistics = replace_with_brick_colors(image_bricks, colors)

# Initialize output image
image_output = cv2.resize(
image_bricks, (w_out, h_out), interpolation=cv2.INTER_NEAREST
)
image_output = cv2.resize(image_bricks, (w_out, h_out), interpolation=cv2.INTER_NEAREST)

# Add helper grid
grid_spacing = args.grid_cell_width, args.grid_cell_height
if args.grid_cell != NO_GRID:
add_grid(image_output, (w, h), grid_spacing)

# Show some statistics
print(
f"Colors ({len(statistics)} colors, {sum([i.count for i in statistics.values()])} tiles):"
)
print(f"Colors ({len(statistics)} colors, {sum([i.count for i in statistics.values()])} tiles):")
for item in sorted(statistics.items(), key=lambda x: -x[1].count):
print(f"{item[0].colorName}: {item[1].count}")

# Output bricklink xml
write_xml(os.path.join(args.output_directory, "bricklink.xml"), statistics)

# Prepare pixelated image for analysis (just resize it)
image_input = cv2.resize(
image_input, (w_out, h_out), interpolation=cv2.INTER_NEAREST
)
image_pixelated = cv2.resize(
image_pixelated, (w_out, h_out), interpolation=cv2.INTER_NEAREST
)
image_input = cv2.resize(image_input, (w_out, h_out), interpolation=cv2.INTER_NEAREST)
image_pixelated = cv2.resize(image_pixelated, (w_out, h_out), interpolation=cv2.INTER_NEAREST)

# Write images
cv2.imwrite(os.path.join(args.output_directory, "1.input.jpg"), image_input)
Expand Down
57 changes: 57 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[build-system]
build-backend = "hatchling.build"
requires = ["hatchling >= 1.13.0"]

[project]
authors = [
{ email = "marius.merschformann@gmail.com", name = "Marius Merschformann" }
]
maintainers = [
{ email = "marius.merschformann@gmail.com", name = "Marius Merschformann" }
]
classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
]
dependencies = [
"opencv-python>=4.8.1.78",
]
description = "brickmos is a humble Lego mosaic generator."
dynamic = [
"version",
]
keywords = [
"lego",
"mosaic",
"bricklink",
]
license = { file = "LICENSE" }
name = "brickmos"
readme = "README.md"
requires-python = ">=3.9"

[project.urls]
Homepage = "https://github.com/merschformann/brickmos"
Repository = "https://github.com/merschformann/brickmos"

[project.scripts]
brickmos = "brickmos.brickify:main"

[tool.ruff]
target-version = "py312"
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"C", # flake8-comprehensions
"B", # flake8-bugbear
"UP", # pyupgrade
]
line-length = 120
[tool.ruff.lint.mccabe]
max-complexity = 15

[tool.hatch.version]
path = "brickmos/__about__.py"
1 change: 0 additions & 1 deletion requirements.txt

This file was deleted.

Loading

0 comments on commit 823bc56

Please sign in to comment.