Skip to content

Commit e242cac

Browse files
committed
feat: detect circular imports
1 parent 60dbc00 commit e242cac

File tree

5 files changed

+26
-4
lines changed

5 files changed

+26
-4
lines changed

lib/travis/imports.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const internals = {
1313
};
1414

1515

16-
internals.normalizeImports = (travisYaml, { relativeTo }) => {
16+
internals.normalizeImports = (travisYaml, { relativeTo, breadcrumb }) => {
1717

1818
const context = relativeTo ? relativeTo.source : '.travis.yml';
1919

@@ -49,6 +49,11 @@ internals.normalizeImports = (travisYaml, { relativeTo }) => {
4949
throw new Error(`Importing at commitish unsupported in ${context}: ${original}`);
5050
}
5151

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+
5257
return entry;
5358
})
5459
.filter((entry) => !entry.if); // @todo: log a warning
@@ -71,13 +76,13 @@ internals.loadSource = async (source, { loadFile }) => {
7176
};
7277

7378

74-
exports.apply = async (yaml, { loadFile, relativeTo }) => {
79+
exports.apply = async (yaml, { loadFile, relativeTo, breadcrumb = ['.travis.yml'] }) => {
7580

7681
if (!yaml.import) {
7782
return;
7883
}
7984

80-
const imports = internals.normalizeImports(yaml, { relativeTo });
85+
const imports = internals.normalizeImports(yaml, { relativeTo, breadcrumb });
8186

8287
for (const entry of imports) {
8388

@@ -88,7 +93,7 @@ exports.apply = async (yaml, { loadFile, relativeTo }) => {
8893
json: true
8994
});
9095

91-
await exports.apply(imported, { loadFile, relativeTo: entry });
96+
await exports.apply(imported, { loadFile, relativeTo: entry, breadcrumb: [...breadcrumb, entry.source] });
9297

9398
delete imported.import;
9499

test/fixtures/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ module.exports = class TestContext {
9393
if (partials) {
9494
Fs.mkdirSync(Path.join(this.path, 'partials'));
9595
const partialYmls = [
96+
'circular.yml',
9697
'commitish.yml',
9798
'indirect-node-14.yml',
9899
'merge-invalid.yml',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
import:
3+
- source: partials/circular.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
import:
3+
- source: partials/circular.yml

test/travis.js

+10
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ describe('.travis.yml parsing', () => {
278278

279279
await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Importing at commitish unsupported in partials/commitish.yml: partials/node-14.yml@main');
280280
});
281+
282+
it('throws when importing a circular dependency', async () => {
283+
284+
await fixture.setupRepoFolder({
285+
partials: true,
286+
travisYml: `testing-imports/circular.yml`
287+
});
288+
289+
await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Circular dependency partials/circular.yml requested by partials/circular.yml (already imported at .travis.yml)');
290+
});
281291
});
282292

283293
describe('Travis merging algorithms', () => {

0 commit comments

Comments
 (0)