Skip to content

Commit 12b61f0

Browse files
committed
deepExtend only deep extends Object, it doesn't deep merge Arrays.
1 parent aedc6ec commit 12b61f0

File tree

8 files changed

+66
-90
lines changed

8 files changed

+66
-90
lines changed

package-lock.json

Lines changed: 11 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
"dependencies": {
1616
"ansi-colors": "4.x",
1717
"dateformat": "3.x",
18-
"dot-prop": "5.x",
18+
"deep-extend": "0.x",
1919
"glob": "7.x",
2020
"js-yaml": "3.x",
21-
"lodash.merge": "4.x",
2221
"pretty-hrtime": "1.x",
2322
"shelljs": "0.x",
2423
"winston": "3.x",
@@ -32,8 +31,8 @@
3231
"author": "Mads Jon Nielsen <madsjon@gmail.com>",
3332
"license": "ISC",
3433
"devDependencies": {
34+
"@types/deep-extend": "0.x",
3535
"@types/js-yaml": "3.x",
36-
"@types/lodash.merge": "4.x",
3736
"@types/pretty-hrtime": "1.x",
3837
"@types/shelljs": "0.x",
3938
"@types/yaml": "1.x",

src/globals.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import * as winston from "winston";
33
import yargs = require("yargs");
44
import {Parser} from "./parser";
55

6-
export interface IKeyValue {
7-
[key: string]: string | undefined;
8-
}
9-
106
const colorizer = winston.format.colorize();
117

128
const logger: winston.Logger = winston.createLogger({

src/job.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import c = require("ansi-colors");
2-
import * as dotProp from "dot-prop";
32
import prettyHrtime = require("pretty-hrtime");
43
import * as shelljs from "shelljs";
5-
import {Globals} from "./globals";
6-
import {IKeyValue} from "./index";
74

85
const shell = process.env.EXEPATH ? `${process.env.EXEPATH}/bash.exe` : "/bin/bash";
96

107
export class Job {
118

129
private static getScriptLikesFromData(jobData: any, keyname: string): string[] | null {
13-
const sc = dotProp.get<string | string[] | undefined>(jobData, keyname);
10+
const sc = jobData[keyname];
1411
if (sc) {
1512
let scripts: string[] = [];
1613
scripts = scripts.concat(sc);
@@ -23,9 +20,9 @@ export class Job {
2320
public readonly name: string;
2421

2522
private readonly cwd: any;
23+
private readonly globals: any;
2624

27-
private readonly globals: Globals;
28-
private readonly variables: IKeyValue;
25+
private readonly variables: {[key: string]: string};
2926

3027
private readonly allowFailure: boolean;
3128

@@ -35,17 +32,18 @@ export class Job {
3532

3633
private running: boolean = false;
3734

38-
constructor(jobData: any, name: string, cwd: any, globals: Globals) {
35+
constructor(jobData: any, name: string, cwd: any, globals: any) {
3936
this.name = name;
4037
this.cwd = cwd;
4138
this.globals = globals;
4239

43-
this.stage = dotProp.get<string>(jobData, "stage") || ".pre";
44-
this.scripts = Job.getScriptLikesFromData(jobData, "script") || [];
45-
this.beforeScripts = Job.getScriptLikesFromData(jobData, "before_script") || globals.beforeScripts || [];
46-
this.afterScripts = Job.getScriptLikesFromData(jobData, "after_script") || globals.afterScripts || [];
47-
this.allowFailure = dotProp.get<boolean>(jobData, "allow_failure") || false;
48-
this.variables = dotProp.get<IKeyValue>(jobData, "variables") || {};
40+
this.stage = jobData.stage || ".pre";
41+
this.scripts = [].concat(jobData.script || []);
42+
43+
this.beforeScripts = [].concat(jobData.before_script || globals.before_script || []);
44+
this.afterScripts = [].concat(jobData.after_script || globals.after_script || []);
45+
this.allowFailure = jobData.allow_failure || false;
46+
this.variables = jobData.variables || {};
4947
}
5048

5149
public async start(): Promise<void> {
@@ -112,8 +110,8 @@ export class Job {
112110
return `${c.blueBright(`${this.name}`)} ${mistakeStr}`;
113111
}
114112

115-
private getEnvs(): IKeyValue {
116-
return {...this.globals.variables, ...this.variables, ...process.env};
113+
private getEnvs(): {[key: string]: string} {
114+
return {...this.globals.variables || {}, ...this.variables, ...process.env};
117115
}
118116

119117
private async exec(script: string): Promise<number> {

src/parser.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import c = require("ansi-colors");
2-
import * as dotProp from "dot-prop";
2+
import deepExtend = require("deep-extend");
33
import fs = require("fs");
44
import yaml = require("js-yaml");
5-
import merge = require("lodash.merge");
65
import * as winston from "winston";
7-
import {IKeyValue} from "./index";
86
import {Job} from "./job";
97
import {Stage} from "./stage";
108

@@ -19,34 +17,51 @@ export class Parser {
1917
private readonly stages: Map<string, Stage> = new Map();
2018

2119
constructor(cwd: any, logger: winston.Logger) {
22-
// Parse .gitlab-ci.yml
20+
// Fail if .gitlab-ci.yml missing
2321
const gitlabCiYmlPath = `${cwd}/.gitlab-ci.yml`;
2422
if (!fs.existsSync(gitlabCiYmlPath)) {
2523
logger.error(`Could not find ${gitlabCiYmlPath}`);
2624
process.exit(1);
2725
}
28-
const gitlabCiContent = fs.readFileSync(gitlabCiYmlPath, "utf8");
29-
const gitlabCiData = yaml.safeLoad(gitlabCiContent);
30-
const globalVariables = dotProp.get<IKeyValue>(gitlabCiData, "variables") || {};
3126

32-
// Parse .gitlab-local.yml
27+
// Fail if .gitlab-ci.local.yml missing
3328
const gitlabCiLocalYmlPath = `${cwd}/.gitlab-ci.local.yml`;
3429
if (!fs.existsSync(gitlabCiLocalYmlPath)) {
3530
logger.error(`Could not find ${gitlabCiLocalYmlPath}`);
3631
process.exit(1);
3732
}
38-
const gitlabCiLocalContent = fs.readFileSync(gitlabCiLocalYmlPath, "utf8");
39-
const gitlabLocalData = yaml.safeLoad(gitlabCiLocalContent);
40-
const globalLocalVariables = dotProp.get<IKeyValue>(gitlabLocalData, "variables") || {};
4133

42-
const gitlabData = merge(gitlabCiData, gitlabLocalData);
43-
gitlabData.variables = {...globalVariables, ...globalLocalVariables};
34+
const orderedVariables = [];
35+
const orderedYml = [];
36+
37+
// Parse .gitlab-ci.yml
38+
orderedYml.push(yaml.safeLoad(fs.readFileSync(gitlabCiYmlPath, "utf8")));
39+
orderedVariables.push(orderedYml[orderedYml.length - 1].variables || {});
40+
41+
// Parse .gitlab-ci.local.yml
42+
orderedYml.push(yaml.safeLoad(fs.readFileSync(gitlabCiLocalYmlPath, "utf8")));
43+
orderedVariables.push(orderedYml[orderedYml.length - 1].variables || {});
44+
45+
// Parse yamls included by other ci files.
46+
const includes = deepExtend.apply(this, orderedYml).include || [];
47+
for (const value of includes) {
48+
if (!value.local) {
49+
continue;
50+
}
51+
52+
orderedYml.unshift(yaml.safeLoad(fs.readFileSync(`${cwd}/${value.local}`, "utf8")));
53+
orderedVariables.unshift(orderedYml[0].variables || {});
54+
}
55+
56+
// Setup variables and "merged" yml
57+
const gitlabData = deepExtend.apply(this, orderedYml);
4458

45-
for (const value of gitlabCiData.stages) {
59+
// Generate stages
60+
for (const value of gitlabData.stages) {
4661
this.stages.set(value, new Stage(value));
4762
}
4863

49-
// Generate all jobs specified in final gitlabData
64+
// Generate jobs and put them into stages
5065
for (const [key, value] of Object.entries(gitlabData)) {
5166
if (this.illigalJobNames.includes(key) || key[0] === ".") {
5267
continue;

tests/test-yml-spec/.ci-include.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
variables:
2-
INCLUDED_FROM_ANOTHER_FILE: "Its correct i'm a var from another file"
2+
PROJECT_NAME: "Trying to override PROJECT_NAME, not going to happen, .gitlab-ci.yml have higher priority than me"
3+
INCLUDED_FROM_ANOTHER_FILE: "Its correct i'm a var from another file" # 'New' var gets recognized
34

45
echo_project_name:
56
tags: [some_runner_tag]
@@ -20,4 +21,5 @@ local_only_job:
2021
new_job_from_include:
2122
tags: [some_runner_tag]
2223
stage: startup
23-
- echo "I get run, because i'm not specified anywhere else"
24+
script:
25+
- echo "I get run, because i'm not specified anywhere else"

tests/test-yml-spec/.gitlab-ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ error_test:
2929
- echo "Throwing an error, but its ok, allow_failure equals true"
3030
- exit 1
3131

32+
var_in_another_file:
33+
<<: *tags
34+
stage: startup
35+
script:
36+
- echo "${INCLUDED_FROM_ANOTHER_FILE}"
37+
3238
after_script_test:
3339
<<: *tags
3440
stage: last

0 commit comments

Comments
 (0)