findExpandableVars returns all unique ${VAR_NAME} patterns in the string. It intentionally skips ${{ }} GitHub Actions expressions: those are evaluated by the GH Actions runner before the shell runs and must remain intact inside single-quoted strings — they should NOT be broken out as shell variable
(s string)
| 192 | // by the GH Actions runner before the shell runs and must remain intact inside |
| 193 | // single-quoted strings — they should NOT be broken out as shell variables. |
| 194 | func findExpandableVars(s string) []string { |
| 195 | var vars []string |
| 196 | seen := make(map[string]struct { |
| 197 | }) |
| 198 | for { |
| 199 | start := strings.Index(s, "${") |
| 200 | if start < 0 { |
| 201 | break |
| 202 | } |
| 203 | // Skip GitHub Actions expressions (${{ ... }}): they start with ${{ and |
| 204 | // must not be treated as shell variable references. |
| 205 | if start+2 < len(s) && s[start+2] == '{' { |
| 206 | s = s[start+3:] |
| 207 | continue |
| 208 | } |
| 209 | end := strings.Index(s[start:], "}") |
| 210 | if end < 0 { |
| 211 | break |
| 212 | } |
| 213 | varRef := s[start : start+end+1] |
| 214 | if !setutil.Contains(seen, varRef) { |
| 215 | seen[varRef] = struct { |
| 216 | }{} |
| 217 | vars = append(vars, varRef) |
| 218 | } |
| 219 | s = s[start+end+1:] |
| 220 | } |
| 221 | return vars |
| 222 | } |
no test coverage detected