Skip to content

Commit 6eb4ebb

Browse files
committed
Add CI workflow for code style checking
This utilizes GitHub Actions workflow to enforce consistent code style: - Black formatter for Python code - shfmt for shell scripts - Newline check for file endings
1 parent 7b671fe commit 6eb4ebb

37 files changed

+4404
-2126
lines changed

.ci/check-format.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
3+
# The -e is not set because we want to get all the mismatch format at once
4+
5+
set -u -o pipefail
6+
7+
set -x
8+
9+
REPO_ROOT="$(git rev-parse --show-toplevel)"
10+
11+
SH_SOURCES=$(find "${REPO_ROOT}" | egrep "\.sh$")
12+
for file in ${SH_SOURCES}; do
13+
shfmt -d "${file}"
14+
done
15+
SH_MISMATCH_FILE_CNT=0
16+
if [ -n "${SH_SOURCES}" ]; then
17+
SH_MISMATCH_FILE_CNT=$(shfmt -l ${SH_SOURCES} | wc -l)
18+
fi
19+
20+
PY_SOURCES=$(find "${REPO_ROOT}" | egrep "\.py$")
21+
for file in ${PY_SOURCES}; do
22+
echo "Checking Python file: ${file}"
23+
black --diff "${file}"
24+
done
25+
PY_MISMATCH_FILE_CNT=0
26+
if [ -n "${PY_SOURCES}" ]; then
27+
PY_MISMATCH_FILE_CNT=$(echo "$(black --check ${PY_SOURCES} 2>&1)" | grep -c "^would reformat ")
28+
fi
29+
30+
exit $((SH_MISMATCH_FILE_CNT + PY_MISMATCH_FILE_CNT))

.ci/check-newline.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
set -e -u -o pipefail
4+
5+
ret=0
6+
show=0
7+
# Reference: https://medium.com/@alexey.inkin/how-to-force-newline-at-end-of-files-and-why-you-should-do-it-fdf76d1d090e
8+
while IFS= read -rd '' f; do
9+
if file --mime-encoding "$f" | grep -qv binary; then
10+
tail -c1 < "$f" | read -r _ || show=1
11+
if [ $show -eq 1 ]; then
12+
echo "Warning: No newline at end of file $f"
13+
ret=1
14+
show=0
15+
fi
16+
fi
17+
done < <(git ls-files -z '*.py' '*.sh' tests examples)
18+
19+
exit $ret

.github/workflows/style.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Style Check
2+
3+
on: [push, pull_request]
4+
5+
concurrency:
6+
group: style-check-${{ github.ref }}
7+
cancel-in-progress: true
8+
9+
jobs:
10+
format-check:
11+
name: Check Code Format
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Check out Kconfiglib source code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v5
20+
with:
21+
python-version: '3.12'
22+
23+
- name: Install tools
24+
run: |
25+
sudo apt-get install -q=2 shfmt python3-pip
26+
pip3 install black==25.1.0
27+
28+
- name: Run format check
29+
run: |
30+
.ci/check-newline.sh
31+
.ci/check-format.sh
32+
shell: bash

check_colors.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env python3
2+
"""
3+
檢查 menuconfig.py 的顏色設定是否符合 mconf
4+
"""
5+
6+
import re
7+
8+
# 讀取 menuconfig.py 的顏色設定
9+
with open("menuconfig.py", "r") as f:
10+
content = f.read()
11+
12+
# 提取 _STYLES["default"]
13+
match = re.search(r'_STYLES = \{[^}]*"default": """([^"]+)"""', content, re.DOTALL)
14+
if match:
15+
styles = match.group(1)
16+
print("Kconfiglib 顏色設定:")
17+
print("=" * 60)
18+
for line in styles.strip().split("\n"):
19+
line = line.strip()
20+
if line:
21+
print(f" {line}")
22+
print()
23+
24+
# mconf 顏色對照表 (from util.c:61-89)
25+
print("mconf bluetitle theme 對照:")
26+
print("=" * 60)
27+
mconf_colors = [
28+
("screen", "CYAN", "BLUE", "bold"),
29+
("dialog", "BLACK", "WHITE", ""),
30+
("title", "YELLOW", "WHITE", "bold"),
31+
("border", "WHITE", "WHITE", "bold"),
32+
("button_active", "WHITE", "BLUE", "bold"),
33+
("button_inactive", "BLACK", "WHITE", ""),
34+
("item", "BLACK", "WHITE", ""),
35+
("item_selected", "WHITE", "BLUE", "bold"),
36+
("tag", "YELLOW", "WHITE", "bold"),
37+
("uarrow/darrow", "GREEN", "WHITE", "bold"),
38+
("menubox", "BLACK", "WHITE", ""),
39+
("menubox_border", "WHITE", "WHITE", "bold"),
40+
]
41+
42+
for name, fg, bg, attr in mconf_colors:
43+
attr_str = f",{attr}" if attr else ""
44+
print(f" {name:20s} = fg:{fg.lower()},bg:{bg.lower()}{attr_str}")
45+
46+
print()
47+
print("對應關係:")
48+
print("=" * 60)
49+
mappings = [
50+
("screen", "→", "螢幕背景 (_stdscr.bkgd)"),
51+
("dialog/item", "→", "list (fg:black,bg:white)"),
52+
("border", "→", "frame (fg:white,bg:white,bold)"),
53+
("item_selected", "→", "selection (fg:white,bg:blue,bold)"),
54+
("tag", "→", "path/help (fg:yellow,bg:white,bold)"),
55+
("uarrow/darrow", "→", "arrow (fg:green,bg:white,bold)"),
56+
("title", "→", "path (fg:yellow,bg:white,bold)"),
57+
]
58+
59+
for mconf, arrow, kconfiglib in mappings:
60+
print(f" {mconf:20s} {arrow} {kconfiglib}")

defconfig.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,16 @@
1919

2020
def main():
2121
parser = argparse.ArgumentParser(
22-
formatter_class=argparse.RawDescriptionHelpFormatter,
23-
description=__doc__)
22+
formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__
23+
)
2424

2525
parser.add_argument(
26-
"--kconfig",
27-
default="Kconfig",
28-
help="Top-level Kconfig file (default: Kconfig)")
26+
"--kconfig", default="Kconfig", help="Top-level Kconfig file (default: Kconfig)"
27+
)
2928

3029
parser.add_argument(
31-
"config",
32-
metavar="CONFIGURATION",
33-
help="Input configuration file")
30+
"config", metavar="CONFIGURATION", help="Input configuration file"
31+
)
3432

3533
args = parser.parse_args()
3634

examples/allnoconfig_walk.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ def do_allnoconfig(node):
2727

2828
# Is the symbol a non-allnoconfig_y symbol that can be set to a
2929
# lower value than its current value?
30-
if (not sym.is_allnoconfig_y and
31-
sym.assignable and
32-
sym.assignable[0] < sym.tri_value):
30+
if (
31+
not sym.is_allnoconfig_y
32+
and sym.assignable
33+
and sym.assignable[0] < sym.tri_value
34+
):
3335

3436
# Yup, lower it
3537
sym.set_value(sym.assignable[0])

examples/dumpvars.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,9 @@
1111
import kconfiglib
1212

1313

14-
print(" ".join("{}='{}'".format(var, os.environ[var])
15-
for var in kconfiglib.Kconfig(sys.argv[1]).env_vars))
14+
print(
15+
" ".join(
16+
"{}='{}'".format(var, os.environ[var])
17+
for var in kconfiglib.Kconfig(sys.argv[1]).env_vars
18+
)
19+
)

examples/eval_expr.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,4 @@
2020
# Enable modules so that m doesn't get demoted to n
2121
kconf.modules.set_value(2)
2222

23-
print("the expression '{}' evaluates to {}"
24-
.format(expr, kconf.eval_string(expr)))
23+
print("the expression '{}' evaluates to {}".format(expr, kconf.eval_string(expr)))

examples/find_symbol.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,25 +88,31 @@
8888
print("No symbol {} exists in the configuration".format(sym_name))
8989
sys.exit(0)
9090

91-
referencing = [node for node in kconf.node_iter()
92-
if kconf.syms[sym_name] in node.referenced]
91+
referencing = [
92+
node for node in kconf.node_iter() if kconf.syms[sym_name] in node.referenced
93+
]
9394
if not referencing:
9495
print("No references to {} found".format(sym_name))
9596
sys.exit(0)
9697

97-
print("Found {} locations that reference {}:\n"
98-
.format(len(referencing), sym_name))
98+
print("Found {} locations that reference {}:\n".format(len(referencing), sym_name))
9999

100100
for i, node in enumerate(referencing, 1):
101-
print("========== Location {} ({}:{}) ==========\n\n{}"
102-
.format(i, node.filename, node.linenr, node))
101+
print(
102+
"========== Location {} ({}:{}) ==========\n\n{}".format(
103+
i, node.filename, node.linenr, node
104+
)
105+
)
103106

104107
# Print the parents of the menu node too
105108

106109
node = node.parent
107110
parent_i = 1
108111
while node is not kconf.top_node:
109-
print("---------- Parent {} ({}:{}) ----------\n\n{}"
110-
.format(parent_i, node.filename, node.linenr, node))
112+
print(
113+
"---------- Parent {} ({}:{}) ----------\n\n{}".format(
114+
parent_i, node.filename, node.linenr, node
115+
)
116+
)
111117
node = node.parent
112118
parent_i += 1

examples/help_grep.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@
4747
for node in Kconfig(sys.argv[1]).node_iter():
4848
match = False
4949

50-
if isinstance(node.item, (Symbol, Choice)) and \
51-
node.help is not None and search(node.help):
50+
if (
51+
isinstance(node.item, (Symbol, Choice))
52+
and node.help is not None
53+
and search(node.help)
54+
):
5255
print(node.item)
5356
match = True
5457

0 commit comments

Comments
 (0)