contribution-city 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- contribution_city-1.3.0/.github/workflows/tests.yml +170 -0
- contribution_city-1.3.0/.gitignore +38 -0
- contribution_city-1.3.0/CHANGELOG.md +132 -0
- contribution_city-1.3.0/IMPLEMENTATION_SUMMARY.md +122 -0
- contribution_city-1.3.0/LICENSE +21 -0
- contribution_city-1.3.0/PKG-INFO +382 -0
- contribution_city-1.3.0/README.md +349 -0
- contribution_city-1.3.0/action.yml +238 -0
- contribution_city-1.3.0/docs/gallery/contact-sheet.png +0 -0
- contribution_city-1.3.0/docs/gallery/manifest.json +5083 -0
- contribution_city-1.3.0/docs/gallery/new-in-1.2.png +0 -0
- contribution_city-1.3.0/docs/preview-compact.png +0 -0
- contribution_city-1.3.0/docs/preview-navy-cyan.png +0 -0
- contribution_city-1.3.0/docs/preview-profile-dark.png +0 -0
- contribution_city-1.3.0/docs/preview-profile-light.png +0 -0
- contribution_city-1.3.0/docs/visual-testing.md +109 -0
- contribution_city-1.3.0/examples/README.md +404 -0
- contribution_city-1.3.0/examples/config/all-options.yaml +62 -0
- contribution_city-1.3.0/examples/config/heights-and-angles.yaml +16 -0
- contribution_city-1.3.0/examples/config/solid.yaml +8 -0
- contribution_city-1.3.0/examples/config/transparent.yaml +9 -0
- contribution_city-1.3.0/examples/config.example.yaml +38 -0
- contribution_city-1.3.0/examples/sample-contributions.json +1831 -0
- contribution_city-1.3.0/examples/workflows/basic-city.yml +43 -0
- contribution_city-1.3.0/examples/workflows/customized-city.yml +38 -0
- contribution_city-1.3.0/examples/workflows/gallery-artifact.yml +44 -0
- contribution_city-1.3.0/examples/workflows/generate-profile-city.yml +87 -0
- contribution_city-1.3.0/examples/workflows/heights-and-angles.yml +35 -0
- contribution_city-1.3.0/examples/workflows/solid-city.yml +43 -0
- contribution_city-1.3.0/examples/workflows/transparent-city.yml +53 -0
- contribution_city-1.3.0/previews/README.md +33 -0
- contribution_city-1.3.0/previews/backgrounds/README.md +12 -0
- contribution_city-1.3.0/previews/backgrounds/auto-with-auto-appearance.on-checkerboard.svg +716 -0
- contribution_city-1.3.0/previews/backgrounds/auto-with-auto-appearance.svg +711 -0
- contribution_city-1.3.0/previews/backgrounds/solid.svg +712 -0
- contribution_city-1.3.0/previews/backgrounds/transparent-sky.on-checkerboard.svg +716 -0
- contribution_city-1.3.0/previews/backgrounds/transparent-sky.svg +711 -0
- contribution_city-1.3.0/previews/backgrounds/transparent.on-checkerboard.svg +661 -0
- contribution_city-1.3.0/previews/backgrounds/transparent.svg +656 -0
- contribution_city-1.3.0/previews/building-styles/README.md +11 -0
- contribution_city-1.3.0/previews/building-styles/detailed.svg +834 -0
- contribution_city-1.3.0/previews/building-styles/solid.svg +510 -0
- contribution_city-1.3.0/previews/heights/README.md +13 -0
- contribution_city-1.3.0/previews/heights/custom-scale-1-5-max-90.svg +892 -0
- contribution_city-1.3.0/previews/heights/standard-linear.svg +642 -0
- contribution_city-1.3.0/previews/heights/standard-log.svg +824 -0
- contribution_city-1.3.0/previews/heights/standard-sqrt.svg +798 -0
- contribution_city-1.3.0/previews/heights/standard.svg +712 -0
- contribution_city-1.3.0/previews/heights/tall-custom.svg +834 -0
- contribution_city-1.3.0/previews/heights/tall-linear.svg +778 -0
- contribution_city-1.3.0/previews/heights/tall-log.svg +914 -0
- contribution_city-1.3.0/previews/heights/tall-sqrt.svg +906 -0
- contribution_city-1.3.0/previews/layouts/README.md +12 -0
- contribution_city-1.3.0/previews/layouts/compact.svg +710 -0
- contribution_city-1.3.0/previews/layouts/dense-grid.svg +712 -0
- contribution_city-1.3.0/previews/layouts/downtown.svg +712 -0
- contribution_city-1.3.0/previews/layouts/floating-island.svg +719 -0
- contribution_city-1.3.0/previews/layouts/wireframe.svg +578 -0
- contribution_city-1.3.0/previews/manifest.json +798 -0
- contribution_city-1.3.0/previews/themes/README.md +14 -0
- contribution_city-1.3.0/previews/themes/arctic-glass.svg +704 -0
- contribution_city-1.3.0/previews/themes/copper-forge.svg +704 -0
- contribution_city-1.3.0/previews/themes/cyberpunk.svg +704 -0
- contribution_city-1.3.0/previews/themes/emerald-matrix.svg +704 -0
- contribution_city-1.3.0/previews/themes/matrix-green.svg +704 -0
- contribution_city-1.3.0/previews/themes/monochrome-slate.svg +704 -0
- contribution_city-1.3.0/previews/themes/navy-cyan-light.svg +704 -0
- contribution_city-1.3.0/previews/themes/navy-cyan.svg +704 -0
- contribution_city-1.3.0/previews/themes/neon-harbor.svg +704 -0
- contribution_city-1.3.0/previews/themes/profile-light.svg +704 -0
- contribution_city-1.3.0/previews/themes/profile.svg +704 -0
- contribution_city-1.3.0/previews/themes/solar-amber.svg +704 -0
- contribution_city-1.3.0/previews/themes/sunset-grid.svg +704 -0
- contribution_city-1.3.0/previews/themes/sunset-neon.svg +704 -0
- contribution_city-1.3.0/previews/viewing-angles/README.md +12 -0
- contribution_city-1.3.0/previews/viewing-angles/high.svg +682 -0
- contribution_city-1.3.0/previews/viewing-angles/low.svg +738 -0
- contribution_city-1.3.0/previews/viewing-angles/standard-isometric.svg +712 -0
- contribution_city-1.3.0/previews/viewing-angles/top-down.svg +628 -0
- contribution_city-1.3.0/pyproject.toml +81 -0
- contribution_city-1.3.0/src/contribution_city/__init__.py +15 -0
- contribution_city-1.3.0/src/contribution_city/_version.py +3 -0
- contribution_city-1.3.0/src/contribution_city/cli.py +475 -0
- contribution_city-1.3.0/src/contribution_city/config.py +345 -0
- contribution_city-1.3.0/src/contribution_city/github_api.py +267 -0
- contribution_city-1.3.0/src/contribution_city/models.py +322 -0
- contribution_city-1.3.0/src/contribution_city/previews.py +556 -0
- contribution_city-1.3.0/src/contribution_city/renderer/__init__.py +14 -0
- contribution_city-1.3.0/src/contribution_city/renderer/geometry.py +98 -0
- contribution_city-1.3.0/src/contribution_city/renderer/layouts.py +102 -0
- contribution_city-1.3.0/src/contribution_city/renderer/palettes.py +106 -0
- contribution_city-1.3.0/src/contribution_city/renderer/presets.py +113 -0
- contribution_city-1.3.0/src/contribution_city/renderer/svg.py +849 -0
- contribution_city-1.3.0/src/contribution_city/renderer/themes.py +489 -0
- contribution_city-1.3.0/src/contribution_city/svgcheck.py +126 -0
- contribution_city-1.3.0/src/contribution_city/visual/__init__.py +17 -0
- contribution_city-1.3.0/src/contribution_city/visual/baseline.py +167 -0
- contribution_city-1.3.0/src/contribution_city/visual/cases.py +449 -0
- contribution_city-1.3.0/src/contribution_city/visual/cli.py +234 -0
- contribution_city-1.3.0/src/contribution_city/visual/compare.py +179 -0
- contribution_city-1.3.0/src/contribution_city/visual/fixtures.py +143 -0
- contribution_city-1.3.0/src/contribution_city/visual/gallery.py +178 -0
- contribution_city-1.3.0/src/contribution_city/visual/render.py +62 -0
- contribution_city-1.3.0/tests/conftest.py +11 -0
- contribution_city-1.3.0/tests/data/v110/reference.json +669 -0
- contribution_city-1.3.0/tests/snapshots/tiny_default.svg +121 -0
- contribution_city-1.3.0/tests/test_action.py +307 -0
- contribution_city-1.3.0/tests/test_action_execution.py +327 -0
- contribution_city-1.3.0/tests/test_backgrounds.py +146 -0
- contribution_city-1.3.0/tests/test_cli.py +176 -0
- contribution_city-1.3.0/tests/test_cli_v12.py +198 -0
- contribution_city-1.3.0/tests/test_config.py +329 -0
- contribution_city-1.3.0/tests/test_docs_and_examples.py +614 -0
- contribution_city-1.3.0/tests/test_github_api.py +265 -0
- contribution_city-1.3.0/tests/test_models.py +241 -0
- contribution_city-1.3.0/tests/test_renderer.py +132 -0
- contribution_city-1.3.0/tests/test_renderer_features.py +207 -0
- contribution_city-1.3.0/tests/test_svg_quality.py +176 -0
- contribution_city-1.3.0/tests/test_themes_layouts.py +324 -0
- contribution_city-1.3.0/tests/test_v13_options.py +464 -0
- contribution_city-1.3.0/tests/test_visual_regression.py +480 -0
- contribution_city-1.3.0/tests/test_workflows.py +94 -0
- contribution_city-1.3.0/tests/visual/README.md +9 -0
- contribution_city-1.3.0/tests/visual/baselines/background-transparent-sky.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/background-transparent.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/custom-size.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fit-off.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-empty.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-extreme.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-isolated-peaks.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-long-streak.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-minimal.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-special-chars.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/fixture-uniform.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/height-linear.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/height-log.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/height-sqrt.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/index.json +264 -0
- contribution_city-1.3.0/tests/visual/baselines/layout-compact.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/layout-dense-grid.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/layout-downtown.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/layout-floating-island.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/layout-wireframe.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/preset-custom.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/preset-tall.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/range-2024-q4.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/style-solid-tall.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/style-solid.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-arctic-glass.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-copper-forge.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-cyberpunk.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-emerald-matrix.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-matrix-green.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-monochrome-slate.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-navy-cyan-light.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-navy-cyan.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-neon-harbor.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-profile-light.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-profile.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-solar-amber.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-sunset-grid.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/theme-sunset-neon.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/view-high-floating-island.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/view-high.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/view-low.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/view-top-down.png +0 -0
- contribution_city-1.3.0/tests/visual/baselines/year-2025.png +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
name: Tests and Quality Checks
|
|
2
|
+
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
|
|
6
|
+
concurrency:
|
|
7
|
+
group: tests-${{ github.ref }}
|
|
8
|
+
cancel-in-progress: true
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main]
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [main]
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
name: Lint & Format Check (Ruff)
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
|
|
30
|
+
- name: Install Ruff
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install --upgrade pip
|
|
33
|
+
pip install ".[dev]"
|
|
34
|
+
|
|
35
|
+
- name: Check code formatting and linting
|
|
36
|
+
run: |
|
|
37
|
+
ruff check .
|
|
38
|
+
ruff format --check .
|
|
39
|
+
|
|
40
|
+
test:
|
|
41
|
+
name: Test Suite (Python ${{ matrix.python-version }} on ${{ matrix.os }})
|
|
42
|
+
needs: lint
|
|
43
|
+
runs-on: ${{ matrix.os }}
|
|
44
|
+
strategy:
|
|
45
|
+
fail-fast: false
|
|
46
|
+
matrix:
|
|
47
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
48
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- name: Checkout repository
|
|
52
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
53
|
+
|
|
54
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
55
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
56
|
+
with:
|
|
57
|
+
python-version: ${{ matrix.python-version }}
|
|
58
|
+
cache: "pip"
|
|
59
|
+
|
|
60
|
+
- name: Install dependencies and package
|
|
61
|
+
run: |
|
|
62
|
+
python -m pip install --upgrade pip
|
|
63
|
+
pip install ".[dev]"
|
|
64
|
+
|
|
65
|
+
# Pixel comparisons against the approved baselines run once, in the "visual" job below,
|
|
66
|
+
# so a font or renderer difference on one operating system cannot fail the whole matrix.
|
|
67
|
+
- name: Run test suite with pytest
|
|
68
|
+
run: |
|
|
69
|
+
pytest --tb=short -m "not baseline"
|
|
70
|
+
|
|
71
|
+
- name: Verify CLI executable works
|
|
72
|
+
run: |
|
|
73
|
+
contribution-city generate --input examples/sample-contributions.json --theme navy-cyan --output dist/ci-test.svg
|
|
74
|
+
test -f dist/ci-test.svg || exit 1
|
|
75
|
+
shell: bash
|
|
76
|
+
|
|
77
|
+
- name: Test composite action directly
|
|
78
|
+
if: runner.os == 'Linux' && matrix.python-version == '3.12'
|
|
79
|
+
uses: ./
|
|
80
|
+
with:
|
|
81
|
+
input: examples/sample-contributions.json
|
|
82
|
+
theme: profile
|
|
83
|
+
appearance: auto
|
|
84
|
+
layout: compact
|
|
85
|
+
height-mode: linear
|
|
86
|
+
transparent: "true"
|
|
87
|
+
output: dist/composite-action-test.svg
|
|
88
|
+
|
|
89
|
+
- name: Check generated SVG is well-formed XML
|
|
90
|
+
if: runner.os == 'Linux' && matrix.python-version == '3.12'
|
|
91
|
+
run: python -c "import xml.dom.minidom as m; m.parse('dist/composite-action-test.svg'); print('well-formed')"
|
|
92
|
+
shell: bash
|
|
93
|
+
|
|
94
|
+
- name: Verify composite action output was generated
|
|
95
|
+
if: runner.os == 'Linux' && matrix.python-version == '3.12'
|
|
96
|
+
run: |
|
|
97
|
+
test -f dist/composite-action-test.svg || exit 1
|
|
98
|
+
shell: bash
|
|
99
|
+
|
|
100
|
+
visual:
|
|
101
|
+
name: Visual regression and gallery
|
|
102
|
+
needs: lint
|
|
103
|
+
runs-on: ubuntu-latest
|
|
104
|
+
steps:
|
|
105
|
+
- name: Checkout repository
|
|
106
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
107
|
+
|
|
108
|
+
- name: Set up Python
|
|
109
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
110
|
+
with:
|
|
111
|
+
python-version: "3.12"
|
|
112
|
+
cache: "pip"
|
|
113
|
+
|
|
114
|
+
- name: Install dependencies and package
|
|
115
|
+
run: |
|
|
116
|
+
python -m pip install --upgrade pip
|
|
117
|
+
pip install ".[dev]"
|
|
118
|
+
|
|
119
|
+
- name: Compare renders with the approved baselines
|
|
120
|
+
run: |
|
|
121
|
+
contribution-city visual check --baseline-dir tests/visual/baselines --artifacts-dir visual-artifacts
|
|
122
|
+
pytest --tb=short -m baseline
|
|
123
|
+
|
|
124
|
+
- name: Upload comparison artifacts (only when the comparison fails)
|
|
125
|
+
if: failure()
|
|
126
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
127
|
+
with:
|
|
128
|
+
name: visual-regression-failures
|
|
129
|
+
path: visual-artifacts/
|
|
130
|
+
if-no-files-found: ignore
|
|
131
|
+
retention-days: 7
|
|
132
|
+
|
|
133
|
+
- name: Check that previews/ and the README grids are up to date
|
|
134
|
+
run: contribution-city previews --check --readme README.md
|
|
135
|
+
|
|
136
|
+
- name: Generate the preview gallery
|
|
137
|
+
if: always()
|
|
138
|
+
run: |
|
|
139
|
+
contribution-city gallery --output-dir gallery --fail-on-error
|
|
140
|
+
contribution-city check-svg gallery/svg/*.svg
|
|
141
|
+
|
|
142
|
+
- name: Upload the gallery (contact sheet, manifest, SVGs, thumbnails)
|
|
143
|
+
if: always()
|
|
144
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
145
|
+
with:
|
|
146
|
+
name: contribution-city-gallery
|
|
147
|
+
path: gallery/
|
|
148
|
+
if-no-files-found: ignore
|
|
149
|
+
retention-days: 14
|
|
150
|
+
|
|
151
|
+
build:
|
|
152
|
+
name: Build package
|
|
153
|
+
needs: lint
|
|
154
|
+
runs-on: ubuntu-latest
|
|
155
|
+
steps:
|
|
156
|
+
- name: Checkout repository
|
|
157
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
158
|
+
|
|
159
|
+
- name: Set up Python
|
|
160
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
161
|
+
with:
|
|
162
|
+
python-version: "3.12"
|
|
163
|
+
|
|
164
|
+
- name: Build wheel and check the reported version
|
|
165
|
+
run: |
|
|
166
|
+
python -m pip install --upgrade pip
|
|
167
|
+
pip wheel . --no-deps -w wheelhouse
|
|
168
|
+
pip install wheelhouse/*.whl
|
|
169
|
+
contribution-city --version
|
|
170
|
+
python -c "import contribution_city; print(contribution_city.__version__)"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
ENV/
|
|
16
|
+
|
|
17
|
+
# Testing and coverage
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
|
|
23
|
+
# IDE files
|
|
24
|
+
.vscode/
|
|
25
|
+
.idea/
|
|
26
|
+
|
|
27
|
+
# Local generated output
|
|
28
|
+
output/
|
|
29
|
+
*.svg.tmp
|
|
30
|
+
|
|
31
|
+
# Generated by `contribution-city gallery` and `contribution-city visual check`
|
|
32
|
+
# (docs/gallery/ holds the small curated copies that ARE committed)
|
|
33
|
+
/gallery/
|
|
34
|
+
/visual-artifacts/
|
|
35
|
+
/wheelhouse/
|
|
36
|
+
dist/
|
|
37
|
+
|
|
38
|
+
.venv-v13/
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.3.0 (2026-11-15)
|
|
4
|
+
|
|
5
|
+
### Changed - please read
|
|
6
|
+
- **The default building height is now the `standard` preset.** Buildings are proportionate to the
|
|
7
|
+
platform (at most about three tiles high) instead of the towers of 1.0 to 1.2. This changes the
|
|
8
|
+
look of every default render.
|
|
9
|
+
- To get the previous look exactly: `--height-preset tall` (action input `height-preset: tall`,
|
|
10
|
+
YAML `city.height_preset: tall`).
|
|
11
|
+
- **Existing configurations that set `building_scale`, `min_building_height` or
|
|
12
|
+
`max_building_height` without a preset are not reinterpreted:** they select the new `custom`
|
|
13
|
+
preset, which is the 1.2.0 look with their numbers.
|
|
14
|
+
- The preset (overall height profile) and the existing `--height-mode` (power, linear, sqrt, log;
|
|
15
|
+
the curve inside the profile) are independent settings.
|
|
16
|
+
- The Python defaults of `building_scale`, `min_building_height` and `max_building_height` in
|
|
17
|
+
`RenderConfig` / `CitySettings` are now `None` ("use the preset") instead of 1.0 / 6.0 / 125.0. Code
|
|
18
|
+
that passes these values explicitly behaves as before.
|
|
19
|
+
- `examples/config.example.yaml` now shows `height_preset` instead of the three explicit numbers.
|
|
20
|
+
- The example workflows use `background:` instead of the legacy `transparent:` input.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Height presets:** `standard` (default), `tall` (the 1.0-1.2 look), `custom`
|
|
24
|
+
(`--height-preset`, action input `height-preset`, YAML `city.height_preset`), plus
|
|
25
|
+
`--min-building-height` / `--max-building-height` and validated limits for every height setting
|
|
26
|
+
(scale 0.1-5, minimum 0-40, maximum 8-400, canvas 100-10000 px).
|
|
27
|
+
- **Building styles:** `--building-style detailed|solid`. `solid` draws plain boxes with three
|
|
28
|
+
shades: no windows, no rooftop beacons, no outlines. Works with every theme, layout, preset and view.
|
|
29
|
+
- **Viewing angles:** `--view-angle isometric|low|high|top-down` (30, 20, 42 and 58 degrees of
|
|
30
|
+
camera elevation) and `--view-elevation DEGREES` (10-70). The projection, building heights,
|
|
31
|
+
platform, island and windows follow the camera; the default `isometric` view is byte-identical to
|
|
32
|
+
1.2.0.
|
|
33
|
+
- **Preview gallery:** `previews/` with about 40 SVGs (themes, layouts, heights, building styles,
|
|
34
|
+
viewing angles, backgrounds), a README index per category, `manifest.json`, and the four preview
|
|
35
|
+
grids in the root README, all generated by the real renderer from deterministic sample data
|
|
36
|
+
(`contribution-city previews`, with `--check` for CI). Transparent previews have
|
|
37
|
+
`*.on-checkerboard.svg` companions; the real files stay transparent.
|
|
38
|
+
- **Examples:** a complete customization guide (`examples/README.md`) and ready-to-copy workflows
|
|
39
|
+
(`basic-city`, `customized-city`, `solid-city`, `heights-and-angles`, `transparent-city`) and
|
|
40
|
+
configurations (`examples/config/`). Tests check that every workflow and every snippet in the guide
|
|
41
|
+
uses only real action inputs with valid values.
|
|
42
|
+
- Action inputs: `height-preset`, `scale` (extended), `min-building-height`, `max-building-height`,
|
|
43
|
+
`building-style`, `view-angle`, `view-elevation`, with early validation of the enumerated values.
|
|
44
|
+
- 70+ new visual cases and 43 approved baselines (was 35).
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- On very small canvases the city could overflow: the fit scale was clamped at 0.5. It now shrinks as
|
|
48
|
+
far as needed (tests: every angle x layout x preset x canvas size stays inside the image).
|
|
49
|
+
- Configuration validation hardening: non-finite and out-of-range tile dimensions are rejected, and
|
|
50
|
+
null, boolean, and invalid non-integer canvas dimensions are rejected with clean ConfigError messages.
|
|
51
|
+
|
|
52
|
+
### Compatibility
|
|
53
|
+
- For the same options, `--height-preset tall` reproduces 1.2.0 (and 1.1.0) output byte for byte, for
|
|
54
|
+
every theme and for the calendar and compact layouts (tested against references generated from the
|
|
55
|
+
1.1.0 source). Layout names, theme names, height modes, background behaviour and every CLI option of
|
|
56
|
+
1.2.0 are unchanged.
|
|
57
|
+
|
|
58
|
+
## 1.2.0 (2026-10-27)
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
- **Themes:** `neon-harbor`, `cyberpunk`, `emerald-matrix`, `copper-forge`, `arctic-glass`,
|
|
62
|
+
`sunset-grid`. They are plain data in `renderer/palettes.py`; tests check text contrast, level
|
|
63
|
+
separation and window visibility for each.
|
|
64
|
+
- **Layouts:** `dense-grid`, `downtown`, `floating-island`, `wireframe`, from a small layout registry
|
|
65
|
+
(`renderer/layouts.py`). `calendar` and `compact` are unchanged.
|
|
66
|
+
- **Background modes:** `--background solid | transparent | transparent-sky | auto` (config
|
|
67
|
+
`city.background`, action input `background`). It takes precedence over the legacy `transparent`
|
|
68
|
+
flag, which keeps working; contradictory settings warn.
|
|
69
|
+
- **Visual regression suite:** deterministic fixtures, a case registry generated from the theme and
|
|
70
|
+
layout registries, resvg-based PNG rendering, tolerance-based comparison that separates
|
|
71
|
+
antialiasing noise from real changes, approved baselines, failure artifacts (current, baseline,
|
|
72
|
+
diff, side-by-side, JSON) and an explicit `visual approve --yes` command. Baselines are never
|
|
73
|
+
written by tests or CI.
|
|
74
|
+
- **Gallery:** `contribution-city gallery` writes SVGs, PNG thumbnails, a labelled contact sheet and a
|
|
75
|
+
deterministic `manifest.json` (settings, validation status, transparency probe, removed duplicates).
|
|
76
|
+
- **`check-svg` command and `svgcheck` module:** well-formed XML, unique ids, resolving references,
|
|
77
|
+
no external resources or active content, matching viewBox.
|
|
78
|
+
- **`--id-prefix`:** namespaces element ids and scopes the CSS so several SVGs can be inlined in one
|
|
79
|
+
page. Without it the ids are exactly the 1.1.0 ones.
|
|
80
|
+
- **Offline `--year`, `--from`, `--to`** now filter `--input` files as well as live data.
|
|
81
|
+
- Action: inputs `background` and `id-prefix`; early validation of `layout`, `appearance`,
|
|
82
|
+
`background`, `height-mode`; local execution tests of the real script (including hostile values).
|
|
83
|
+
- CI: a `visual` job (baseline comparison, gallery, SVG checks, artifacts) and a `build` job that
|
|
84
|
+
checks the reported version. Example `gallery-artifact.yml` (read-only permissions).
|
|
85
|
+
|
|
86
|
+
### Changed
|
|
87
|
+
- Default output is byte-identical to 1.1.0 for the same input and options (tested against
|
|
88
|
+
references generated from the 1.1.0 source).
|
|
89
|
+
- CLI help lists themes and layouts from the registries.
|
|
90
|
+
- Window contrast of three palettes added in this cycle was raised after the contrast tests found it
|
|
91
|
+
too low (`neon-harbor`, `emerald-matrix`, `arctic-glass`).
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
- The gallery records a case with invalid options as `failed` instead of stopping.
|
|
95
|
+
|
|
96
|
+
## 1.1.0
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
- **SVG escaping:** `custom_title` and the username were written into the SVG unescaped, which could
|
|
100
|
+
produce invalid XML (a broken image) or inject markup. All text is now escaped.
|
|
101
|
+
- **Shell injection in `action.yml`:** inputs were pasted into the bash script. They now reach the
|
|
102
|
+
script only through environment variables, and the token is no longer passed on the command line.
|
|
103
|
+
- **Version and name mismatches:** the version now lives in one place (`_version.py`) and is used by
|
|
104
|
+
the package, the build and the HTTP User-Agent. Docs, example workflow, license and author point
|
|
105
|
+
at `partialHuman/contribution-city`.
|
|
106
|
+
- **README** contained the whole document twice; it now exists once.
|
|
107
|
+
- **`isometric` layout** was only an alias of `calendar`. It was removed from the CLI, the action and
|
|
108
|
+
the config (a helpful error explains that `calendar` is the isometric view).
|
|
109
|
+
- **Streaks** no longer treat missing dates in custom data as consecutive days.
|
|
110
|
+
|
|
111
|
+
### Added
|
|
112
|
+
- **Auto-fit:** the city is scaled to fill the canvas (`auto_fit`, `--no-fit` to turn it off).
|
|
113
|
+
- **Light and dark:** `appearance: auto` embeds a light palette and follows `prefers-color-scheme`;
|
|
114
|
+
`transparent` removes the background. New themes: `profile`, `profile-light`, `navy-cyan-light`.
|
|
115
|
+
- **Height modes:** `power` (default), `linear` (proportional), `sqrt`, `log`.
|
|
116
|
+
- **Date ranges and several years:** `--year` (repeatable), `--from`, `--to`.
|
|
117
|
+
- **Private contributions:** the count of restricted contributions is read and shown in the header.
|
|
118
|
+
- **Retries** with exponential back-off for network errors, 5xx responses and secondary rate limits.
|
|
119
|
+
- **Accessibility:** root `<title>`, `<desc>` and `role="img"` with totals.
|
|
120
|
+
- **Pixel-art edges** (`crispEdges`) by default (`--smooth` to turn off).
|
|
121
|
+
- `compact` layout leaves a tile between buildings so towers no longer hide each other.
|
|
122
|
+
- Example workflow publishes to an `output` branch (one commit, no history growth) and shows the
|
|
123
|
+
light/dark `<picture>` setup. Third-party actions are pinned to commit SHAs.
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
- Smaller files: empty tiles are one path with no tooltip, styling uses CSS classes, and windows are
|
|
127
|
+
four paths per building instead of a line each. The sample city went from about 308 KB to about
|
|
128
|
+
140 KB.
|
|
129
|
+
- Raising the canvas size now enlarges the city (it used to stay at a fixed 18 px tile size).
|
|
130
|
+
|
|
131
|
+
## 1.0.0
|
|
132
|
+
- Initial release.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Implementation summary: Contribution City 1.3.0
|
|
2
|
+
|
|
3
|
+
Built from the 1.2.0 release archive. Everything below was implemented in the source and checked
|
|
4
|
+
by running the commands listed under [Verification](#verification).
|
|
5
|
+
|
|
6
|
+
## Read this first
|
|
7
|
+
|
|
8
|
+
- **The reference SVGs and screenshots mentioned in the task did not arrive** (only the 1.2.0 ZIP was
|
|
9
|
+
attached). The *standard* height preset, the solid style and the angle presets were therefore
|
|
10
|
+
designed from the proportions described in the task and from the renderer's own geometry, not
|
|
11
|
+
matched to the images. The values are data in one file
|
|
12
|
+
([`renderer/presets.py`](src/contribution_city/renderer/presets.py)) if you want to tune them to
|
|
13
|
+
your reference: `STANDARD` (min 3, max 56, growth 3.8, against the old 6 / 125 / 8.5) and
|
|
14
|
+
`VIEW_ANGLES` (30, 20, 42 and 58 degrees).
|
|
15
|
+
- **The default look changes** (standard heights). The old look is `--height-preset tall`.
|
|
16
|
+
Configurations with explicit `building_scale` / `min_building_height` / `max_building_height` are
|
|
17
|
+
not reinterpreted. See [Backward compatibility](#backward-compatibility).
|
|
18
|
+
|
|
19
|
+
## What was added
|
|
20
|
+
|
|
21
|
+
| Area | New | Where |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Heights | Presets `standard` (default), `tall`, `custom`; `--min-building-height`, `--max-building-height`; validated limits | `renderer/presets.py`, `renderer/svg.py`, `config.py`, `cli.py` |
|
|
24
|
+
| Building style | `--building-style detailed\|solid` (solid: no windows, beacons or outlines; three shades) | `renderer/svg.py` |
|
|
25
|
+
| Viewing angle | `--view-angle isometric\|low\|high\|top-down`, `--view-elevation 10-70` | `renderer/svg.py`, `renderer/presets.py` |
|
|
26
|
+
| Gallery | `previews/` (41 SVGs in 6 categories, a README per category, `manifest.json`), four grids in the root README, `contribution-city previews [--check]` | `previews.py`, `previews/`, `README.md` |
|
|
27
|
+
| Examples | `examples/README.md` (19-section guide), 5 new workflows, 4 new configurations | `examples/` |
|
|
28
|
+
| Action | inputs `height-preset`, `min-building-height`, `max-building-height`, `building-style`, `view-angle`, `view-elevation`, early validation | `action.yml` |
|
|
29
|
+
| Tests | 382 new tests (568 in 1.2.0, 950 collected now) | `tests/` |
|
|
30
|
+
| Release | version 1.3.0, changelog section, CI job for gallery freshness | `_version.py`, `CHANGELOG.md`, `.github/workflows/tests.yml` |
|
|
31
|
+
|
|
32
|
+
### Preset versus mode
|
|
33
|
+
|
|
34
|
+
- **Height preset** = the overall profile (how tall the tallest building may be, and the growth rate).
|
|
35
|
+
- **Height mode** (`power`, `linear`, `sqrt`, `log`, unchanged) = the curve from a day's count to a
|
|
36
|
+
height inside that profile. All four modes work with all presets (tested).
|
|
37
|
+
|
|
38
|
+
### Defaults, identical in the CLI, YAML and the action
|
|
39
|
+
|
|
40
|
+
| Setting | Default |
|
|
41
|
+
|---|---|
|
|
42
|
+
| height preset | `standard` (it stays unset and becomes `custom` only if scale or min/max are set without a preset) |
|
|
43
|
+
| height mode | `power` |
|
|
44
|
+
| building style | `detailed` |
|
|
45
|
+
| view angle | `isometric` |
|
|
46
|
+
| layout / theme / background | `calendar` / `navy-cyan` / `solid` |
|
|
47
|
+
|
|
48
|
+
A test renders once with the CLI, once with a YAML file and once from Python with nothing set and
|
|
49
|
+
requires identical SVGs; another does the same for every new option.
|
|
50
|
+
|
|
51
|
+
## Backward compatibility
|
|
52
|
+
|
|
53
|
+
- With `--height-preset tall`, output is **byte-identical to 1.2.0 and 1.1.0** for every original
|
|
54
|
+
theme in the calendar and compact layouts and for the other tested options (23 reference renders
|
|
55
|
+
generated from the original 1.1.0 source). The default `isometric` view is byte-identical to 1.2.0.
|
|
56
|
+
- Explicit legacy height values keep their look: `RenderConfig(building_scale=1.0)` equals `tall`.
|
|
57
|
+
- No theme, layout, height mode, background mode or CLI option was removed or renamed.
|
|
58
|
+
- Python API change: the defaults of `building_scale`, `min_building_height` and
|
|
59
|
+
`max_building_height` in `RenderConfig` / `CitySettings` are `None` ("use the preset") rather than
|
|
60
|
+
1.0 / 6.0 / 125.0. Code that passes them explicitly is unaffected.
|
|
61
|
+
|
|
62
|
+
## A bug found and fixed while testing
|
|
63
|
+
|
|
64
|
+
On small canvases the auto-fit scale was clamped at 0.5, so the city could overflow the image. It
|
|
65
|
+
now shrinks as far as needed (regression tests cover every angle x layout x preset x canvas size).
|
|
66
|
+
|
|
67
|
+
## Verification
|
|
68
|
+
|
|
69
|
+
Run in a clean copy of the final tree (Python 3.12.3, resvg-py 0.5.0, Pillow 13.0.0, Linux):
|
|
70
|
+
|
|
71
|
+
| Command | Result |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `pytest` | **949 passed, 1 skipped** (950 collected). The skip is intentional: one 1.1.0 reference sets `building_scale`, and a separate test covers that case. |
|
|
74
|
+
| `pytest -m baseline` / `-m "not baseline"` | 46 passed / 903 passed, 1 skipped |
|
|
75
|
+
| `ruff check .` | All checks passed |
|
|
76
|
+
| `ruff format --check .` | 53 files already formatted |
|
|
77
|
+
| `pip wheel . --no-deps` | `contribution_city-1.3.0-py3-none-any.whl` built; installed into a fresh virtual environment, `contribution-city --version` prints `1.3.0`, `contribution_city.__version__` is `1.3.0` |
|
|
78
|
+
| CLI smoke tests from the installed wheel | 26 runs covering every preset, mode, style, view angle, background mode and layout: 26 ok, 0 failed. Invalid values print readable errors. |
|
|
79
|
+
| `contribution-city check-svg` on those 26 outputs | all OK |
|
|
80
|
+
| `contribution-city previews --check --readme README.md` | up to date (files and README grids) |
|
|
81
|
+
| `contribution-city visual check` | 43 compared, 43 match |
|
|
82
|
+
| `contribution-city gallery --fail-on-error` | 66 cases: 66 ok, 0 invalid, 0 failed |
|
|
83
|
+
| Link test | every relative link and image in the READMEs, the guide and the preview indexes resolves |
|
|
84
|
+
|
|
85
|
+
### Not run, and why
|
|
86
|
+
|
|
87
|
+
- **The workflows were not executed on GitHub** (no GitHub access here). What was run: the action's real
|
|
88
|
+
bash script locally with controlled inputs (including hostile values), plus structural tests that
|
|
89
|
+
every `with:` key exists in `action.yml`, values are valid, third-party actions are pinned, permissions
|
|
90
|
+
are minimal and committing workflows cannot trigger themselves.
|
|
91
|
+
- **Image links were checked locally** (the files exist at the relative paths); how GitHub renders them
|
|
92
|
+
was not observed.
|
|
93
|
+
- **No browser test** of `prefers-color-scheme` inside `<img>`; the docs recommend the `<picture>` method
|
|
94
|
+
for GitHub.
|
|
95
|
+
- The pixel baselines were produced and compared on Linux with one renderer version.
|
|
96
|
+
- `@v1` in the examples resolves only after you publish the release and create or move the `v1` tag.
|
|
97
|
+
|
|
98
|
+
## Known limitations
|
|
99
|
+
|
|
100
|
+
- No oblique (non-symmetric) projection; the four presets change the camera elevation only.
|
|
101
|
+
- `--no-fit` with a low or steep angle can leave the canvas (the default fit cannot).
|
|
102
|
+
- The preview gallery uses dark themes; light-page rendering is covered by the `*-light` themes.
|
|
103
|
+
- `downtown` is not chronological; `wireframe` on a transparent background uses the theme's paper colour
|
|
104
|
+
to hide lines.
|
|
105
|
+
- Some documented GitHub screens (token creation, workflow permissions) may change wording over time.
|
|
106
|
+
|
|
107
|
+
## Files
|
|
108
|
+
|
|
109
|
+
**Added (72):** `previews/` (49 generated files, of which 41 SVGs), 8 new baseline images,
|
|
110
|
+
`examples/README.md`, `examples/config/{all-options,solid,transparent,heights-and-angles}.yaml`,
|
|
111
|
+
`examples/workflows/{basic-city,customized-city,solid-city,heights-and-angles,transparent-city}.yml`,
|
|
112
|
+
`src/contribution_city/previews.py`, `src/contribution_city/renderer/presets.py`,
|
|
113
|
+
`tests/test_v13_options.py`, `tests/test_docs_and_examples.py`, this file.
|
|
114
|
+
|
|
115
|
+
**Modified (56):** `README.md`, `CHANGELOG.md`, `action.yml`, `.github/workflows/tests.yml`,
|
|
116
|
+
`docs/visual-testing.md`, `docs/gallery/{contact-sheet.png,manifest.json}`, `examples/config.example.yaml`,
|
|
117
|
+
`examples/workflows/generate-profile-city.yml`, `src/contribution_city/{_version,cli,config}.py`,
|
|
118
|
+
`src/contribution_city/renderer/svg.py`, `src/contribution_city/visual/{cases,cli,fixtures}.py`,
|
|
119
|
+
`tests/{snapshots/tiny_default.svg,test_action_execution,test_svg_quality,test_themes_layouts}.py`,
|
|
120
|
+
and 35 re-approved baseline images plus their `index.json` (their default heights changed).
|
|
121
|
+
|
|
122
|
+
**Removed (1):** `docs/gallery/new-in-1.2.png` (a generated image of the previous release).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 partialHuman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|