refactor(pipeline-tasks-runner): rabbitmq
This commit is contained in:
parent
4041a6fd2a
commit
b3a2b11db9
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -1,13 +1,18 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Repos",
|
"Repos",
|
||||||
|
"amqp",
|
||||||
"boardcat",
|
"boardcat",
|
||||||
|
"errout",
|
||||||
|
"fanout",
|
||||||
"gitea",
|
"gitea",
|
||||||
|
"golevelup",
|
||||||
"lpush",
|
"lpush",
|
||||||
"lrange",
|
"lrange",
|
||||||
"metatype",
|
"metatype",
|
||||||
"pmessage",
|
"pmessage",
|
||||||
"psubscribe",
|
"psubscribe",
|
||||||
|
"rabbitmq",
|
||||||
"rpop",
|
"rpop",
|
||||||
"rpush"
|
"rpush"
|
||||||
]
|
]
|
||||||
|
@ -14,5 +14,7 @@ db:
|
|||||||
port: 6379
|
port: 6379
|
||||||
password:
|
password:
|
||||||
prefix: fennec
|
prefix: fennec
|
||||||
|
rabbitmq:
|
||||||
|
uri: 'amqp://fennec:fennec@192.168.31.194:5672'
|
||||||
workspaces:
|
workspaces:
|
||||||
root: '/Users/ivanli/Projects/fennec/workspaces'
|
root: '/Users/ivanli/Projects/fennec/workspaces'
|
317
package-lock.json
generated
317
package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@golevelup/nestjs-rabbitmq": "^1.16.1",
|
||||||
"@nestjs/bull": "^0.3.1",
|
"@nestjs/bull": "^0.3.1",
|
||||||
"@nestjs/common": "^7.5.1",
|
"@nestjs/common": "^7.5.1",
|
||||||
"@nestjs/config": "^0.6.2",
|
"@nestjs/config": "^0.6.2",
|
||||||
@ -1411,6 +1412,51 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@golevelup/nestjs-common": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-common/-/nestjs-common-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-mdXppMelEYO+HTilg4W8h8Bt4u1s9qvOip2dygRMxY3O1/JK6GPpPgJ99CiuAT+xxFG9igeN8lfpAnO0+mJXxA==",
|
||||||
|
"dependencies": {
|
||||||
|
"shortid": "^2.2.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@golevelup/nestjs-discovery": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-discovery/-/nestjs-discovery-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-K3NG34hK1/UM1ardiUSS9c43AAdk6IBJHUMZbBGavqfgNo17N2wjygSDMHFd5Cf+jqTPkt+n5Vr9ua22yCLzlg==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.15"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@golevelup/nestjs-modules": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-modules/-/nestjs-modules-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-v2GYGtJ8moTfhehavNFBwnHQ+QcgYHssxfqbJZcY4CUqB97E2sWmnAmtgscHDTvHqABOCaq2xvwfw4YTwZU2Ug==",
|
||||||
|
"dependencies": {
|
||||||
|
"shortid": "^2.2.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@golevelup/nestjs-rabbitmq": {
|
||||||
|
"version": "1.16.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-rabbitmq/-/nestjs-rabbitmq-1.16.1.tgz",
|
||||||
|
"integrity": "sha512-+5rss427yqPbvtIZxQUdjvaXe0Xtq6tE/PVmkHgPETEVDZY+DfqQSYiL/E3QPfFzCytiYxBTSlQZZVjUaNV8Cg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@golevelup/nestjs-common": "^1.4.2",
|
||||||
|
"@golevelup/nestjs-discovery": "^2.3.1",
|
||||||
|
"@golevelup/nestjs-modules": "^0.4.1",
|
||||||
|
"amqp-connection-manager": "^3.0.0",
|
||||||
|
"amqplib": "^0.7.1",
|
||||||
|
"uuid": "^3.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@golevelup/nestjs-rabbitmq/node_modules/uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@graphql-tools/batch-delegate": {
|
"node_modules/@graphql-tools/batch-delegate": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-tools/batch-delegate/-/batch-delegate-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-tools/batch-delegate/-/batch-delegate-7.0.2.tgz",
|
||||||
@ -3571,6 +3617,77 @@
|
|||||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/amqp-connection-manager": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-o+6Kb4p+xFYwU8MuFxnrPQzhefCE2dcCd8dnevWLTRgQCtOTVC9AQ434hQyjB+Bpq6Vl9cDMWTOZT11ajB6ZSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"promise-breaker": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0",
|
||||||
|
"npm": ">5.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"amqplib": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/amqplib": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.7.1.tgz",
|
||||||
|
"integrity": "sha512-KePK3tTOLGU4emTo+PwSDMbc123jrxo13FpRpim1LzJoSlQrIBB2/kMeCC40jK/Zb0olHGaABjLqXDsdK46iLA==",
|
||||||
|
"dependencies": {
|
||||||
|
"bitsyntax": "~0.1.0",
|
||||||
|
"bluebird": "^3.7.2",
|
||||||
|
"buffer-more-ints": "~1.0.0",
|
||||||
|
"readable-stream": "1.x >=1.1.9",
|
||||||
|
"safe-buffer": "~5.2.1",
|
||||||
|
"url-parse": "~1.5.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8 <=15"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/amqplib/node_modules/isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
},
|
||||||
|
"node_modules/amqplib/node_modules/readable-stream": {
|
||||||
|
"version": "1.1.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||||
|
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.1",
|
||||||
|
"isarray": "0.0.1",
|
||||||
|
"string_decoder": "~0.10.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/amqplib/node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/amqplib/node_modules/string_decoder": {
|
||||||
|
"version": "0.10.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||||
|
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||||
|
},
|
||||||
"node_modules/ansi-colors": {
|
"node_modules/ansi-colors": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||||
@ -4571,6 +4688,32 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bitsyntax": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-more-ints": "~1.0.0",
|
||||||
|
"debug": "~2.6.9",
|
||||||
|
"safe-buffer": "~5.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bitsyntax/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bitsyntax/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
},
|
||||||
"node_modules/bl": {
|
"node_modules/bl": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
@ -4596,6 +4739,11 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bluebird": {
|
||||||
|
"version": "3.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||||
|
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
|
||||||
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.19.0",
|
"version": "1.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||||
@ -4727,6 +4875,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-more-ints": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
|
||||||
|
},
|
||||||
"node_modules/buffer-writer": {
|
"node_modules/buffer-writer": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||||
@ -10113,6 +10266,11 @@
|
|||||||
"thenify-all": "^1.0.0"
|
"thenify-all": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "2.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
|
||||||
|
"integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA=="
|
||||||
|
},
|
||||||
"node_modules/nanomatch": {
|
"node_modules/nanomatch": {
|
||||||
"version": "1.2.13",
|
"version": "1.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
||||||
@ -11185,6 +11343,11 @@
|
|||||||
"asap": "~2.0.3"
|
"asap": "~2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/promise-breaker": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA=="
|
||||||
|
},
|
||||||
"node_modules/promise-inflight": {
|
"node_modules/promise-inflight": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||||
@ -12404,6 +12567,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
|
||||||
"integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
|
"integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/shortid": {
|
||||||
|
"version": "2.2.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz",
|
||||||
|
"integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/side-channel": {
|
"node_modules/side-channel": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||||
@ -16145,6 +16316,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@golevelup/nestjs-common": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-common/-/nestjs-common-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-mdXppMelEYO+HTilg4W8h8Bt4u1s9qvOip2dygRMxY3O1/JK6GPpPgJ99CiuAT+xxFG9igeN8lfpAnO0+mJXxA==",
|
||||||
|
"requires": {
|
||||||
|
"shortid": "^2.2.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@golevelup/nestjs-discovery": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-discovery/-/nestjs-discovery-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-K3NG34hK1/UM1ardiUSS9c43AAdk6IBJHUMZbBGavqfgNo17N2wjygSDMHFd5Cf+jqTPkt+n5Vr9ua22yCLzlg==",
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.15"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@golevelup/nestjs-modules": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-modules/-/nestjs-modules-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-v2GYGtJ8moTfhehavNFBwnHQ+QcgYHssxfqbJZcY4CUqB97E2sWmnAmtgscHDTvHqABOCaq2xvwfw4YTwZU2Ug==",
|
||||||
|
"requires": {
|
||||||
|
"shortid": "^2.2.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@golevelup/nestjs-rabbitmq": {
|
||||||
|
"version": "1.16.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@golevelup/nestjs-rabbitmq/-/nestjs-rabbitmq-1.16.1.tgz",
|
||||||
|
"integrity": "sha512-+5rss427yqPbvtIZxQUdjvaXe0Xtq6tE/PVmkHgPETEVDZY+DfqQSYiL/E3QPfFzCytiYxBTSlQZZVjUaNV8Cg==",
|
||||||
|
"requires": {
|
||||||
|
"@golevelup/nestjs-common": "^1.4.2",
|
||||||
|
"@golevelup/nestjs-discovery": "^2.3.1",
|
||||||
|
"@golevelup/nestjs-modules": "^0.4.1",
|
||||||
|
"amqp-connection-manager": "^3.0.0",
|
||||||
|
"amqplib": "^0.7.1",
|
||||||
|
"uuid": "^3.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@graphql-tools/batch-delegate": {
|
"@graphql-tools/batch-delegate": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-tools/batch-delegate/-/batch-delegate-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-tools/batch-delegate/-/batch-delegate-7.0.2.tgz",
|
||||||
@ -18146,6 +18361,55 @@
|
|||||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"amqp-connection-manager": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-o+6Kb4p+xFYwU8MuFxnrPQzhefCE2dcCd8dnevWLTRgQCtOTVC9AQ434hQyjB+Bpq6Vl9cDMWTOZT11ajB6ZSg==",
|
||||||
|
"requires": {
|
||||||
|
"promise-breaker": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"amqplib": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.7.1.tgz",
|
||||||
|
"integrity": "sha512-KePK3tTOLGU4emTo+PwSDMbc123jrxo13FpRpim1LzJoSlQrIBB2/kMeCC40jK/Zb0olHGaABjLqXDsdK46iLA==",
|
||||||
|
"requires": {
|
||||||
|
"bitsyntax": "~0.1.0",
|
||||||
|
"bluebird": "^3.7.2",
|
||||||
|
"buffer-more-ints": "~1.0.0",
|
||||||
|
"readable-stream": "1.x >=1.1.9",
|
||||||
|
"safe-buffer": "~5.2.1",
|
||||||
|
"url-parse": "~1.5.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "1.1.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||||
|
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.1",
|
||||||
|
"isarray": "0.0.1",
|
||||||
|
"string_decoder": "~0.10.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "0.10.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||||
|
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-colors": {
|
"ansi-colors": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||||
@ -18983,6 +19247,31 @@
|
|||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
|
||||||
},
|
},
|
||||||
|
"bitsyntax": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==",
|
||||||
|
"requires": {
|
||||||
|
"buffer-more-ints": "~1.0.0",
|
||||||
|
"debug": "~2.6.9",
|
||||||
|
"safe-buffer": "~5.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
@ -19007,6 +19296,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bluebird": {
|
||||||
|
"version": "3.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||||
|
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
|
||||||
|
},
|
||||||
"body-parser": {
|
"body-parser": {
|
||||||
"version": "1.19.0",
|
"version": "1.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||||
@ -19122,6 +19416,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||||
},
|
},
|
||||||
|
"buffer-more-ints": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
|
||||||
|
},
|
||||||
"buffer-writer": {
|
"buffer-writer": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||||
@ -23479,6 +23778,11 @@
|
|||||||
"thenify-all": "^1.0.0"
|
"thenify-all": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nanoid": {
|
||||||
|
"version": "2.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
|
||||||
|
"integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA=="
|
||||||
|
},
|
||||||
"nanomatch": {
|
"nanomatch": {
|
||||||
"version": "1.2.13",
|
"version": "1.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
||||||
@ -24343,6 +24647,11 @@
|
|||||||
"asap": "~2.0.3"
|
"asap": "~2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"promise-breaker": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA=="
|
||||||
|
},
|
||||||
"promise-inflight": {
|
"promise-inflight": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||||
@ -25346,6 +25655,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
|
||||||
"integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
|
"integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
|
||||||
},
|
},
|
||||||
|
"shortid": {
|
||||||
|
"version": "2.2.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz",
|
||||||
|
"integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==",
|
||||||
|
"requires": {
|
||||||
|
"nanoid": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"side-channel": {
|
"side-channel": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@golevelup/nestjs-rabbitmq": "^1.16.1",
|
||||||
"@nestjs/bull": "^0.3.1",
|
"@nestjs/bull": "^0.3.1",
|
||||||
"@nestjs/common": "^7.5.1",
|
"@nestjs/common": "^7.5.1",
|
||||||
"@nestjs/config": "^0.6.2",
|
"@nestjs/config": "^0.6.2",
|
||||||
|
@ -18,6 +18,8 @@ import { ParseBodyMiddleware } from './commons/middlewares/parse-body.middleware
|
|||||||
import { BullModule } from '@nestjs/bull';
|
import { BullModule } from '@nestjs/bull';
|
||||||
import { PubSubModule } from './commons/pub-sub/pub-sub.module';
|
import { PubSubModule } from './commons/pub-sub/pub-sub.module';
|
||||||
import { LoggerModule } from 'nestjs-pino';
|
import { LoggerModule } from 'nestjs-pino';
|
||||||
|
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
|
||||||
import pinoPretty from 'pino-pretty';
|
import pinoPretty from 'pino-pretty';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
13
src/pipeline-tasks/models/pipeline-task-event.ts
Normal file
13
src/pipeline-tasks/models/pipeline-task-event.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { PipelineUnits } from '../enums/pipeline-units.enum';
|
||||||
|
import { TaskStatuses } from '../enums/task-statuses.enum';
|
||||||
|
|
||||||
|
export class PipelineTaskEvent {
|
||||||
|
taskId: string;
|
||||||
|
pipelineId: string;
|
||||||
|
projectId: string;
|
||||||
|
unit: PipelineUnits | null;
|
||||||
|
emittedAt: Date;
|
||||||
|
message: string;
|
||||||
|
messageType: 'stdout' | 'stderr' | 'stdin';
|
||||||
|
status: TaskStatuses;
|
||||||
|
}
|
322
src/pipeline-tasks/pipeline-task.runner.spec.ts
Normal file
322
src/pipeline-tasks/pipeline-task.runner.spec.ts
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ReposService } from '../repos/repos.service';
|
||||||
|
import { PipelineUnits } from './enums/pipeline-units.enum';
|
||||||
|
import { PipelineTask } from './pipeline-task.entity';
|
||||||
|
import { Pipeline } from '../pipelines/pipeline.entity';
|
||||||
|
import { Project } from '../projects/project.entity';
|
||||||
|
import { TaskStatuses } from './enums/task-statuses.enum';
|
||||||
|
import { getLoggerToken, PinoLogger } from 'nestjs-pino';
|
||||||
|
import { PipelineTaskRunner } from './pipeline-task.runner';
|
||||||
|
import { WorkUnitMetadata } from './models/work-unit-metadata.model';
|
||||||
|
import { Code } from 'typeorm';
|
||||||
|
describe('PipelineTaskRunner', () => {
|
||||||
|
let runner: PipelineTaskRunner;
|
||||||
|
let reposService: ReposService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ReposService,
|
||||||
|
useValue: {
|
||||||
|
getWorkspaceRootByTask: () => 'workspace-root',
|
||||||
|
checkout: async () => undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: getLoggerToken(PipelineTaskRunner.name),
|
||||||
|
useValue: new PinoLogger({}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: 'spawn',
|
||||||
|
useValue: () => undefined,
|
||||||
|
},
|
||||||
|
PipelineTaskRunner,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
reposService = module.get(ReposService);
|
||||||
|
runner = module.get(PipelineTaskRunner);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(runner).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onNewTask', async () => {
|
||||||
|
const task = new PipelineTask();
|
||||||
|
let tmpTask;
|
||||||
|
const doTask = jest
|
||||||
|
.spyOn(runner, 'doTask')
|
||||||
|
.mockImplementation(async (task) => {
|
||||||
|
tmpTask = task;
|
||||||
|
});
|
||||||
|
await runner.onNewTask(task);
|
||||||
|
expect(tmpTask).toEqual(task);
|
||||||
|
expect(doTask).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('test biz', () => {
|
||||||
|
let emitEvent: jest.SpyInstance;
|
||||||
|
beforeEach(() => {
|
||||||
|
emitEvent = jest
|
||||||
|
.spyOn(runner, 'emitEvent')
|
||||||
|
.mockImplementation((..._) => Promise.resolve());
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('doTask', () => {
|
||||||
|
let checkout: jest.SpyInstance;
|
||||||
|
let doTaskUnit: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
checkout = jest
|
||||||
|
.spyOn(runner, 'checkout')
|
||||||
|
.mockImplementation((..._) => Promise.resolve('/null'));
|
||||||
|
doTaskUnit = jest
|
||||||
|
.spyOn(runner, 'doTaskUnit')
|
||||||
|
.mockImplementation((..._) => Promise.resolve());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only checkout', async () => {
|
||||||
|
const task = new PipelineTask();
|
||||||
|
(task.id = 'taskId'), (task.pipeline = new Pipeline());
|
||||||
|
task.units = [PipelineUnits.checkout];
|
||||||
|
task.pipeline.id = 'pipelineId';
|
||||||
|
task.pipeline.project = new Project();
|
||||||
|
task.pipeline.project.id = 'projectId';
|
||||||
|
task.pipeline.workUnitMetadata = new WorkUnitMetadata();
|
||||||
|
task.pipeline.workUnitMetadata.version = 1;
|
||||||
|
task.pipeline.workUnitMetadata.units = [
|
||||||
|
{
|
||||||
|
type: PipelineUnits.checkout,
|
||||||
|
scripts: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
await runner.doTask(task);
|
||||||
|
|
||||||
|
expect(checkout).toBeCalledTimes(1);
|
||||||
|
expect(doTaskUnit).toBeCalledTimes(0);
|
||||||
|
expect(emitEvent).toBeCalledTimes(2);
|
||||||
|
expect(emitEvent.mock.calls[0][0]).toMatchObject(task);
|
||||||
|
expect(emitEvent.mock.calls[0][1]).toBeNull();
|
||||||
|
expect(emitEvent.mock.calls[0][2]).toEqual(TaskStatuses.working);
|
||||||
|
expect(emitEvent.mock.calls[1][0]).toMatchObject(task);
|
||||||
|
expect(emitEvent.mock.calls[1][1]).toBeNull();
|
||||||
|
expect(emitEvent.mock.calls[1][2]).toEqual(TaskStatuses.success);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('many units', async () => {
|
||||||
|
const task = new PipelineTask();
|
||||||
|
(task.id = 'taskId'), (task.pipeline = new Pipeline());
|
||||||
|
task.units = [
|
||||||
|
PipelineUnits.checkout,
|
||||||
|
PipelineUnits.test,
|
||||||
|
PipelineUnits.deploy,
|
||||||
|
];
|
||||||
|
task.pipeline.id = 'pipelineId';
|
||||||
|
task.pipeline.project = new Project();
|
||||||
|
task.pipeline.project.id = 'projectId';
|
||||||
|
task.pipeline.workUnitMetadata = new WorkUnitMetadata();
|
||||||
|
task.pipeline.workUnitMetadata.version = 1;
|
||||||
|
task.pipeline.workUnitMetadata.units = [
|
||||||
|
{
|
||||||
|
type: PipelineUnits.checkout,
|
||||||
|
scripts: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: PipelineUnits.installDependencies,
|
||||||
|
scripts: ['pwd'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: PipelineUnits.test,
|
||||||
|
scripts: ['pwd'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: PipelineUnits.deploy,
|
||||||
|
scripts: ['pwd', 'uname'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
await runner.doTask(task);
|
||||||
|
|
||||||
|
expect(checkout).toBeCalledTimes(1);
|
||||||
|
expect(doTaskUnit).toBeCalledTimes(2);
|
||||||
|
expect(emitEvent).toBeCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('unit work failed', async () => {
|
||||||
|
const task = new PipelineTask();
|
||||||
|
(task.id = 'taskId'), (task.pipeline = new Pipeline());
|
||||||
|
task.units = [PipelineUnits.checkout, PipelineUnits.test];
|
||||||
|
task.pipeline.id = 'pipelineId';
|
||||||
|
task.pipeline.project = new Project();
|
||||||
|
task.pipeline.project.id = 'projectId';
|
||||||
|
task.pipeline.workUnitMetadata = new WorkUnitMetadata();
|
||||||
|
task.pipeline.workUnitMetadata.version = 1;
|
||||||
|
task.pipeline.workUnitMetadata.units = [
|
||||||
|
{
|
||||||
|
type: PipelineUnits.checkout,
|
||||||
|
scripts: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: PipelineUnits.test,
|
||||||
|
scripts: ['pwd'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
doTaskUnit = jest
|
||||||
|
.spyOn(runner, 'doTaskUnit')
|
||||||
|
.mockImplementation((..._) =>
|
||||||
|
Promise.reject(new Error('test error')),
|
||||||
|
);
|
||||||
|
await runner.doTask(task);
|
||||||
|
|
||||||
|
expect(checkout).toBeCalledTimes(1);
|
||||||
|
expect(doTaskUnit).toBeCalledTimes(1);
|
||||||
|
expect(emitEvent).toBeCalledTimes(2);
|
||||||
|
expect(emitEvent.mock.calls[1][0]).toMatchObject(task);
|
||||||
|
expect(emitEvent.mock.calls[1][1]).toBeNull();
|
||||||
|
expect(emitEvent.mock.calls[1][2]).toEqual(TaskStatuses.failed);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('doTaskUnit', () => {
|
||||||
|
it('success', async () => {
|
||||||
|
const runScript = jest
|
||||||
|
.spyOn(runner, 'runScript')
|
||||||
|
.mockImplementation((..._) => Promise.resolve());
|
||||||
|
const task = new PipelineTask();
|
||||||
|
|
||||||
|
const unit = PipelineUnits.test;
|
||||||
|
const workspacePath = '/null';
|
||||||
|
await runner.doTaskUnit(unit, ['pwd'], task, workspacePath);
|
||||||
|
|
||||||
|
expect(emitEvent.mock.calls[0][0]).toEqual(task);
|
||||||
|
expect(emitEvent.mock.calls[0][1]).toEqual(unit);
|
||||||
|
expect(emitEvent.mock.calls[0][2]).toEqual(TaskStatuses.working);
|
||||||
|
expect(emitEvent.mock.calls[1][0]).toEqual(task);
|
||||||
|
expect(emitEvent.mock.calls[1][1]).toEqual(unit);
|
||||||
|
expect(emitEvent.mock.calls[1][2]).toEqual(TaskStatuses.success);
|
||||||
|
expect(runScript.mock.calls[0][0]).toEqual('pwd');
|
||||||
|
expect(runScript.mock.calls[0][1]).toEqual(workspacePath);
|
||||||
|
expect(runScript.mock.calls[0][2]).toEqual(task);
|
||||||
|
expect(runScript.mock.calls[0][3]).toEqual(unit);
|
||||||
|
});
|
||||||
|
it('failed', async () => {
|
||||||
|
const runScript = jest
|
||||||
|
.spyOn(runner, 'runScript')
|
||||||
|
.mockImplementation((..._) =>
|
||||||
|
Promise.reject(new Error('test error')),
|
||||||
|
);
|
||||||
|
const task = new PipelineTask();
|
||||||
|
|
||||||
|
const unit = PipelineUnits.test;
|
||||||
|
const workspacePath = '/null';
|
||||||
|
await expect(
|
||||||
|
runner.doTaskUnit(unit, ['pwd'], task, workspacePath),
|
||||||
|
).rejects.toThrow('test error');
|
||||||
|
|
||||||
|
expect(emitEvent.mock.calls[1]?.[0]).toEqual(task);
|
||||||
|
expect(emitEvent.mock.calls[1]?.[1]).toEqual(unit);
|
||||||
|
expect(emitEvent.mock.calls[1]?.[2]).toEqual(TaskStatuses.failed);
|
||||||
|
expect(runScript).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('runScript', () => {
|
||||||
|
it('normal', async () => {
|
||||||
|
const spawn = jest.fn((..._: any[]) => ({
|
||||||
|
stdout: {
|
||||||
|
on: () => undefined,
|
||||||
|
},
|
||||||
|
stderr: {
|
||||||
|
on: () => undefined,
|
||||||
|
},
|
||||||
|
addListener: (_: any, fn: (code: number) => void) => {
|
||||||
|
fn(0);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
(runner as any).spawn = spawn;
|
||||||
|
|
||||||
|
const task = new PipelineTask();
|
||||||
|
task.id = 'taskId';
|
||||||
|
const unit = PipelineUnits.deploy;
|
||||||
|
|
||||||
|
await runner.runScript('script name', 'workspaceRoot', task, unit);
|
||||||
|
expect(spawn).toHaveBeenCalledTimes(1);
|
||||||
|
expect(spawn.mock.calls[0][0]).toEqual('script name');
|
||||||
|
expect(spawn.mock.calls[0][1]).toMatchObject({
|
||||||
|
shell: true,
|
||||||
|
cwd: 'workspaceRoot',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('failed', async () => {
|
||||||
|
const spawn = jest.fn((..._: any[]) => ({
|
||||||
|
stdout: {
|
||||||
|
on: () => undefined,
|
||||||
|
},
|
||||||
|
stderr: {
|
||||||
|
on: () => undefined,
|
||||||
|
},
|
||||||
|
addListener: (_: any, fn: (code: number) => void) => {
|
||||||
|
fn(1);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
(runner as any).spawn = spawn;
|
||||||
|
|
||||||
|
const task = new PipelineTask();
|
||||||
|
task.id = 'taskId';
|
||||||
|
const unit = PipelineUnits.deploy;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
runner.runScript('script name', 'workspaceRoot', task, unit),
|
||||||
|
).rejects.toThrowError();
|
||||||
|
});
|
||||||
|
it('wait emit message done', async () => {
|
||||||
|
let finishedFn: () => void;
|
||||||
|
const on = jest.fn((_: any, fn: (buff: Buffer) => void) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
fn(Buffer.from('message 1'));
|
||||||
|
setTimeout(() => {
|
||||||
|
fn(Buffer.from('message 2'));
|
||||||
|
setTimeout(() => {
|
||||||
|
fn(Buffer.from('message 3'));
|
||||||
|
finishedFn();
|
||||||
|
}, 1000);
|
||||||
|
}, 10);
|
||||||
|
}, 10);
|
||||||
|
});
|
||||||
|
const spawn = jest.fn((..._: any[]) => ({
|
||||||
|
stdout: {
|
||||||
|
on,
|
||||||
|
},
|
||||||
|
stderr: {
|
||||||
|
on,
|
||||||
|
},
|
||||||
|
addListener: (_: any, fn: (code: number) => void) => {
|
||||||
|
finishedFn = () => fn(0);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
let emitSuccessCount = 0;
|
||||||
|
jest.spyOn(runner, 'emitEvent').mockImplementation((..._: any[]) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
emitSuccessCount++;
|
||||||
|
resolve();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(runner as any).spawn = spawn;
|
||||||
|
|
||||||
|
const task = new PipelineTask();
|
||||||
|
task.id = 'taskId';
|
||||||
|
const unit = PipelineUnits.deploy;
|
||||||
|
|
||||||
|
await runner.runScript('script name', 'workspaceRoot', task, unit);
|
||||||
|
expect(emitSuccessCount).toEqual(1 + 6);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
253
src/pipeline-tasks/pipeline-task.runner.ts
Normal file
253
src/pipeline-tasks/pipeline-task.runner.ts
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
import { ReposService } from '../repos/repos.service';
|
||||||
|
import { spawn, ChildProcessWithoutNullStreams } from 'child_process';
|
||||||
|
import { PipelineTask } from './pipeline-task.entity';
|
||||||
|
import { ApplicationException } from '../commons/exceptions/application.exception';
|
||||||
|
import { PipelineUnits } from './enums/pipeline-units.enum';
|
||||||
|
import { TaskStatuses } from './enums/task-statuses.enum';
|
||||||
|
import { InjectPinoLogger, PinoLogger } from 'nestjs-pino';
|
||||||
|
import { RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { PipelineTaskEvent } from './models/pipeline-task-event';
|
||||||
|
import { last } from 'ramda';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
|
||||||
|
type Spawn = typeof spawn;
|
||||||
|
|
||||||
|
export class PipelineTaskRunner {
|
||||||
|
readonly processes = new Map<string, ChildProcessWithoutNullStreams>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly reposService: ReposService,
|
||||||
|
@InjectPinoLogger(PipelineTaskRunner.name)
|
||||||
|
private readonly logger: PinoLogger,
|
||||||
|
@Inject('spawn')
|
||||||
|
private readonly spawn: Spawn,
|
||||||
|
) {}
|
||||||
|
@RabbitSubscribe({
|
||||||
|
exchange: 'new-pipeline-task',
|
||||||
|
routingKey: 'mac',
|
||||||
|
queue: 'mac.new-pipeline-task',
|
||||||
|
})
|
||||||
|
async onNewTask(task: PipelineTask) {
|
||||||
|
this.logger.info({ task }, 'on new task [%s].', task.id);
|
||||||
|
try {
|
||||||
|
await this.doTask(task);
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.error({ task, err }, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@RabbitSubscribe({
|
||||||
|
exchange: 'stop-pipeline-task',
|
||||||
|
routingKey: 'mac',
|
||||||
|
queue: 'mac.stop-pipeline-task',
|
||||||
|
})
|
||||||
|
async onStopTask(task: PipelineTask) {
|
||||||
|
this.logger.info({ task }, 'on stop task [%s].', task.id);
|
||||||
|
const process = this.processes.get(task.id);
|
||||||
|
if (process) {
|
||||||
|
this.logger.info({ task }, 'send signal SIGINT to child process.');
|
||||||
|
process.kill('SIGINT');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (process === this.processes.get(task.id)) {
|
||||||
|
this.logger.info({ task }, 'send signal SIGKILL to child process.');
|
||||||
|
process.kill('SIGKILL');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.processes.has(task.id)) {
|
||||||
|
this.logger.error(
|
||||||
|
{ task },
|
||||||
|
'this pipeline task not stop yet. there is a new process running, maybe is a bug about error capture',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, 10_000);
|
||||||
|
} else {
|
||||||
|
this.logger.info({ task }, 'child process is not running.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async doTask(task: PipelineTask) {
|
||||||
|
if (task.pipeline.workUnitMetadata.version !== 1) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
'work unit metadata version is not match.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
null,
|
||||||
|
TaskStatuses.working,
|
||||||
|
`[start task]`,
|
||||||
|
'stdout',
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.info('running task [%s].', task.id);
|
||||||
|
try {
|
||||||
|
const workspaceRoot = await this.checkout(task);
|
||||||
|
const units = task.units
|
||||||
|
.filter((unit) => unit !== PipelineUnits.checkout)
|
||||||
|
.map(
|
||||||
|
(type) =>
|
||||||
|
task.pipeline.workUnitMetadata.units.find(
|
||||||
|
(unit) => unit.type === type,
|
||||||
|
) ?? { type: type, scripts: [] },
|
||||||
|
);
|
||||||
|
this.logger.info({ units }, 'begin run units.');
|
||||||
|
for (const unit of units) {
|
||||||
|
await this.doTaskUnit(unit.type, unit.scripts, task, workspaceRoot);
|
||||||
|
}
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
null,
|
||||||
|
TaskStatuses.success,
|
||||||
|
`[finished task] success`,
|
||||||
|
'stdout',
|
||||||
|
);
|
||||||
|
this.logger.info({ task }, 'task [%s] completed.', task.id);
|
||||||
|
} catch (err) {
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
null,
|
||||||
|
TaskStatuses.failed,
|
||||||
|
`[finished unit] ${err.message}`,
|
||||||
|
'stderr',
|
||||||
|
);
|
||||||
|
this.logger.error({ task, error: err }, 'task [%s] failed.', task.id);
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async doTaskUnit(
|
||||||
|
unit: PipelineUnits,
|
||||||
|
scripts: string[],
|
||||||
|
task: PipelineTask,
|
||||||
|
workspaceRoot: string,
|
||||||
|
) {
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
unit,
|
||||||
|
TaskStatuses.working,
|
||||||
|
`[begin unit] ${unit}`,
|
||||||
|
'stdin',
|
||||||
|
);
|
||||||
|
this.logger.info({ task }, 'curr unit is %s', unit);
|
||||||
|
try {
|
||||||
|
for (const script of scripts) {
|
||||||
|
this.logger.debug('begin runScript %s', script);
|
||||||
|
await this.runScript(script, workspaceRoot, task, unit);
|
||||||
|
this.logger.debug('end runScript %s', script);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
unit,
|
||||||
|
TaskStatuses.success,
|
||||||
|
`[finished unit] ${unit}`,
|
||||||
|
'stdout',
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
unit,
|
||||||
|
TaskStatuses.failed,
|
||||||
|
`[finished unit] ${err.message}`,
|
||||||
|
'stderr',
|
||||||
|
);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkout(task: PipelineTask) {
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
PipelineUnits.checkout,
|
||||||
|
TaskStatuses.working,
|
||||||
|
'[begin unit] checkout',
|
||||||
|
'stdin',
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const path = await this.reposService.checkout4Task(task);
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
PipelineUnits.checkout,
|
||||||
|
TaskStatuses.success,
|
||||||
|
'checkout success.',
|
||||||
|
'stdout',
|
||||||
|
);
|
||||||
|
return path;
|
||||||
|
} catch (err) {
|
||||||
|
await this.emitEvent(
|
||||||
|
task,
|
||||||
|
PipelineUnits.checkout,
|
||||||
|
TaskStatuses.failed,
|
||||||
|
'checkout failed.',
|
||||||
|
'stderr',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async emitEvent(
|
||||||
|
task: PipelineTask,
|
||||||
|
unit: PipelineUnits | null,
|
||||||
|
status: TaskStatuses,
|
||||||
|
message: string,
|
||||||
|
messageType: 'stderr' | 'stdout' | 'stdin',
|
||||||
|
) {
|
||||||
|
const event: PipelineTaskEvent = {
|
||||||
|
taskId: task.id,
|
||||||
|
pipelineId: task.pipeline.id,
|
||||||
|
projectId: task.pipeline.project.id,
|
||||||
|
unit,
|
||||||
|
emittedAt: new Date(),
|
||||||
|
message: last(message) === '\n' ? message : message + '\n',
|
||||||
|
messageType,
|
||||||
|
status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async runScript(
|
||||||
|
script: string,
|
||||||
|
workspaceRoot: string,
|
||||||
|
task: PipelineTask,
|
||||||
|
unit: PipelineUnits,
|
||||||
|
): Promise<void> {
|
||||||
|
await this.emitEvent(task, unit, TaskStatuses.working, script, 'stdin');
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const sub = this.spawn(script, {
|
||||||
|
shell: true,
|
||||||
|
cwd: workspaceRoot,
|
||||||
|
});
|
||||||
|
this.processes.set(task.id, sub);
|
||||||
|
let loggingCount = 0; // semaphore
|
||||||
|
|
||||||
|
sub.stderr.on('data', (data: Buffer) => {
|
||||||
|
const str = data.toString();
|
||||||
|
loggingCount++;
|
||||||
|
|
||||||
|
this.emitEvent(task, unit, TaskStatuses.working, str, 'stdout').finally(
|
||||||
|
() => loggingCount--,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
sub.stdout.on('data', (data: Buffer) => {
|
||||||
|
const str = data.toString();
|
||||||
|
loggingCount++;
|
||||||
|
|
||||||
|
this.emitEvent(task, unit, TaskStatuses.working, str, 'stderr').finally(
|
||||||
|
() => loggingCount--,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
sub.addListener('close', async (code) => {
|
||||||
|
this.processes.delete(task.id);
|
||||||
|
await new Promise<void>(async (resolve) => {
|
||||||
|
for (let i = 0; i < 10 && loggingCount > 0; i++) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
this.logger.debug('waiting logging... (%dx500ms)', i);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
if (code === 0) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
return reject(new ApplicationException('exec script failed'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,10 @@ import { PipelineTaskConsumer } from './pipeline-task.consumer';
|
|||||||
import { PIPELINE_TASK_QUEUE } from './pipeline-tasks.constants';
|
import { PIPELINE_TASK_QUEUE } from './pipeline-tasks.constants';
|
||||||
import { PipelineTaskLogsService } from './pipeline-task-logs.service';
|
import { PipelineTaskLogsService } from './pipeline-task-logs.service';
|
||||||
import { PubSubModule } from '../commons/pub-sub/pub-sub.module';
|
import { PubSubModule } from '../commons/pub-sub/pub-sub.module';
|
||||||
|
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
import { PipelineTaskRunner } from './pipeline-task.runner';
|
||||||
|
import { spawn } from 'child_process';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -21,12 +25,48 @@ import { PubSubModule } from '../commons/pub-sub/pub-sub.module';
|
|||||||
PubSubModule.forFeature(),
|
PubSubModule.forFeature(),
|
||||||
RedisModule,
|
RedisModule,
|
||||||
ReposModule,
|
ReposModule,
|
||||||
|
|
||||||
|
RabbitMQModule.forRootAsync(RabbitMQModule, {
|
||||||
|
imports: [ConfigModule],
|
||||||
|
useFactory: (configService: ConfigService) => ({
|
||||||
|
uri: configService.get<string>('db.rabbitmq.uri'),
|
||||||
|
exchanges: [
|
||||||
|
{
|
||||||
|
name: 'new-pipeline-task',
|
||||||
|
type: 'fanout',
|
||||||
|
options: {
|
||||||
|
durable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'stop-pipeline-task',
|
||||||
|
type: 'fanout',
|
||||||
|
options: {
|
||||||
|
durable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'update-pipeline-task',
|
||||||
|
type: 'fanout',
|
||||||
|
options: {
|
||||||
|
durable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
inject: [ConfigService],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
PipelineTasksService,
|
PipelineTasksService,
|
||||||
PipelineTasksResolver,
|
PipelineTasksResolver,
|
||||||
PipelineTaskConsumer,
|
PipelineTaskConsumer,
|
||||||
PipelineTaskLogsService,
|
PipelineTaskLogsService,
|
||||||
|
PipelineTaskRunner,
|
||||||
|
{
|
||||||
|
provide: 'spawn',
|
||||||
|
useValue: spawn,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
exports: [PipelineTasksService],
|
exports: [PipelineTasksService],
|
||||||
})
|
})
|
||||||
|
@ -46,7 +46,12 @@ export class PipelineTasksResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Query(() => PipelineTask)
|
@Query(() => PipelineTask)
|
||||||
async findPipelineTask(@Args('id') id: string) {
|
async pipelineTask(@Args('id') id: string) {
|
||||||
return await this.service.findTaskById(id);
|
return await this.service.findTaskById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Boolean)
|
||||||
|
async stopPipelineTask(@Args('id') id: string) {
|
||||||
|
const task = await this.service.findTaskById(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import debug from 'debug';
|
|||||||
import { InjectPubSub } from '../commons/pub-sub/decorators/inject-pub-sub.decorator';
|
import { InjectPubSub } from '../commons/pub-sub/decorators/inject-pub-sub.decorator';
|
||||||
import { PubSub } from '../commons/pub-sub/pub-sub';
|
import { PubSub } from '../commons/pub-sub/pub-sub';
|
||||||
import { observableToAsyncIterable } from '@graphql-tools/utils';
|
import { observableToAsyncIterable } from '@graphql-tools/utils';
|
||||||
|
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
|
||||||
const log = debug('fennec:pipeline-tasks:service');
|
const log = debug('fennec:pipeline-tasks:service');
|
||||||
|
|
||||||
@ -30,37 +31,29 @@ export class PipelineTasksService {
|
|||||||
private readonly redis: RedisService,
|
private readonly redis: RedisService,
|
||||||
@InjectPubSub()
|
@InjectPubSub()
|
||||||
private readonly pubSub: PubSub,
|
private readonly pubSub: PubSub,
|
||||||
|
private readonly amqpConnection: AmqpConnection,
|
||||||
) {}
|
) {}
|
||||||
async addTask(dto: CreatePipelineTaskInput) {
|
async addTask(dto: CreatePipelineTaskInput) {
|
||||||
const pipeline = await this.pipelineRepository.findOneOrFail({
|
const pipeline = await this.pipelineRepository.findOneOrFail({
|
||||||
where: { id: dto.pipelineId },
|
where: { id: dto.pipelineId },
|
||||||
relations: ['project'],
|
relations: ['project'],
|
||||||
});
|
});
|
||||||
const hasUnfinishedTask = await this.repository
|
// const hasUnfinishedTask = await this.repository
|
||||||
.findOne({
|
// .findOne({
|
||||||
pipelineId: dto.pipelineId,
|
// pipelineId: dto.pipelineId,
|
||||||
commit: dto.commit,
|
// commit: dto.commit,
|
||||||
status: In([TaskStatuses.pending, TaskStatuses.working]),
|
// status: In([TaskStatuses.pending, TaskStatuses.working]),
|
||||||
})
|
// })
|
||||||
.then((val) => !isNil(val));
|
// .then((val) => !isNil(val));
|
||||||
if (hasUnfinishedTask) {
|
// if (hasUnfinishedTask) {
|
||||||
throw new ConflictException(
|
// throw new ConflictException(
|
||||||
'There are the same tasks among the unfinished tasks!',
|
// 'There are the same tasks among the unfinished tasks!',
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
const task = await this.repository.save(this.repository.create(dto));
|
const task = await this.repository.save(this.repository.create(dto));
|
||||||
task.pipeline = pipeline;
|
task.pipeline = pipeline;
|
||||||
|
|
||||||
const tasksKey = this.getRedisTokens(pipeline)[1];
|
this.amqpConnection.publish('new-pipeline-task', 'mac', task);
|
||||||
const redis = this.redis.getClient();
|
|
||||||
await redis.lpush(tasksKey, JSON.stringify(task));
|
|
||||||
log(
|
|
||||||
'add task %s:%s-%s',
|
|
||||||
task.id,
|
|
||||||
task.pipeline.branch,
|
|
||||||
task.commit.slice(0, 6),
|
|
||||||
);
|
|
||||||
await this.doNextTask(pipeline);
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,4 +105,10 @@ export class ReposService {
|
|||||||
encodeURIComponent(`${task.pipeline.name}-${task.commit}`),
|
encodeURIComponent(`${task.pipeline.name}-${task.commit}`),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkout4Task(task: PipelineTask): Promise<string> {
|
||||||
|
const path = this.getWorkspaceRootByTask(task);
|
||||||
|
await this.checkout(task, path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user