Compare commits

..
Author SHA1 Message Date
Sam Robson 0911ee96d2 Merge pull request #4303 from github/mergeback/v4.39.3-to-main-33d7b85d
Mergeback v4.39.3 refs/heads/releases/v4 into main
2026-11-04 17:52:12 +00:00
github-actions[bot] d11b2246b1 Rebuild 2026-11-04 16:49:37 +00:00
github-actions[bot] 8e42d3873f Update changelog and version after v4.39.3 2026-11-04 16:49:21 +00:00
Sam Robson 33d7b85da1 Merge pull request #4299 from github/update-v4.39.3-064910ba2
Merge main into releases/v4
2026-11-04 16:47:01 +00:00
Michael B. Gale 8aab3d8601 Merge pull request #4298 from github/mbg/decouple-features-enum
Move `Feature` enum to a separate file
2026-11-04 15:50:28 +00:00
github-actions[bot] 24393f8692 Update changelog for v4.39.3 2026-11-04 15:21:56 +00:00
Michael B. Gale 064910ba27 Merge pull request #4297 from github/mbg/update-glob
Update `glob` to `14.0.3`
2026-11-04 13:56:56 +00:00
Michael B. Gale f532ac5951 Update glob to 14.0.3 2026-11-04 13:08:55 +00:00
17 changed files with 3044 additions and 2972 deletions

No files matched your search

+4
View File
@@ -6,6 +6,10 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
No user facing changes.
## 4.39.3 - 04 Nov 2026
- Fixed diff-informed alert filtering incorrectly removing alerts in changed files whose paths contain spaces, special characters, or non-ASCII characters. [#4283](https://github.com/github/codeql-action/pull/4283)
## 4.39.2 - 03 Nov 2026
- Update default CodeQL bundle version to [2.27.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.4). [#4284](https://github.com/github/codeql-action/pull/4284)
+2841 -2359
View File
File diff suppressed because it is too large. Load diff
+118 -252
View File
@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "4.39.3",
"version": "4.39.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "4.39.3",
"version": "4.39.4",
"license": "MIT",
"workspaces": [
"pr-checks"
@@ -33,7 +33,6 @@
"js-yaml": "^5.5.0",
"jsonschema": "1.5.0",
"long": "^5.3.2",
"minimatch": "^11.0.2",
"node-forge": "^1.4.1",
"semver": "^7.8.5",
"undici": "^7.30.1",
@@ -60,7 +59,7 @@
"eslint-plugin-import-x": "^4.17.1",
"eslint-plugin-jsdoc": "^65.4.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^13.0.6",
"glob": "^14.0.3",
"globals": "^17.13.0",
"nock": "^14.0.17",
"prettier": "^3.9.10",
@@ -565,28 +564,6 @@
"minimatch": "^3.0.4"
}
},
"node_modules/@actions/glob/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@actions/glob/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@actions/http-client": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.2.tgz",
@@ -1579,30 +1556,6 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@eslint/config-array/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@eslint/config-helpers": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
@@ -1666,17 +1619,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
@@ -1713,19 +1655,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@eslint/js": {
"version": "9.39.5",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz",
@@ -1835,30 +1764,6 @@
"node": ">=10.10.0"
}
},
"node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"dev": true,
@@ -2000,17 +1905,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@microsoft/eslint-formatter-sarif/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@microsoft/eslint-formatter-sarif/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2226,19 +2120,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@microsoft/eslint-formatter-sarif/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@mswjs/interceptors": {
"version": "0.41.3",
"resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz",
@@ -3127,6 +3008,29 @@
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -3626,7 +3530,6 @@
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3636,7 +3539,6 @@
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -4180,24 +4082,13 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/brace-expansion/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
@@ -4552,7 +4443,6 @@
},
"node_modules/color-convert": {
"version": "2.0.1",
"dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
@@ -4563,7 +4453,6 @@
},
"node_modules/color-name": {
"version": "1.1.4",
"dev": true,
"license": "MIT"
},
"node_modules/comment-parser": {
@@ -4600,8 +4489,6 @@
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/concordance": {
@@ -4690,7 +4577,6 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -4945,7 +4831,6 @@
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"dev": true,
"license": "MIT"
},
"node_modules/es-abstract": {
@@ -5492,6 +5377,29 @@
}
}
},
"node_modules/eslint-plugin-import-x/node_modules/balanced-match": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz",
"integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==",
"dev": true,
"license": "MIT",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/eslint-plugin-import-x/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/eslint-plugin-import-x/node_modules/minimatch": {
"version": "10.2.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
@@ -5508,17 +5416,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/eslint-plugin-import/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/eslint-plugin-import/node_modules/debug": {
"version": "3.2.7",
"dev": true,
@@ -5527,19 +5424,6 @@
"ms": "^2.1.1"
}
},
"node_modules/eslint-plugin-import/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/eslint-plugin-jsdoc": {
"version": "65.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-65.4.0.tgz",
@@ -5669,17 +5553,6 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@@ -5687,19 +5560,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/eslint-plugin-no-async-foreach": {
"version": "0.1.1",
"dev": true,
@@ -5814,17 +5674,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/eslint/node_modules/chalk": {
"version": "4.1.0",
"dev": true,
@@ -5875,19 +5724,6 @@
"node": ">=10.13.0"
}
},
"node_modules/eslint/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/espree": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
@@ -6437,14 +6273,14 @@
}
},
"node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-14.0.3.tgz",
"integrity": "sha512-A1vjIwC3qpdCso45Iw127gnp7sPhqgY8lUQhDrArIs+GbmfaaVPFuoyy7WyLT9EPZCRZ7j7aLdwUhQmHWesEow==",
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.2.2",
"minimatch": "^11.0.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
"path-scurry": "^3.0.0"
},
"engines": {
"node": "18 || 20 || >=22"
@@ -6466,13 +6302,35 @@
"node": ">= 6"
}
},
"node_modules/glob/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/glob/node_modules/minimatch": {
"version": "10.2.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.2.tgz",
"integrity": "sha512-pWTgz5CN3tjqyZNSK2tePlSmu9IwM41q8yn8Usdqqwe9TIHh+9dEpLLjF4uApsfPEAZY71qtSiA2B2APEr+1Yw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.2"
"@isaacs/nonrecursive-glob-match": "^1.0.2",
"brace-expansion": "^5.0.12"
},
"engines": {
"node": "18 || 20 || >=22"
@@ -7001,7 +6859,6 @@
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -7312,7 +7169,6 @@
},
"node_modules/isexe": {
"version": "2.0.0",
"dev": true,
"license": "ISC"
},
"node_modules/js-string-escape": {
@@ -7622,9 +7478,9 @@
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="
},
"node_modules/lru-cache": {
"version": "11.5.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
"integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
"version": "11.5.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz",
"integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==",
"license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
@@ -8226,19 +8082,15 @@
}
},
"node_modules/minimatch": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.2.tgz",
"integrity": "sha512-pWTgz5CN3tjqyZNSK2tePlSmu9IwM41q8yn8Usdqqwe9TIHh+9dEpLLjF4uApsfPEAZY71qtSiA2B2APEr+1Yw==",
"license": "BlueOak-1.0.0",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"@isaacs/nonrecursive-glob-match": "^1.0.2",
"brace-expansion": "^5.0.12"
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
"node": "*"
}
},
"node_modules/minimist": {
@@ -8719,7 +8571,6 @@
},
"node_modules/path-key": {
"version": "3.1.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -8731,9 +8582,9 @@
"license": "MIT"
},
"node_modules/path-scurry": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-3.0.0.tgz",
"integrity": "sha512-1pTbQqH1wIwMi/eleQ5leFTTCkzFsPcgXNjwOA8YGGW/W4/kHT3dssE7Z6NH+zuqNLOzOB0uaD61yl7cAcVhgg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
@@ -8949,6 +8800,27 @@
"url": "https://github.com/sponsors/yqnn"
}
},
"node_modules/readdir-glob/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/readdir-glob/node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/readdir-glob/node_modules/minimatch": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
@@ -9298,7 +9170,6 @@
},
"node_modules/shebang-command": {
"version": "2.0.0",
"dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -9309,7 +9180,6 @@
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -9395,7 +9265,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
},
@@ -9582,7 +9451,6 @@
},
"node_modules/string-width": {
"version": "4.2.3",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -9668,7 +9536,6 @@
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -10406,7 +10273,6 @@
},
"node_modules/which": {
"version": "2.0.2",
"dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
+3 -4
View File
@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "4.39.3",
"version": "4.39.4",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -43,7 +43,6 @@
"js-yaml": "^5.5.0",
"jsonschema": "1.5.0",
"long": "^5.3.2",
"minimatch": "^11.0.2",
"node-forge": "^1.4.1",
"semver": "^7.8.5",
"undici": "^7.30.1",
@@ -70,7 +69,7 @@
"eslint-plugin-import-x": "^4.17.1",
"eslint-plugin-jsdoc": "^65.4.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^13.0.6",
"glob": "^14.0.3",
"globals": "^17.13.0",
"nock": "^14.0.17",
"prettier": "^3.9.10",
@@ -97,7 +96,7 @@
"eslint-plugin-jsx-a11y": {
"semver": ">=6.3.1"
},
"glob": "^13.0.6",
"glob": "^14.0.3",
"undici": "^7.30.1"
}
}
+6
View File
@@ -78,6 +78,12 @@ export function getTemporaryDirectory(env: ReadOnlyEnv = getEnv()): string {
);
}
const PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json";
export function getDiffRangesJsonFilePath(env: Env = getEnv()): string {
return path.join(getTemporaryDirectory(env), PR_DIFF_RANGE_JSON_FILENAME);
}
export function getActionVersion(): string {
return __CODEQL_ACTION_VERSION__;
}
+3 -7
View File
@@ -19,10 +19,9 @@ import {
} from "./dependency-caching";
import { addDiagnostic, makeDiagnostic } from "./diagnostics";
import {
type DiffThunkRange,
getDiffRangesJsonFilePath,
DiffThunkRange,
readDiffRangesJsonFile,
} from "./diff-informed";
} from "./diff-informed-analysis-utils";
import { EnvVar } from "./environment";
import { FeatureEnablement, Feature } from "./feature-flags";
import { getGitRoot } from "./git-utils";
@@ -296,10 +295,7 @@ export async function setupDiffInformedQueryRun(
return await withGroupAsync(
"Generating diff range extension pack",
async () => {
const diffRanges = readDiffRangesJsonFile(
logger,
getDiffRangesJsonFilePath(),
);
const diffRanges = readDiffRangesJsonFile(logger);
if (diffRanges === undefined) {
logger.info(
"No precomputed diff ranges found; skipping diff-informed analysis stage.",
+11 -18
View File
@@ -15,7 +15,6 @@ import { createStubCodeQL } from "./codeql";
import { UserConfig } from "./config/db-config";
import * as file from "./config/file";
import * as configUtils from "./config-utils";
import { ActionsEnvVars } from "./environment";
import * as errorMessages from "./error-messages";
import { Feature } from "./feature-flags";
import { RepositoryProperties } from "./feature-flags/properties";
@@ -43,7 +42,6 @@ import {
SAMPLE_DOTCOM_API_DETAILS,
AssertableTarget,
RecordingLogger,
getTestEnv,
} from "./testing-utils";
import {
GitHubVariant,
@@ -153,11 +151,9 @@ function mockListLanguages(languages: string[]) {
test.serial("load empty config", async (t) => {
return await withTmpDir(async (tempDir) => {
const logger = new RecordingLogger();
const state = initAllState({ logger });
const languages = "javascript,python";
setupActionsVars(tempDir, tempDir, {}, state.env);
setupActionsVars(tempDir, tempDir);
const codeql = createStubCodeQL({
async resolveLanguages() {
@@ -170,6 +166,7 @@ test.serial("load empty config", async (t) => {
},
});
const state = initAllState({ logger });
const config = await configUtils.initConfig(
state,
createTestInitConfigInputs({
@@ -200,10 +197,9 @@ test.serial("load empty config", async (t) => {
test.serial("load code quality config", async (t) => {
return await withTmpDir(async (tempDir) => {
const logger = new RecordingLogger();
const state = initAllState({ logger });
const languages = "actions";
setupActionsVars(tempDir, tempDir, {}, state.env);
setupActionsVars(tempDir, tempDir);
const codeql = createStubCodeQL({
async resolveLanguages() {
@@ -215,6 +211,7 @@ test.serial("load code quality config", async (t) => {
},
});
const state = initAllState({ logger });
const config = await configUtils.initConfig(
state,
createTestInitConfigInputs({
@@ -256,10 +253,9 @@ test.serial(
async (t) => {
return await withTmpDir(async (tempDir) => {
const logger = new RecordingLogger();
const state = initAllState({ logger });
const languages = "javascript";
setupActionsVars(tempDir, tempDir, {}, state.env);
setupActionsVars(tempDir, tempDir);
const codeql = createStubCodeQL({
async resolveLanguages() {
@@ -295,6 +291,7 @@ test.serial(
repositoryProperties,
});
const state = initAllState({ logger });
await t.notThrowsAsync(async () => {
const config = await configUtils.initConfig(
state,
@@ -319,8 +316,6 @@ test.serial(
test.serial("loading a saved config produces the same config", async (t) => {
return await withTmpDir(async (tempDir) => {
const logger = new RecordingLogger();
const state = initAllState({ logger });
setupActionsVars(tempDir, tempDir, {}, state.env);
const codeql = createStubCodeQL({
async resolveLanguages() {
@@ -339,6 +334,7 @@ test.serial("loading a saved config produces the same config", async (t) => {
// Sanity check that getConfig returns undefined before we have called initConfig
t.deepEqual(await configUtils.getConfig(tempDir, logger), undefined);
const state = initAllState({ logger });
const config1 = await configUtils.initConfig(
state,
createTestInitConfigInputs({
@@ -368,8 +364,6 @@ test.serial("loading a saved config produces the same config", async (t) => {
test.serial("loading config with version mismatch throws", async (t) => {
return await withTmpDir(async (tempDir) => {
const logger = new RecordingLogger();
const state = initAllState({ logger });
setupActionsVars(tempDir, tempDir, {}, state.env);
const codeql = createStubCodeQL({
async resolveLanguages() {
@@ -393,6 +387,7 @@ test.serial("loading config with version mismatch throws", async (t) => {
.stub(actionsUtil, "getActionVersion")
.returns("does-not-exist");
const state = initAllState({ logger });
const config = await configUtils.initConfig(
state,
createTestInitConfigInputs({
@@ -502,8 +497,7 @@ const otherConfigFileContents = `
test.serial("load non-empty input", async (t) => {
return await withTmpDir(async (tempDir) => {
const state = initAllState();
setupActionsVars(tempDir, tempDir, {}, state.env);
setupActionsVars(tempDir, tempDir);
const codeql = createStubCodeQL({
async resolveLanguages() {
@@ -544,6 +538,7 @@ test.serial("load non-empty input", async (t) => {
const languagesInput = "javascript";
const configFilePath = createConfigFile(otherConfigFileContents, tempDir);
const state = initAllState();
const actualConfig = await configUtils.initConfig(
state,
createTestInitConfigInputs({
@@ -662,9 +657,7 @@ test.serial("API client used when reading remote config", async (t) => {
const configFile = "octo-org/codeql-config/config.yaml@main";
const languagesInput = "javascript";
const state = initAllState({
env: getTestEnv({ [ActionsEnvVars.RUNNER_TEMP]: tempDir }),
});
const state = initAllState();
await configUtils.initConfig(
state,
createTestInitConfigInputs({
+3 -7
View File
@@ -48,10 +48,7 @@ import {
addNoLanguageDiagnostic,
makeTelemetryDiagnostic,
} from "./diagnostics";
import {
getDiffRangesJsonFilePath,
prepareDiffInformedAnalysis,
} from "./diff-informed";
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
import { EnvVar, exportEnvVar, getEnv } from "./environment";
import * as errorMessages from "./error-messages";
import { Feature, FeatureEnablement, FeatureWithoutCLI } from "./feature-flags";
@@ -1291,10 +1288,9 @@ export async function initConfig(
}
const hasDiffRanges = await prepareDiffInformedAnalysis(
logger,
inputs.features,
inputs.codeql,
getDiffRangesJsonFilePath(actionState.env),
inputs.features,
logger,
);
await applyIncrementalAnalysisSettings(
@@ -1,12 +1,16 @@
import test, { ExecutionContext } from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "../actions-util";
import type { PullRequestBranches } from "../actions-util";
import * as apiClient from "../api-client";
import { getEnv } from "../environment";
import { Feature, FeatureEnablement, initFeatures } from "../feature-flags";
import { parseRepositoryNwo } from "../repository";
import * as actionsUtil from "./actions-util";
import type { PullRequestBranches } from "./actions-util";
import * as apiClient from "./api-client";
import {
getDiffInformedAnalysisBranches,
prepareDiffInformedAnalysis,
exportedForTesting,
} from "./diff-informed-analysis-utils";
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
import { parseRepositoryNwo } from "./repository";
import {
setupTests,
createFeatures,
@@ -15,16 +19,9 @@ import {
setupActionsVars,
makeMacro,
RecordingLogger,
} from "../testing-utils";
import { GitHubVariant, withTmpDir } from "../util";
import type { GitHubVersion } from "../util";
import {
getDiffInformedAnalysisBranches,
prepareDiffInformedAnalysis,
exportedForTesting,
getDiffRangesJsonFilePath,
} from ".";
} from "./testing-utils";
import { GitHubVariant, withTmpDir } from "./util";
import type { GitHubVersion } from "./util";
setupTests(test);
@@ -195,10 +192,9 @@ test.serial(
.resolves({ type: GitHubVariant.DOTCOM });
const result = await prepareDiffInformedAnalysis(
logger,
features,
codeql,
getDiffRangesJsonFilePath(getEnv()),
features,
logger,
);
t.false(result);
@@ -226,10 +222,9 @@ test.serial(
};
const result = await prepareDiffInformedAnalysis(
logger,
features,
codeql,
getDiffRangesJsonFilePath(getEnv()),
features,
logger,
);
t.false(result);
@@ -264,10 +259,9 @@ test.serial(
} as any);
const result = await prepareDiffInformedAnalysis(
logger,
features,
codeql,
getDiffRangesJsonFilePath(getEnv()),
features,
logger,
);
t.true(result);
@@ -302,10 +296,9 @@ test.serial(
} as any);
const result = await prepareDiffInformedAnalysis(
logger,
features,
codeql,
getDiffRangesJsonFilePath(getEnv()),
features,
logger,
);
t.false(result);
@@ -1,43 +1,23 @@
import * as fs from "fs";
import path from "path";
import * as actionsUtil from "../actions-util";
import type { PullRequestBranches } from "../actions-util";
import { getApiClient, getGitHubVersion } from "../api-client";
import type { CodeQL } from "../codeql";
import { type Env, getEnv } from "../environment";
import type { FeatureEnablement } from "../feature-flags";
import { Feature } from "../feature-flags/features";
import { Logger } from "../logging";
import { getRepositoryNwoFromEnv } from "../repository";
import { getErrorMessage, GitHubVariant, satisfiesGHESVersion } from "../util";
/** The filename used to persist PR diff ranges. */
const PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json";
/**
* Gets the full path of the file used to persist PR diff ranges.
*/
export function getDiffRangesJsonFilePath(env: Env = getEnv()): string {
return path.join(
actionsUtil.getTemporaryDirectory(env),
PR_DIFF_RANGE_JSON_FILENAME,
);
}
import * as actionsUtil from "./actions-util";
import type { PullRequestBranches } from "./actions-util";
import { getApiClient, getGitHubVersion } from "./api-client";
import type { CodeQL } from "./codeql";
import { Feature, FeatureEnablement } from "./feature-flags";
import { Logger } from "./logging";
import { getRepositoryNwoFromEnv } from "./repository";
import { getErrorMessage, GitHubVariant, satisfiesGHESVersion } from "./util";
/**
* This interface is an abbreviated version of the file diff object returned by
* the GitHub API.
*/
export interface FileDiff {
/** The name of the file that has changed. */
interface FileDiff {
filename: string;
/** The number of changes. */
changes: number;
/**
* The diff, if available. It may be absent if the file is binary, if the file diff is too large,
* or if the file is unchanged.
*/
// A patch may be absent if the file is binary, if the file diff is too large,
// or if the file is unchanged.
patch?: string | undefined;
}
@@ -83,10 +63,9 @@ export async function getDiffInformedAnalysisBranches(
* and are therefore available for use, `false` otherwise.
*/
export async function prepareDiffInformedAnalysis(
logger: Logger,
features: FeatureEnablement,
codeql: CodeQL,
jsonFilePath: string,
features: FeatureEnablement,
logger: Logger,
): Promise<boolean> {
let branches: PullRequestBranches | undefined;
try {
@@ -105,7 +84,7 @@ export async function prepareDiffInformedAnalysis(
}
try {
return await computeAndPersistDiffRanges(logger, jsonFilePath, branches);
return await computeAndPersistDiffRanges(branches, logger);
} catch (e) {
logger.warning(
`Failed to compute diff-informed analysis ranges: ${getErrorMessage(e)}`,
@@ -114,45 +93,29 @@ export async function prepareDiffInformedAnalysis(
}
}
/** Describes a changed line range in a file. */
export interface DiffThunkRange {
/** Relative path from the repository root, using forward slashes as separators. */
path: string;
/** The starting line of the change (1-based and inclusive). */
startLine: number;
/** The last line of the change (1-based and inclusive). */
endLine: number;
}
/**
* Writes an array of {@link DiffThunkRange} objects to the file given by {@link jsonFilePath}.
*
* @param logger The logger to use.
* @param jsonFilePath The path of the file to write.
* @param ranges The changed line ranges to write.
*/
export function writeDiffRangesJsonFile(
logger: Logger,
jsonFilePath: string,
ranges: DiffThunkRange[],
): void {
const jsonContents = JSON.stringify(ranges, null, 2);
const jsonFilePath = actionsUtil.getDiffRangesJsonFilePath();
fs.writeFileSync(jsonFilePath, jsonContents);
logger.debug(
`Wrote pr-diff-range JSON file to ${jsonFilePath}:\n${jsonContents}`,
);
}
/**
* Reads an array of {@link DiffThunkRange} objects from the file given by {@link jsonFilePath}.
*
* @param logger The logger to use.
* @returns The array of {@link DiffThunkRange} objects or `undefined` if the file couldn't be read.
*/
export function readDiffRangesJsonFile(
logger: Logger,
jsonFilePath: string,
): DiffThunkRange[] | undefined {
const jsonFilePath = actionsUtil.getDiffRangesJsonFilePath();
if (!fs.existsSync(jsonFilePath)) {
logger.debug(`Diff ranges JSON file does not exist at ${jsonFilePath}`);
return undefined;
@@ -175,12 +138,12 @@ export function readDiffRangesJsonFile(
* Return the file line ranges that were added or modified in the pull request.
*
* @param branches The base and head branches of the pull request.
* @param logger The logger to use.
*
* @returns
* An array of {@link DiffThunkRange} objects, where each describes a line range in a file
* that was changed in the pull request described by {@link branches} or `undefined` if
* we were unable to compute them.
* @param logger
* @returns An array of tuples, where each tuple contains the relative path of a
* file (relative to the repository root, as returned by the GitHub compare API),
* the start line and the end line (both 1-based and inclusive) of an
* added or modified range in that file. Returns `undefined` if the action was
* not triggered by a pull request or if there was an error.
*/
export async function getPullRequestEditedDiffRanges(
branches: PullRequestBranches,
@@ -217,25 +180,22 @@ export async function getPullRequestEditedDiffRanges(
* diff from the GitHub API and writes it to the diff ranges JSON file so that
* CodeQL can use it for diff-informed analysis.
*
* @param logger The logger to use.
* @param jsonFilePath The path of the JSON file to write.
* @param branches The base and head branches of the pull request, as returned
* by `getDiffInformedAnalysisBranches`.
*
* @param logger
* @returns `true` if the diff ranges were successfully computed and persisted,
* otherwise `false`.
*/
export async function computeAndPersistDiffRanges(
logger: Logger,
jsonFilePath: string,
branches: PullRequestBranches,
logger: Logger,
): Promise<boolean> {
logger.info("Computing PR diff ranges...");
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
if (ranges === undefined) {
return false;
}
writeDiffRangesJsonFile(logger, jsonFilePath, ranges);
writeDiffRangesJsonFile(logger, ranges);
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
logger.info(
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
@@ -243,19 +203,6 @@ export async function computeAndPersistDiffRanges(
return true;
}
/**
* Fetch an array of {@link FileDiff} objects using the GitHub API describing the changed files
* in the pull request with the base and head refs given by {@link branches}.
*
* @param branches The pull request branch refs.
* @param logger The logger to use.
*
* @throws Non-HTTP errors that occur while fetching the file diffs.
*
* @returns
* An array of {@link FileDiff} objects describing the changed files in the PR, or
* `undefined` if we couldn't obtain the changed files from the API.
*/
async function getFileDiffsWithBasehead(
branches: PullRequestBranches,
logger: Logger,
@@ -296,16 +243,6 @@ async function getFileDiffsWithBasehead(
}
}
/**
* Extracts an array of {@link DiffThunkRange} objects from {@link fileDiff}.
*
* @param fileDiff The {@link FileDiff} object describing changes to a particular file.
* @param logger The logger to use.
*
* @returns
* The {@link DiffThunkRange} objects extracted from {@link fileDiff},
* or `undefined` if there are none that could be extracted.
*/
function getDiffRanges(
fileDiff: FileDiff,
logger: Logger,
-79
View File
@@ -1,79 +0,0 @@
import test from "ava";
import type { FileDiff } from "../diff-informed";
import { setupTests } from "../testing-utils";
import { matchPatterns, relevantChangeFor } from "./changes";
setupTests(test);
function mkTestDiff(filename: string): FileDiff {
return { filename, changes: 42 };
}
test("matchPatterns - true if any pattern matches", (t) => {
t.true(matchPatterns("/path/to/file.js", ["*.js"]));
t.true(matchPatterns("/path/to", ["/path/**"]));
t.true(matchPatterns("/path/to", ["foo.txt", "/path/**"]));
t.true(matchPatterns("/path/to", ["foo.txt", "/path/from", "/path/to*"]));
});
test("matchPatterns - false if no pattern matches", (t) => {
t.false(matchPatterns("/path/to", []));
t.false(matchPatterns("/path/to", ["/some/path/**"]));
});
test("relevantChangeFor - relevant if expected", (t) => {
// No configuration: all files are relevant
t.true(relevantChangeFor({}, mkTestDiff("/path/to/file.js")));
// Various configurations that we expect to match the given path.
t.true(
relevantChangeFor({ patterns: ["*.js"] }, mkTestDiff("/path/to/file.js")),
);
t.true(
relevantChangeFor(
{ patterns: ["/path/**"] },
mkTestDiff("/path/to/file.js"),
),
);
// `exclude` configuration doesn't apply
t.true(
relevantChangeFor({ exclude: ["*.ts"] }, mkTestDiff("/path/to/file.js")),
);
t.true(
relevantChangeFor(
{ patterns: ["*.js"], exclude: ["file.ts"] },
mkTestDiff("/path/to/file.js"),
),
);
t.true(
relevantChangeFor(
{ patterns: ["/path/**"], exclude: ["/path/to/**/*.ts"] },
mkTestDiff("/path/to/file.js"),
),
);
});
test("relevantChangeFor - exclude patterns filter results", (t) => {
// No patterns: all files are relevant, but `exclude` filters `.js` files.
t.false(
relevantChangeFor({ exclude: ["*.js"] }, mkTestDiff("/path/to/file.js")),
);
// Various `patterns` configurations that we expect to match the given path and
// more specific `exclude` configurations that we expect to also match.
t.false(
relevantChangeFor(
{ patterns: ["*.js"], exclude: ["file.js"] },
mkTestDiff("/path/to/file.js"),
),
);
t.false(
relevantChangeFor(
{ patterns: ["/path/**"], exclude: ["/path/to/**/*.js"] },
mkTestDiff("/path/to/file.js"),
),
);
});
-112
View File
@@ -1,112 +0,0 @@
import { minimatch } from "minimatch";
import type { FileDiff } from "../diff-informed";
import { BuiltInLanguage } from ".";
/**
* Represents configurations for how to detect whether changes relate to a given analysis.
*/
export type ChangePatterns = {
/**
* A list of glob patterns.
*
* If a changed file has matches one of these, we conclude that files relevant to the
* analysis have changed.
*
* If undefined, all changes are considered relevant.
*/
patterns?: string[];
/**
* A list of glob patterns to exclude from `patterns`. Allows specific patterns to be excluded
* that would otherwise be included by `patterns`.
*
* If a changed file matches one of `patterns` and `exclude`, then it is not considered
* relevant to the analysis.
*/
exclude?: string[];
};
/**
* A mapping from all {@link BuildInLanguage}s to a {@link ChangePatterns} configuration.
*/
export const CHANGE_PATTERNS: Record<BuiltInLanguage, ChangePatterns> = {
[BuiltInLanguage.actions]: {},
[BuiltInLanguage.cpp]: {},
[BuiltInLanguage.csharp]: {},
[BuiltInLanguage.go]: {},
[BuiltInLanguage.java]: {},
[BuiltInLanguage.javascript]: {},
[BuiltInLanguage.python]: {},
[BuiltInLanguage.ruby]: {},
[BuiltInLanguage.rust]: {},
[BuiltInLanguage.swift]: {},
};
/**
* Decides whether {@link val} matches any of {@link patterns}. Returns early
* as soon as a pattern matches.
*/
export function matchPatterns(val: string, patterns: string[]): boolean {
for (const pattern of patterns) {
if (minimatch(val, pattern, { matchBase: true })) {
return true;
}
}
return false;
}
/**
* Decides whether {@link diff} matches the configuration in {@link changePatterns}.
*
* @param changePatterns The configuration of patterns to match {@link diff}'s path against.
* @param diff A description of a change.
*/
export function relevantChangeFor(
changePatterns: ChangePatterns,
diff: FileDiff,
): boolean {
// If `patterns` is defined and none match, then the change is not relevant.
if (
changePatterns.patterns !== undefined &&
!matchPatterns(diff.filename, changePatterns.patterns)
) {
return false;
}
// At this point we have decided that the change is relevant, either because no
// patterns are configured (all changes are relevant) or because one of the configured
// patterns matched. Let's check if `exclude` patterns are configured and if any match.
// If so, then we don't consider the change relevant after all.
if (
changePatterns.exclude !== undefined &&
matchPatterns(diff.filename, changePatterns.exclude)
) {
return false;
}
// The change is relevant and none of the `exclude` patterns matched (or none were configured).
return true;
}
/**
* Decides whether at least one of the given {@link diffs} matches the configuration for {@link language}
* from {@link CHANGE_PATTERNS}.
*
* @param language The language to check for changes for.
* @param diffs All changes to check.
*/
export function relevantChangesFor(
language: BuiltInLanguage,
diffs: FileDiff[],
): boolean {
for (const diff of diffs) {
if (relevantChangeFor(CHANGE_PATTERNS[language], diff)) {
return true;
}
}
return false;
}
+4 -5
View File
@@ -5,7 +5,6 @@ import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "../actions-util";
import * as diffInformed from "../diff-informed";
import * as gitUtils from "../git-utils";
import {
createTestConfig,
@@ -61,7 +60,7 @@ test.serial(
const diffRangeFilePath = path.join(tempDir, "pr-diff-range.json");
sinon.stub(actionsUtil, "getTemporaryDirectory").returns(tempDir);
sinon
.stub(diffInformed, "getDiffRangesJsonFilePath")
.stub(actionsUtil, "getDiffRangesJsonFilePath")
.returns(diffRangeFilePath);
sinon.stub(gitUtils, "getGitRoot").resolves(sourceRoot);
const changesFilePath = await writeOverlayChangesFile(
@@ -127,7 +126,7 @@ test.serial(
const diffRangeFilePath = path.join(tempDir, "pr-diff-range.json");
sinon.stub(actionsUtil, "getTemporaryDirectory").returns(tempDir);
sinon
.stub(diffInformed, "getDiffRangesJsonFilePath")
.stub(actionsUtil, "getDiffRangesJsonFilePath")
.returns(diffRangeFilePath);
sinon.stub(gitUtils, "getGitRoot").resolves(sourceRoot);
@@ -197,7 +196,7 @@ test.serial(
const diffRangeFilePath = path.join(tempDir, "pr-diff-range.json");
sinon.stub(actionsUtil, "getTemporaryDirectory").returns(tempDir);
sinon
.stub(diffInformed, "getDiffRangesJsonFilePath")
.stub(actionsUtil, "getDiffRangesJsonFilePath")
.returns(diffRangeFilePath);
sinon.stub(gitUtils, "getGitRoot").resolves(sourceRoot);
@@ -260,7 +259,7 @@ test.serial(
const diffRangeFilePath = path.join(tempDir, "pr-diff-range.json");
sinon.stub(actionsUtil, "getTemporaryDirectory").returns(tempDir);
sinon
.stub(diffInformed, "getDiffRangesJsonFilePath")
.stub(actionsUtil, "getDiffRangesJsonFilePath")
.returns(diffRangeFilePath);
// getGitRoot returns the repo root (parent of sourceRoot)
sinon.stub(gitUtils, "getGitRoot").resolves(repoRoot);
+2 -2
View File
@@ -1,9 +1,9 @@
import * as fs from "fs";
import * as path from "path";
import * as actionsUtil from "../actions-util";
import { getOptionalInput, getTemporaryDirectory } from "../actions-util";
import { type Config } from "../config-utils";
import { getDiffRangesJsonFilePath } from "../diff-informed";
import { getFileOidsUnderPath, getGitRoot } from "../git-utils";
import { Logger } from "../logging";
import { getBaseDatabaseOidsFilePath } from "../util";
@@ -135,7 +135,7 @@ async function getDiffRangeFilePaths(
sourceRoot: string,
logger: Logger,
): Promise<string[]> {
const jsonFilePath = getDiffRangesJsonFilePath();
const jsonFilePath = actionsUtil.getDiffRangesJsonFilePath();
if (!fs.existsSync(jsonFilePath)) {
logger.debug(
+1 -2
View File
@@ -9,7 +9,7 @@ import * as sinon from "sinon";
import * as analyses from "./analyses";
import { AnalysisKind, CodeQuality, CodeScanning } from "./analyses";
import * as api from "./api-client";
import * as diffUtils from "./diff-informed";
import * as diffUtils from "./diff-informed-analysis-utils";
import { getEnv } from "./environment";
import { Logger } from "./logging";
import * as sarif from "./sarif";
@@ -1074,7 +1074,6 @@ function runFilterAlertsByDiffRange(
logger: Logger = new RecordingLogger(),
): Partial<sarif.Log> {
sinon.stub(diffUtils, "readDiffRangesJsonFile").returns(diffRanges);
sinon.stub(diffUtils, "getDiffRangesJsonFilePath").returns("");
return uploadLib.filterAlertsByDiffRange(logger, input);
}
+2 -8
View File
@@ -13,10 +13,7 @@ import * as api from "./api-client";
import { getGitHubVersion, wrapApiConfigurationError } from "./api-client";
import { CodeQL, getCodeQL } from "./codeql";
import type { ActionConfig } from "./config/action-config";
import {
getDiffRangesJsonFilePath,
readDiffRangesJsonFile,
} from "./diff-informed";
import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils";
import { ActionsEnvVars, EnvVar, exportEnvVar } from "./environment";
import { FeatureEnablement } from "./feature-flags";
import * as fingerprints from "./fingerprints";
@@ -1082,10 +1079,7 @@ export function filterAlertsByDiffRange(
logger: Logger,
sarifLog: Partial<sarif.Log>,
): Partial<sarif.Log> {
const diffRanges = readDiffRangesJsonFile(
logger,
getDiffRangesJsonFilePath(),
);
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges?.length) {
return sarifLog;
}
@@ -1 +0,0 @@
- Fixed diff-informed alert filtering incorrectly removing alerts in changed files whose paths contain spaces, special characters, or non-ASCII characters. [#4283](https://github.com/github/codeql-action/pull/4283)