Skip to content

Commit 6a8e5be

Browse files
committed
Merge branch 'feat-3' into alpha
2 parents 09cced0 + 8a3e35f commit 6a8e5be

30 files changed

+934
-186
lines changed

lib/deps.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ const Tmp = require('tmp');
99
const Package = require('./package');
1010
const Utils = require('./utils');
1111

12-
const internals = {};
13-
14-
15-
internals.log = Debug('detect-node-support');
12+
const internals = {
13+
log: Debug('detect-node-support')
14+
};
1615

1716

1817
internals.resolve = async ({ packageJson, lockfile }, options) => {

lib/loader.js

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
const Debug = require('debug');
34
const Fs = require('fs');
45
const GitUrlParse = require('git-url-parse');
56
const Package = require('../package.json');
@@ -9,7 +10,10 @@ const Wreck = require('@hapi/wreck');
910

1011
const Utils = require('./utils');
1112

12-
const internals = {};
13+
const internals = {
14+
cache: new Map(),
15+
log: Debug('detect-node-support-loader')
16+
};
1317

1418

1519
internals.parseRepository = (packument) => {
@@ -85,15 +89,27 @@ internals.createRepositoryLoader = (repository) => {
8589
}
8690

8791
const url = `https://raw.githubusercontent.com/${parsedRepository.full_name}/HEAD/${filename}`;
92+
internals.log('Loading: %s', url);
93+
94+
if (options === undefined && internals.cache.has(url)) {
95+
internals.log('From cache: %s', url);
96+
return internals.cache[url];
97+
}
8898

8999
try {
90100
const { payload } = await Wreck.get(url, options);
91101

102+
if (options === undefined) {
103+
internals.cache.set(url, payload);
104+
}
105+
106+
internals.log('Loaded: %s', url);
92107
return payload;
93108
}
94109
catch (err) {
95110

96111
if (err.output && err.output.statusCode === 404) {
112+
internals.log('Not found: %s', url);
97113
const error = new Error(`${repository} does not contain a ${filename}`);
98114
error.code = 'ENOENT';
99115
throw error;
@@ -152,3 +168,9 @@ exports.create = ({ path, repository, packageName }) => {
152168

153169
return internals.createPathLoader(path);
154170
};
171+
172+
173+
exports.clearCache = () => {
174+
175+
internals.cache = new Map();
176+
};

lib/travis/imports.js

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
'use strict';
2+
3+
const Yaml = require('js-yaml');
4+
5+
const Loader = require('../loader');
6+
const Utils = require('../utils');
7+
8+
const TravisMerge = require('./merge');
9+
10+
11+
const internals = {
12+
validMergeModes: new Set(['deep_merge_append', 'deep_merge_prepend', 'deep_merge', 'merge'])
13+
};
14+
15+
16+
internals.normalizeImports = (travisYaml, { relativeTo, breadcrumb }) => {
17+
18+
const context = relativeTo ? relativeTo.source : '.travis.yml';
19+
20+
return Utils.toArray(travisYaml.import)
21+
.map((entry) => {
22+
23+
if (typeof entry === 'string') {
24+
entry = { source: entry };
25+
}
26+
27+
const original = entry.source;
28+
29+
if (entry.source.startsWith('./')) {
30+
entry.source = entry.source.substring(2);
31+
32+
if (relativeTo) {
33+
const relativeParts = relativeTo.source.split('/');
34+
relativeParts.pop();
35+
relativeParts.push(entry.source);
36+
entry.source = relativeParts.join('/');
37+
}
38+
}
39+
40+
if (!entry.mode) {
41+
entry.mode = 'deep_merge_append';
42+
}
43+
44+
if (!internals.validMergeModes.has(entry.mode)) {
45+
throw new Error(`Invalid merge mode for ${original} in ${context}: ${entry.mode}`);
46+
}
47+
48+
if (original.includes('@')) {
49+
throw new Error(`Importing at commitish unsupported in ${context}: ${original}`);
50+
}
51+
52+
const alreadyImported = breadcrumb.indexOf(entry.source);
53+
if (alreadyImported >= 0) {
54+
throw new Error(`Circular dependency ${entry.source} requested by ${context} (already imported at ${breadcrumb[alreadyImported - 1]})`);
55+
}
56+
57+
return entry;
58+
})
59+
.filter((entry) => !entry.if); // @todo: log a warning
60+
};
61+
62+
63+
internals.loadSource = async (source, { loadFile }) => {
64+
65+
let path = source;
66+
67+
if (source.includes(':')) {
68+
const [repository, fileName] = source.split(':');
69+
const loader = await Loader.create({ repository: `https://github.com/${repository}` });
70+
71+
path = fileName;
72+
loadFile = loader.loadFile;
73+
}
74+
75+
return loadFile(path);
76+
};
77+
78+
79+
exports.apply = async (yaml, { loadFile, relativeTo, breadcrumb = ['.travis.yml'] }) => {
80+
81+
if (!yaml.import) {
82+
return;
83+
}
84+
85+
const imports = internals.normalizeImports(yaml, { relativeTo, breadcrumb });
86+
87+
for (const entry of imports) {
88+
89+
const buffer = await internals.loadSource(entry.source, { loadFile });
90+
91+
const imported = Yaml.safeLoad(buffer, {
92+
schema: Yaml.FAILSAFE_SCHEMA,
93+
json: true
94+
});
95+
96+
await exports.apply(imported, { loadFile, relativeTo: entry, breadcrumb: [...breadcrumb, entry.source] });
97+
98+
delete imported.import;
99+
100+
TravisMerge[entry.mode](yaml, imported);
101+
}
102+
};

lib/travis.js lib/travis/index.js

+11-15
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,35 @@
33
const Nv = require('@pkgjs/nv');
44
const Yaml = require('js-yaml');
55

6+
const TravisImports = require('./imports');
7+
const Utils = require('../utils');
8+
69

710
const internals = {};
811

12+
913
internals.nodeAliases = {
1014
latest: 'active',
1115
node: 'active',
1216
stable: 'active'
1317
};
1418

1519

16-
internals.toArray = (v) => {
17-
18-
if (v === undefined) {
19-
return [];
20-
}
21-
22-
return Array.isArray(v) ? v : [v];
23-
};
24-
20+
internals.scan = async (travisYaml, options) => {
2521

26-
internals.scan = async (travisYaml) => {
22+
await TravisImports.apply(travisYaml, options);
2723

2824
const rawSet = new Set();
2925

30-
for (const v of internals.toArray(travisYaml.node_js)) {
26+
for (const v of Utils.toArray(travisYaml.node_js)) {
3127
rawSet.add(v);
3228
}
3329

3430
if (travisYaml.env) {
3531

36-
for (const env of internals.toArray(travisYaml.env.matrix)) {
32+
for (const env of Utils.toArray(travisYaml.env.matrix)) {
3733

38-
const matches = env.match(/(?:NODEJS_VER|TRAVIS_NODE_VERSION|NODE_VER)="?(node\/)?(?<version>[\w./*]+)"?/); /* hack syntax highlighter 🤦‍♂️ */
34+
const matches = env.match(/(?:NODEJS_VER|TRAVIS_NODE_VERSION|NODE_VER)="?(node\/)?(?<version>[\w./*]+)"?/);
3935

4036
if (matches) {
4137
rawSet.add(matches.groups.version);
@@ -45,7 +41,7 @@ internals.scan = async (travisYaml) => {
4541

4642
if (travisYaml.matrix) {
4743

48-
for (const include of internals.toArray(travisYaml.matrix.include)) {
44+
for (const include of Utils.toArray(travisYaml.matrix.include)) {
4945

5046
if (include.node_js) {
5147
rawSet.add(include.node_js);
@@ -96,6 +92,6 @@ exports.detect = async ({ loadFile }) => {
9692
});
9793

9894
return {
99-
travis: await internals.scan(travisYaml)
95+
travis: await internals.scan(travisYaml, { loadFile })
10096
};
10197
};

lib/travis/merge.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
3+
// ref: https://github.com/travis-ci/travis-yml/blob/bf82881491134c72a64778f9664a8dd3f97158e7/lib/travis/yml/support/merge.rb
4+
5+
const internals = {};
6+
7+
8+
internals.isObject = (arg) => typeof arg === 'object' && !Array.isArray(arg);
9+
10+
11+
exports.deep_merge_append = (left, right) => {
12+
13+
for (const key in right) {
14+
15+
if (internals.isObject(left[key]) && internals.isObject(right[key])) {
16+
exports.deep_merge_append(left[key], right[key]);
17+
continue;
18+
}
19+
20+
if (Array.isArray(left[key]) && Array.isArray(right[key])) {
21+
left[key].push(...right[key]);
22+
continue;
23+
}
24+
25+
left[key] = right[key];
26+
}
27+
};
28+
29+
exports.deep_merge_prepend = (left, right) => {
30+
31+
for (const key in right) {
32+
33+
if (internals.isObject(left[key]) && internals.isObject(right[key])) {
34+
exports.deep_merge_prepend(left[key], right[key]);
35+
continue;
36+
}
37+
38+
if (Array.isArray(left[key]) && Array.isArray(right[key])) {
39+
left[key].unshift(...right[key]);
40+
continue;
41+
}
42+
43+
left[key] = right[key];
44+
}
45+
};
46+
47+
exports.deep_merge = (left, right) => {
48+
49+
for (const key in right) {
50+
51+
if (internals.isObject(left[key]) && internals.isObject(right[key])) {
52+
exports.deep_merge(left[key], right[key]);
53+
continue;
54+
}
55+
56+
left[key] = right[key];
57+
}
58+
};
59+
60+
exports.merge = (left, right) => {
61+
62+
for (const key in right) {
63+
left[key] = right[key];
64+
}
65+
};

lib/utils.js

+10
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,13 @@ exports.getErrorMessage = (error) => {
2222

2323
return null;
2424
};
25+
26+
27+
exports.toArray = (v) => {
28+
29+
if (v === undefined) {
30+
return [];
31+
}
32+
33+
return Array.isArray(v) ? v : [v];
34+
};

0 commit comments

Comments
 (0)