Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F29398201
D263.1768001345.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D263.1768001345.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D263: Support regex and when/only/except
Attached
Detach File
Event Timeline
Log In to Comment