@opentermsarchive/engine 13.0.1 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/scripts/declarations/validate/index.mocha.js +8 -0
- package/src/archivist/fetcher/fullDomFetcher.js +3 -6
- package/src/archivist/recorder/repositories/git/git.js +3 -1
- package/src/archivist/recorder/repositories/git/git.test.js +28 -0
- package/src/archivist/services/terms.js +12 -0
- package/src/archivist/services/terms.test.js +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentermsarchive/engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.1.0",
|
|
4
4
|
"description": "Tracks and makes visible changes to the terms of online services",
|
|
5
5
|
"homepage": "https://opentermsarchive.org",
|
|
6
6
|
"bugs": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"morgan": "^1.10.1",
|
|
93
93
|
"node-fetch": "^3.3.2",
|
|
94
94
|
"octokit": "^5.0.3",
|
|
95
|
-
"puppeteer": "^25.
|
|
95
|
+
"puppeteer": "^25.2.0",
|
|
96
96
|
"puppeteer-extra": "^3.3.6",
|
|
97
97
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
98
98
|
"simple-git": "^3.28.0",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"@opentermsarchive/terms-types": "^2.2.0"
|
|
117
117
|
},
|
|
118
118
|
"engines": {
|
|
119
|
-
"node": ">=
|
|
119
|
+
"node": ">=22 <=26"
|
|
120
120
|
},
|
|
121
121
|
"overrides": {
|
|
122
122
|
"jsdom": {
|
|
@@ -118,6 +118,14 @@ export default async options => {
|
|
|
118
118
|
describe(type, () => {
|
|
119
119
|
const terms = service.getTerms({ type });
|
|
120
120
|
|
|
121
|
+
if (terms.hasMultipleSourceDocuments) {
|
|
122
|
+
it('does not declare the same source document more than once', () => {
|
|
123
|
+
const duplicateLocations = [...new Set(terms.duplicateSourceDocuments.map(sourceDocument => sourceDocument.location))];
|
|
124
|
+
|
|
125
|
+
expect(duplicateLocations, `The same source document is declared more than once within the "${type}" combine: ${duplicateLocations.join(', ')}`).to.be.empty;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
terms.sourceDocuments.forEach(sourceDocument => {
|
|
122
130
|
let filteredContent;
|
|
123
131
|
|
|
@@ -108,7 +108,7 @@ export default async function fetch(url, cssSelectors, config) {
|
|
|
108
108
|
|
|
109
109
|
throw new Error(error.message);
|
|
110
110
|
} finally {
|
|
111
|
-
await cleanupPage(client,
|
|
111
|
+
await cleanupPage(client, context);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -261,14 +261,11 @@ async function waitForSelectors(page, selectors, timeout) {
|
|
|
261
261
|
});
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
async function cleanupPage(client,
|
|
264
|
+
async function cleanupPage(client, context) {
|
|
265
265
|
if (client) {
|
|
266
266
|
await client.detach().catch(() => {});
|
|
267
267
|
}
|
|
268
|
-
if (page) {
|
|
269
|
-
await page.close().catch(() => {});
|
|
270
|
-
}
|
|
271
268
|
if (context) {
|
|
272
|
-
await context.close().catch(() => {}); //
|
|
269
|
+
await context.close().catch(() => {}); // Closing the context disposes its page too; closing the page explicitly is not only redundant but can hang indefinitely when a navigation is still in flight, for instance after a navigation timeout
|
|
273
270
|
}
|
|
274
271
|
}
|
|
@@ -33,7 +33,8 @@ export default class Git {
|
|
|
33
33
|
.addConfig('user.name', this.author.name)
|
|
34
34
|
.addConfig('user.email', this.author.email)
|
|
35
35
|
.addConfig('core.quotePath', false) // Disable Git's encoding of special characters in pathnames. For example, `service·A` will be encoded as `service\302\267A` without this setting, leading to issues. See https://git-scm.com/docs/git-config#Documentation/git-config.txt-corequotePath
|
|
36
|
-
.addConfig('core.commitGraph', true)
|
|
36
|
+
.addConfig('core.commitGraph', true) // Enable `commit-graph` feature for efficient commit data storage, improving performance of operations like `git log`
|
|
37
|
+
.addConfig('gc.writeCommitGraph', false); // Prevent automatic `git gc` from also writing the commit-graph: the engine writes it explicitly (see `writeCommitGraph`/`updateCommitGraph`), and a concurrent gc write races those, which can leave a stale `commit-graph.lock` and make subsequent operations fail
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
add(filePath) {
|
|
@@ -128,6 +129,7 @@ export default class Git {
|
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
async cleanUp() {
|
|
132
|
+
await fs.rm(path.join(this.path, '.git', 'objects', 'info', 'commit-graph.lock'), { force: true }); // Remove a leftover commit-graph lock from a previous `commit-graph write` that was killed mid-write (e.g. the process was terminated during a deploy or restart). The commit-graph is a disposable cache rebuilt by `writeCommitGraph`, so clearing a stale lock is safe and prevents every subsequent run from failing.
|
|
131
133
|
await this.git.reset('hard');
|
|
132
134
|
|
|
133
135
|
return this.git.clean('f', '-d');
|
|
@@ -83,4 +83,32 @@ describe('Git', () => {
|
|
|
83
83
|
});
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
|
+
|
|
87
|
+
describe('#cleanUp', () => {
|
|
88
|
+
context('when a commit-graph lock has been left behind by an interrupted process', () => {
|
|
89
|
+
const infoDirectoryPath = path.join(RECORDER_PATH, '.git', 'objects', 'info');
|
|
90
|
+
const lockFilePath = path.join(infoDirectoryPath, 'commit-graph.lock');
|
|
91
|
+
|
|
92
|
+
before(async () => {
|
|
93
|
+
const filePath = `${RECORDER_PATH}/file-to-clean.md`;
|
|
94
|
+
|
|
95
|
+
await fs.writeFile(filePath, DEFAULT_CONTENT);
|
|
96
|
+
await subject.add(filePath);
|
|
97
|
+
await subject.commit({ filePath, message: DEFAULT_COMMIT_MESSAGE });
|
|
98
|
+
|
|
99
|
+
await fs.mkdir(infoDirectoryPath, { recursive: true });
|
|
100
|
+
await fs.writeFile(lockFilePath, '');
|
|
101
|
+
|
|
102
|
+
await subject.cleanUp();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
after(() => subject.destroyHistory());
|
|
106
|
+
|
|
107
|
+
it('removes the stale commit-graph lock', async () => {
|
|
108
|
+
const infoDirectoryContent = await fs.readdir(infoDirectoryPath);
|
|
109
|
+
|
|
110
|
+
expect(infoDirectoryContent).to.not.include('commit-graph.lock');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
86
114
|
});
|
|
@@ -13,6 +13,18 @@ export default class Terms {
|
|
|
13
13
|
return this.sourceDocuments.length > 1;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
get duplicateSourceDocuments() {
|
|
17
|
+
const seenLocations = new Set();
|
|
18
|
+
|
|
19
|
+
return this.sourceDocuments.filter(({ location }) => {
|
|
20
|
+
const isDuplicate = seenLocations.has(location);
|
|
21
|
+
|
|
22
|
+
seenLocations.add(location);
|
|
23
|
+
|
|
24
|
+
return isDuplicate;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
16
28
|
toPersistence() {
|
|
17
29
|
return {
|
|
18
30
|
name: this.service.name,
|
|
@@ -80,4 +80,12 @@ describe('Terms', () => {
|
|
|
80
80
|
expect(result).to.deep.equal(expectedResult);
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
|
+
|
|
84
|
+
describe('#duplicateSourceDocuments', () => {
|
|
85
|
+
it('returns the source documents that repeat a location', () => {
|
|
86
|
+
const terms = new Terms({ service, type: termsType, sourceDocuments: [ document1, document2 ] });
|
|
87
|
+
|
|
88
|
+
expect(terms.duplicateSourceDocuments).to.deep.equal([document2]);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
83
91
|
});
|