Page MenuHomePhorge

D263.1768001345.diff
No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None

D263.1768001345.diff

diff --git a/lilybuild/lilybuild/ci_steps.py b/lilybuild/lilybuild/ci_steps.py
--- a/lilybuild/lilybuild/ci_steps.py
+++ b/lilybuild/lilybuild/ci_steps.py
@@ -76,10 +76,11 @@
should_run = True
if len(job.rules):
should_run = False
+ default_when = job.struct_raw.get('when', 'on_success')
for r in job.rules:
try:
- when = r.get('when', 'on_success')
- if when == 'never':
+ when = r.get('when', default_when)
+ if when == 'never' or when == 'manual':
should_run_to_set = False
else:
should_run_to_set = True
diff --git a/lilybuild/lilybuild/ci_syntax/ci_file.py b/lilybuild/lilybuild/ci_syntax/ci_file.py
--- a/lilybuild/lilybuild/ci_syntax/ci_file.py
+++ b/lilybuild/lilybuild/ci_syntax/ci_file.py
@@ -89,6 +89,46 @@
del res['extends']
return res
+def get_ref_from_ref_cond(ref_cond):
+ # We don't support project name so ignore everything after @
+ pos = ref_cond.rfind('@')
+ if pos != -1:
+ ref_cond = ref_cond[:pos]
+ if ref_cond[0] == '/' and ref_cond[-1] == '/':
+ return '$CI_COMMIT_REF_NAME =~ ' + ref_cond
+ else:
+ return '$CI_COMMIT_REF_NAME == "' + ref_cond.replace('\\', '\\\\').replace('"', '\\"') + '"'
+
+def get_alt_rules_from_job_struct(job_struct):
+ # Convert when/only/except to rules
+ when = None
+ if job_struct.get('when'):
+ when = job_struct.get('when')
+ positive_cond = []
+ if job_struct.get('only'):
+ for ref_cond in job_struct.get('only'):
+ positive_cond.append(get_ref_from_ref_cond(ref_cond))
+ negative_cond = []
+ if job_struct.get('except'):
+ for ref_cond in job_struct.get('except'):
+ negative_cond.append(get_ref_from_ref_cond(ref_cond))
+ rule_if = ''
+ if positive_cond:
+ rule_if += '(' + ' || '.join(positive_cond) + ')'
+ if negative_cond:
+ rule_if += ' && '
+ if negative_cond:
+ rule_if += '!(' + ' || '.join(negative_cond) + ')'
+ rule = {}
+ if when:
+ rule['when'] = when
+ if positive_cond or negative_cond:
+ rule['if'] = rule_if
+ if rule:
+ return [rule]
+ else:
+ return []
+
class CIJob:
def __init__(self, job_name, job_stage, job_struct):
self.name = job_name
@@ -99,7 +139,7 @@
self.script = normalize_script(job_struct.get('script'))
self.after_script = normalize_script(job_struct.get('after_script'))
self.artifacts = job_struct.get('artifacts') or {}
- self.rules = job_struct.get('rules') or []
+ self.rules = job_struct.get('rules') or get_alt_rules_from_job_struct(job_struct)
self.dependencies = job_struct.get('dependencies')
self.services = job_struct.get('services') or []
diff --git a/lilybuild/lilybuild/ci_syntax/rules.py b/lilybuild/lilybuild/ci_syntax/rules.py
--- a/lilybuild/lilybuild/ci_syntax/rules.py
+++ b/lilybuild/lilybuild/ci_syntax/rules.py
@@ -9,6 +9,7 @@
'PAREN_RIGHT': re.compile(r'\s*\)'),
'STR_DOUBLE': re.compile(r'''\s*"((?:[^\\"]|\\.)*)"'''),
'STR_SINGLE': re.compile(r"""\s*'((?:[^\\']|\\.)*)'"""),
+ 'REGEX': re.compile(r'''\s*/((?:[^\\/]|\\.)*)/'''),
'VAR': re.compile(r'\s*\$([A-Za-z_][A-Za-z0-9_]*)'),
'NULL': re.compile(r'\s*null'),
'END': re.compile(r'\s*$'),
@@ -17,8 +18,8 @@
ops = {
'==': (2, lambda a, b: a == b),
'!=': (2, lambda a, b: a != b),
- '=~': (2, lambda a, b: False),
- '!~': (2, lambda a, b: False),
+ '=~': (2, lambda a, b: not not re.search(b, a)),
+ '!~': (2, lambda a, b: not re.search(b, a)),
'!': (1, lambda a: not a),
'&&': (2, lambda a, b: a and b),
'||': (2, lambda a, b: a or b),
@@ -27,7 +28,7 @@
PAREN_PRECEDENCE = 8
def is_term(token):
- return token[0] in ['STR_DOUBLE', 'STR_SINGLE', 'VAR', 'NULL']
+ return token[0] in ['STR_DOUBLE', 'STR_SINGLE', 'REGEX', 'VAR', 'NULL']
def get_precedence(token):
if is_term(token):
@@ -108,11 +109,20 @@
c = match.groups()[0]
return c
+def replace_backslash_in_regex(match):
+ c = match.groups()[0]
+ if c == '/':
+ return c
+ # Treat everything except \/ as is
+ return '\\' + c
+
def evaluate_rule(expr, variables):
if expr[0] == 'VAR':
return variables.get(expr[1][0])
elif expr[0] == 'STR_DOUBLE' or expr[0] == 'STR_SINGLE':
return backslash_re.sub(replace_backslash, expr[1][0])
+ elif expr[0] == 'REGEX':
+ return backslash_re.sub(replace_backslash_in_regex, expr[1][0])
elif expr[0] == 'NULL':
return None
elif expr[0] == 'OP':
diff --git a/lilybuild/lilybuild/tests/ci_syntax/ci_file_test.py b/lilybuild/lilybuild/tests/ci_syntax/ci_file_test.py
--- a/lilybuild/lilybuild/tests/ci_syntax/ci_file_test.py
+++ b/lilybuild/lilybuild/tests/ci_syntax/ci_file_test.py
@@ -180,6 +180,24 @@
r = CIFile(get_res('variables'))
self.assertEqual(r.jobs['build-a'].get_predefined_ci_variables()['foo'], 'bar')
+ def test_when_only_except(self):
+ r = CIFile(get_res('when-only-except'))
+ expected_if = r'''($CI_COMMIT_REF_NAME =~ /a/ || $CI_COMMIT_REF_NAME =~ /bb$/ || $CI_COMMIT_REF_NAME == "ccccccc" || $CI_COMMIT_REF_NAME == "ddd" || $CI_COMMIT_REF_NAME == "ff\\\\\"f" || $CI_COMMIT_REF_NAME == "ff\\'f" || $CI_COMMIT_REF_NAME == "ff\\\"") && !($CI_COMMIT_REF_NAME == "bbb" || $CI_COMMIT_REF_NAME =~ /^ba/ || $CI_COMMIT_REF_NAME =~ /ff\w/ || $CI_COMMIT_REF_NAME =~ /@@@/ || $CI_COMMIT_REF_NAME == "@@@")'''
+ self.assertEqual(r.jobs['a'].rules, [{
+ 'when': 'manual',
+ 'if': expected_if
+ }])
+ self.assertEqual(r.jobs['b'].rules, [{
+ 'if': '($CI_COMMIT_REF_NAME == "servant")'
+ }])
+ self.assertEqual(r.jobs['c'].rules, [{
+ 'if': '!($CI_COMMIT_REF_NAME == "servant")'
+ }])
+ self.assertEqual(r.jobs['d'].rules, [])
+ self.assertEqual(r.jobs['e'].rules, [{
+ 'when': 'always'
+ }])
+
class GetJobExtendSeqTest(unittest.TestCase):
def test_no_extends(self):
all_jobs = {
diff --git a/lilybuild/lilybuild/tests/ci_syntax/res/when-only-except.yaml b/lilybuild/lilybuild/tests/ci_syntax/res/when-only-except.yaml
new file mode 100644
--- /dev/null
+++ b/lilybuild/lilybuild/tests/ci_syntax/res/when-only-except.yaml
@@ -0,0 +1,31 @@
+
+a:
+ when: manual
+ only:
+ - /a/
+ - /bb$/@abcabc/defdef
+ - ccccccc@abcabc/defdef
+ - ddd
+ - 'ff\\"f'
+ - "ff\\'f"
+ - 'ff\"'
+ except:
+ - bbb
+ - /^ba/
+ - /ff\w/@abcabc/defdef
+ - /@@@/@abcabc/defdef
+ - '@@@@abcabc/defdef'
+
+b:
+ only:
+ - servant
+
+c:
+ except:
+ - servant
+
+d:
+ image: alpine
+
+e:
+ when: always
diff --git a/lilybuild/lilybuild/tests/ci_syntax/rules_test.py b/lilybuild/lilybuild/tests/ci_syntax/rules_test.py
--- a/lilybuild/lilybuild/tests/ci_syntax/rules_test.py
+++ b/lilybuild/lilybuild/tests/ci_syntax/rules_test.py
@@ -9,6 +9,16 @@
('OP', ('==',)),
('STR_SINGLE', ('',)),
])
+ self.assertEqual(tokenize_rule("$VAR_FOO =~ /abc/"), [
+ ('VAR', ('VAR_FOO',)),
+ ('OP', ('=~',)),
+ ('REGEX', ('abc',)),
+ ])
+ self.assertEqual(tokenize_rule(r"$VAR_FOO =~ /ab\s\/c/"), [
+ ('VAR', ('VAR_FOO',)),
+ ('OP', ('=~',)),
+ ('REGEX', ('ab\\s\\/c',)),
+ ])
self.assertEqual(tokenize_rule(r'$VAR_FOO == "xxx\""'), [
('VAR', ('VAR_FOO',)),
('OP', ('==',)),
@@ -36,6 +46,9 @@
tokenize_rule(r'$VAR_FOO == "foo')
with self.assertRaises(SyntaxError) as m:
tokenize_rule(r'$VAR_FOO == "foo\\\"')
+ # bareword after regex
+ with self.assertRaises(SyntaxError) as m:
+ tokenize_rule(r"$VAR_FOO =~ /ab\s\/c/d")
def test_make_tree(self):
self.assertEqual(make_tree(tokenize_rule(r'($FOO)')), ('VAR', ('FOO',)))
@@ -116,3 +129,15 @@
evaluate_rule(parse_rule(r"$VAR_FOO == 'x\a\\\'x'"), {
'VAR_FOO': r"xa\'x",
}), True)
+ self.assertEqual(
+ evaluate_rule(parse_rule(r"$VAR_FOO =~ /ab\s\/c/"), {
+ 'VAR_FOO': 'XXab /c/def',
+ }), True)
+ self.assertEqual(
+ evaluate_rule(parse_rule(r"$VAR_FOO =~ /ab\s\/c/"), {
+ 'VAR_FOO': 'ab \\/c',
+ }), False)
+ self.assertEqual(
+ evaluate_rule(parse_rule(r"$VAR_FOO !~ /ab\s\/c/"), {
+ 'VAR_FOO': 'ab \\/c',
+ }), True)

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 9, 3:29 PM (4 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
935479
Default Alt Text
D263.1768001345.diff (8 KB)

Event Timeline