Skip to content

Commit

Permalink
fix(gitlabci): gracefully handle errors (#9163)
Browse files Browse the repository at this point in the history
* fix(gitlabci): gracefully handle errors

* fix: remove debugging

* Update lib/manager/gitlabci/utils.ts

Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>

Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
  • Loading branch information
viceice and HonkingGoose committed Mar 16, 2021
1 parent 295d5ab commit 668c879
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 21 deletions.
7 changes: 7 additions & 0 deletions lib/manager/gitlabci/__fixtures__/gitlab-ci.3.yaml
Expand Up @@ -10,4 +10,11 @@ services:

include:
- local: 'lib/manager/gitlabci/__fixtures__/include.yml'
- local: 'lib/manager/gitlabci/__fixtures__/include.yml' # Loop detection
- local: 'lib/manager/gitlabci/__fixtures__/include.1.yml'
- project: 'my-group/my-project'
ref: master
file: '/templates/.gitlab-ci-template.yml'

script:
- !reference [.setup, script]
7 changes: 7 additions & 0 deletions lib/manager/gitlabci/__fixtures__/gitlab-ci.4.yaml
@@ -0,0 +1,7 @@
include:
- local: 'lib/manager/gitlabci/__fixtures__/include.yml'

test:
script:
- !abc [.setup, script]
- echo running my own command
3 changes: 3 additions & 0 deletions lib/manager/gitlabci/__fixtures__/include.1.yml
@@ -1,3 +1,6 @@
# not existing
include: 'lib/manager/gitlabci/__fixtures__/include.2.yml'

test:
stage: test
image: node:12
Expand Down
5 changes: 5 additions & 0 deletions lib/manager/gitlabci/__fixtures__/include.yml
@@ -1,5 +1,10 @@

# Loop detection
include: 'lib/manager/gitlabci/__fixtures__/include.yml'

test:
stage: test
image: alpine:3.11
script:
- echo test
- !reference [.setup, script]
18 changes: 9 additions & 9 deletions lib/manager/gitlabci/__snapshots__/extract.spec.ts.snap
Expand Up @@ -148,30 +148,30 @@ Array [
"deps": Array [
Object {
"autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
"commitMessageTopic": "Node.js",
"currentDigest": undefined,
"currentValue": "3.11",
"currentValue": "12",
"datasource": "docker",
"depName": "alpine",
"depName": "node",
"depType": "image",
"replaceString": "alpine:3.11",
"replaceString": "node:12",
},
],
"packageFile": "lib/manager/gitlabci/__fixtures__/include.yml",
"packageFile": "lib/manager/gitlabci/__fixtures__/include.1.yml",
},
Object {
"deps": Array [
Object {
"autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
"commitMessageTopic": "Node.js",
"currentDigest": undefined,
"currentValue": "12",
"currentValue": "3.11",
"datasource": "docker",
"depName": "node",
"depName": "alpine",
"depType": "image",
"replaceString": "node:12",
"replaceString": "alpine:3.11",
},
],
"packageFile": "lib/manager/gitlabci/__fixtures__/include.1.yml",
"packageFile": "lib/manager/gitlabci/__fixtures__/include.yml",
},
]
`;
13 changes: 12 additions & 1 deletion lib/manager/gitlabci/extract.spec.ts
@@ -1,4 +1,4 @@
import { getName } from '../../../test/util';
import { getName, logger } from '../../../test/util';
import type { PackageDependency } from '../types';
import { extractAllPackageFiles } from './extract';

Expand All @@ -11,6 +11,7 @@ describe(getName(__filename), () => {
])
).toBeNull();
});

it('extracts multiple included image lines', async () => {
const res = await extractAllPackageFiles({}, [
'lib/manager/gitlabci/__fixtures__/gitlab-ci.3.yaml',
Expand All @@ -26,6 +27,7 @@ describe(getName(__filename), () => {
});
expect(deps).toHaveLength(5);
});

it('extracts multiple image lines', async () => {
const res = await extractAllPackageFiles({}, [
'lib/manager/gitlabci/__fixtures__/gitlab-ci.yaml',
Expand All @@ -43,6 +45,7 @@ describe(getName(__filename), () => {

expect(deps.some((dep) => dep.currentValue.includes("'"))).toBe(false);
});

it('extracts multiple image lines with comments', async () => {
const res = await extractAllPackageFiles({}, [
'lib/manager/gitlabci/__fixtures__/gitlab-ci.1.yaml',
Expand All @@ -58,5 +61,13 @@ describe(getName(__filename), () => {
});
expect(deps).toHaveLength(3);
});

it('catches errors', async () => {
const res = await extractAllPackageFiles({}, [
'lib/manager/gitlabci/__fixtures__/gitlab-ci.4.yaml',
]);
expect(res).toBeNull();
expect(logger.logger.warn).toHaveBeenCalled();
});
});
});
39 changes: 28 additions & 11 deletions lib/manager/gitlabci/extract.ts
Expand Up @@ -4,6 +4,8 @@ import { logger } from '../../logger';
import { readLocalFile } from '../../util/fs';
import { getDep } from '../dockerfile/extract';
import type { ExtractConfig, PackageDependency, PackageFile } from '../types';
import type { GitlabPipeline } from './types';
import { replaceReferenceTags } from './utils';

function skipCommentLines(
lines: string[],
Expand Down Expand Up @@ -84,28 +86,43 @@ export function extractPackageFile(content: string): PackageFile | null {
}

export async function extractAllPackageFiles(
config: ExtractConfig,
_config: ExtractConfig,
packageFiles: string[]
): Promise<PackageFile[] | null> {
const filesToExamine = new Set<string>(packageFiles);
const filesToExamine = [...packageFiles];
const seen = new Set<string>(packageFiles);
const results: PackageFile[] = [];

// extract all includes from the files
while (filesToExamine.size > 0) {
const file = filesToExamine.values().next().value;
filesToExamine.delete(file);
while (filesToExamine.length > 0) {
const file = filesToExamine.pop();

const content = await readLocalFile(file, 'utf8');
const doc = yaml.safeLoad(content, { json: true }) as any;
if (doc?.include && is.array(doc.include)) {
let doc: GitlabPipeline;
try {
doc = yaml.safeLoad(replaceReferenceTags(content), {
json: true,
}) as GitlabPipeline;
} catch (err) {
logger.warn({ err, file }, 'Error extracting GitLab CI dependencies');
}

if (is.array(doc?.include)) {
for (const includeObj of doc.include) {
if (includeObj.local) {
const fileObj = (includeObj.local as string).replace(/^\//, '');
if (!filesToExamine.has(fileObj)) {
filesToExamine.add(fileObj);
if (is.string(includeObj.local)) {
const fileObj = includeObj.local.replace(/^\//, '');
if (!seen.has(fileObj)) {
seen.add(fileObj);
filesToExamine.push(fileObj);
}
}
}
} else if (is.string(doc?.include)) {
const fileObj = doc.include.replace(/^\//, '');
if (!seen.has(fileObj)) {
seen.add(fileObj);
filesToExamine.push(fileObj);
}
}

const result = extractPackageFile(content);
Expand Down
7 changes: 7 additions & 0 deletions lib/manager/gitlabci/types.ts
@@ -0,0 +1,7 @@
export interface GitlabInclude {
local?: string;
}

export interface GitlabPipeline {
include?: GitlabInclude[] | string;
}
12 changes: 12 additions & 0 deletions lib/manager/gitlabci/utils.ts
@@ -0,0 +1,12 @@
const re = /!reference \[\.\w+?(?:, \w+?)\]/g;

/**
* Replaces GitLab reference tags before parsing, because our yaml parser cannot process them anyway.
* @param content pipeline yaml
* @returns replaced pipeline content
* https://docs.gitlab.com/ee/ci/yaml/#reference-tags
*/
export function replaceReferenceTags(content: string): string {
const res = content.replace(re, '');
return res;
}

0 comments on commit 668c879

Please sign in to comment.