diff --git a/.coveragerc b/.coveragerc index a9417ac42accecb3b351172f82616455c5226605..a4faf805dbac31700cc1061cc5d52c14457ab653 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,14 +1,39 @@ [report] +# When running a summary report, show missing lines. +# (boolean) show_missing = True +# Any line of source code that matches one of these regexes is excluded +# from being reported as missing. +# (multi-string) exclude_lines = # Have to re-enable the standard pragma pragma: no cover # Don't complain if tests don't hit defensive assertion code: + raise AssertionError raise NotImplementedError +# List of file name patterns, the files to include in reporting. +# (multi-string) +include = + */api_doc/* + */api_roundup/* + */aslint/* + */hgaster/hooks/*.py + #*/api_bitbucket/* + +# List of file name patterns, the files to leave out of reporting. +# (multi-string) +omit = + */api_roundup/stats.py + */hgaster/hooks/codeaster.py + */share/test/* + + [run] +# List of file name patterns, the files to include in measurement. +# (multi-string) include = */api_doc/* */api_roundup/* @@ -16,6 +41,8 @@ include = */hgaster/hooks/*.py #*/api_bitbucket/* +# List of file name patterns, the files to leave out of measurement. +# (multi-string) omit = */api_roundup/stats.py */hgaster/hooks/codeaster.py diff --git a/bin/maint/mergexx b/bin/maint/mergexx index 6ce1e66ea792e624188104a0d39faa377d0cc3d9..6029c03fadec85ce434c0977df7cd708a71b7359 100755 --- a/bin/maint/mergexx +++ b/bin/maint/mergexx @@ -48,7 +48,7 @@ run_main() [ $# -ne 1 ] && _error "exactly one argument is expected." tag="$1" - if [ $(hg status | wc -l) -ne 0 ]; then + if [ $(hg status -ardm | wc -l) -ne 0 ]; then _error "uncommitted changes! Please discard or commit first." fi @@ -65,7 +65,7 @@ run_main() printf "\ncommitting with message '${msg}'...\n" hg ci -m "${msg}" || _error "failed" - printf "\nDo forget to submit the new revision!\n" + printf "\nDo not forget to submit the new revision!\n" return ${?} } diff --git a/lib/aslint/check_global.py b/lib/aslint/check_global.py index 23293015679eb7627b5da703f594c5b5f3eefd1d..ff633476d3af7227da0eac6176b939fff98221f4 100644 --- a/lib/aslint/check_global.py +++ b/lib/aslint/check_global.py @@ -31,24 +31,8 @@ class ErrorMessages(DirnameCat, GenericMsg): # only in 'src' if not osp.isdir(osp.join(srcdir, 'bibpyt', 'Messages')): return result - found = False - subdirs = ['build', 'build/std', 'build/mpi'] - if ASCFG.get('waf.builddir') not in subdirs: - subdirs.insert(0, ASCFG.get('waf.builddir')) - for bld in ('release', 'debug'): - for sub in subdirs: - instdir = osp.join(srcdir, sub, bld) - fconf = osp.join(instdir, 'data', 'config.txt') - if osp.isfile(osp.join(instdir, 'config.txt')) or \ - osp.isfile(fconf): - found = True - break - if not found: - return [": can not check messages, 'config.txt' not found in " - "debug/release of this directories {0}" - .format(tuple(subdirs))] try: - unused, not_found = check_messages(instdir, srcdir) + unused, not_found = check_messages(srcdir) result.extend([': %s (unused)' % msg for msg in unused]) result.extend([': %s (missing)' % msg for msg in not_found]) except ValueError, exc: @@ -87,14 +71,15 @@ class Supv002aRequirement(DirnameCat, GenericMsg): CHECK_LIST = checkers_from_context(globals(), TextMsg) -def check_messages(instdir, srcdir): +def check_messages(srcdir): """Check the errors messages""" from aslint.messages import MessagesManager, CataMessageError tmpcache = tempfile.NamedTemporaryFile(prefix='cachedict.').name catapy = osp.abspath(osp.join(srcdir, 'code_aster')) if not osp.exists(catapy): catapy = osp.abspath(osp.join(srcdir, 'catapy')) - msgman = MessagesManager(repref=instdir, + # repref is not necessary because fort, pyt and capy are absolute paths + msgman = MessagesManager(repref="__unused__", fort=osp.abspath(osp.join(srcdir, 'bibfor')), pyt=osp.abspath(osp.join(srcdir, 'bibpyt')), capy=catapy, diff --git a/lib/aslint/fortran/check_source.py b/lib/aslint/fortran/check_source.py index 1b377d6a1b338929ddbbef9578402ddf62afa1c6..a05873f6a8fbdada6e1318de2e97023db2129d47 100644 --- a/lib/aslint/fortran/check_source.py +++ b/lib/aslint/fortran/check_source.py @@ -15,15 +15,27 @@ from aslint.config import ASCFG from aslint.decorators import interrupt_decorator from aslint.utils import apply_in_sandbox from aslint.base_checkers import ( - Report, MsgList, CheckList, CompilMsg, + Report, MsgList, CheckList, CompilMsg, GenericMsg, call_checkers, check_file_content, check_filename, check_disabled, check_fortran_code, ) +from aslint.fortran.free.fortran_code import FortranParserError import aslint.fortran.gfortran_checkers as GFORT import aslint.fortran.static_fortran_checkers as STAT import aslint.common_checkers as COMM +class ParserMsg(GenericMsg): + """Fortran parser error + There is probably an error reported by the compiler. Otherwise, please + report this error.""" + id = 'C1011' + + def search(self, txt): + """Returns the error message""" + return [": " + txt] + + @interrupt_decorator def check_fortran_source(fname, flags, incdir, checklist, tmpdir=None): """Check a fortran source file.""" @@ -42,9 +54,12 @@ def check_fortran_source(fname, flags, incdir, checklist, tmpdir=None): lmsg.extend(check_file_content(fname, checklist.on_content())) lmsg.extend(check_fortran_code(fname, checklist.on_fortran_code())) lmsg.extend(check_filename(fname, checklist.on_filename())) - except: + except FortranParserError as exc: + checker = ParserMsg(None) + checker.check(lmsg, exc.msg) + except Exception as exc: logger.error(_("cannot check %r"), fname) - raise + raise RuntimeError(exc) check_disabled(fname, checklist, lmsg) report = Report() report.set(fname, lmsg) diff --git a/lib/hgaster/ascommands.py b/lib/hgaster/ascommands.py index f4da15b0426df692de7f137af2de273c8300c03e..3c1628c9b0a941b08ee4ec0b5f99f287d16bc355 100644 --- a/lib/hgaster/ascommands.py +++ b/lib/hgaster/ascommands.py @@ -34,6 +34,7 @@ from .ext_utils import (check_for_updates, get_changed_files, get_description, parent_is_last, sendmail, shortrev, shortrev_s, valid_branch) from .request_queue import QueueError, Request, RequestQueue, requestkey +from .hooks.generic import OK cmdtable = {} command = cmdutil.command(cmdtable) @@ -110,7 +111,7 @@ def submit(ui, repo, *args, **opts): if reponame == "devtools": class_ = SubmitDevtools elif reponame in ("data", "src", "validation"): - class_ = SubmitAster + class_ = SubmitAsterLegacy elif reponame in ("data-xx", "src-xx", "validation-xx"): class_ = SubmitAsterXX elif reponame == "salome-codeaster-study": @@ -329,7 +330,7 @@ class CandidateRevisionCheck(object): if not self._local: self.refrev = self.get_reference_revision() if not self._local: - if not self.valid_branch(self.repo, self.wrkbranch): + if not self.valid_branch(): self._error(_("integration is not allowed in the branch '{0}'") .format(self.wrkbranch)) if not self.refrev: @@ -580,10 +581,20 @@ class CandidateRevisionCheck(object): self._error(_("can not find the last integrated revision")) return refrev - @staticmethod - def valid_branch(repo, branch): + def check_single_head(self): + """Check for single heads in branch.""" + from hooks.generic import single_head_per_branch_hook + checker = single_head_per_branch_hook() + return checker(self.ui, self.repo, self.wrkrev) == OK + + def check_branch(self, repo, branch): # pragma pylint: disable=unused-argument """Check branch validity.""" - return valid_branch(repo, branch) + raise NotImplementedError("must be subclassed") + + def valid_branch(self): + """Check branch validity.""" + return (self.check_branch(self.repo, self.wrkbranch) and + self.check_single_head()) class CandidateRevisionCheckAster(CandidateRevisionCheck): @@ -656,9 +667,8 @@ class CandidateRevisionCheckAster(CandidateRevisionCheck): for fname in lfiles: adiff = get_diff(self.ui, self.repo, revs, [fname]) diffs[typ][fname] = adiff - errcode = check_diff(self._report, diffs) + check_diff(self._report, diffs) os.chdir(prev) - return errcode @stop_on_failure def check_waf_build(self): @@ -944,7 +954,7 @@ class AbstractSubmit(CandidateRevisionCheck): return 0 -class SubmitAster(CandidateRevisionCheckAster, AbstractSubmit): +class AbstractSubmitAster(CandidateRevisionCheckAster, AbstractSubmit): """Check code_aster source files at the parent revision and, in case of success, submit changesets for continuous integration. @@ -952,7 +962,7 @@ class SubmitAster(CandidateRevisionCheckAster, AbstractSubmit): def __init__(self, ui, repo, *args, **opts): """Initialization""" - super(SubmitAster, self).__init__(ui, repo, *args, **opts) + super(AbstractSubmitAster, self).__init__(ui, repo, *args, **opts) self._resutest = opts.get("resutest") @stop_on_failure @@ -992,7 +1002,7 @@ class SubmitAster(CandidateRevisionCheckAster, AbstractSubmit): def run(self): """Execute the elementary tasks""" - super(SubmitAster, self).check_init() + super(AbstractSubmitAster, self).check_init() self.set_working_revision() self.set_parameters() logger.title(_("asking integration in branch '{0}' of the repository" @@ -1025,7 +1035,24 @@ class SubmitAster(CandidateRevisionCheckAster, AbstractSubmit): return 0 -class SubmitAsterXX(SubmitAster): +class SubmitAsterLegacy(AbstractSubmitAster): + + """Check code_aster source files at the parent revision + and, in case of success, submit changesets for continuous integration. + """ + + @staticmethod + def check_single_head(): + """Check single heads in branch.""" + # multiple heads allowed in code_aster legacy repositories + return True + + def check_branch(self, repo, branch): + """Check branch validity.""" + return valid_branch(repo, branch) + + +class SubmitAsterXX(AbstractSubmitAster): """Check code_aster++ source files at the parent revision and, in case of success, submit changesets for continuous integration. @@ -1055,10 +1082,9 @@ class SubmitAsterXX(SubmitAster): XXCFG.waf_builddir = "build/std" return XXCFG.get(key, default) - @staticmethod - def valid_branch(dummy, branch): + def check_branch(self, dummy, branch): """Check branch validity.""" - from hooks.generic import OK, branch_checker + from hooks.generic import branch_checker return branch_checker('^asterxx/')(branch) == OK def accept_special_issue(self, issue_id): @@ -1109,22 +1135,20 @@ class SubmitDevtools(AbstractSubmit): par = super(SubmitDevtools, self) return par.check_issues_status(expected, logfunc=logger.warn) - @staticmethod - def valid_branch(dummy, branch): + def check_branch(self, dummy, branch): """Check branch validity.""" - from hooks.generic import OK from hooks.devtools import repo_branch_checker return repo_branch_checker(branch) == OK -class SubmitSMecaMinimal(AbstractSubmit): +class AbstractSubmitSmeca(AbstractSubmit): """Minimal 'submit' command for some salome_meca tools (only push changes). """ def __init__(self, ui, repo, *args, **opts): """Initialization""" - super(SubmitSMecaMinimal, self).__init__(ui, repo, *args, **opts) + super(AbstractSubmitSmeca, self).__init__(ui, repo, *args, **opts) self.refbranch = "edf/default" @classmethod @@ -1133,7 +1157,7 @@ class SubmitSMecaMinimal(AbstractSubmit): return SMCFG.get(key, default) -class SubmitAsterStudy(SubmitSMecaMinimal): +class SubmitAsterStudy(AbstractSubmitSmeca): """Check AsterStudy source files at the parent revision and, in case of success, submit changesets for continuous integration. @@ -1142,28 +1166,22 @@ class SubmitAsterStudy(SubmitSMecaMinimal): command_lint = ["./check_lint.sh", "-p"] command_tests = [["./check_salome.sh", "-c"], ["./check_docs.sh"], - ["./check_comm2study.sh", "clean", "--jobs=4"], - ["./check_comm2code.sh", "clean", "--jobs=4"], - ["./check_persistence.sh", "clean", "--jobs=4"], - ["./check_performance.sh", "clean", "--jobs=4"], ] @staticmethod - def valid_branch(dummy, branch): + def check_branch(dummy, branch): """Check branch validity.""" - from hooks.generic import OK from hooks.asterstudy import repo_branch_checker return repo_branch_checker(branch) == OK -class SubmitRTool(SubmitSMecaMinimal): +class SubmitRTool(AbstractSubmitSmeca): """Submit command for some salome_meca RTOOL plugin.""" @staticmethod - def valid_branch(dummy, branch): + def check_branch(dummy, branch): """Check branch validity.""" - from hooks.generic import OK from hooks.rtool import repo_branch_checker return repo_branch_checker(branch) == OK diff --git a/lib/hgaster/ext_utils.py b/lib/hgaster/ext_utils.py index d61731d893af082a4c854582e90ace66d59b87c0..9a25641e49f0bda6557752070971c1ef01d7839e 100644 --- a/lib/hgaster/ext_utils.py +++ b/lib/hgaster/ext_utils.py @@ -205,7 +205,7 @@ def get_hgpath(ui, repo, dest): def valid_branch(repo, branch): - """Return True if 'branch' is one of the open branches + """Return True if 'branch' is one of the opened branches (default or the last vNN)""" if branch == 'default': return True diff --git a/lib/hgaster/hooks/generic.py b/lib/hgaster/hooks/generic.py index 5a0ce33134cc40881b8a635599adbbe558c4bd0b..f15ce050885b9d839312ab59ef1be81c69c308c0 100644 --- a/lib/hgaster/hooks/generic.py +++ b/lib/hgaster/hooks/generic.py @@ -180,6 +180,8 @@ def single_head_per_branch_hook(in_branch=None): for branch, heads in repo.branchmap().items(): if in_branch and not re.search(in_branch, branch): continue + if node.branch() != branch: + continue unclosed = [head for head in heads if not repo[head].extra().get("close")] if len(unclosed) > 1: diff --git a/share/test/aslint/test_check_files.py b/share/test/aslint/test_check_files.py index 5d4df03015a660c12493749d3c15436dd16ba924..17359c70f0a91fca4154f7d6639e76580a7be41e 100644 --- a/share/test/aslint/test_check_files.py +++ b/share/test/aslint/test_check_files.py @@ -6,12 +6,26 @@ Tests for the Docaster API. import os import os.path as osp +import tempfile import unittest from hamcrest import * from testutils import CODEASTER_SRC +# the parser fails in eval_parameters if 'if' statement is incomplete +SNIPPET_PARSER_ERROR = """ +subroutine rc32t + implicit none + character(len=8) :: option, poum + if (option .eq. 'RIGI_MECA_TANG') + poum = '-' + else + poum = '+' + endif +end subroutine +""" + def test_get_file_type(): """test manifest""" from aslint.filetype import get_file_type @@ -55,19 +69,24 @@ def test_filter_names(): assert len(filter_names(flist)) == 3 def test_check_files(): - """check a source file""" + """check source files""" from aslint.base_checkers import Report from aslint.check_files import check_files, read_waf_parameters from aslint.filetype import filter_arguments + from aslint.fortran.check_source import ParserMsg from aslint.logger import logger - args = ['bibc/supervis/aster_module.c', 'bibfor/utilifor/ibmain.F90'] + fname = tempfile.NamedTemporaryFile(suffix='.F90').name + with open(fname, 'w') as fort: + fort.write(SNIPPET_PARSER_ERROR) + + args = ['bibc/supervis/indik8.c', 'bibfor/utilifor/ibmain.F90', fname] args = [osp.join(CODEASTER_SRC, i) for i in args] filtered_args = filter_arguments(args, status='M') assert_that(filtered_args, has_key('c')) assert_that(filtered_args['c'], has_length(1)) assert_that(filtered_args, has_key('for')) - assert_that(filtered_args['for'], has_length(1)) + assert_that(filtered_args['for'], has_length(2)) wafc4che = osp.join(CODEASTER_SRC, 'build', 'std', 'c4che', 'release_cache.py') @@ -84,6 +103,16 @@ def test_check_files(): os.chdir(prev) logger.info(report.to_text()) + assert_that(report, has_key(fname)) + parser_error = [i for i in report[fname] if isinstance(i, ParserMsg)] + assert_that(parser_error, has_length(1)) + + +def test_check_messages(): + # useful to increase coverage without an installation directory + from aslint.check_global import check_messages + check_messages(CODEASTER_SRC) + if __name__ == "__main__": import sys diff --git a/share/test/aslint/test_fortran_code.py b/share/test/aslint/test_fortran_code.py index 56d312aee6253e438c29478c758bc1a7d1015720..d0a318980dd6f3911520ac8436b66bd3ff054ba7 100644 --- a/share/test/aslint/test_fortran_code.py +++ b/share/test/aslint/test_fortran_code.py @@ -647,6 +647,15 @@ def test_long_assign(): lines = src.code_text().splitlines() assert len(lines) == 5, lines +def test_parser_error(): + """parser error""" + src = FC_source80(os.linesep.join([ + "if (cond.eq.1)", + " continue", + "endif" + ]), init_level=3) + assert_that(calling(src.code_text), raises(FC.FortranParserError)) + if __name__ == "__main__": import sys diff --git a/share/test/hgaster/test_hooks.py b/share/test/hgaster/test_hooks.py index a2833cc1752e6f07d83318568b0db1c3c2114600..53d6c6ee8d637a2d21ecc985b6c7bae90695c04f 100644 --- a/share/test/hgaster/test_hooks.py +++ b/share/test/hgaster/test_hooks.py @@ -209,7 +209,7 @@ def test_single_head(): FakeCset(0, branch='default'), FakeCset(1, branch='edf/user', head=True), ]) - assert_that(single_head_per_branch(ui, repo, 1, + assert_that(single_head_per_branch(ui, repo, repo[1], hooktype='pretxnchangegroup'), equal_to(OK)) @@ -218,7 +218,7 @@ def test_single_head(): FakeCset(1, branch='edf/user', head=True), FakeCset(2, branch='edf/user', head=True), ]) - assert_that(single_head_per_branch(ui, repo, 1, + assert_that(single_head_per_branch(ui, repo, repo[1], hooktype='pretxnchangegroup'), equal_to(NOOK))