firecow / gitlab-ci-local

Tired of pushing to test your .gitlab-ci.yml?
MIT License
2.18k stars 125 forks source link

PCRE RegEx broken #932

Open djettah opened 1 year ago

djettah commented 1 year ago

Minimal .gitlab-ci.yml illustrating the issue

build-fake:
  stage: build
  variables:
    REGEX: '/^(\d+(\.\d+)*|latest)$/'
  script:
    - echo fake build
  rules:
    - if: $CI_COMMIT_TAG =~ $REGEX

Expected behavior It should match a job but it doesn't:

# gitlab-ci-local --list --variable CI_COMMIT_TAG=1.11  
parsing and downloads finished in 56 ms
name        description  stage   when   allow_failure  needs

# gitlab-ci-local --list --variable CI_COMMIT_TAG=latest
parsing and downloads finished in 80 ms
name        description  stage   when        allow_failure  needs
build-fake               build   on_success  false      

Doesn't it support PCRE? GitLab does.

Host information Ubuntu gitlab-ci-local 4.41.2

Additional context Add any other context about the problem here.

firecow commented 1 year ago

We must support PCRE, but i don't think we do at the moment :+1:

image

Something is definitely wrong :smiley:

naweiss commented 1 year ago

According to https://docs.gitlab.com/ee/ci/jobs/job_control.html#compare-a-variable-to-a-regex-pattern the regex syntax is called RE2.

firecow commented 1 year ago

Great, we need to utilize this package if possible then. https://www.npmjs.com/package/re2

naweiss commented 1 year ago

@firecow I wish I would understood your first comment earlier. After digging into this subject for 3 hours I found out that the image you posted clearly shows that the specific regex mentioned in this issue should work using RegExp without the need for RE2 or PCRE. gitlab-ci-local handles the following case perfectly fine:

build-fake:
  stage: build
  script:
    - echo fake build
  rules:
    - if: $CI_COMMIT_TAG =~ /^(\d+(\.\d+)*|latest)$/

To be clear, yes we should support RE2 to allow things like '/^([[:digit:]]+(\.[[:digit:]]+)*|latest)$/' which are not supported by JS RegExp. But, there is another bug that causes the mentioned REGEX expansion to fail: https://github.com/firecow/gitlab-ci-local/blob/0e442a8a25982246427dacbdbd3bc4088afd7dd6/src/utils.ts#L202

since REGEX is a variable it is replaced with JSON.stringify(envs[name]) which replaces every \ with \\. So, the evaluated result becomes: "1.11".match(/^(\\d+(\.\\d+)*|latest)$/) != null instead of "1.11".match(/^(\d+(\.\d+)*|latest)$/) != null.