"Support regular expressions in rules:changes/exists"
### Problem to solve
Users need the ability to run a job **only** when at least one file was changed **outside** of specific paths. Currently, `rules:changes` and `rules:exists` use [glob patterns](https://ruby-doc.org/3.2.3/File.html#method-c-fnmatch) which don't support negation or full regular expression matching.
**Common use cases:**
- Skip build/test jobs when **only** documentation files (`.md`) are changed
- In monorepos: skip project-specific jobs when changes are **only** in unrelated directories
- Run full pipeline when both relevant code AND irrelevant files (docs, configs) change together
### Proposal
Add support for regular expressions in `rules:changes` and `rules:exists`:
```yaml
job1:
script:
- exit 0
rules:
- changes:
regexp: "^(?!docs/).*$" # Match files NOT in docs/
job2:
script:
- exit 0
rules:
- exists:
regexp: "^.*\\.rb$" # Match any .rb file
```
**How it works:**
- Files are iterated and matched against the provided regular expression
- If any file matches the regexp, the condition is satisfied
- This enables negation patterns using regex negative lookahead
### Security Considerations
To prevent ReDoS (Regular Expression Denial of Service) attacks from user-provided regexps:
1. Use Ruby 3.2+ `Regexp.timeout` feature: `Regexp.new(user_input_regexp, timeout: 1)`
- MR merged: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145679
2. Alternative: Use [`Gitlab::UntrustedRegexp`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/untrusted_regexp.rb) which uses RE2 engine (no backtracking, immune to ReDoS)
- Note: RE2 doesn't support lookaheads/lookbehinds, but sufficient for most glob-like patterns
issue