• R/O
  • SSH
  • HTTPS

chibios: Commit


Commit MetaInfo

Révision14609 (tree)
l'heure2021-07-23 04:26:53
Auteurakscram

Message de Log

Add scripts for automation testing in Jenkins

The following targets are supported by the new makefile:

* makefiles (default) - builds all projects and stores results in the

test_results directory, exits with non-zero code if there is at
least one build failure.

* info - prints versions of used tools.
* lint - runs linter checks and exists with non-zero status if there

is at leat one linter error.

* docs - builds HTML versions of docs and stores results in

the doc_results directory.

* clean - removes test_results and doc_results directories.

Change Summary

Modification

--- trunk/tools/workflows/Makefile (nonexistent)
+++ trunk/tools/workflows/Makefile (revision 14609)
@@ -0,0 +1,87 @@
1+# Used by Jenkins for automation purposes to build projects, run tests,
2+# gather test results, build documentation.
3+
4+ROOT := $(realpath ../..)
5+
6+# Directories to store results of tests and docs
7+TEST_RESULTS := $(ROOT)/test_results
8+DOC_RESULTS := $(ROOT)/doc_results
9+
10+# Defines what targets to build in makefile based projects, the order matter.
11+TARGETS := all clean
12+
13+# Find all projects to build
14+makefiles := $(shell find $(ROOT)/demos -type f -name Makefile)
15+makefiles += $(shell find $(ROOT)/test -type f -name Makefile)
16+makefiles += $(shell find $(ROOT)/testex -type f -name Makefile)
17+makefiles += $(shell find $(ROOT)/testhal -type f -name Makefile -not \
18+ -path "*/multi/*")
19+makefiles += $(shell find $(ROOT)/testrt -type f -name Makefile)
20+multi_makefiles := $(shell find $(ROOT)/testhal -type f -path "*/multi/*" \
21+ -name "*.make")
22+docs := $(shell find $(ROOT)/doc -type f -name Doxyfile_html)
23+linters := $(shell find $(ROOT)/tools/style -type f -name "*.sh")
24+
25+.PHONY : all makefiles docs info lint clean
26+.PHONY : $(makefiles) $(multi_makefiles)
27+.PHONY : $(linters) $(docs)
28+
29+# Build makefile based projects
30+all : makefiles
31+makefiles : $(makefiles) $(multi_makefiles)
32+ @! grep -q -r -m 1 \\"failure\\" $(TEST_RESULTS) 2>&1 > /dev/null || ( \
33+ echo "Exiting because there are build failures"; \
34+ exit 1)
35+
36+$(makefiles) :
37+ @mkdir -p $(TEST_RESULTS)/$(subst $(ROOT)/,,$(@D))
38+ +python $(ROOT)/tools/workflows/make.py -C $(@D) -f $(@F) \
39+ -p $(ROOT)/ -r $(TEST_RESULTS) $(TARGETS)
40+
41+$(multi_makefiles) :
42+ @mkdir -p $(TEST_RESULTS)/$(subst $(ROOT)/,,$(@D))
43+ +python $(ROOT)/tools/workflows/make.py -C $(dir $(@D)) -f make/$(@F) \
44+ -p $(ROOT)/ -r $(TEST_RESULTS) $(TARGETS)
45+
46+# Build documentation
47+docs : $(docs)
48+$(docs) : %Doxyfile_html:
49+ @mkdir -p $(DOC_RESULTS)
50+ cd $(@D) && doxygen $(@F)
51+ tar -czf $(DOC_RESULTS)/$(subst /,_,$(subst $(ROOT)/,,$(@D)))_html.tar.gz \
52+ --transform "s/^\./$(subst /,_,$(subst $(ROOT)/,,$(@D)))_html/g" \
53+ -C $(@D)/html .
54+
55+# Linter checks
56+lint : $(linters)
57+ @! grep -r -m 1 ^error: $(TEST_RESULTS)/lint 2>&1 > /dev/null || ( \
58+ echo "Exiting because there are linter errors"; \
59+ exit 1)
60+
61+$(linters) :
62+ @mkdir -p $(TEST_RESULTS)/lint
63+ cd $(ROOT)/tools/style && bash $(@F) 2>&1 | \
64+ tee $(TEST_RESULTS)/lint/$(basename $(@F)).log
65+
66+# Print versions of used tools
67+info :
68+ @which make && make -v
69+ @echo
70+ @which ccache && ccache -V || echo "ccache not present"
71+ @echo
72+ @which arm-none-eabi-gcc && arm-none-eabi-gcc -v || \
73+ echo "arm-none-eabi-gcc not present"
74+ @echo
75+ @which avr-gcc && avr-gcc -v || echo "avr-gcc not present"
76+ @echo
77+ @which doxygen && doxygen -v || echo "doxygen not present"
78+ @echo
79+ @which dot && dot -V || echo "graphviz not present"
80+ @echo
81+ @which perl && perl -v || echo "perl not present"
82+ @echo
83+
84+# Clean up results of tests and docs
85+clean :
86+ rm -rf $(TEST_RESULTS)
87+ rm -rf $(DOC_RESULTS)
--- trunk/tools/workflows/make.py (nonexistent)
+++ trunk/tools/workflows/make.py (revision 14609)
@@ -0,0 +1,145 @@
1+#!/usr/bin/env python
2+
3+"""
4+This script is intended to be used to run make under supervision for
5+the purpose of capturing its stdout/stderr and retcode to generate
6+a JUnit XML report. This report can be used in Jenkins or any other CI.
7+This report contains one test suite and as many cases as many targets
8+are specified.
9+
10+To get help on usage, possible options and their descriptions, use
11+the following command:
12+
13+ make.py --help
14+
15+An example of running this script for building a demo project:
16+
17+ make.py -C demos/STM32/RT-STM32WB55RG-NUCLEO68 -f Makefile all
18+
19+This script requires the following packages to be installed:
20+
21+ pip install junit-xml
22+"""
23+
24+import argparse
25+import os
26+import subprocess
27+import sys
28+import time
29+
30+import junit_xml
31+
32+
33+def get_jobserver_auth_fds():
34+ """Get "jobserver" file descriptors from MAKEFLAGS."""
35+ make_flags = os.environ.get('MAKEFLAGS', '')
36+ jobserver_auth_flag = '--jobserver-auth='
37+
38+ for make_flag in make_flags.split():
39+ if make_flag.startswith(jobserver_auth_flag):
40+ fdr, _, fdw = make_flag[len(jobserver_auth_flag):].partition(',')
41+ return (int(fdr), int(fdw))
42+
43+ return ()
44+
45+
46+def make(args):
47+ directory = args.directory or ''
48+ makefile = args.makefile or ''
49+
50+ path = os.path.join(directory, makefile)
51+ if args.prefix:
52+ assert path.startswith(args.prefix)
53+ path = path[len(args.prefix):]
54+
55+ suite = junit_xml.TestSuite(
56+ path,
57+ timestamp=time.time(),
58+ file=path,
59+ )
60+
61+ cmd = ['/usr/bin/env', 'make']
62+ if args.directory:
63+ cmd.extend(['-C', args.directory])
64+ if args.makefile:
65+ cmd.extend(['-f', args.makefile])
66+ if args.jobs > 1:
67+ cmd.extend(['-j', str(args.jobs)])
68+
69+ jobserver_auth_fds = get_jobserver_auth_fds()
70+
71+ for target in args.targets:
72+ if not target:
73+ continue
74+
75+ cmd_target = cmd + [target]
76+
77+ timestamp=time.time()
78+ start = time.monotonic()
79+ # To better control the use of resources by a subprocess make, pass
80+ # jobserver auth file descriptors in the subprocess, so it will
81+ # participate in the jobserver protocol and schedule its jobs
82+ # accordingly.
83+ ret = subprocess.run(cmd_target, pass_fds=jobserver_auth_fds,
84+ capture_output=True, text=True)
85+ end = time.monotonic()
86+
87+ case_name = 'make ' + target
88+ case_log = ' '.join(cmd_target)
89+ case = junit_xml.TestCase(
90+ case_name,
91+ classname=path,
92+ file=path,
93+ log=case_log,
94+ timestamp=timestamp,
95+ elapsed_sec=(end - start),
96+ stdout=ret.stdout,
97+ stderr=ret.stderr,
98+ )
99+
100+ if ret.returncode != 0:
101+ case.add_failure_info(
102+ 'Ended with non-zero exit code: {}'.format(ret.returncode))
103+
104+ suite.test_cases.append(case)
105+
106+ if args.result == '-':
107+ suite.to_file(sys.stdout, [suite])
108+ else:
109+ test_result_path = os.path.join(args.result, path) + '.xml'
110+ with open(test_result_path, 'w') as f:
111+ suite.to_file(f, [suite])
112+
113+
114+def main():
115+ parser = argparse.ArgumentParser(description=(
116+ 'Execute make targets and generate JUnit results'
117+ ))
118+ # Make specific arguments
119+ parser.add_argument('-C', '--directory', metavar='dir',
120+ help='Change directory to dir (equivalent to '
121+ '`make -C dir`)')
122+ parser.add_argument('-f', '--makefile', metavar='file',
123+ help='Use file as a makefile (equivalent to '
124+ '`make -f file`)')
125+ parser.add_argument('-j', '--jobs', metavar='jobs',
126+ type=int, default=1,
127+ help='Number of simultaneous jobs (equivalent to '
128+ '`make -j jobs`)')
129+ # Test specific arguments
130+ parser.add_argument('-r', '--result', metavar='result',
131+ default='-',
132+ help='Directory to store JUnit XML test result')
133+ parser.add_argument('-p', '--prefix', metavar='prefix',
134+ help=('Prefix path which should be removed for test '
135+ 'result'))
136+ parser.add_argument('targets', metavar='target', nargs='*',
137+ default=['all', 'clean'],
138+ help='Names of targets to run')
139+
140+ args = parser.parse_args()
141+ make(args)
142+
143+
144+if __name__ == '__main__':
145+ main()
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Afficher sur ancien navigateur de dépôt.