Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove node_modules and compile typescript into minified scripts #2578

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
lib/*.js linguist-generated=true
*/*-action.js linguist-generated=true
*/*-action-post.js linguist-generated=true
.github/workflows/__* linguist-generated=true

# Reduce incidence of needless merge conflicts on CHANGELOG.md
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/prepare-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ outputs:
runs:
using: composite
steps:
- name: npm install
shell: bash
run: |
if command -v npm >/dev/null 2>/dev/null; then
npm ci
fi
Comment on lines +25 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the if necessary? If npm isn't available, how are we going to install dependencies?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for

- name: Prepare test
id: prepare-test
uses: ./.github/actions/prepare-test
with:
version: ${{ matrix.version }}
use-all-platform-bundle: 'false'
setup-kotlin: 'false'

because it uses an ubuntu:22.04 container that doesn't have npm:
container:
image: ubuntu:22.04

But it doesn't need node_modules for the magic that it's doing...

- name: Move codeql-action
shell: bash
run: |
Expand Down
4 changes: 4 additions & 0 deletions .github/actions/update-bundle/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ runs:
shell: bash
run: npm install -g ts-node

- name: Install
shell: bash
run: npm ci

- name: Run update script
working-directory: ${{ github.action_path }}
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/update-bundle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async function main() {
const previousDefaults: Defaults = JSON.parse(fs.readFileSync('../../../src/defaults.json', 'utf8'));
const newDefaults = await getNewDefaults(previousDefaults);
// Update the source file in the repository. Calling workflows should subsequently rebuild
// the Action to update `lib/defaults.json`.
// the Action.
fs.writeFileSync('../../../src/defaults.json', JSON.stringify(newDefaults, null, 2) + "\n");
}

Expand Down
43 changes: 29 additions & 14 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,23 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Install
shell: bash
run: npm install

- name: Lint
id: lint
run: npm run-script lint-ci

- name: Upload sarif
uses: github/codeql-action/upload-sarif@v3
# Only upload SARIF for the latest version of Node.js
if: "!cancelled() && matrix.node-types-version == 'current' && !startsWith(github.head_ref, 'dependabot/')"
if: ${{ !cancelled() && matrix.node-types-version == 'current' && !startsWith(github.head_ref, 'dependabot/') }}
with:
sarif_file: eslint.sarif
category: eslint

- name: Update version of @types/node
- name: Override version of @types/node
if: matrix.node-types-version != 'current'
env:
NODE_TYPES_VERSION: ${{ matrix.node-types-version }}
Expand All @@ -52,6 +56,25 @@ jobs:
# `npm install` on Linux.
npm install
# esbuild embeds package.json version details into these files.
# Since the jq step has actively changed package.json, we know that if these files
# are successfully rebuilt (without the changes below), they would be dirty.
#
# In order to allow check-js.sh to verify that it can build them at all, we ignore them,
# delete them, and commit those changes. Thus, when it runs, it will be able to try to
# build them, and as long at they build, it will be happy. If it can't build them, it can
# complain, although that error won't make much sense, because you shouldn't update them
# using the wrong node types version information.
(
echo '*/*-action.js';
echo '*/*-action-post.js'
) >> .gitignore
for action in $(
find * -mindepth 1 -maxdepth 1 -type f -name action.yml
); do
git rm -f "$(dirname "$action")"/*-action*.js
done
Comment on lines +68 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is necessary as a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can explain the problem here. I'm not entirely certain what the code is doing/trying to do.

The problem is that because we're bundling all the pieces from node_modules that we actually use as well as any dependency information, there's a segment in each of these files...

that looks like
{ Kie.exports = { name: "codeql", version: "3.27.1", private: !0, description: "CodeQL action", scripts: { build: "tsc --build && npm run package", package: "bash .github/workflows/script/package.sh", test: "ava src/**.test.ts --serial --verbose", "test-debug": "ava src/**.test.ts --serial --verbose --timeout=20m", lint: "eslint --report-unused-disable-directives --max-warnings=0 .", "lint-fix": "eslint --report-unused-disable-directives --max-warnings=0 . --fix", "lint-ci": "SARIF_ESLINT_IGNORE_SUPPRESSED=true eslint --report-unused-disable-directives --max-warnings=0 . --format @microsoft/eslint-formatter-sarif --output-file=eslint.sarif" }, ava: { typescript: { rewritePaths: { "src/": "lib/" }, compile: !1 } }, license: "MIT", dependencies: { "@actions/artifact": "^2.1.9", "@actions/artifact-legacy": "npm:@actions/artifact@^1.1.2", "@actions/cache": "^3.2.4", "@actions/core": "^1.11.1", "@actions/exec": "^1.1.1", "@actions/github": "^5.1.1", "@actions/glob": "^0.4.0", "@actions/io": "^1.1.3", "@actions/tool-cache": "^2.0.1", "@chrisgavin/safe-which": "^1.0.2", "@octokit/plugin-retry": "^5.0.2", "@octokit/types": "^13.6.1", "@schemastore/package": "0.0.10", "@types/node-forge": "^1.3.11", "@types/uuid": "^10.0.0", "adm-zip": "^0.5.16", "check-disk-space": "^3.4.0", "console-log-level": "^1.4.1", del: "^6.1.1", "fast-deep-equal": "^3.1.3", "file-url": "^3.0.0", "follow-redirects": "^1.15.9", fs: "0.0.1-security", "get-folder-size": "^2.0.1", "js-yaml": "^4.1.0", jsonschema: "1.4.1", long: "^5.2.3", "node-forge": "^1.3.1", path: "^0.12.7", semver: "^7.6.3", uuid: "^11.0.1", zlib: "^1.0.5" }, "//": ["micromatch is an unspecified dependency of ava"], devDependencies: { "@ava/typescript": "4.1.0", "@eslint/compat": "^1.1.1", "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.13.0", "@microsoft/eslint-formatter-sarif": "^3.1.0", "@types/adm-zip": "^0.5.5", "@types/console-log-level": "^1.4.5", "@types/follow-redirects": "^1.14.4", "@types/get-folder-size": "^2.0.0", "@types/js-yaml": "^4.0.9", "@types/node": "20.9.0", "@types/semver": "^7.5.8", "@types/sinon": "^17.0.3", "@typescript-eslint/eslint-plugin": "^8.11.0", "@typescript-eslint/parser": "^8.11.0", ava: "^5.3.1", esbuild: "^0.24.0", eslint: "^8.57.1", "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-filenames": "^1.3.2", "eslint-plugin-github": "^5.0.2", "eslint-plugin-import": "2.29.1", "eslint-plugin-no-async-foreach": "^0.1.1", micromatch: "4.0.8", nock: "^13.5.5", sinon: "^19.0.2", typescript: "^5.6.3" }, overrides: { "@actions/tool-cache": { semver: ">=6.3.1" }, "eslint-plugin-import": { semver: ">=6.3.1" }, "eslint-plugin-jsx-a11y": { semver: ">=6.3.1" } } } })
reformatted as almost json
{ name: "codeql", version: "3.27.1", private: !0, description: "CodeQL action", scripts: { build: "tsc --build && npm run package", package: "bash .github/workflows/script/package.sh", test: "ava src/**.test.ts --serial --verbose",
    "test-debug": "ava src/**.test.ts --serial --verbose --timeout=20m", lint: "eslint --report-unused-disable-directives --max-warnings=0 .",
    "lint-fix": "eslint --report-unused-disable-directives --max-warnings=0 . --fix",
    "lint-ci": "SARIF_ESLINT_IGNORE_SUPPRESSED=true eslint --report-unused-disable-directives --max-warnings=0 . --format @microsoft/eslint-formatter-sarif --output-file=eslint.sarif"
  }, ava: { typescript: { rewritePaths: {
        "src/": "lib/"
      }, compile: !1
    }
  }, license: "MIT", dependencies: {
    "@actions/artifact": "^2.1.9",
    "@actions/artifact-legacy": "npm:@actions/artifact@^1.1.2",
    "@actions/cache": "^3.2.4",
    "@actions/core": "^1.11.1",
    "@actions/exec": "^1.1.1",
    "@actions/github": "^5.1.1",
    "@actions/glob": "^0.4.0",
    "@actions/io": "^1.1.3",
    "@actions/tool-cache": "^2.0.1",
    "@chrisgavin/safe-which": "^1.0.2",
    "@octokit/plugin-retry": "^5.0.2",
    "@octokit/types": "^13.6.1",
    "@schemastore/package": "0.0.10",
    "@types/node-forge": "^1.3.11",
    "@types/uuid": "^10.0.0",
    "adm-zip": "^0.5.16",
    "check-disk-space": "^3.4.0",
    "console-log-level": "^1.4.1", del: "^6.1.1",
    "fast-deep-equal": "^3.1.3",
    "file-url": "^3.0.0",
    "follow-redirects": "^1.15.9", fs: "0.0.1-security",
    "get-folder-size": "^2.0.1",
    "js-yaml": "^4.1.0", jsonschema: "1.4.1", long: "^5.2.3",
    "node-forge": "^1.3.1", path: "^0.12.7", semver: "^7.6.3", uuid: "^11.0.1", zlib: "^1.0.5"
  },
  "//": [
    "micromatch is an unspecified dependency of ava"
  ], devDependencies: {
    "@ava/typescript": "4.1.0",
    "@eslint/compat": "^1.1.1",
    "@eslint/eslintrc": "^3.1.0",
    "@eslint/js": "^9.13.0",
    "@microsoft/eslint-formatter-sarif": "^3.1.0",
    "@types/adm-zip": "^0.5.5",
    "@types/console-log-level": "^1.4.5",
    "@types/follow-redirects": "^1.14.4",
    "@types/get-folder-size": "^2.0.0",
    "@types/js-yaml": "^4.0.9",
    "@types/node": "20.9.0",
    "@types/semver": "^7.5.8",
    "@types/sinon": "^17.0.3",
    "@typescript-eslint/eslint-plugin": "^8.11.0",
    "@typescript-eslint/parser": "^8.11.0", ava: "^5.3.1", esbuild: "^0.24.0", eslint: "^8.57.1",
    "eslint-import-resolver-typescript": "^3.6.3",
    "eslint-plugin-filenames": "^1.3.2",
    "eslint-plugin-github": "^5.0.2",
    "eslint-plugin-import": "2.29.1",
    "eslint-plugin-no-async-foreach": "^0.1.1", micromatch: "4.0.8", nock: "^13.5.5", sinon: "^19.0.2", typescript: "^5.6.3"
  }, overrides: {
    "@actions/tool-cache": { semver: ">=6.3.1"
    },
    "eslint-plugin-import": { semver: ">=6.3.1"
    },
    "eslint-plugin-jsx-a11y": { semver: ">=6.3.1"
    }
  }
}

Focussing just on the...

devDependencies
{
    "@ava/typescript": "4.1.0",
    "@eslint/compat": "^1.1.1",
    "@eslint/eslintrc": "^3.1.0",
    "@eslint/js": "^9.13.0",
    "@microsoft/eslint-formatter-sarif": "^3.1.0",
    "@types/adm-zip": "^0.5.5",
    "@types/console-log-level": "^1.4.5",
    "@types/follow-redirects": "^1.14.4",
    "@types/get-folder-size": "^2.0.0",
    "@types/js-yaml": "^4.0.9",
    "@types/node": "20.9.0",
    "@types/semver": "^7.5.8",
    "@types/sinon": "^17.0.3",
    "@typescript-eslint/eslint-plugin": "^8.11.0",
    "@typescript-eslint/parser": "^8.11.0", ava: "^5.3.1", esbuild: "^0.24.0", eslint: "^8.57.1",
    "eslint-import-resolver-typescript": "^3.6.3",
    "eslint-plugin-filenames": "^1.3.2",
    "eslint-plugin-github": "^5.0.2",
    "eslint-plugin-import": "2.29.1",
    "eslint-plugin-no-async-foreach": "^0.1.1", micromatch: "4.0.8", nock: "^13.5.5", sinon: "^19.0.2", typescript: "^5.6.3"
  }

... anyway, in there is this field:

    "@types/node": "20.9.0",

Which will be, by definition, different when we install a different version of @types/node.

Assuming all the code wants to know is "does this stuff compile", then the changes here are the steps required to make it happy. It basically removes the current versions of the files, adds them to ignore (because the check tool uses git porcelain to complain about any unknown or dirty files).

It's possible that this script could be simplified to do less checking, but it required a lot of thought just to understand why it was unhappy and how to make it happy, deciding whether it was still relevant was above my pay grade (you can see the same story with the removeNPMAbsolutePaths thing which I suspected wasn't necessary but wasn't confident about).

Note: the presence of the above blob makes each change annoying (as you will see when I refresh this branch with the location change to package.sh). If it's possible to remove the dependency information without breaking any code or legal requirements, I'd personally be inclined to do so. I'm not sure who's asking for it/why -- perhaps there's a contract that a library be able to inspect itself to determine which versions it thought it asked for? I don't really think that the app needs to know which build scripts were present in package.json.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if [ ! -z "$(git status --porcelain)" ]; then
git config --global user.email "[email protected]"
git config --global user.name "github-actions[bot]"
Expand All @@ -63,17 +86,6 @@ jobs:
- name: Check generated JS
run: .github/workflows/script/check-js.sh

check-node-modules:
if: github.event_name != 'push' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/releases/v')
name: Check modules up to date
runs-on: macos-latest
timeout-minutes: 45

steps:
- uses: actions/checkout@v4
- name: Check node modules up to date
run: .github/workflows/script/check-node-modules.sh

check-file-contents:
if: github.event_name != 'push' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/releases/v')
name: Check file contents
Expand Down Expand Up @@ -102,7 +114,7 @@ jobs:
npm-test:
if: github.event_name != 'push' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/releases/v')
name: Unit Test
needs: [check-js, check-node-modules]
needs: check-js
strategy:
fail-fast: false
matrix:
Expand All @@ -112,6 +124,9 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Build
run: |
npm run build
- name: npm test
run: |
# Run any commands referenced in package.json using Bash, otherwise
Expand Down
17 changes: 11 additions & 6 deletions .github/workflows/rebuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ jobs:
run: |
git fetch origin "$BASE_BRANCH"

# Allow merge conflicts in `lib`, since rebuilding should resolve them.
# Allow merge conflicts in `action(-post|-pre|).js`, since rebuilding should resolve them.
git merge "origin/$BASE_BRANCH" || echo "Merge conflicts detected"

# Check for merge conflicts outside of `lib`. Disable git diff's trailing whitespace check
# since `node_modules/@types/semver/README.md` fails it.
if git -c core.whitespace=-trailing-space diff --check | grep --invert-match '^lib/'; then
echo "Merge conflicts detected outside of lib/ directory. Please resolve them manually."
git -c core.whitespace=-trailing-space diff --check | grep --invert-match '^lib/' || true
git_diff_ignore_generated_actions() {
git diff --check |
grep --invert-match -- '-action-pre\.js$' |
grep --invert-match -- '-action\.js$' |
grep --invert-match -- '-action-post\.js$'
}

if git_diff_ignore_generated_actions | grep -q .; then
echo "Merge conflicts detected outside of generated action js files. Please resolve them manually."
git_diff_ignore_generated_actions || true
exit 1
fi

Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/script/check-js.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ if [ ! -z "$(git status --porcelain)" ]; then
>&2 echo "Failed: Repo should be clean before testing!"
exit 1
fi
# Wipe the lib directory in case there are extra unnecessary files in there
rm -rf lib
# Generate the JavaScript files
npm run-script build
# Check that repo is still clean
if [ ! -z "$(git status --porcelain)" ]; then
# If we get a fail here then the PR needs attention
>&2 echo "Failed: JavaScript files are not up to date. Run 'rm -rf lib && npm run-script build' to update"
>&2 echo "Failed: JavaScript files are not up to date. Run 'npm run-script build' to update"
git status
exit 1
fi
Expand Down
20 changes: 0 additions & 20 deletions .github/workflows/script/check-node-modules.sh

This file was deleted.

18 changes: 18 additions & 0 deletions .github/workflows/script/package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh
bundle_file() {
module=$(dirname "$1")
file=$(perl -ne 'next unless m<'"$2"': .(?:.*/|)(.*\.js)>;print $1' "$1")
if [ -n "$file" ]; then
if [ "$2" = main ]; then
suffix=''
else
suffix="-$2"
fi
./node_modules/.bin/esbuild "lib/$module-action$suffix.js" --bundle --minify --platform=node --outfile="./$module/$file"
perl -pi -e 's/scripts:\{.*?\}/scripts:{}/' "./$module/$file"
fi
};
for a in */action.yml; do
bundle_file $a main;
bundle_file $a post;
done
21 changes: 0 additions & 21 deletions .github/workflows/script/update-node-modules.sh

This file was deleted.

7 changes: 3 additions & 4 deletions .github/workflows/update-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ jobs:
run: |
git fetch origin "$BRANCH" --depth=1
git checkout "origin/$BRANCH"
.github/workflows/script/update-node-modules.sh update
npm run build
if [ ! -z "$(git status --porcelain)" ]; then
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git add node_modules
git commit -am "Update checked-in dependencies"
git commit -am "Update action bundles"
git push origin "HEAD:$BRANCH"
echo "Pushed a commit to update the checked-in dependencies." \
echo "Pushed a commit to update the checked-in action bundles." \
"Please mark the PR as ready for review to trigger PR checks." |
gh pr comment --body-file - --repo github/codeql-action "${{ github.event.pull_request.number }}"
gh pr ready --undo --repo github/codeql-action "${{ github.event.pull_request.number }}"
Expand Down
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Ignore for example failing-tests.json from AVA
node_modules/.cache/
# actions are bundled to make this repository lightweight for consumers
node_modules/
# lib is generated by tsc
lib
# Java build files
.gradle/
*.class
Expand All @@ -8,4 +10,4 @@ node_modules/.cache/
# eslint sarif report
eslint.sarif
# for local incremental compilation
tsconfig.tsbuildinfo
tsconfig.tsbuildinfo
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ No user facing changes.

- The CodeQL Action now downloads bundles compressed using Zstandard on GitHub Enterprise Server when using Linux or macOS runners. This speeds up the installation of the CodeQL tools. This feature is already available to GitHub.com users. [#2573](https://github.com/github/codeql-action/pull/2573)
- Update default CodeQL bundle version to 2.19.3. [#2576](https://github.com/github/codeql-action/pull/2576)
- The CodeQL Action is now faster to download by several seconds since `node_modules` are no longer included in this repository. [#2578](https://github.com/github/codeql-action/pull/2578)

## 3.27.0 - 22 Oct 2024

Expand Down
12 changes: 3 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,14 @@ Before you start, ensure that you have a recent version of node (16 or higher) i

### Common tasks

* Transpile the TypeScript to JavaScript: `npm run build`. Note that the JavaScript files are committed to git.
* Run tests: `npm run test`. You’ll need to ensure that the JavaScript files are up-to-date first by running the command above.
* Run the linter: `npm run lint`.
* Transpile the TypeScript to JavaScript: `npm run build`. Note that the bundled action files are committed to git.
* Run tests: `npm run test`. You’ll need to ensure that the `node_modules` are available and JavaScript files are up-to-date first by running the commands above.
* Run the linter: `npm run lint` (requires the first command).

This project also includes configuration to run tests from VSCode (with support for breakpoints) - open the test file you wish to run and choose "Debug AVA test file" from the Run menu in the Run panel.

You may want to run `tsc --watch` from the command line or inside of vscode in order to ensure build artifacts are up to date as you are working.

### Checking in compiled artifacts and `node_modules`

Because CodeQL Action users consume the code directly from this repository, and there can be no build step during an GitHub Actions run, this repository contains all compiled artifacts and node modules. There is a PR check that will fail if any of the compiled artifacts are not up to date. Compiled artifacts are stored in the `lib/` directory. For all day-to-day development purposes, this folder can be ignored.

Only run `npm install` if you are explicitly changing the set of dependencies in `package.json`. The `node_modules` directory should be up to date when you check out, but if for some reason, there is an inconsistency use `npm ci && npm run removeNPMAbsolutePaths` to ensure the directory is in a state consistent with the `package-lock.json`. Note that due to a macOS-specific dependency, this command should be run on a macOS machine. There is a PR check to ensure the consistency of the `node_modules` directory.

### Running the action

To see the effect of your changes and to test them, push your changes in a branch and then look at the [Actions output](https://github.com/github/codeql-action/actions) for that branch. You can also exercise the code locally by running the automated tests.
Expand Down
4 changes: 2 additions & 2 deletions analyze/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,5 @@ outputs:
description: The ID of the uploaded SARIF file.
runs:
using: node20
main: "../lib/analyze-action.js"
post: "../lib/analyze-action-post.js"
main: "analyze-action.js"
post: "analyze-action-post.js"
Loading