summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/lint.yml25
-rw-r--r--data/mappings/keyboard_aliases.hjson64
-rw-r--r--lib/python/qmk/cli/__init__.py1
-rw-r--r--lib/python/qmk/cli/ci/__init__.py0
-rw-r--r--lib/python/qmk/cli/ci/validate_aliases.py46
-rw-r--r--lib/python/qmk/commands.py11
-rw-r--r--lib/python/qmk/keyboard.py5
7 files changed, 97 insertions, 55 deletions
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 9862ff502c..19dd7c70a9 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -74,31 +74,10 @@ jobs:
74 fi 74 fi
75 exit $exit_code 75 exit $exit_code
76 76
77 - name: Verify at most one added keyboard 77 - name: Verify keyboard aliases
78 if: always() 78 if: always()
79 shell: 'bash {0}' 79 shell: 'bash {0}'
80 run: | 80 run: |
81 git reset --hard 81 git reset --hard
82 git clean -xfd 82 git clean -xfd
83 83 qmk ci-validate-aliases
84 # Get the keyboard list and count for the target branch
85 git checkout -f ${{ github.base_ref }}
86 git pull --ff-only
87 QMK_KEYBOARDS_BASE=$(qmk list-keyboards)
88 QMK_KEYBOARDS_BASE_COUNT=$(qmk list-keyboards | wc -l)
89
90 # Get the keyboard list and count for the PR
91 git checkout -f ${{ github.head_ref }}
92 git merge --no-commit --squash ${{ github.base_ref }}
93 QMK_KEYBOARDS_PR=$(qmk list-keyboards)
94 QMK_KEYBOARDS_PR_COUNT=$(qmk list-keyboards | wc -l)
95
96 echo "::group::Keyboards changes in this PR"
97 diff -d -U 0 <(echo "$QMK_KEYBOARDS_BASE") <(echo "$QMK_KEYBOARDS_PR") | grep -vE '^(---|\+\+\+|@@)' | sed -e 's@^-@Removed: @g' -e 's@^+@ Added: @g'
98 echo "::endgroup::"
99
100 if [[ $QMK_KEYBOARDS_PR_COUNT -gt $(($QMK_KEYBOARDS_BASE_COUNT + 1)) ]]; then
101 echo "More than one keyboard added in this PR -- see the PR Checklist."
102 echo "::error::More than one keyboard added in this PR -- see the PR Checklist."
103 exit 1
104 fi
diff --git a/data/mappings/keyboard_aliases.hjson b/data/mappings/keyboard_aliases.hjson
index 8fc5e59925..992564702b 100644
--- a/data/mappings/keyboard_aliases.hjson
+++ b/data/mappings/keyboard_aliases.hjson
@@ -4,6 +4,13 @@
4 // "target": "<keyboard_folder>" 4 // "target": "<keyboard_folder>"
5 // } 5 // }
6 // 6 //
7
8 /* This list of aliases is for testing purposes -- ensures "linked list" recursive traversal works correctly. */
9 "_test_a": { "target": "_test_b" },
10 "_test_b": { "target": "_test_c" },
11 "_test_c": { "target": "planck/rev6" },
12
13 /* The main list of aliases for moved keyboards within QMK. */
7 "2_milk": { 14 "2_milk": {
8 "target": "spaceman/2_milk" 15 "target": "spaceman/2_milk"
9 }, 16 },
@@ -35,7 +42,7 @@
35 "target": "amjkeyboard/amjpad" 42 "target": "amjkeyboard/amjpad"
36 }, 43 },
37 "angel64": { 44 "angel64": {
38 "target": "angel64/alpha" 45 "target": "kakunpc/angel64/alpha"
39 }, 46 },
40 "ashpil/modelm_usbc": { 47 "ashpil/modelm_usbc": {
41 "target": "ibm/model_m/ashpil_usbc" 48 "target": "ibm/model_m/ashpil_usbc"
@@ -47,10 +54,10 @@
47 "target": "viktus/at101_bh" 54 "target": "viktus/at101_bh"
48 }, 55 },
49 "atom47/rev2": { 56 "atom47/rev2": {
50 "target": "maartenwut/atom47/rev2" 57 "target": "evyd13/atom47/rev2"
51 }, 58 },
52 "atom47/rev3": { 59 "atom47/rev3": {
53 "target": "maartenwut/atom47/rev3" 60 "target": "evyd13/atom47/rev3"
54 }, 61 },
55 "bakeneko60": { 62 "bakeneko60": {
56 "target": "kkatano/bakeneko60" 63 "target": "kkatano/bakeneko60"
@@ -65,7 +72,7 @@
65 "target": "bear_face/v1" 72 "target": "bear_face/v1"
66 }, 73 },
67 "bm16a": { 74 "bm16a": {
68 "target": "kprepublic/bm16a" 75 "target": "kprepublic/bm16a/v1"
69 }, 76 },
70 "bm16s": { 77 "bm16s": {
71 "target": "kprepublic/bm16s" 78 "target": "kprepublic/bm16s"
@@ -77,16 +84,16 @@
77 "target": "kprepublic/bm43a" 84 "target": "kprepublic/bm43a"
78 }, 85 },
79 "bm60poker": { 86 "bm60poker": {
80 "target": "kprepublic/bm60poker" 87 "target": "kprepublic/bm60hsrgb_poker/rev1"
81 }, 88 },
82 "bm60rgb": { 89 "bm60rgb": {
83 "target": "kprepublic/bm60rgb" 90 "target": "kprepublic/bm60hsrgb/rev1"
84 }, 91 },
85 "bm60rgb_iso": { 92 "bm60rgb_iso": {
86 "target": "kprepublic/bm60rgb_iso" 93 "target": "kprepublic/bm60hsrgb_iso/rev1"
87 }, 94 },
88 "bm68rgb": { 95 "bm68rgb": {
89 "target": "kprepublic/bm68rgb" 96 "target": "kprepublic/bm68hsrgb/rev1"
90 }, 97 },
91 "bpiphany/pegasushoof": { 98 "bpiphany/pegasushoof": {
92 "target": "bpiphany/pegasushoof/2013" 99 "target": "bpiphany/pegasushoof/2013"
@@ -140,7 +147,10 @@
140 "target": "jagdpietr/drakon" 147 "target": "jagdpietr/drakon"
141 }, 148 },
142 "durgod/k320": { 149 "durgod/k320": {
143 "target": "durgod/k3x0/k320" 150 "target": "durgod/k320/base"
151 },
152 "durgod/k3x0/k320": {
153 "target": "durgod/k320/base"
144 }, 154 },
145 "durgod/hades": { 155 "durgod/hades": {
146 "target": "durgod/dgk6x/hades_ansi" 156 "target": "durgod/dgk6x/hades_ansi"
@@ -275,7 +285,7 @@
275 "target": "idb/idb_60" 285 "target": "idb/idb_60"
276 }, 286 },
277 "idobo": { 287 "idobo": {
278 "target": "idobao/id75" 288 "target": "idobao/id75/v1"
279 }, 289 },
280 "jacky_studio/piggy60": { 290 "jacky_studio/piggy60": {
281 "target": "jacky_studio/piggy60/rev1" 291 "target": "jacky_studio/piggy60/rev1"
@@ -407,7 +417,7 @@
407 "target": "mechlovin/adelais/rgb_led/rev1" 417 "target": "mechlovin/adelais/rgb_led/rev1"
408 }, 418 },
409 "mechlovin/adelais/standard_led": { 419 "mechlovin/adelais/standard_led": {
410 "target": "mechlovin/adelais/standard_led/rev2" 420 "target": "mechlovin/adelais/standard_led/arm/rev2"
411 }, 421 },
412 "mechlovin/delphine": { 422 "mechlovin/delphine": {
413 "target": "mechlovin/delphine/mono_led" 423 "target": "mechlovin/delphine/mono_led"
@@ -461,10 +471,10 @@
461 "target": "pabile/p20/ver1" 471 "target": "pabile/p20/ver1"
462 }, 472 },
463 "pancake/feather": { 473 "pancake/feather": {
464 "target": "spaceman/pancake/feather" 474 "target": "spaceman/pancake/rev1/feather"
465 }, 475 },
466 "pancake/promicro": { 476 "pancake/promicro": {
467 "target": "spaceman/pancake/promicro" 477 "target": "spaceman/pancake/rev1/promicro"
468 }, 478 },
469 "peiorisboards/ixora": { 479 "peiorisboards/ixora": {
470 "target": "coarse/ixora" 480 "target": "coarse/ixora"
@@ -473,7 +483,7 @@
473 "target": "dm9records/plaid" 483 "target": "dm9records/plaid"
474 }, 484 },
475 "plain60": { 485 "plain60": {
476 "target": "maartenwut/plain60" 486 "target": "evyd13/plain60"
477 }, 487 },
478 "ploopyco/trackball": { 488 "ploopyco/trackball": {
479 "target": "ploopyco/trackball/rev1_005" 489 "target": "ploopyco/trackball/rev1_005"
@@ -509,10 +519,10 @@
509 "target": "wilba_tech/rama_works_u80_a" 519 "target": "wilba_tech/rama_works_u80_a"
510 }, 520 },
511 "ramonimbao/herringbone": { 521 "ramonimbao/herringbone": {
512 "target": "ramonimbao/herringbone/v1" 522 "target": "rmi_kb/herringbone/v1"
513 }, 523 },
514 "ramonimbao/mona": { 524 "ramonimbao/mona": {
515 "target": "ramonimbao/mona/v1" 525 "target": "rmi_kb/mona/v1"
516 }, 526 },
517 "rgbkb/pan": { 527 "rgbkb/pan": {
518 "target": "rgbkb/pan/rev1/32a" 528 "target": "rgbkb/pan/rev1/32a"
@@ -548,10 +558,10 @@
548 "target": "tkw/stoutgat/v1" 558 "target": "tkw/stoutgat/v1"
549 }, 559 },
550 "suihankey": { 560 "suihankey": {
551 "target": "suihankey/split/alpha" 561 "target": "kakunpc/suihankey/split/alpha"
552 }, 562 },
553 "ta65": { 563 "ta65": {
554 "target": "maartenwut/ta65" 564 "target": "evyd13/ta65"
555 }, 565 },
556 "tartan": { 566 "tartan": {
557 "target": "dm9records/tartan" 567 "target": "dm9records/tartan"
@@ -569,13 +579,13 @@
569 "target": "matthewdias/txuu" 579 "target": "matthewdias/txuu"
570 }, 580 },
571 "underscore33": { 581 "underscore33": {
572 "target": "underscore33/rev1" 582 "target": "tominabox1/underscore33/rev1"
573 }, 583 },
574 "vinta": { 584 "vinta": {
575 "target": "coarse/vinta" 585 "target": "coarse/vinta"
576 }, 586 },
577 "wasdat": { 587 "wasdat": {
578 "target": "maartenwut/wasdat" 588 "target": "evyd13/wasdat"
579 }, 589 },
580 "westfoxtrot/cypher": { 590 "westfoxtrot/cypher": {
581 "target": "westfoxtrot/cypher/rev1" 591 "target": "westfoxtrot/cypher/rev1"
@@ -587,10 +597,10 @@
587 "target": "xiudi/xd002" 597 "target": "xiudi/xd002"
588 }, 598 },
589 "xd004": { 599 "xd004": {
590 "target": "xiudi/xd004" 600 "target": "xiudi/xd004/v1"
591 }, 601 },
592 "xd60": { 602 "xd60": {
593 "target": "xiudi/xd60" 603 "target": "xiudi/xd60/rev2"
594 }, 604 },
595 "xd68": { 605 "xd68": {
596 "target": "xiudi/xd68" 606 "target": "xiudi/xd68"
@@ -837,7 +847,7 @@
837 "target": "kagizaraya/halberd" 847 "target": "kagizaraya/halberd"
838 }, 848 },
839 "handwired/hillside/0_1": { 849 "handwired/hillside/0_1": {
840 "target": "handwired/hillside/48" 850 "target": "hillside/48/0_1"
841 }, 851 },
842 "hecomi/alpha": { 852 "hecomi/alpha": {
843 "target": "takashiski/hecomi/alpha" 853 "target": "takashiski/hecomi/alpha"
@@ -849,10 +859,10 @@
849 "target": "bpiphany/hid_liber" 859 "target": "bpiphany/hid_liber"
850 }, 860 },
851 "id67/default_rgb": { 861 "id67/default_rgb": {
852 "target": "idobao/id67/default_rgb" 862 "target": "idobao/id67"
853 }, 863 },
854 "id67/rgb": { 864 "id67/rgb": {
855 "target": "idobao/id67/rgb" 865 "target": "idobao/id67"
856 }, 866 },
857 "id80": { 867 "id80": {
858 "target": "idobao/id80/v2/ansi" 868 "target": "idobao/id80/v2/ansi"
@@ -1254,7 +1264,7 @@
1254 "target": "marksard/treadstone48/rev2" 1264 "target": "marksard/treadstone48/rev2"
1255 }, 1265 },
1256 "tronguylabs/m122_3270": { 1266 "tronguylabs/m122_3270": {
1257 "target": "ibm/model_m_122/m122_3270" 1267 "target": "ibm/model_m_122/m122_3270/teensy"
1258 }, 1268 },
1259 "ua62": { 1269 "ua62": {
1260 "target": "nacly/ua62" 1270 "target": "nacly/ua62"
@@ -1308,7 +1318,7 @@
1308 "target": "ydkb/yd68" 1318 "target": "ydkb/yd68"
1309 }, 1319 },
1310 "ymd75": { 1320 "ymd75": {
1311 "target": "ymdk/ymd75" 1321 "target": "ymdk/ymd75/rev1"
1312 }, 1322 },
1313 "ymd96": { 1323 "ymd96": {
1314 "target": "ymdk/ymd96" 1324 "target": "ymdk/ymd96"
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index 9c3decf4f7..b8bc99aa0d 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -31,6 +31,7 @@ safe_commands = [
31] 31]
32 32
33subcommands = [ 33subcommands = [
34 'qmk.cli.ci.validate_aliases',
34 'qmk.cli.bux', 35 'qmk.cli.bux',
35 'qmk.cli.c2json', 36 'qmk.cli.c2json',
36 'qmk.cli.cd', 37 'qmk.cli.cd',
diff --git a/lib/python/qmk/cli/ci/__init__.py b/lib/python/qmk/cli/ci/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/python/qmk/cli/ci/__init__.py
diff --git a/lib/python/qmk/cli/ci/validate_aliases.py b/lib/python/qmk/cli/ci/validate_aliases.py
new file mode 100644
index 0000000000..a205d03cff
--- /dev/null
+++ b/lib/python/qmk/cli/ci/validate_aliases.py
@@ -0,0 +1,46 @@
1"""Validates the list of keyboard aliases.
2"""
3from pathlib import Path
4
5from milc import cli
6
7from qmk.json_schema import json_load
8from qmk.keyboard import resolve_keyboard, keyboard_folder
9
10
11def _safe_keyboard_folder(target):
12 try:
13 return keyboard_folder(target) # throws ValueError if it's invalid
14 except Exception:
15 return None
16
17
18def _target_keyboard_exists(target):
19 # If there's no target, then we can't build it.
20 if not target:
21 return False
22
23 # If the target directory existed but there was no rules.mk or rules.mk was incorrectly parsed, then we can't build it.
24 if not resolve_keyboard(target):
25 return False
26
27 # If the target directory exists but it itself has an invalid alias or invalid rules.mk, then we can't build it either.
28 if not _safe_keyboard_folder(target):
29 return False
30
31 # As far as we can tell, we can build it!
32 return True
33
34
35@cli.subcommand('Validates the list of keyboard aliases.', hidden=True)
36def ci_validate_aliases(cli):
37 aliases = json_load(Path('data/mappings/keyboard_aliases.hjson'))
38
39 success = True
40 for alias in aliases.keys():
41 target = aliases[alias].get('target', None)
42 if not _target_keyboard_exists(target):
43 cli.log.error(f'Keyboard alias {alias} has a target that doesn\'t exist: {target}')
44 success = False
45
46 return success
diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py
index 660b2ff72e..34696e3793 100644
--- a/lib/python/qmk/commands.py
+++ b/lib/python/qmk/commands.py
@@ -212,13 +212,16 @@ def parse_configurator_json(configurator_file):
212 cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}') 212 cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}')
213 exit(1) 213 exit(1)
214 214
215 orig_keyboard = user_keymap['keyboard'] 215 keyboard = user_keymap['keyboard']
216 aliases = json_load(Path('data/mappings/keyboard_aliases.hjson')) 216 aliases = json_load(Path('data/mappings/keyboard_aliases.hjson'))
217 217
218 if orig_keyboard in aliases: 218 while keyboard in aliases:
219 if 'target' in aliases[orig_keyboard]: 219 last_keyboard = keyboard
220 user_keymap['keyboard'] = aliases[orig_keyboard]['target'] 220 keyboard = aliases[keyboard].get('target', keyboard)
221 if keyboard == last_keyboard:
222 break
221 223
224 user_keymap['keyboard'] = keyboard
222 return user_keymap 225 return user_keymap
223 226
224 227
diff --git a/lib/python/qmk/keyboard.py b/lib/python/qmk/keyboard.py
index 18ca5a9534..9826f3f887 100644
--- a/lib/python/qmk/keyboard.py
+++ b/lib/python/qmk/keyboard.py
@@ -92,8 +92,11 @@ def keyboard_folder(keyboard):
92 """ 92 """
93 aliases = json_load(Path('data/mappings/keyboard_aliases.hjson')) 93 aliases = json_load(Path('data/mappings/keyboard_aliases.hjson'))
94 94
95 if keyboard in aliases: 95 while keyboard in aliases:
96 last_keyboard = keyboard
96 keyboard = aliases[keyboard].get('target', keyboard) 97 keyboard = aliases[keyboard].get('target', keyboard)
98 if keyboard == last_keyboard:
99 break
97 100
98 rules_mk_file = Path(base_path, keyboard, 'rules.mk') 101 rules_mk_file = Path(base_path, keyboard, 'rules.mk')
99 102