Skip to content

Commit

Permalink
🌱 Add checks for package-lock.json to lint-staged and CI (#1365)
Browse files Browse the repository at this point in the history
Following up on #1357, we now know that while a `package-lock.json` can
be valid and build upstream without a `resolved` field for each external
package, for a downstream build it is not valid. In a network detached
downstream build environment, a dependency downloader will be needed to
fetch and archive all of the project's dependencies (see cachito).
Without the lock file's resolved fields, the downloader cannot ensure
the source of the packages and will fail.

To help identify this situation, the `verify_lock.mjs` script will look
for this invalid pattern and report back.

The script will be called automatically when:

- (via lint-staged) a git commit is being created and it includes a
change to `package-lock.json`

- (via github actions) as part of CI tests when a PR is submitted or
updated

With both of these test points in place, it should be difficult to merge
a change to the lockfile that will break a downstream build.

Signed-off-by: Scott J Dickerson <[email protected]>
Co-authored-by: Ian Bolton <[email protected]>
  • Loading branch information
sjd78 and ibolton336 authored Sep 15, 2023
1 parent df2df8c commit 2ec8184
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 2 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ jobs:
with:
node-version: ${{ matrix.node-version }}

- name: Verify package-lock.json
run: ./scripts/verify_lock.mjs

- name: Install
run: npm clean-install
run: npm clean-install --ignore-scripts

- name: Lint sources
run: npm run lint
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"port-forward": "concurrently -c auto 'npm:port-forward:*'"
},
"lint-staged": {
"*": "prettier --ignore-unknown --write"
"package-lock.json": "./scripts/verify_lock.mjs",
"!(package-lock.json)*": "prettier --ignore-unknown --write"
},
"workspaces": [
"common",
Expand Down
66 changes: 66 additions & 0 deletions scripts/verify_lock.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env node

import process from "node:process";
import path from "node:path";
import { readFileSync } from "node:fs";

// set the working directory to project root
// fs.accessSync("./package-lock.json")
const getProjectRoot = () => path.resolve(path.dirname(process.argv[1]), "../");
process.chdir(getProjectRoot());

// load the lock file
const lockFilePath = path.resolve(process.cwd(), "package-lock.json");
const lockFile = JSON.parse(readFileSync(lockFilePath));

const toLog = {
name: lockFile.name,
version: lockFile.version,
lockfileVersion: lockFile.lockfileVersion,
};

// check the packages packages
const removeUndefined = (obj) =>
Object.fromEntries(Object.entries(obj).filter((e) => e[1] !== undefined));

const results = {
project: [],
resolved: [],
unresolved: [],
};
Object.entries(lockFile.packages).forEach(([name, p]) => {
const bucket = p.name?.startsWith("@konveyor-ui")
? results.project
: p.resolved
? results.resolved
: results.unresolved;

bucket.push(
removeUndefined({
name,
version: p.version,
resolved: p.resolved,
packageName: p.name,
})
);
});

// log findings
toLog.packages = results.project;
toLog.dependencies = {
countResolved: results.resolved.length,
countUnresolved: results.unresolved.length,
unresolved: results.unresolved,
};

console.log(`package-lock.json (${lockFilePath}) status:`);
console.dir(toLog, { depth: 3 });
console.log();
if (results.unresolved.length === 0) {
console.log("\u{1f600} lock file is ok!");
} else {
console.log("\u{1f621} lock file contains unresolved dependencies!");
}

// exit the script with an appropriate error code
process.exit(results.unresolved.length === 0 ? 0 : 1);

0 comments on commit 2ec8184

Please sign in to comment.