Compare commits
178 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3683743f3c | |||
| 41237e0e5f | |||
| bce84a0e74 | |||
| 79bed919d8 | |||
| 4b202ce00e | |||
| 16ca787314 | |||
| 3a9b6f658a | |||
| 5c5dbf303f | |||
| 4c07131e51 | |||
| ba039469ff | |||
| 49f2498ecd | |||
| 1060060366 | |||
| 0fa3a579f7 | |||
| 0e4556d59e | |||
| e2e7967fba | |||
| 45b8d67abf | |||
| 0a69aa5d62 | |||
| dfbab1a1df | |||
| e58f009a24 | |||
| 2afd9cddc5 | |||
| d79c5366ef | |||
| 8e4f7ad244 | |||
| 39de3a1601 | |||
| cb3d2964d1 | |||
| 6b5390cef8 | |||
| 2736b85de3 | |||
| 82d7778f59 | |||
| 8c99cc0491 | |||
| 955e3d0dbe | |||
| 702ae8bed8 | |||
| b6f0723b75 | |||
| 8a2fb30e59 | |||
| 95b4030120 | |||
| 5c77cfbdc2 | |||
| 5ea42320a9 | |||
| d07ebfc9c6 | |||
| bbb5718184 | |||
| 0d8b54637c | |||
| e51b2e28b9 | |||
| f767140cc8 | |||
| 0d4d69f072 | |||
| a3e628c43f | |||
| a58fa135c1 | |||
| 93c7af6c91 | |||
| ad0e12bf7b | |||
| 498dd6eff6 | |||
| b3aa964739 | |||
| 03eb9d2657 | |||
| 373a838a6a | |||
| 960e3f4675 | |||
| 09bf676b58 | |||
| 76ba8e2ab9 | |||
| aaaaca2d19 | |||
| 71b27eda17 | |||
| 2d00882fd7 | |||
| ba5e69041f | |||
| d2871d601a | |||
| 9c66d88dc0 | |||
| fb4c84e1de | |||
| 57aca36f11 | |||
| 905f594af1 | |||
| b788b7f96b | |||
| 319a2dc41a | |||
| e01a998f0e | |||
| e40606d97b | |||
| 449c7b2c04 | |||
| 006782b57f | |||
| d643da29b0 | |||
| 635f92d2bc | |||
| 9a2cb56094 | |||
| 5886283002 | |||
| f886194c9c | |||
| e4efec89d9 | |||
| dbc12a593f | |||
| d7666e862b | |||
| e262d29510 | |||
| 858d97cb5c | |||
| b8a2df66fe | |||
| 1c128dd694 | |||
| 2744d0bf7f | |||
| 9eb232da39 | |||
| 52af1d5188 | |||
| 4325f21c8c | |||
| 6cd3eaceb4 | |||
| f850c79b6c | |||
| efdf789575 | |||
| 6ef6446022 | |||
| ef7d85e7c4 | |||
| 93b5d9869b | |||
| 2a0cfeffe9 | |||
| 909aafbd5f | |||
| 91288e2d74 | |||
| 25709b1f9a | |||
| 8a03d9aa94 | |||
| bbe1cf770a | |||
| ac8190282f | |||
| 446d140e32 | |||
| 726948651e | |||
| dd0a7bb782 | |||
| fca00ffcf8 | |||
| 13f6334ae5 | |||
| 7275a858d6 | |||
| 5a3befe5af | |||
| 385a93a05e | |||
| b4d444ff05 | |||
| 487bcb9a70 | |||
| aaf11b66d7 | |||
| 83d7d46896 | |||
| 693bda6a49 | |||
| bfe3e266ee | |||
| 5f33ebd8a7 | |||
| f78c80e100 | |||
| f4d8656831 | |||
| 2290081ef0 | |||
| 189d02a16f | |||
| 55aee04334 | |||
| 0e407b9b9d | |||
| 24095bbd40 | |||
| f97ee94b5a | |||
| 4cf7aea374 | |||
| 6ab5e9cb30 | |||
| 95c1145bf5 | |||
| ea04a1b788 | |||
| 3bc2499d09 | |||
| 1f5967ac45 | |||
| fd952f086b | |||
| 79500cb2c2 | |||
| 6c58864fcf | |||
| 7ea3ac182d | |||
| 8979d26005 | |||
| c8876dac88 | |||
| 9c8a257c2a | |||
| 8b77930ece | |||
| ba672d030f | |||
| 8ad7e016e7 | |||
| d843311d7b | |||
| 14ef2cfa9b | |||
| 648effcf86 | |||
| 572738e88f | |||
| 129ae93044 | |||
| e910892231 | |||
| 6d9cabf7ee | |||
| 7c7787e811 | |||
| bde26cc312 | |||
| 29e81f3ae7 | |||
| 6337b20d62 | |||
| 6dd537fe43 | |||
| 7191b172a4 | |||
| 9a4611b70f | |||
| 189dbc3654 | |||
| fc95fc96ed | |||
| 467eed57d7 | |||
| a5ca5444a0 | |||
| 17610cb834 | |||
| e1f2b5c6fe | |||
| edbbae0bd0 | |||
| 0e820bec27 | |||
| 91a3d612c6 | |||
| c696730e55 | |||
| 38d38ce246 | |||
| adfdf68c38 | |||
| d4a4d69941 | |||
| c1fed2c758 | |||
| 9918d81f59 | |||
| 59d8338f6e | |||
| a4f8bd3320 | |||
| 7c2fdb7224 | |||
| 37384aeb57 | |||
| 60efda263f | |||
| 19831037ec | |||
| a1d52af813 | |||
| 0a49ff9b03 | |||
| ca62326b46 | |||
| e1de0ee479 | |||
| 0dea101c07 | |||
| 380a49c59f | |||
| 5133651e34 | |||
| c8f26c7c48 |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
name: Default (not tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm and npmci
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
|
||||||
|
- name: Run npm prepare
|
||||||
|
run: npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
108
.gitea/workflows/default_tags.yaml
Normal file
108
.gitea/workflows/default_tags.yaml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
name: Default (tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_LOGIN_DOCKER_GITEA: ${{secrets.NPMCI_DOCKER_REGISTRYURL_DEFAULT}}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm and npmci
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
|
||||||
|
- name: Run npm prepare
|
||||||
|
run: npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm publish
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Code quality
|
||||||
|
run: |
|
||||||
|
npmci command npm install -g typescript
|
||||||
|
npmci npm prepare
|
||||||
|
npmci npm install
|
||||||
|
|
||||||
|
- name: Trigger
|
||||||
|
run: npmci trigger
|
||||||
|
|
||||||
|
- name: Build docs and upload artifacts
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
pnpm install -g @gitzone/tsdoc
|
||||||
|
npmci command tsdoc
|
||||||
|
continue-on-error: true
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -8,12 +8,13 @@ pages/
|
|||||||
# installs
|
# installs
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
# caches and builds
|
# caches
|
||||||
.yarn/
|
.yarn/
|
||||||
.cache/
|
.cache/
|
||||||
|
.rpt2_cache
|
||||||
|
|
||||||
|
# builds
|
||||||
dist/
|
dist/
|
||||||
dist_web/
|
dist_*/
|
||||||
dist_serve/
|
|
||||||
dist_ts_web/
|
|
||||||
|
|
||||||
# custom
|
# custom
|
||||||
125
.gitlab-ci.yml
125
.gitlab-ci.yml
@@ -1,125 +0,0 @@
|
|||||||
# gitzone standard
|
|
||||||
image: hosttoday/ht-docker-node:npmci
|
|
||||||
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- .npmci_cache/
|
|
||||||
key: "$CI_BUILD_STAGE"
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- security
|
|
||||||
- test
|
|
||||||
- release
|
|
||||||
- metadata
|
|
||||||
|
|
||||||
# ====================
|
|
||||||
# security stage
|
|
||||||
# ====================
|
|
||||||
mirror:
|
|
||||||
stage: security
|
|
||||||
script:
|
|
||||||
- npmci git mirror
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
snyk:
|
|
||||||
stage: security
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci command npm install -g snyk
|
|
||||||
- npmci command npm install --ignore-scripts
|
|
||||||
- npmci command snyk test
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
# ====================
|
|
||||||
# test stage
|
|
||||||
# ====================
|
|
||||||
|
|
||||||
testLTS:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci node install lts
|
|
||||||
- npmci npm install
|
|
||||||
- npmci npm test
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
testSTABLE:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci node install stable
|
|
||||||
- npmci npm install
|
|
||||||
- npmci npm test
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
release:
|
|
||||||
stage: release
|
|
||||||
script:
|
|
||||||
- npmci node install stable
|
|
||||||
- npmci npm publish
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
# ====================
|
|
||||||
# metadata stage
|
|
||||||
# ====================
|
|
||||||
codequality:
|
|
||||||
stage: metadata
|
|
||||||
image: docker:stable
|
|
||||||
allow_failure: true
|
|
||||||
services:
|
|
||||||
- docker:stable-dind
|
|
||||||
script:
|
|
||||||
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
|
|
||||||
- docker run
|
|
||||||
--env SOURCE_CODE="$PWD"
|
|
||||||
--volume "$PWD":/code
|
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
|
|
||||||
artifacts:
|
|
||||||
paths: [codeclimate.json]
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- priv
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
stage: metadata
|
|
||||||
script:
|
|
||||||
- npmci trigger
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
pages:
|
|
||||||
image: hosttoday/ht-docker-node:npmci
|
|
||||||
stage: metadata
|
|
||||||
script:
|
|
||||||
- npmci command npm install -g typedoc typescript
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci npm install
|
|
||||||
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
paths:
|
|
||||||
- public
|
|
||||||
allow_failure: true
|
|
||||||
4
.snyk
4
.snyk
@@ -1,4 +0,0 @@
|
|||||||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
|
||||||
version: v1.13.1
|
|
||||||
ignore: {}
|
|
||||||
patch: {}
|
|
||||||
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"command": "npm test",
|
||||||
|
"name": "Run npm test",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": ["/npmextra.json"],
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"npmci": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "settings for npmci"
|
||||||
|
},
|
||||||
|
"gitzone": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "settings for gitzone",
|
||||||
|
"properties": {
|
||||||
|
"projectType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
4
cli.child.ts
Normal file
4
cli.child.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
process.env.CLI_CALL = 'true';
|
||||||
|
import * as cliTool from './ts/index.js';
|
||||||
|
cliTool.runCli();
|
||||||
3
cli.js
3
cli.js
@@ -1,3 +1,4 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
process.env.CLI_CALL = 'true';
|
process.env.CLI_CALL = 'true';
|
||||||
require('./dist/index');
|
const cliTool = await import('./dist_ts/index.js');
|
||||||
|
cliTool.runCli();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
process.env.CLI_CALL = 'true';
|
process.env.CLI_CALL = 'true';
|
||||||
require('@gitzone/tsrun');
|
|
||||||
require('./ts/index');
|
import * as tsrun from '@gitzone/tsrun';
|
||||||
|
tsrun.runPath('./cli.child.js', import.meta.url);
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
{
|
{
|
||||||
"npmts": {
|
|
||||||
"mode": "default",
|
|
||||||
"coverageTreshold": "70",
|
|
||||||
"cli": true
|
|
||||||
},
|
|
||||||
"npmci": {
|
"npmci": {
|
||||||
"npmGlobalTools": [],
|
"npmGlobalTools": [],
|
||||||
"npmAccessLevel": "public",
|
"npmAccessLevel": "public",
|
||||||
@@ -14,11 +9,12 @@
|
|||||||
"command": "npmci test stable"
|
"command": "npmci test stable"
|
||||||
},
|
},
|
||||||
"gitzone": {
|
"gitzone": {
|
||||||
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "gitlab.com",
|
"githost": "gitlab.com",
|
||||||
"gitscope": "shipzone",
|
"gitscope": "shipzone",
|
||||||
"gitrepo": "npmci",
|
"gitrepo": "npmci",
|
||||||
"shortDescription": "node and docker in gitlab ci on steroids",
|
"description": "node and docker in gitlab ci on steroids",
|
||||||
"npmPackagename": "@shipzone/npmci",
|
"npmPackagename": "@shipzone/npmci",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
|
|||||||
3458
package-lock.json
generated
3458
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
87
package.json
87
package.json
@@ -1,17 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "@shipzone/npmci",
|
"name": "@shipzone/npmci",
|
||||||
"version": "3.1.26",
|
"version": "4.1.21",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "node and docker in gitlab ci on steroids",
|
"description": "node and docker in gitlab ci on steroids",
|
||||||
"main": "dist/index.js",
|
"main": "dist_ts/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
"npmci": "cli.js"
|
"npmci": "cli.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(rm -f config.json) && tstest test/",
|
"test": "tstest test/",
|
||||||
"build": "(rm -f config.json) && tsbuild && (npm run testVersion)",
|
"build": "tsbuild --allowimplicitany && (npm run testVersion)",
|
||||||
"testVersion": "(cd test/assets/ && node ../../cli.js -v)"
|
"testVersion": "(cd test/assets/ && node ../../cli.js -v)",
|
||||||
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -24,33 +26,52 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/gitzone/npmci#README",
|
"homepage": "https://gitlab.com/gitzone/npmci#README",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.1.11",
|
"@gitzone/tsbuild": "^2.1.66",
|
||||||
"@gitzone/tsrun": "^1.2.6",
|
"@gitzone/tsrun": "^1.2.42",
|
||||||
"@gitzone/tstest": "^1.0.20",
|
"@gitzone/tstest": "^1.0.74",
|
||||||
"@pushrocks/tapbundle": "^3.0.9",
|
"@push.rocks/tapbundle": "^5.0.8",
|
||||||
"@types/node": "^12.0.0",
|
"@types/node": "^20.4.1"
|
||||||
"tslint": "^5.16.0",
|
|
||||||
"tslint-config-prettier": "^1.18.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pushrocks/lik": "^3.0.5",
|
"@apiglobal/typedrequest": "^2.0.12",
|
||||||
"@pushrocks/npmextra": "^3.0.1",
|
"@push.rocks/lik": "^6.0.3",
|
||||||
"@pushrocks/projectinfo": "^4.0.2",
|
"@push.rocks/npmextra": "^3.0.9",
|
||||||
"@pushrocks/smartanalytics": "^2.0.15",
|
"@push.rocks/projectinfo": "^5.0.1",
|
||||||
"@pushrocks/smartcli": "^3.0.7",
|
"@push.rocks/qenv": "^5.0.2",
|
||||||
"@pushrocks/smartdelay": "^2.0.3",
|
"@push.rocks/smartanalytics": "^2.0.15",
|
||||||
"@pushrocks/smartfile": "^7.0.2",
|
"@push.rocks/smartcli": "^4.0.6",
|
||||||
"@pushrocks/smartlog": "^2.0.19",
|
"@push.rocks/smartdelay": "^3.0.1",
|
||||||
"@pushrocks/smartlog-destination-local": "^7.0.5",
|
"@push.rocks/smartenv": "^5.0.5",
|
||||||
"@pushrocks/smartparam": "^1.0.4",
|
"@push.rocks/smartfile": "^10.0.28",
|
||||||
"@pushrocks/smartpromise": "^3.0.2",
|
"@push.rocks/smartgit": "^3.0.0",
|
||||||
"@pushrocks/smartrequest": "^1.1.15",
|
"@push.rocks/smartlog": "^3.0.2",
|
||||||
"@pushrocks/smartshell": "^2.0.13",
|
"@push.rocks/smartlog-destination-local": "^9.0.0",
|
||||||
"@pushrocks/smartsocket": "^1.1.36",
|
"@push.rocks/smartobject": "^1.0.10",
|
||||||
"@pushrocks/smartssh": "^1.2.3",
|
"@push.rocks/smartpath": "^5.0.11",
|
||||||
"@pushrocks/smartstring": "^3.0.10",
|
"@push.rocks/smartpromise": "^4.0.2",
|
||||||
"@types/shelljs": "^0.8.5",
|
"@push.rocks/smartrequest": "^2.0.18",
|
||||||
"@types/through2": "^2.0.34",
|
"@push.rocks/smartshell": "^3.0.3",
|
||||||
"through2": "^3.0.1"
|
"@push.rocks/smartsocket": "^2.0.19",
|
||||||
}
|
"@push.rocks/smartssh": "^2.0.0",
|
||||||
|
"@push.rocks/smartstring": "^4.0.7",
|
||||||
|
"@servezone/interfaces": "^1.0.3",
|
||||||
|
"@tsclass/tsclass": "^4.0.42",
|
||||||
|
"@types/through2": "^2.0.38",
|
||||||
|
"through2": "^4.0.2"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"ts/**/*",
|
||||||
|
"ts_web/**/*",
|
||||||
|
"dist/**/*",
|
||||||
|
"dist_*/**/*",
|
||||||
|
"dist_ts/**/*",
|
||||||
|
"dist_ts_web/**/*",
|
||||||
|
"assets/**/*",
|
||||||
|
"cli.js",
|
||||||
|
"npmextra.json",
|
||||||
|
"readme.md"
|
||||||
|
],
|
||||||
|
"browserslist": [
|
||||||
|
"last 1 chrome versions"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4920
pnpm-lock.yaml
generated
Normal file
4920
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
readme.md
31
readme.md
@@ -8,13 +8,19 @@ node and docker in gitlab ci on steroids
|
|||||||
* [docs (typedoc)](https://shipzone.gitlab.io/npmci/)
|
* [docs (typedoc)](https://shipzone.gitlab.io/npmci/)
|
||||||
|
|
||||||
## Status for master
|
## Status for master
|
||||||
[](https://gitlab.com/shipzone/npmci/commits/master)
|
|
||||||
[](https://gitlab.com/shipzone/npmci/commits/master)
|
Status Category | Status Badge
|
||||||
[](https://www.npmjs.com/package/@shipzone/npmci)
|
-- | --
|
||||||
[](https://snyk.io/test/npm/@shipzone/npmci)
|
GitLab Pipelines | [](https://lossless.cloud)
|
||||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
npm | [](https://lossless.cloud)
|
||||||
[](https://prettier.io/)
|
Snyk | [](https://lossless.cloud)
|
||||||
|
TypeScript Support | [](https://lossless.cloud)
|
||||||
|
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||||
|
Code Style | [](https://lossless.cloud)
|
||||||
|
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||||
|
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||||
|
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -93,9 +99,12 @@ For further information read the linked docs at the top of this README.
|
|||||||
|
|
||||||
Use TypeScript for best in class instellisense.
|
Use TypeScript for best in class instellisense.
|
||||||
|
|
||||||
|
## Contribution
|
||||||
|
|
||||||
|
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||||
|
|
||||||
For further information read the linked docs at the top of this readme.
|
For further information read the linked docs at the top of this readme.
|
||||||
|
|
||||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
## Legal
|
||||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html)
|
> MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc)
|
||||||
|
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||||
[](https://maintainedby.lossless.com)
|
|
||||||
|
|||||||
26
test/test.cloudly.ts
Normal file
26
test/test.cloudly.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
|
import * as cloudlyConnectorMod from '../ts/connector.cloudly/cloudlyconnector.js';
|
||||||
|
|
||||||
|
tap.test('should be able to announce a container to cloudly', async () => {
|
||||||
|
const cloudlyConnector = new cloudlyConnectorMod.CloudlyConnector(null);
|
||||||
|
await cloudlyConnector.announceDockerContainer(
|
||||||
|
{
|
||||||
|
registryUrl: 'registry.losssless.com',
|
||||||
|
tag: 'testcontainer',
|
||||||
|
version: 'x.x.x',
|
||||||
|
labels: [],
|
||||||
|
},
|
||||||
|
'cloudly.lossless.one'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should close the program despite socket timeout', async (toolsArg) => {
|
||||||
|
// TODO: remove when unreffed timeouts in webrequest have been solved.
|
||||||
|
toolsArg.delayFor(0).then(() => {
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start();
|
||||||
97
test/test.ts
97
test/test.ts
@@ -1,8 +1,9 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as smartpath from '@push.rocks/smartpath';
|
||||||
|
|
||||||
// Setup test
|
|
||||||
process.env.NPMTS_TEST = 'true';
|
process.env.NPMTS_TEST = 'true';
|
||||||
|
process.env.NPMCI_URL_CLOUDLY = 'localhost';
|
||||||
|
|
||||||
// set up environment
|
// set up environment
|
||||||
process.env.CI_REPOSITORY_URL = 'https://yyyyyy:xxxxxxxx@gitlab.com/mygroup/myrepo.git';
|
process.env.CI_REPOSITORY_URL = 'https://yyyyyy:xxxxxxxx@gitlab.com/mygroup/myrepo.git';
|
||||||
@@ -15,70 +16,82 @@ process.env.NPMCI_LOGIN_DOCKER = 'docker.io|someuser|somepass';
|
|||||||
process.env.NPMCI_SSHKEY_1 = 'hostString|somePrivKey|##';
|
process.env.NPMCI_SSHKEY_1 = 'hostString|somePrivKey|##';
|
||||||
|
|
||||||
process.cwd = () => {
|
process.cwd = () => {
|
||||||
return path.join(__dirname, 'assets/');
|
return path.join(smartpath.get.dirnameFromImportMetaUrl(import.meta.url), 'assets/');
|
||||||
};
|
};
|
||||||
|
|
||||||
// require NPMCI files
|
let npmci: typeof import('../ts/index.js');
|
||||||
import '../ts/index';
|
|
||||||
import npmciModDocker = require('../ts/mod_docker/index');
|
type TNpmciTypes = typeof import('../ts/index.js');
|
||||||
import npmciModNpm = require('../ts/mod_npm/index');
|
|
||||||
import npmciModNode = require('../ts/mod_node/index');
|
tap.preTask('should import npmci', async () => {
|
||||||
import npmciModSsh = require('../ts/mod_ssh/index');
|
npmci = await import('../ts/index.js');
|
||||||
import npmciEnv = require('../ts/npmci.env');
|
});
|
||||||
|
|
||||||
// ======
|
// ======
|
||||||
// Docker
|
// Docker
|
||||||
// ======
|
// ======
|
||||||
|
|
||||||
let dockerfile1: npmciModDocker.Dockerfile;
|
let dockerfile1: npmci.Dockerfile;
|
||||||
let dockerfile2: npmciModDocker.Dockerfile;
|
let dockerfile2: npmci.Dockerfile;
|
||||||
let sortableArray: npmciModDocker.Dockerfile[];
|
let sortableArray: npmci.Dockerfile[];
|
||||||
|
|
||||||
tap.test('should return valid Dockerfiles', async () => {
|
tap.test('should return valid Dockerfiles', async () => {
|
||||||
dockerfile1 = new npmciModDocker.Dockerfile({ filePath: './Dockerfile', read: true });
|
const npmciInstance = new npmci.Npmci();
|
||||||
dockerfile2 = new npmciModDocker.Dockerfile({ filePath: './Dockerfile_sometag1', read: true });
|
dockerfile1 = new npmci.Dockerfile(npmciInstance.dockerManager, {
|
||||||
expect(dockerfile1.version).to.equal('latest');
|
filePath: './Dockerfile',
|
||||||
return expect(dockerfile2.version).to.equal('sometag1');
|
read: true,
|
||||||
|
});
|
||||||
|
dockerfile2 = new npmci.Dockerfile(npmciInstance.dockerManager, {
|
||||||
|
filePath: './Dockerfile_sometag1',
|
||||||
|
read: true,
|
||||||
|
});
|
||||||
|
expect(dockerfile1.version).toEqual('latest');
|
||||||
|
return expect(dockerfile2.version).toEqual('sometag1');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should read a directory of Dockerfiles', async () => {
|
tap.test('should read a directory of Dockerfiles', async () => {
|
||||||
return npmciModDocker.helpers
|
const npmciInstance = new npmci.Npmci();
|
||||||
.readDockerfiles()
|
return npmci.Dockerfile.readDockerfiles(npmciInstance.dockerManager).then(
|
||||||
.then(async (readDockerfilesArrayArg: npmciModDocker.Dockerfile[]) => {
|
async (readDockerfilesArrayArg: npmci.Dockerfile[]) => {
|
||||||
sortableArray = readDockerfilesArrayArg;
|
sortableArray = readDockerfilesArrayArg;
|
||||||
return expect(readDockerfilesArrayArg[1].version).to.equal('sometag1');
|
return expect(readDockerfilesArrayArg[1].version).toEqual('sometag1');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should sort an array of Dockerfiles', async () => {
|
tap.test('should sort an array of Dockerfiles', async () => {
|
||||||
return npmciModDocker.helpers
|
return npmci.Dockerfile.sortDockerfiles(sortableArray).then(
|
||||||
.sortDockerfiles(sortableArray)
|
async (sortedArrayArg: npmci.Dockerfile[]) => {
|
||||||
.then(async (sortedArrayArg: npmciModDocker.Dockerfile[]) => {
|
|
||||||
console.log(sortedArrayArg);
|
console.log(sortedArrayArg);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should build all Dockerfiles', async () => {
|
tap.test('should build all Dockerfiles', async () => {
|
||||||
return npmciModDocker.handleCli({
|
const npmciInstance = new npmci.Npmci();
|
||||||
_: ['docker', 'build']
|
return npmciInstance.dockerManager.handleCli({
|
||||||
|
_: ['docker', 'build'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should test all Dockerfiles', async () => {
|
tap.test('should test all Dockerfiles', async () => {
|
||||||
return await npmciModDocker.handleCli({
|
const npmciInstance = new npmci.Npmci();
|
||||||
_: ['docker', 'test']
|
return npmciInstance.dockerManager.handleCli({
|
||||||
|
_: ['docker', 'test'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should test dockerfiles', async () => {
|
tap.test('should test dockerfiles', async () => {
|
||||||
return await npmciModDocker.handleCli({
|
const npmciInstance = new npmci.Npmci();
|
||||||
_: ['docker', 'test']
|
return npmciInstance.dockerManager.handleCli({
|
||||||
|
_: ['docker', 'test'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should login docker daemon', async () => {
|
tap.test('should login docker daemon', async () => {
|
||||||
return await npmciModDocker.handleCli({
|
const npmciInstance = new npmci.Npmci();
|
||||||
_: ['docker', 'login']
|
return npmciInstance.dockerManager.handleCli({
|
||||||
|
_: ['docker', 'login'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -86,8 +99,9 @@ tap.test('should login docker daemon', async () => {
|
|||||||
// SSH
|
// SSH
|
||||||
// ===
|
// ===
|
||||||
tap.test('should prepare SSH keys', async () => {
|
tap.test('should prepare SSH keys', async () => {
|
||||||
|
const npmciModSsh = await import('../ts/mod_ssh/index.js');
|
||||||
return await npmciModSsh.handleCli({
|
return await npmciModSsh.handleCli({
|
||||||
_: ['ssh', 'prepare']
|
_: ['ssh', 'prepare'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,14 +109,15 @@ tap.test('should prepare SSH keys', async () => {
|
|||||||
// node
|
// node
|
||||||
// ====
|
// ====
|
||||||
tap.test('should install a certain version of node', async () => {
|
tap.test('should install a certain version of node', async () => {
|
||||||
await npmciModNode.handleCli({
|
const npmciInstance = new npmci.Npmci();
|
||||||
_: ['node', 'install', 'stable']
|
await npmciInstance.nodejsManager.handleCli({
|
||||||
|
_: ['node', 'install', 'stable'],
|
||||||
});
|
});
|
||||||
await npmciModNode.handleCli({
|
await npmciInstance.nodejsManager.handleCli({
|
||||||
_: ['node', 'install', 'lts']
|
_: ['node', 'install', 'lts'],
|
||||||
});
|
});
|
||||||
await npmciModNode.handleCli({
|
await npmciInstance.nodejsManager.handleCli({
|
||||||
_: ['node', 'install', 'legacy']
|
_: ['node', 'install', 'legacy'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @pushrocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@shipzone/npmci',
|
||||||
|
version: '4.1.21',
|
||||||
|
description: 'node and docker in gitlab ci on steroids'
|
||||||
|
}
|
||||||
39
ts/connector.cloudly/cloudlyconnector.ts
Normal file
39
ts/connector.cloudly/cloudlyconnector.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import * as plugins from '../npmci.plugins.js';
|
||||||
|
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connects to cloudly
|
||||||
|
*/
|
||||||
|
export class CloudlyConnector {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
constructor(npmciRefArg: Npmci) {
|
||||||
|
this.npmciRef = npmciRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async announceDockerContainer(
|
||||||
|
optionsArg: plugins.tsclass.container.IContainer,
|
||||||
|
testCloudlyUrlArg?: string
|
||||||
|
) {
|
||||||
|
const cloudlyUrl = testCloudlyUrlArg || this.npmciRef.npmciConfig.getConfig().urlCloudly;
|
||||||
|
if (!cloudlyUrl) {
|
||||||
|
logger.log(
|
||||||
|
'warn',
|
||||||
|
'no cloudly url provided. Thus we cannot announce the newly built Dockerimage!'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const typedrequest =
|
||||||
|
new plugins.typedrequest.TypedRequest<plugins.servezoneInterfaces.requests.IRequest_InformAboutNewContainerImage>(
|
||||||
|
`https://${cloudlyUrl}/typedrequest`,
|
||||||
|
'servezonestandard_InformAboutNewContainerVersion'
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await typedrequest.fire({
|
||||||
|
containerImageInfo: optionsArg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
11
ts/index.ts
11
ts/index.ts
@@ -1 +1,10 @@
|
|||||||
import './npmci.cli';
|
import { Npmci } from './npmci.classes.npmci.js';
|
||||||
|
import { Dockerfile } from './manager.docker/mod.classes.dockerfile.js';
|
||||||
|
|
||||||
|
export const npmciInstance = new Npmci();
|
||||||
|
|
||||||
|
export { Dockerfile, Npmci };
|
||||||
|
|
||||||
|
export const runCli = async () => {
|
||||||
|
npmciInstance.start();
|
||||||
|
};
|
||||||
|
|||||||
67
ts/manager.cloudron/index.ts
Normal file
67
ts/manager.cloudron/index.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import * as plugins from './mod.plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
import { bash } from '../npmci.bash.js';
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciCloudronManager {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
constructor(npmciArg: Npmci) {
|
||||||
|
this.npmciRef = npmciArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle cli input
|
||||||
|
* @param argvArg
|
||||||
|
*/
|
||||||
|
public handleCli = async (argvArg: any) => {
|
||||||
|
if (argvArg._.length >= 2) {
|
||||||
|
const action: string = argvArg._[1];
|
||||||
|
switch (action) {
|
||||||
|
case 'deploy':
|
||||||
|
await this.deploy();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.log('error', `>>npmci cloudron ...<< action >>${action}<< not supported`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`>>npmci cloudron ...<< cli arguments invalid... Please read the documentation.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the version string in CloudronManifest file
|
||||||
|
* @param versionArg
|
||||||
|
*/
|
||||||
|
public deploy = async () => {
|
||||||
|
logger.log('info', 'now deploying to cloudron...');
|
||||||
|
logger.log('info', 'installing cloudron cli...');
|
||||||
|
await bash(`pnpm install -g cloudron`);
|
||||||
|
logger.log('ok', 'cloudron cli installed');
|
||||||
|
|
||||||
|
// lets set the version in the CloudronManifest file
|
||||||
|
await this.prepareCloudronManifest(this.npmciRef.npmciConfig.getConfig().projectInfo.npm.version);
|
||||||
|
logger.log('ok', 'CloudronManifest prepared');
|
||||||
|
|
||||||
|
// lets figure out the docker image tag
|
||||||
|
const dockerImageTag = await this.npmciRef.npmciConfig.kvStorage.readKey('latestPushedDockerTag');
|
||||||
|
const appName = this.npmciRef.npmciConfig.getConfig().cloudronAppName;
|
||||||
|
|
||||||
|
const cloudronEnvVar = process.env.NPMCI_LOGIN_CLOUDRON;
|
||||||
|
const cloudronServer = cloudronEnvVar.split('|')[0];
|
||||||
|
const cloudronToken = cloudronEnvVar.split('|')[1];
|
||||||
|
await bash(`cloudron update --server ${cloudronServer} --token ${cloudronToken} --image ${dockerImageTag} --app ${appName}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
private prepareCloudronManifest = async (versionArg: string) => {
|
||||||
|
const manifestPath = plugins.path.join(paths.cwd, 'CloudronManifest.json');
|
||||||
|
let manifestFile = plugins.smartfile.fs.toStringSync(manifestPath);
|
||||||
|
manifestFile = manifestFile.replace(/##version##/g, versionArg);
|
||||||
|
plugins.smartfile.memory.toFsSync(manifestFile, manifestPath);
|
||||||
|
logger.log('info', 'Version replaced in CloudronManifest file');
|
||||||
|
}
|
||||||
|
}
|
||||||
1
ts/manager.cloudron/mod.plugins.ts
Normal file
1
ts/manager.cloudron/mod.plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../npmci.plugins.js';
|
||||||
190
ts/manager.docker/index.ts
Normal file
190
ts/manager.docker/index.ts
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import * as plugins from './mod.plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
import { bash } from '../npmci.bash.js';
|
||||||
|
|
||||||
|
// classes
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
import { Dockerfile } from './mod.classes.dockerfile.js';
|
||||||
|
import { DockerRegistry } from './mod.classes.dockerregistry.js';
|
||||||
|
import { RegistryStorage } from './mod.classes.registrystorage.js';
|
||||||
|
|
||||||
|
export class NpmciDockerManager {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
public npmciRegistryStorage = new RegistryStorage();
|
||||||
|
|
||||||
|
constructor(npmciArg: Npmci) {
|
||||||
|
this.npmciRef = npmciArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle cli input
|
||||||
|
* @param argvArg
|
||||||
|
*/
|
||||||
|
public handleCli = async (argvArg: any) => {
|
||||||
|
if (argvArg._.length >= 2) {
|
||||||
|
const action: string = argvArg._[1];
|
||||||
|
switch (action) {
|
||||||
|
case 'build':
|
||||||
|
await this.build();
|
||||||
|
break;
|
||||||
|
case 'login':
|
||||||
|
case 'prepare':
|
||||||
|
await this.login();
|
||||||
|
break;
|
||||||
|
case 'test':
|
||||||
|
await this.test();
|
||||||
|
break;
|
||||||
|
case 'push':
|
||||||
|
await this.push(argvArg);
|
||||||
|
break;
|
||||||
|
case 'pull':
|
||||||
|
await this.pull(argvArg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.log('error', `>>npmci docker ...<< action >>${action}<< not supported`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`>>npmci docker ...<< cli arguments invalid... Please read the documentation.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* builds a cwd of Dockerfiles by triggering a promisechain
|
||||||
|
*/
|
||||||
|
public build = async () => {
|
||||||
|
await this.prepare();
|
||||||
|
logger.log('info', 'now building Dockerfiles...');
|
||||||
|
await Dockerfile.readDockerfiles(this)
|
||||||
|
.then(Dockerfile.sortDockerfiles)
|
||||||
|
.then(Dockerfile.mapDockerfiles)
|
||||||
|
.then(Dockerfile.buildDockerfiles);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* login to the DockerRegistries
|
||||||
|
*/
|
||||||
|
public login = async () => {
|
||||||
|
await this.prepare();
|
||||||
|
await this.npmciRegistryStorage.loginAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logs in docker
|
||||||
|
*/
|
||||||
|
public prepare = async () => {
|
||||||
|
// Always login to GitLab Registry
|
||||||
|
if (process.env.GITLAB_CI) {
|
||||||
|
console.log('gitlab ci detected');
|
||||||
|
if (!process.env.CI_JOB_TOKEN || process.env.CI_JOB_TOKEN === '') {
|
||||||
|
logger.log('error', 'Running in Gitlab CI, but no registry token specified by gitlab!');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
this.npmciRegistryStorage.addRegistry(
|
||||||
|
new DockerRegistry({
|
||||||
|
registryUrl: 'registry.gitlab.com',
|
||||||
|
username: 'gitlab-ci-token',
|
||||||
|
password: process.env.CI_JOB_TOKEN,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle registries
|
||||||
|
await plugins.smartobject.forEachMinimatch(
|
||||||
|
process.env,
|
||||||
|
'NPMCI_LOGIN_DOCKER*',
|
||||||
|
async (envString: string) => {
|
||||||
|
this.npmciRegistryStorage.addRegistry(DockerRegistry.fromEnvString(envString));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pushes an image towards a registry
|
||||||
|
* @param argvArg
|
||||||
|
*/
|
||||||
|
public push = async (argvArg: any) => {
|
||||||
|
await this.prepare();
|
||||||
|
let dockerRegistryUrls: string[] = [];
|
||||||
|
|
||||||
|
// lets parse the input of cli and npmextra
|
||||||
|
if (argvArg._.length >= 3 && argvArg._[2] !== 'npmextra') {
|
||||||
|
dockerRegistryUrls.push(argvArg._[2]);
|
||||||
|
} else {
|
||||||
|
if (this.npmciRef.npmciConfig.getConfig().dockerRegistries.length === 0) {
|
||||||
|
logger.log(
|
||||||
|
'warn',
|
||||||
|
`There are no docker registries listed in npmextra.json! This is strange!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dockerRegistryUrls = dockerRegistryUrls.concat(
|
||||||
|
this.npmciRef.npmciConfig.getConfig().dockerRegistries
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets determine the suffix
|
||||||
|
let suffix = null;
|
||||||
|
if (argvArg._.length >= 4) {
|
||||||
|
suffix = argvArg._[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets push to the registries
|
||||||
|
for (const dockerRegistryUrl of dockerRegistryUrls) {
|
||||||
|
const dockerfileArray = await Dockerfile.readDockerfiles(this)
|
||||||
|
.then(Dockerfile.sortDockerfiles)
|
||||||
|
.then(Dockerfile.mapDockerfiles);
|
||||||
|
const dockerRegistryToPushTo = await this.npmciRegistryStorage.getRegistryByUrl(
|
||||||
|
dockerRegistryUrl
|
||||||
|
);
|
||||||
|
if (!dockerRegistryToPushTo) {
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Cannot push to registry ${dockerRegistryUrl}, because it was not found in the authenticated registry list.`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
for (const dockerfile of dockerfileArray) {
|
||||||
|
await dockerfile.push(dockerRegistryToPushTo, suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pulls an image
|
||||||
|
*/
|
||||||
|
public pull = async (argvArg: any) => {
|
||||||
|
await this.prepare();
|
||||||
|
const registryUrlArg = argvArg._[2];
|
||||||
|
let suffix = null;
|
||||||
|
if (argvArg._.length >= 4) {
|
||||||
|
suffix = argvArg._[3];
|
||||||
|
}
|
||||||
|
const localDockerRegistry = await this.npmciRegistryStorage.getRegistryByUrl(registryUrlArg);
|
||||||
|
const dockerfileArray = await Dockerfile.readDockerfiles(this)
|
||||||
|
.then(Dockerfile.sortDockerfiles)
|
||||||
|
.then(Dockerfile.mapDockerfiles);
|
||||||
|
for (const dockerfile of dockerfileArray) {
|
||||||
|
await dockerfile.pull(localDockerRegistry, suffix);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests docker files
|
||||||
|
*/
|
||||||
|
public test = async () => {
|
||||||
|
await this.prepare();
|
||||||
|
return await Dockerfile.readDockerfiles(this).then(Dockerfile.testDockerfiles);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* can be used to get the Dockerfiles in the directory
|
||||||
|
*/
|
||||||
|
getDockerfiles = async () => {
|
||||||
|
const dockerfiles = await Dockerfile.readDockerfiles(this);
|
||||||
|
return dockerfiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
336
ts/manager.docker/mod.classes.dockerfile.ts
Normal file
336
ts/manager.docker/mod.classes.dockerfile.ts
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
import * as plugins from './mod.plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
|
||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import { bash } from '../npmci.bash.js';
|
||||||
|
|
||||||
|
import { DockerRegistry } from './mod.classes.dockerregistry.js';
|
||||||
|
import * as helpers from './mod.helpers.js';
|
||||||
|
import { NpmciDockerManager } from './index.js';
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class Dockerfile represents a Dockerfile on disk in npmci
|
||||||
|
*/
|
||||||
|
export class Dockerfile {
|
||||||
|
// STATIC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates instance of class Dockerfile for all Dockerfiles in cwd
|
||||||
|
* @returns Promise<Dockerfile[]>
|
||||||
|
*/
|
||||||
|
public static async readDockerfiles(
|
||||||
|
npmciDockerManagerRefArg: NpmciDockerManager
|
||||||
|
): Promise<Dockerfile[]> {
|
||||||
|
const fileTree = await plugins.smartfile.fs.listFileTree(paths.cwd, 'Dockerfile*');
|
||||||
|
|
||||||
|
// create the Dockerfile array
|
||||||
|
const readDockerfilesArray: Dockerfile[] = [];
|
||||||
|
logger.log('info', `found ${fileTree.length} Dockerfiles:`);
|
||||||
|
console.log(fileTree);
|
||||||
|
for (const dockerfilePath of fileTree) {
|
||||||
|
const myDockerfile = new Dockerfile(npmciDockerManagerRefArg, {
|
||||||
|
filePath: dockerfilePath,
|
||||||
|
read: true,
|
||||||
|
});
|
||||||
|
readDockerfilesArray.push(myDockerfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readDockerfilesArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sorts Dockerfiles into a dependency chain
|
||||||
|
* @param sortableArrayArg an array of instances of class Dockerfile
|
||||||
|
* @returns Promise<Dockerfile[]>
|
||||||
|
*/
|
||||||
|
public static async sortDockerfiles(sortableArrayArg: Dockerfile[]): Promise<Dockerfile[]> {
|
||||||
|
const done = plugins.smartpromise.defer<Dockerfile[]>();
|
||||||
|
logger.log('info', 'sorting Dockerfiles:');
|
||||||
|
const sortedArray: Dockerfile[] = [];
|
||||||
|
const cleanTagsOriginal = Dockerfile.cleanTagsArrayFunction(sortableArrayArg, sortedArray);
|
||||||
|
let sorterFunctionCounter: number = 0;
|
||||||
|
const sorterFunction = () => {
|
||||||
|
sortableArrayArg.forEach((dockerfileArg) => {
|
||||||
|
const cleanTags = Dockerfile.cleanTagsArrayFunction(sortableArrayArg, sortedArray);
|
||||||
|
if (
|
||||||
|
cleanTags.indexOf(dockerfileArg.baseImage) === -1 &&
|
||||||
|
sortedArray.indexOf(dockerfileArg) === -1
|
||||||
|
) {
|
||||||
|
sortedArray.push(dockerfileArg);
|
||||||
|
}
|
||||||
|
if (cleanTagsOriginal.indexOf(dockerfileArg.baseImage) !== -1) {
|
||||||
|
dockerfileArg.localBaseImageDependent = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (sortableArrayArg.length === sortedArray.length) {
|
||||||
|
let counter = 1;
|
||||||
|
for (const dockerfile of sortedArray) {
|
||||||
|
logger.log('info', `tag ${counter}: -> ${dockerfile.cleanTag}`);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
done.resolve(sortedArray);
|
||||||
|
} else if (sorterFunctionCounter < 10) {
|
||||||
|
sorterFunctionCounter++;
|
||||||
|
sorterFunction();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sorterFunction();
|
||||||
|
return done.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* maps local Dockerfiles dependencies to the correspoding Dockerfile class instances
|
||||||
|
*/
|
||||||
|
public static async mapDockerfiles(sortedDockerfileArray: Dockerfile[]): Promise<Dockerfile[]> {
|
||||||
|
sortedDockerfileArray.forEach((dockerfileArg) => {
|
||||||
|
if (dockerfileArg.localBaseImageDependent) {
|
||||||
|
sortedDockerfileArray.forEach((dockfile2: Dockerfile) => {
|
||||||
|
if (dockfile2.cleanTag === dockerfileArg.baseImage) {
|
||||||
|
dockerfileArg.localBaseDockerfile = dockfile2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sortedDockerfileArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* builds the correspoding real docker image for each Dockerfile class instance
|
||||||
|
*/
|
||||||
|
public static async buildDockerfiles(sortedArrayArg: Dockerfile[]) {
|
||||||
|
for (const dockerfileArg of sortedArrayArg) {
|
||||||
|
await dockerfileArg.build();
|
||||||
|
}
|
||||||
|
return sortedArrayArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests all Dockerfiles in by calling class Dockerfile.test();
|
||||||
|
* @param sortedArrayArg Dockerfile[] that contains all Dockerfiles in cwd
|
||||||
|
*/
|
||||||
|
public static async testDockerfiles(sortedArrayArg: Dockerfile[]) {
|
||||||
|
for (const dockerfileArg of sortedArrayArg) {
|
||||||
|
await dockerfileArg.test();
|
||||||
|
}
|
||||||
|
return sortedArrayArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a version for a docker file
|
||||||
|
* @execution SYNC
|
||||||
|
*/
|
||||||
|
public static dockerFileVersion(dockerfileInstanceArg: Dockerfile, dockerfileNameArg: string): string {
|
||||||
|
let versionString: string;
|
||||||
|
const versionRegex = /Dockerfile_([^:_]*)$/;
|
||||||
|
const regexResultArray = versionRegex.exec(dockerfileNameArg);
|
||||||
|
if (regexResultArray && regexResultArray.length === 2) {
|
||||||
|
versionString = regexResultArray[1];
|
||||||
|
} else {
|
||||||
|
versionString = 'latest';
|
||||||
|
}
|
||||||
|
versionString = versionString.replace(
|
||||||
|
'##version##',
|
||||||
|
dockerfileInstanceArg.npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().projectInfo.npm.version
|
||||||
|
);
|
||||||
|
return versionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the docker base image for a Dockerfile
|
||||||
|
*/
|
||||||
|
public static dockerBaseImage(dockerfileContentArg: string): string {
|
||||||
|
const baseImageRegex = /FROM\s([a-zA-z0-9\/\-\:]*)\n?/;
|
||||||
|
const regexResultArray = baseImageRegex.exec(dockerfileContentArg);
|
||||||
|
return regexResultArray[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the docker tag
|
||||||
|
*/
|
||||||
|
public static getDockerTagString(
|
||||||
|
npmciDockerManagerRef: NpmciDockerManager,
|
||||||
|
registryArg: string,
|
||||||
|
repoArg: string,
|
||||||
|
versionArg: string,
|
||||||
|
suffixArg?: string
|
||||||
|
): string {
|
||||||
|
// determine wether the repo should be mapped accordingly to the registry
|
||||||
|
const mappedRepo =
|
||||||
|
npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().dockerRegistryRepoMap[registryArg];
|
||||||
|
const repo = (() => {
|
||||||
|
if (mappedRepo) {
|
||||||
|
return mappedRepo;
|
||||||
|
} else {
|
||||||
|
return repoArg;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
// determine wether the version contais a suffix
|
||||||
|
let version = versionArg;
|
||||||
|
if (suffixArg) {
|
||||||
|
version = versionArg + '_' + suffixArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagString = `${registryArg}/${repo}:${version}`;
|
||||||
|
return tagString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getDockerBuildArgs(
|
||||||
|
npmciDockerManagerRef: NpmciDockerManager
|
||||||
|
): Promise<string> {
|
||||||
|
logger.log('info', 'checking for env vars to be supplied to the docker build');
|
||||||
|
let buildArgsString: string = '';
|
||||||
|
for (const dockerArgKey of Object.keys(
|
||||||
|
npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().dockerBuildargEnvMap
|
||||||
|
)) {
|
||||||
|
const dockerArgOuterEnvVar =
|
||||||
|
npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().dockerBuildargEnvMap[dockerArgKey];
|
||||||
|
logger.log(
|
||||||
|
'note',
|
||||||
|
`docker ARG "${dockerArgKey}" maps to outer env var "${dockerArgOuterEnvVar}"`
|
||||||
|
);
|
||||||
|
const targetValue = process.env[dockerArgOuterEnvVar];
|
||||||
|
buildArgsString = `${buildArgsString} --build-arg ${dockerArgKey}="${targetValue}"`;
|
||||||
|
}
|
||||||
|
return buildArgsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static cleanTagsArrayFunction(
|
||||||
|
dockerfileArrayArg: Dockerfile[],
|
||||||
|
trackingArrayArg: Dockerfile[]
|
||||||
|
): string[] {
|
||||||
|
const cleanTagsArray: string[] = [];
|
||||||
|
dockerfileArrayArg.forEach((dockerfileArg) => {
|
||||||
|
if (trackingArrayArg.indexOf(dockerfileArg) === -1) {
|
||||||
|
cleanTagsArray.push(dockerfileArg.cleanTag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return cleanTagsArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public npmciDockerManagerRef: NpmciDockerManager;
|
||||||
|
|
||||||
|
public filePath: string;
|
||||||
|
public repo: string;
|
||||||
|
public version: string;
|
||||||
|
public cleanTag: string;
|
||||||
|
public buildTag: string;
|
||||||
|
public pushTag: string;
|
||||||
|
public containerName: string;
|
||||||
|
public content: string;
|
||||||
|
public baseImage: string;
|
||||||
|
public localBaseImageDependent: boolean;
|
||||||
|
public localBaseDockerfile: Dockerfile;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
dockerManagerRefArg: NpmciDockerManager,
|
||||||
|
options: { filePath?: string; fileContents?: string | Buffer; read?: boolean }
|
||||||
|
) {
|
||||||
|
this.npmciDockerManagerRef = dockerManagerRefArg;
|
||||||
|
this.filePath = options.filePath;
|
||||||
|
this.repo =
|
||||||
|
this.npmciDockerManagerRef.npmciRef.npmciEnv.repo.user +
|
||||||
|
'/' +
|
||||||
|
this.npmciDockerManagerRef.npmciRef.npmciEnv.repo.repo;
|
||||||
|
this.version = Dockerfile.dockerFileVersion(this, plugins.path.parse(options.filePath).base);
|
||||||
|
this.cleanTag = this.repo + ':' + this.version;
|
||||||
|
this.buildTag = this.cleanTag;
|
||||||
|
|
||||||
|
this.containerName = 'dockerfile-' + this.version;
|
||||||
|
if (options.filePath && options.read) {
|
||||||
|
this.content = plugins.smartfile.fs.toStringSync(plugins.path.resolve(options.filePath));
|
||||||
|
}
|
||||||
|
this.baseImage = Dockerfile.dockerBaseImage(this.content);
|
||||||
|
this.localBaseImageDependent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* builds the Dockerfile
|
||||||
|
*/
|
||||||
|
public async build() {
|
||||||
|
logger.log('info', 'now building Dockerfile for ' + this.cleanTag);
|
||||||
|
const buildArgsString = await Dockerfile.getDockerBuildArgs(this.npmciDockerManagerRef);
|
||||||
|
const buildCommand = `docker build --label="version=${
|
||||||
|
this.npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().projectInfo.npm.version
|
||||||
|
}" -t ${this.buildTag} -f ${this.filePath} ${buildArgsString} .`;
|
||||||
|
await bash(buildCommand);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pushes the Dockerfile to a registry
|
||||||
|
*/
|
||||||
|
public async push(dockerRegistryArg: DockerRegistry, versionSuffix: string = null) {
|
||||||
|
this.pushTag = Dockerfile.getDockerTagString(
|
||||||
|
this.npmciDockerManagerRef,
|
||||||
|
dockerRegistryArg.registryUrl,
|
||||||
|
this.repo,
|
||||||
|
this.version,
|
||||||
|
versionSuffix
|
||||||
|
);
|
||||||
|
await bash(`docker tag ${this.buildTag} ${this.pushTag}`);
|
||||||
|
await bash(`docker push ${this.pushTag}`);
|
||||||
|
const imageDigest = (
|
||||||
|
await bash(`docker inspect --format="{{index .RepoDigests 0}}" ${this.pushTag}`)
|
||||||
|
).split('@')[1];
|
||||||
|
console.log(`The image ${this.pushTag} has digest ${imageDigest}`);
|
||||||
|
await this.npmciDockerManagerRef.npmciRef.cloudlyConnector.announceDockerContainer({
|
||||||
|
registryUrl: this.pushTag,
|
||||||
|
tag: this.buildTag,
|
||||||
|
labels: [],
|
||||||
|
version: this.npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().projectInfo.npm.version,
|
||||||
|
});
|
||||||
|
await this.npmciDockerManagerRef.npmciRef.npmciConfig.kvStorage.writeKey('latestPushedDockerTag', this.pushTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pulls the Dockerfile from a registry
|
||||||
|
*/
|
||||||
|
public async pull(registryArg: DockerRegistry, versionSuffixArg: string = null) {
|
||||||
|
const pullTag = Dockerfile.getDockerTagString(
|
||||||
|
this.npmciDockerManagerRef,
|
||||||
|
registryArg.registryUrl,
|
||||||
|
this.repo,
|
||||||
|
this.version,
|
||||||
|
versionSuffixArg
|
||||||
|
);
|
||||||
|
await bash(`docker pull ${pullTag}`);
|
||||||
|
await bash(`docker tag ${pullTag} ${this.buildTag}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tests the Dockerfile;
|
||||||
|
*/
|
||||||
|
public async test() {
|
||||||
|
const testFile: string = plugins.path.join(paths.NpmciTestDir, 'test_' + this.version + '.sh');
|
||||||
|
const testFileExists: boolean = plugins.smartfile.fs.fileExistsSync(testFile);
|
||||||
|
if (testFileExists) {
|
||||||
|
// run tests
|
||||||
|
await bash(
|
||||||
|
`docker run --name npmci_test_container --entrypoint="bash" ${this.buildTag} -c "mkdir /npmci_test"`
|
||||||
|
);
|
||||||
|
await bash(`docker cp ${testFile} npmci_test_container:/npmci_test/test.sh`);
|
||||||
|
await bash(`docker commit npmci_test_container npmci_test_image`);
|
||||||
|
await bash(`docker run --entrypoint="bash" npmci_test_image -x /npmci_test/test.sh`);
|
||||||
|
await bash(`docker rm npmci_test_container`);
|
||||||
|
await bash(`docker rmi --force npmci_test_image`);
|
||||||
|
} else {
|
||||||
|
logger.log('warn', 'skipping tests for ' + this.cleanTag + ' because no testfile was found!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the id of a Dockerfile
|
||||||
|
*/
|
||||||
|
public async getId() {
|
||||||
|
const containerId = await bash(
|
||||||
|
'docker inspect --type=image --format="{{.Id}}" ' + this.buildTag
|
||||||
|
);
|
||||||
|
return containerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { logger } from '../npmci.logging';
|
import { logger } from '../npmci.logging.js';
|
||||||
import * as plugins from './mod.plugins';
|
import * as plugins from './mod.plugins.js';
|
||||||
import { bash } from '../npmci.bash';
|
import { bash } from '../npmci.bash.js';
|
||||||
|
|
||||||
export interface IDockerRegistryConstructorOptions {
|
export interface IDockerRegistryConstructorOptions {
|
||||||
registryUrl: string;
|
registryUrl: string;
|
||||||
@@ -26,13 +26,13 @@ export class DockerRegistry {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const registryUrl = dockerRegexResultArray[0];
|
const registryUrl = dockerRegexResultArray[0].replace('https://', '').replace('http://', '');
|
||||||
const username = dockerRegexResultArray[1];
|
const username = dockerRegexResultArray[1];
|
||||||
const password = dockerRegexResultArray[2];
|
const password = dockerRegexResultArray[2];
|
||||||
return new DockerRegistry({
|
return new DockerRegistry({
|
||||||
registryUrl: registryUrl,
|
registryUrl: registryUrl,
|
||||||
username: username,
|
username: username,
|
||||||
password: password
|
password: password,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
import { logger } from '../npmci.logging';
|
import { logger } from '../npmci.logging.js';
|
||||||
import * as plugins from './mod.plugins';
|
import * as plugins from './mod.plugins.js';
|
||||||
import { Objectmap } from '@pushrocks/lik';
|
|
||||||
|
|
||||||
import { DockerRegistry } from './mod.classes.dockerregistry';
|
import { DockerRegistry } from './mod.classes.dockerregistry.js';
|
||||||
|
|
||||||
export class RegistryStorage {
|
export class RegistryStorage {
|
||||||
objectMap = new Objectmap<DockerRegistry>();
|
objectMap = new plugins.lik.ObjectMap<DockerRegistry>();
|
||||||
constructor() {
|
constructor() {
|
||||||
// Nothing here
|
// Nothing here
|
||||||
}
|
}
|
||||||
@@ -15,13 +14,13 @@ export class RegistryStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getRegistryByUrl(registryUrlArg: string) {
|
getRegistryByUrl(registryUrlArg: string) {
|
||||||
return this.objectMap.find(registryArg => {
|
return this.objectMap.findSync((registryArg) => {
|
||||||
return registryArg.registryUrl === registryUrlArg;
|
return registryArg.registryUrl === registryUrlArg;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginAll() {
|
async loginAll() {
|
||||||
await this.objectMap.forEach(async registryArg => {
|
await this.objectMap.forEach(async (registryArg) => {
|
||||||
await registryArg.login();
|
await registryArg.login();
|
||||||
});
|
});
|
||||||
logger.log('success', 'logged in successfully into all available DockerRegistries!');
|
logger.log('success', 'logged in successfully into all available DockerRegistries!');
|
||||||
5
ts/manager.docker/mod.helpers.ts
Normal file
5
ts/manager.docker/mod.helpers.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import * as plugins from './mod.plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
|
||||||
|
import { Dockerfile } from './mod.classes.dockerfile.js';
|
||||||
1
ts/manager.docker/mod.plugins.ts
Normal file
1
ts/manager.docker/mod.plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../npmci.plugins.js';
|
||||||
71
ts/manager.git/index.ts
Normal file
71
ts/manager.git/index.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import * as plugins from './mod.plugins.js';
|
||||||
|
import { bash, bashNoError } from '../npmci.bash.js';
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciGitManager {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
constructor(npmciRefArg: Npmci) {
|
||||||
|
this.npmciRef = npmciRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle cli input
|
||||||
|
* @param argvArg
|
||||||
|
*/
|
||||||
|
public handleCli = async (argvArg: any) => {
|
||||||
|
if (argvArg._.length >= 2) {
|
||||||
|
const action: string = argvArg._[1];
|
||||||
|
switch (action) {
|
||||||
|
case 'mirror':
|
||||||
|
await this.mirror();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.log('error', `npmci git -> action >>${action}<< not supported!`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.log('info', `npmci git -> cli arguments invalid! Please read the documentation.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public mirror = async () => {
|
||||||
|
const githubToken = process.env.NPMCI_GIT_GITHUBTOKEN;
|
||||||
|
const githubUser = process.env.NPMCI_GIT_GITHUBGROUP || this.npmciRef.npmciEnv.repo.user;
|
||||||
|
const githubRepo = process.env.NPMCI_GIT_GITHUB || this.npmciRef.npmciEnv.repo.repo;
|
||||||
|
if (
|
||||||
|
this.npmciRef.npmciConfig.getConfig().projectInfo.npm.packageJson.private === true ||
|
||||||
|
this.npmciRef.npmciConfig.getConfig().npmAccessLevel === 'private'
|
||||||
|
) {
|
||||||
|
logger.log(
|
||||||
|
'warn',
|
||||||
|
`refusing to mirror due to private property use a private mirror location instead`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (githubToken) {
|
||||||
|
logger.log('info', 'found github token.');
|
||||||
|
logger.log('info', 'attempting the mirror the repository to GitHub');
|
||||||
|
|
||||||
|
// remove old mirrors
|
||||||
|
await bashNoError('git remote rm mirror');
|
||||||
|
|
||||||
|
await bash(`git fetch`);
|
||||||
|
// add the mirror
|
||||||
|
await bashNoError(
|
||||||
|
`git remote add mirror https://${githubToken}@github.com/${githubUser}/${githubRepo}.git`
|
||||||
|
);
|
||||||
|
await bashNoError(`git push mirror --all`);
|
||||||
|
await bashNoError(`git checkout origin/master`);
|
||||||
|
await bashNoError(`git push mirror master`);
|
||||||
|
logger.log('ok', 'pushed all branches to mirror!');
|
||||||
|
await bashNoError(`git push mirror --tags`);
|
||||||
|
logger.log('ok', 'pushed all tags to mirror!');
|
||||||
|
// remove old mirrors
|
||||||
|
await bashNoError('git remote rm mirror');
|
||||||
|
} else {
|
||||||
|
logger.log('error', `cannot find NPMCI_GIT_GITHUBTOKEN env var!`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
1
ts/manager.git/mod.plugins.ts
Normal file
1
ts/manager.git/mod.plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../npmci.plugins.js';
|
||||||
82
ts/manager.nodejs/index.ts
Normal file
82
ts/manager.nodejs/index.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import * as plugins from '../npmci.plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
|
||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import { bash, bashNoError, nvmAvailable } from '../npmci.bash.js';
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciNodeJsManager {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
constructor(npmciRefArg: Npmci) {
|
||||||
|
this.npmciRef = npmciRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle cli input
|
||||||
|
* @param argvArg
|
||||||
|
*/
|
||||||
|
public async handleCli(argvArg: any) {
|
||||||
|
if (argvArg._.length >= 3) {
|
||||||
|
const action: string = argvArg._[1];
|
||||||
|
switch (action) {
|
||||||
|
case 'install':
|
||||||
|
await this.install(argvArg._[2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.log('error', `>>npmci node ...<< action >>${action}<< not supported`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`>>npmci node ...<< cli arguments invalid... Please read the documentation.`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a specific version of node
|
||||||
|
* @param versionArg
|
||||||
|
*/
|
||||||
|
public async install(versionArg: any) {
|
||||||
|
logger.log('info', `now installing node version ${versionArg}`);
|
||||||
|
let version: string;
|
||||||
|
if (versionArg === 'stable') {
|
||||||
|
version = '18';
|
||||||
|
} else if (versionArg === 'lts') {
|
||||||
|
version = '16';
|
||||||
|
} else if (versionArg === 'legacy') {
|
||||||
|
version = '14';
|
||||||
|
} else {
|
||||||
|
version = versionArg;
|
||||||
|
}
|
||||||
|
if (await nvmAvailable.promise) {
|
||||||
|
await bash(`nvm install ${version} && nvm alias default ${version}`);
|
||||||
|
logger.log('success', `Node version ${version} successfully installed!`);
|
||||||
|
} else {
|
||||||
|
logger.log('warn', 'Nvm not in path so staying at installed node version!');
|
||||||
|
}
|
||||||
|
logger.log('info', 'now installing latest npm version');
|
||||||
|
await bash('npm install -g npm');
|
||||||
|
await bash('node -v');
|
||||||
|
await bash('npm -v');
|
||||||
|
|
||||||
|
// lets look for further config
|
||||||
|
const config = await this.npmciRef.npmciConfig.getConfig();
|
||||||
|
logger.log('info', 'Now checking for needed global npm tools...');
|
||||||
|
for (const npmTool of config.npmGlobalTools) {
|
||||||
|
logger.log('info', `Checking for global "${npmTool}"`);
|
||||||
|
const whichOutput: string = await bashNoError(`which ${npmTool}`);
|
||||||
|
const toolAvailable: boolean = !(/not\sfound/.test(whichOutput) || whichOutput === '');
|
||||||
|
if (toolAvailable) {
|
||||||
|
logger.log('info', `Tool ${npmTool} is available`);
|
||||||
|
} else {
|
||||||
|
logger.log('info', `globally installing ${npmTool} from npm`);
|
||||||
|
await bash(`npm install ${npmTool} -q -g`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.log('success', 'all global npm tools specified in npmextra.json are now available!');
|
||||||
|
}
|
||||||
|
}
|
||||||
189
ts/manager.npm/index.ts
Normal file
189
ts/manager.npm/index.ts
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
import * as plugins from './mod.plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
|
||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import { bash, bashNoError, nvmAvailable } from '../npmci.bash.js';
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciNpmManager {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
constructor(npmciRefArg: Npmci) {
|
||||||
|
this.npmciRef = npmciRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle cli input
|
||||||
|
* @param argvArg
|
||||||
|
*/
|
||||||
|
public async handleCli(argvArg: any) {
|
||||||
|
if (argvArg._.length >= 2) {
|
||||||
|
const action: string = argvArg._[1];
|
||||||
|
switch (action) {
|
||||||
|
case 'install':
|
||||||
|
await this.install();
|
||||||
|
break;
|
||||||
|
case 'build':
|
||||||
|
await this.build();
|
||||||
|
break;
|
||||||
|
case 'prepare':
|
||||||
|
await this.prepare();
|
||||||
|
break;
|
||||||
|
case 'test':
|
||||||
|
await this.test();
|
||||||
|
break;
|
||||||
|
case 'publish':
|
||||||
|
await this.publish();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.log('error', `>>npmci npm ...<< action >>${action}<< not supported`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`>>npmci npm ...<< cli arguments invalid... Please read the documentation.`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* authenticates npm with token from env var
|
||||||
|
*/
|
||||||
|
public async prepare() {
|
||||||
|
const config = this.npmciRef.npmciConfig.getConfig();
|
||||||
|
let npmrcFileString: string = '';
|
||||||
|
await plugins.smartobject.forEachMinimatch(
|
||||||
|
process.env,
|
||||||
|
'NPMCI_TOKEN_NPM*',
|
||||||
|
(npmEnvArg: string) => {
|
||||||
|
const npmRegistryUrl = npmEnvArg.split('|')[0];
|
||||||
|
logger.log('ok', `found token for ${npmRegistryUrl}`);
|
||||||
|
let npmToken = npmEnvArg.split('|')[1];
|
||||||
|
if (npmEnvArg.split('|')[2] && npmEnvArg.split('|')[2] === 'plain') {
|
||||||
|
logger.log('ok', 'npm token not base64 encoded.');
|
||||||
|
} else {
|
||||||
|
logger.log('ok', 'npm token base64 encoded.');
|
||||||
|
npmToken = plugins.smartstring.base64.decode(npmToken);
|
||||||
|
}
|
||||||
|
npmrcFileString += `//${npmRegistryUrl}/:_authToken="${npmToken}"\n`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
logger.log('info', `setting default npm registry to ${config.npmRegistryUrl}`);
|
||||||
|
npmrcFileString += `registry=https://${config.npmRegistryUrl}\n`;
|
||||||
|
|
||||||
|
// final check
|
||||||
|
if (npmrcFileString.length > 0) {
|
||||||
|
logger.log('info', 'found one or more access tokens');
|
||||||
|
} else {
|
||||||
|
logger.log('error', 'no access token found! Exiting!');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets save it to disk
|
||||||
|
plugins.smartfile.memory.toFsSync(npmrcFileString, '/root/.npmrc');
|
||||||
|
|
||||||
|
// lets set the cache directory
|
||||||
|
await bash(`npm config set cache ${paths.NpmciCacheDir} --global `);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* publish a package to npm
|
||||||
|
*/
|
||||||
|
public async publish() {
|
||||||
|
const buildPublishCommand = async () => {
|
||||||
|
let npmAccessCliString = ``;
|
||||||
|
let npmRegistryCliString = ``;
|
||||||
|
let publishVerdaccioAsWell = false;
|
||||||
|
const config = this.npmciRef.npmciConfig.getConfig();
|
||||||
|
const availableRegistries: string[] = [];
|
||||||
|
await plugins.smartobject.forEachMinimatch(
|
||||||
|
process.env,
|
||||||
|
'NPMCI_TOKEN_NPM*',
|
||||||
|
(npmEnvArg: string) => {
|
||||||
|
availableRegistries.push(npmEnvArg.split('|')[0]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// -> configure package access level
|
||||||
|
if (config.npmAccessLevel) {
|
||||||
|
npmAccessCliString = `--access=${config.npmAccessLevel}`;
|
||||||
|
if (config.npmAccessLevel === 'public') {
|
||||||
|
publishVerdaccioAsWell = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('You need to set a npmAccessLevel!!!');
|
||||||
|
}
|
||||||
|
// -> configure registry url
|
||||||
|
if (config.npmRegistryUrl) {
|
||||||
|
npmRegistryCliString = `--registry=https://${config.npmRegistryUrl}`;
|
||||||
|
} else {
|
||||||
|
logger.log('error', `no registry url specified. Can't publish!`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let publishCommand = `npm publish ${npmAccessCliString} ${npmRegistryCliString} `;
|
||||||
|
|
||||||
|
// publishEverywhere
|
||||||
|
if (publishVerdaccioAsWell) {
|
||||||
|
const verdaccioRegistry = availableRegistries.find((registryString) =>
|
||||||
|
registryString.startsWith('verdaccio')
|
||||||
|
);
|
||||||
|
if (verdaccioRegistry) {
|
||||||
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`package is public and verdaccio registry is specified. Also publishing to Verdaccio!`
|
||||||
|
);
|
||||||
|
publishCommand = `${publishCommand} && npm publish ${npmAccessCliString} --registry=https://${verdaccioRegistry}`;
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`This package should also be published to Verdaccio, however there is no Verdaccio registry data available!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return publishCommand;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -> preparing
|
||||||
|
logger.log('info', `now preparing environment:`);
|
||||||
|
this.prepare();
|
||||||
|
await bash(`npm -v`);
|
||||||
|
await bash(`pnpm -v`);
|
||||||
|
|
||||||
|
// -> build it
|
||||||
|
await this.install();
|
||||||
|
await this.build();
|
||||||
|
|
||||||
|
logger.log('success', `Nice!!! The build for the publication was successfull!`);
|
||||||
|
logger.log('info', `Lets clean up so we don't publish any packages that don't belong to us:`);
|
||||||
|
// -> clean up before we publish stuff
|
||||||
|
await bashNoError(`rm -r ./.npmci_cache`);
|
||||||
|
await bash(`rm -r ./node_modules`);
|
||||||
|
|
||||||
|
logger.log('success', `Cleaned up!:`);
|
||||||
|
|
||||||
|
// -> publish it
|
||||||
|
logger.log('info', `now invoking npm to publish the package!`);
|
||||||
|
await bash(await buildPublishCommand());
|
||||||
|
logger.log('success', `Package was successfully published!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async install(): Promise<void> {
|
||||||
|
logger.log('info', 'now installing dependencies:');
|
||||||
|
await bash('pnpm install');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async build(): Promise<void> {
|
||||||
|
logger.log('info', 'now building the project:');
|
||||||
|
await bash('pnpm run build');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async test(): Promise<void> {
|
||||||
|
logger.log('info', 'now starting tests:');
|
||||||
|
await bash('pnpm test');
|
||||||
|
}
|
||||||
|
}
|
||||||
1
ts/manager.npm/mod.plugins.ts
Normal file
1
ts/manager.npm/mod.plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../npmci.plugins.js';
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as plugins from './mod.plugins';
|
import * as plugins from './mod.plugins.js';
|
||||||
import * as paths from '../npmci.paths';
|
import * as paths from '../npmci.paths.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cleans npmci config files
|
* cleans npmci config files
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export * from '../npmci.plugins';
|
export * from '../npmci.plugins.js';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as plugins from './mod.plugins';
|
import * as plugins from './mod.plugins.js';
|
||||||
import { bash } from '../npmci.bash';
|
import { bash } from '../npmci.bash.js';
|
||||||
|
|
||||||
export let command = async () => {
|
export let command = async () => {
|
||||||
let wrappedCommand: string = '';
|
let wrappedCommand: string = '';
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export * from '../npmci.plugins';
|
export * from '../npmci.plugins.js';
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
import { logger } from '../npmci.logging';
|
|
||||||
import * as plugins from './mod.plugins';
|
|
||||||
import * as paths from '../npmci.paths';
|
|
||||||
import { bash } from '../npmci.bash';
|
|
||||||
|
|
||||||
import * as helpers from './mod.helpers';
|
|
||||||
|
|
||||||
// classes
|
|
||||||
import { Dockerfile } from './mod.classes.dockerfile';
|
|
||||||
import { DockerRegistry } from './mod.classes.dockerregistry';
|
|
||||||
import { RegistryStorage } from './mod.classes.registrystorage';
|
|
||||||
|
|
||||||
// instances
|
|
||||||
const npmciRegistryStorage = new RegistryStorage();
|
|
||||||
|
|
||||||
export { Dockerfile, helpers };
|
|
||||||
|
|
||||||
export let modArgvArg; // will be set through the build command
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handle cli input
|
|
||||||
* @param argvArg
|
|
||||||
*/
|
|
||||||
export let handleCli = async argvArg => {
|
|
||||||
modArgvArg = argvArg;
|
|
||||||
if (argvArg._.length >= 2) {
|
|
||||||
const action: string = argvArg._[1];
|
|
||||||
switch (action) {
|
|
||||||
case 'build':
|
|
||||||
await build();
|
|
||||||
break;
|
|
||||||
case 'login':
|
|
||||||
case 'prepare':
|
|
||||||
await login();
|
|
||||||
break;
|
|
||||||
case 'test':
|
|
||||||
await test();
|
|
||||||
break;
|
|
||||||
case 'push':
|
|
||||||
await push(argvArg);
|
|
||||||
break;
|
|
||||||
case 'pull':
|
|
||||||
await pull(argvArg);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger.log('error', `>>npmci docker ...<< action >>${action}<< not supported`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.log(
|
|
||||||
'info',
|
|
||||||
`>>npmci docker ...<< cli arguments invalid... Please read the documentation.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* builds a cwd of Dockerfiles by triggering a promisechain
|
|
||||||
*/
|
|
||||||
export let build = async () => {
|
|
||||||
await prepare();
|
|
||||||
logger.log('info', 'now building Dockerfiles...');
|
|
||||||
await helpers
|
|
||||||
.readDockerfiles()
|
|
||||||
.then(helpers.sortDockerfiles)
|
|
||||||
.then(helpers.mapDockerfiles)
|
|
||||||
.then(helpers.buildDockerfiles);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* login to the DockerRegistries
|
|
||||||
*/
|
|
||||||
export let login = async () => {
|
|
||||||
await prepare();
|
|
||||||
await npmciRegistryStorage.loginAll();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* logs in docker
|
|
||||||
*/
|
|
||||||
export let prepare = async () => {
|
|
||||||
// Always login to GitLab Registry
|
|
||||||
if (!process.env.CI_BUILD_TOKEN || process.env.CI_BUILD_TOKEN === '') {
|
|
||||||
logger.log('error', 'No registry token specified by gitlab!');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
npmciRegistryStorage.addRegistry(
|
|
||||||
new DockerRegistry({
|
|
||||||
registryUrl: 'registry.gitlab.com',
|
|
||||||
username: 'gitlab-ci-token',
|
|
||||||
password: process.env.CI_BUILD_TOKEN
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// handle registries
|
|
||||||
await plugins.smartparam.forEachMinimatch(process.env, 'NPMCI_LOGIN_DOCKER*', async envString => {
|
|
||||||
npmciRegistryStorage.addRegistry(DockerRegistry.fromEnvString(envString));
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
export let push = async argvArg => {
|
|
||||||
await prepare();
|
|
||||||
const registryUrlArg = argvArg._[2];
|
|
||||||
let suffix = null;
|
|
||||||
if (argvArg._.length >= 4) {
|
|
||||||
suffix = argvArg._[3];
|
|
||||||
}
|
|
||||||
const dockerfileArray = await helpers
|
|
||||||
.readDockerfiles()
|
|
||||||
.then(helpers.sortDockerfiles)
|
|
||||||
.then(helpers.mapDockerfiles);
|
|
||||||
const localDockerRegistry = npmciRegistryStorage.getRegistryByUrl(registryUrlArg);
|
|
||||||
if (!localDockerRegistry) {
|
|
||||||
logger.log(
|
|
||||||
'error',
|
|
||||||
`Cannot push to registry ${registryUrlArg}, because it was not found in the authenticated registry list.`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
for (const dockerfile of dockerfileArray) {
|
|
||||||
await dockerfile.push(localDockerRegistry, suffix);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export let pull = async argvArg => {
|
|
||||||
await prepare();
|
|
||||||
const registryUrlArg = argvArg._[2];
|
|
||||||
let suffix = null;
|
|
||||||
if (argvArg._.length >= 4) {
|
|
||||||
suffix = argvArg._[3];
|
|
||||||
}
|
|
||||||
const localDockerRegistry = npmciRegistryStorage.getRegistryByUrl(registryUrlArg);
|
|
||||||
const dockerfileArray = await helpers
|
|
||||||
.readDockerfiles()
|
|
||||||
.then(helpers.sortDockerfiles)
|
|
||||||
.then(helpers.mapDockerfiles);
|
|
||||||
for (const dockerfile of dockerfileArray) {
|
|
||||||
await dockerfile.pull(localDockerRegistry, suffix);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export let test = async () => {
|
|
||||||
await prepare();
|
|
||||||
return await helpers.readDockerfiles().then(helpers.testDockerfiles);
|
|
||||||
};
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
import { logger } from '../npmci.logging';
|
|
||||||
import * as plugins from './mod.plugins';
|
|
||||||
import * as NpmciEnv from '../npmci.env';
|
|
||||||
import { bash } from '../npmci.bash';
|
|
||||||
import * as paths from '../npmci.paths';
|
|
||||||
|
|
||||||
import { DockerRegistry } from './mod.classes.dockerregistry';
|
|
||||||
import * as helpers from './mod.helpers';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* class Dockerfile represents a Dockerfile on disk in npmci
|
|
||||||
*/
|
|
||||||
export class Dockerfile {
|
|
||||||
public filePath: string;
|
|
||||||
public repo: string;
|
|
||||||
public version: string;
|
|
||||||
public cleanTag: string;
|
|
||||||
public buildTag: string;
|
|
||||||
public containerName: string;
|
|
||||||
public content: string;
|
|
||||||
public baseImage: string;
|
|
||||||
public localBaseImageDependent: boolean;
|
|
||||||
public localBaseDockerfile: Dockerfile;
|
|
||||||
constructor(options: { filePath?: string; fileContents?: string | Buffer; read?: boolean }) {
|
|
||||||
this.filePath = options.filePath;
|
|
||||||
this.repo = NpmciEnv.repo.user + '/' + NpmciEnv.repo.repo;
|
|
||||||
this.version = helpers.dockerFileVersion(plugins.path.parse(options.filePath).base);
|
|
||||||
this.cleanTag = this.repo + ':' + this.version;
|
|
||||||
this.buildTag = this.cleanTag;
|
|
||||||
|
|
||||||
this.containerName = 'dockerfile-' + this.version;
|
|
||||||
if (options.filePath && options.read) {
|
|
||||||
this.content = plugins.smartfile.fs.toStringSync(plugins.path.resolve(options.filePath));
|
|
||||||
}
|
|
||||||
this.baseImage = helpers.dockerBaseImage(this.content);
|
|
||||||
this.localBaseImageDependent = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* builds the Dockerfile
|
|
||||||
*/
|
|
||||||
public async build() {
|
|
||||||
logger.log('info', 'now building Dockerfile for ' + this.cleanTag);
|
|
||||||
const buildArgsString = await helpers.getDockerBuildArgs();
|
|
||||||
const buildCommand = `docker build -t ${this.buildTag} -f ${
|
|
||||||
this.filePath
|
|
||||||
} ${buildArgsString} .`;
|
|
||||||
await bash(buildCommand);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pushes the Dockerfile to a registry
|
|
||||||
*/
|
|
||||||
public async push(dockerRegistryArg: DockerRegistry, versionSuffix: string = null) {
|
|
||||||
const pushTag = helpers.getDockerTagString(
|
|
||||||
dockerRegistryArg.registryUrl,
|
|
||||||
this.repo,
|
|
||||||
this.version,
|
|
||||||
versionSuffix
|
|
||||||
);
|
|
||||||
await bash(`docker tag ${this.buildTag} ${pushTag}`);
|
|
||||||
await bash(`docker push ${pushTag}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pulls the Dockerfile from a registry
|
|
||||||
*/
|
|
||||||
public async pull(registryArg: DockerRegistry, versionSuffixArg: string = null) {
|
|
||||||
const pullTag = helpers.getDockerTagString(
|
|
||||||
registryArg.registryUrl,
|
|
||||||
this.repo,
|
|
||||||
this.version,
|
|
||||||
versionSuffixArg
|
|
||||||
);
|
|
||||||
await bash(`docker pull ${pullTag}`);
|
|
||||||
await bash(`docker tag ${pullTag} ${this.buildTag}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* tests the Dockerfile;
|
|
||||||
*/
|
|
||||||
public async test() {
|
|
||||||
const testFile: string = plugins.path.join(paths.NpmciTestDir, 'test_' + this.version + '.sh');
|
|
||||||
const testFileExists: boolean = plugins.smartfile.fs.fileExistsSync(testFile);
|
|
||||||
if (testFileExists) {
|
|
||||||
// run tests
|
|
||||||
await bash(
|
|
||||||
`docker run --name npmci_test_container --entrypoint="bash" ${
|
|
||||||
this.buildTag
|
|
||||||
} -c "mkdir /npmci_test"`
|
|
||||||
);
|
|
||||||
await bash(`docker cp ${testFile} npmci_test_container:/npmci_test/test.sh`);
|
|
||||||
await bash(`docker commit npmci_test_container npmci_test_image`);
|
|
||||||
await bash(`docker run --entrypoint="bash" npmci_test_image -x /npmci_test/test.sh`);
|
|
||||||
await bash(`docker rm npmci_test_container`);
|
|
||||||
await bash(`docker rmi --force npmci_test_image`);
|
|
||||||
} else {
|
|
||||||
logger.log('warn', 'skipping tests for ' + this.cleanTag + ' because no testfile was found!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the id of a Dockerfile
|
|
||||||
*/
|
|
||||||
public async getId() {
|
|
||||||
const containerId = await bash(
|
|
||||||
'docker inspect --type=image --format="{{.Id}}" ' + this.buildTag
|
|
||||||
);
|
|
||||||
return containerId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
import { logger } from '../npmci.logging';
|
|
||||||
import * as plugins from './mod.plugins';
|
|
||||||
import * as paths from '../npmci.paths';
|
|
||||||
import * as NpmciEnv from '../npmci.env';
|
|
||||||
import * as NpmciConfig from '../npmci.config';
|
|
||||||
import { bash } from '../npmci.bash';
|
|
||||||
|
|
||||||
import { Dockerfile } from './mod.classes.dockerfile';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates instance of class Dockerfile for all Dockerfiles in cwd
|
|
||||||
* @returns Promise<Dockerfile[]>
|
|
||||||
*/
|
|
||||||
export let readDockerfiles = async (): Promise<Dockerfile[]> => {
|
|
||||||
const fileTree = await plugins.smartfile.fs.listFileTree(paths.cwd, 'Dockerfile*');
|
|
||||||
|
|
||||||
// create the Dockerfile array
|
|
||||||
const readDockerfilesArray: Dockerfile[] = [];
|
|
||||||
logger.log('info', `found ${fileTree.length} Dockerfiles:`);
|
|
||||||
console.log(fileTree);
|
|
||||||
for (const dockerfilePath of fileTree) {
|
|
||||||
const myDockerfile = new Dockerfile({
|
|
||||||
filePath: dockerfilePath,
|
|
||||||
read: true
|
|
||||||
});
|
|
||||||
readDockerfilesArray.push(myDockerfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
return readDockerfilesArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sorts Dockerfiles into a dependency chain
|
|
||||||
* @param sortableArrayArg an array of instances of class Dockerfile
|
|
||||||
* @returns Promise<Dockerfile[]>
|
|
||||||
*/
|
|
||||||
export let sortDockerfiles = (sortableArrayArg: Dockerfile[]): Promise<Dockerfile[]> => {
|
|
||||||
const done = plugins.smartpromise.defer<Dockerfile[]>();
|
|
||||||
logger.log('info', 'sorting Dockerfiles:');
|
|
||||||
const sortedArray: Dockerfile[] = [];
|
|
||||||
const cleanTagsOriginal = cleanTagsArrayFunction(sortableArrayArg, sortedArray);
|
|
||||||
let sorterFunctionCounter: number = 0;
|
|
||||||
const sorterFunction = () => {
|
|
||||||
sortableArrayArg.forEach(dockerfileArg => {
|
|
||||||
const cleanTags = cleanTagsArrayFunction(sortableArrayArg, sortedArray);
|
|
||||||
if (
|
|
||||||
cleanTags.indexOf(dockerfileArg.baseImage) === -1 &&
|
|
||||||
sortedArray.indexOf(dockerfileArg) === -1
|
|
||||||
) {
|
|
||||||
sortedArray.push(dockerfileArg);
|
|
||||||
}
|
|
||||||
if (cleanTagsOriginal.indexOf(dockerfileArg.baseImage) !== -1) {
|
|
||||||
dockerfileArg.localBaseImageDependent = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (sortableArrayArg.length === sortedArray.length) {
|
|
||||||
let counter = 1;
|
|
||||||
for (const dockerfile of sortedArray) {
|
|
||||||
logger.log('info', `tag ${counter}: -> ${dockerfile.cleanTag}`);
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
done.resolve(sortedArray);
|
|
||||||
} else if (sorterFunctionCounter < 10) {
|
|
||||||
sorterFunctionCounter++;
|
|
||||||
sorterFunction();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sorterFunction();
|
|
||||||
return done.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* maps local Dockerfiles dependencies to the correspoding Dockerfile class instances
|
|
||||||
*/
|
|
||||||
export let mapDockerfiles = async (sortedArray: Dockerfile[]): Promise<Dockerfile[]> => {
|
|
||||||
sortedArray.forEach(dockerfileArg => {
|
|
||||||
if (dockerfileArg.localBaseImageDependent) {
|
|
||||||
sortedArray.forEach((dockfile2: Dockerfile) => {
|
|
||||||
if (dockfile2.cleanTag === dockerfileArg.baseImage) {
|
|
||||||
dockerfileArg.localBaseDockerfile = dockfile2;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return sortedArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* builds the correspoding real docker image for each Dockerfile class instance
|
|
||||||
*/
|
|
||||||
export let buildDockerfiles = async (sortedArrayArg: Dockerfile[]) => {
|
|
||||||
for (const dockerfileArg of sortedArrayArg) {
|
|
||||||
await dockerfileArg.build();
|
|
||||||
}
|
|
||||||
return sortedArrayArg;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* tests all Dockerfiles in by calling class Dockerfile.test();
|
|
||||||
* @param sortedArrayArg Dockerfile[] that contains all Dockerfiles in cwd
|
|
||||||
*/
|
|
||||||
export let testDockerfiles = async (sortedArrayArg: Dockerfile[]) => {
|
|
||||||
for (const dockerfileArg of sortedArrayArg) {
|
|
||||||
await dockerfileArg.test();
|
|
||||||
}
|
|
||||||
return sortedArrayArg;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a version for a docker file
|
|
||||||
* @execution SYNC
|
|
||||||
*/
|
|
||||||
export let dockerFileVersion = (dockerfileNameArg: string): string => {
|
|
||||||
let versionString: string;
|
|
||||||
const versionRegex = /Dockerfile_([a-zA-Z0-9\.]*)$/;
|
|
||||||
const regexResultArray = versionRegex.exec(dockerfileNameArg);
|
|
||||||
if (regexResultArray && regexResultArray.length === 2) {
|
|
||||||
versionString = regexResultArray[1];
|
|
||||||
} else {
|
|
||||||
versionString = 'latest';
|
|
||||||
}
|
|
||||||
return versionString;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the docker base image for a Dockerfile
|
|
||||||
*/
|
|
||||||
export let dockerBaseImage = (dockerfileContentArg: string) => {
|
|
||||||
const baseImageRegex = /FROM\s([a-zA-z0-9\/\-\:]*)\n?/;
|
|
||||||
const regexResultArray = baseImageRegex.exec(dockerfileContentArg);
|
|
||||||
return regexResultArray[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the docker tag
|
|
||||||
*/
|
|
||||||
export let getDockerTagString = (
|
|
||||||
registryArg: string,
|
|
||||||
repoArg: string,
|
|
||||||
versionArg: string,
|
|
||||||
suffixArg?: string
|
|
||||||
): string => {
|
|
||||||
// determine wether the repo should be mapped accordingly to the registry
|
|
||||||
const mappedRepo = NpmciConfig.configObject.dockerRegistryRepoMap[registryArg];
|
|
||||||
const repo = (() => {
|
|
||||||
if (mappedRepo) {
|
|
||||||
return mappedRepo;
|
|
||||||
} else {
|
|
||||||
return repoArg;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// determine wether the version contais a suffix
|
|
||||||
let version = versionArg;
|
|
||||||
if (suffixArg) {
|
|
||||||
version = versionArg + '_' + suffixArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagString = `${registryArg}/${repo}:${version}`;
|
|
||||||
return tagString;
|
|
||||||
};
|
|
||||||
|
|
||||||
export let getDockerBuildArgs = async (): Promise<string> => {
|
|
||||||
logger.log('info', 'checking for env vars to be supplied to the docker build');
|
|
||||||
let buildArgsString: string = '';
|
|
||||||
for (const key in NpmciConfig.configObject.dockerBuildargEnvMap) {
|
|
||||||
const targetValue = process.env[NpmciConfig.configObject.dockerBuildargEnvMap[key]];
|
|
||||||
buildArgsString = `${buildArgsString} --build-arg ${key}="${targetValue}"`;
|
|
||||||
}
|
|
||||||
return buildArgsString;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export let cleanTagsArrayFunction = (
|
|
||||||
dockerfileArrayArg: Dockerfile[],
|
|
||||||
trackingArrayArg: Dockerfile[]
|
|
||||||
): string[] => {
|
|
||||||
const cleanTagsArray: string[] = [];
|
|
||||||
dockerfileArrayArg.forEach(dockerfileArg => {
|
|
||||||
if (trackingArrayArg.indexOf(dockerfileArg) === -1) {
|
|
||||||
cleanTagsArray.push(dockerfileArg.cleanTag);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return cleanTagsArray;
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from '../npmci.plugins';
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import { logger } from '../npmci.logging';
|
|
||||||
import * as plugins from './mod.plugins';
|
|
||||||
import { bash } from '../npmci.bash';
|
|
||||||
import { repo } from '../npmci.env';
|
|
||||||
|
|
||||||
import { configObject } from '../npmci.config';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handle cli input
|
|
||||||
* @param argvArg
|
|
||||||
*/
|
|
||||||
export let handleCli = async argvArg => {
|
|
||||||
if (argvArg._.length >= 2) {
|
|
||||||
const action: string = argvArg._[1];
|
|
||||||
switch (action) {
|
|
||||||
case 'mirror':
|
|
||||||
await mirror();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger.log('error', `npmci git -> action >>${action}<< not supported!`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.log('info', `npmci git -> cli arguments invalid! Please read the documentation.`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export let mirror = async () => {
|
|
||||||
const githubToken = process.env.NPMCI_GIT_GITHUBTOKEN;
|
|
||||||
const githubUser = process.env.NPMCI_GIT_GITHUBGROUP || repo.user;
|
|
||||||
const githubRepo = process.env.NPMCI_GIT_GITHUB || repo.repo;
|
|
||||||
if (
|
|
||||||
configObject.projectInfo.npm.packageJson.private === true ||
|
|
||||||
configObject.npmAccessLevel === 'private'
|
|
||||||
) {
|
|
||||||
logger.log(
|
|
||||||
'warn',
|
|
||||||
`refusing to mirror due to private property use a private mirror location instead`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (githubToken) {
|
|
||||||
logger.log('info', 'found github token.');
|
|
||||||
logger.log('info', 'attempting the mirror the repository to GitHub');
|
|
||||||
// add the mirror
|
|
||||||
await bash(
|
|
||||||
`git remote add mirror https://${githubToken}@github.com/${githubUser}/${githubRepo}.git`
|
|
||||||
);
|
|
||||||
await bash(`git push mirror --all`);
|
|
||||||
logger.log('ok', 'pushed all branches to mirror!');
|
|
||||||
await bash(`git push mirror --tags`);
|
|
||||||
logger.log('ok', 'pushed all tags to mirror!');
|
|
||||||
} else {
|
|
||||||
logger.log('error', `cannot find NPMCI_GIT_GITHUBTOKEN env var!`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from '../npmci.plugins';
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import { logger } from '../npmci.logging';
|
|
||||||
import * as plugins from '../npmci.plugins';
|
|
||||||
import * as paths from '../npmci.paths';
|
|
||||||
import * as npmciConfig from '../npmci.config';
|
|
||||||
import { bash, bashNoError, nvmAvailable } from '../npmci.bash';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handle cli input
|
|
||||||
* @param argvArg
|
|
||||||
*/
|
|
||||||
export let handleCli = async argvArg => {
|
|
||||||
if (argvArg._.length >= 3) {
|
|
||||||
const action: string = argvArg._[1];
|
|
||||||
switch (action) {
|
|
||||||
case 'install':
|
|
||||||
await install(argvArg._[2]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger.log('error', `>>npmci node ...<< action >>${action}<< not supported`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.log(
|
|
||||||
'error',
|
|
||||||
`>>npmci node ...<< cli arguments invalid... Please read the documentation.`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install a specific version of node
|
|
||||||
* @param versionArg
|
|
||||||
*/
|
|
||||||
export let install = async versionArg => {
|
|
||||||
logger.log('info', `now installing node version ${versionArg}`);
|
|
||||||
let version: string;
|
|
||||||
if (versionArg === 'stable') {
|
|
||||||
version = '12';
|
|
||||||
} else if (versionArg === 'lts') {
|
|
||||||
version = '10';
|
|
||||||
} else if (versionArg === 'legacy') {
|
|
||||||
version = '8';
|
|
||||||
} else {
|
|
||||||
version = versionArg;
|
|
||||||
}
|
|
||||||
if (await nvmAvailable.promise) {
|
|
||||||
await bash(`nvm install ${version} && nvm alias default ${version}`);
|
|
||||||
logger.log('success', `Node version ${version} successfully installed!`);
|
|
||||||
} else {
|
|
||||||
logger.log('warn', 'Nvm not in path so staying at installed node version!');
|
|
||||||
}
|
|
||||||
await bash('node -v');
|
|
||||||
await bash('npm -v');
|
|
||||||
await bash(`npm config set cache ${paths.NpmciCacheDir} --global `);
|
|
||||||
// lets look for further config
|
|
||||||
await npmciConfig.getConfig().then(async configArg => {
|
|
||||||
logger.log('info', 'Now checking for needed global npm tools...');
|
|
||||||
for (const npmTool of configArg.npmGlobalTools) {
|
|
||||||
logger.log('info', `Checking for global "${npmTool}"`);
|
|
||||||
const whichOutput: string = await bashNoError(`which ${npmTool}`);
|
|
||||||
const toolAvailable: boolean = !(/not\sfound/.test(whichOutput) || whichOutput === '');
|
|
||||||
if (toolAvailable) {
|
|
||||||
logger.log('info', `Tool ${npmTool} is available`);
|
|
||||||
} else {
|
|
||||||
logger.log('info', `globally installing ${npmTool} from npm`);
|
|
||||||
await bash(`npm install ${npmTool} -q -g`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.log('success', 'all global npm tools specified in npmextra.json are now available!');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import { logger } from '../npmci.logging';
|
|
||||||
import * as plugins from './mod.plugins';
|
|
||||||
import * as configModule from '../npmci.config';
|
|
||||||
import { bash, bashNoError, nvmAvailable } from '../npmci.bash';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handle cli input
|
|
||||||
* @param argvArg
|
|
||||||
*/
|
|
||||||
export let handleCli = async argvArg => {
|
|
||||||
if (argvArg._.length >= 2) {
|
|
||||||
const action: string = argvArg._[1];
|
|
||||||
switch (action) {
|
|
||||||
case 'install':
|
|
||||||
await install();
|
|
||||||
break;
|
|
||||||
case 'prepare':
|
|
||||||
await prepare();
|
|
||||||
break;
|
|
||||||
case 'test':
|
|
||||||
await test();
|
|
||||||
break;
|
|
||||||
case 'publish':
|
|
||||||
await publish();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger.log('error', `>>npmci npm ...<< action >>${action}<< not supported`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.log('info', `>>npmci npm ...<< cli arguments invalid... Please read the documentation.`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* authenticates npm with token from env var
|
|
||||||
*/
|
|
||||||
const prepare = async () => {
|
|
||||||
const config = await configModule.getConfig();
|
|
||||||
let npmrcFileString: string = '';
|
|
||||||
await plugins.smartparam.forEachMinimatch(process.env, 'NPMCI_TOKEN_NPM*', npmEnvArg => {
|
|
||||||
const npmRegistryUrl = npmEnvArg.split('|')[0];
|
|
||||||
const npmToken = npmEnvArg.split('|')[1];
|
|
||||||
npmrcFileString += `//${npmRegistryUrl}/:_authToken="${plugins.smartstring.base64.decode(
|
|
||||||
npmToken
|
|
||||||
)}"\n`;
|
|
||||||
});
|
|
||||||
logger.log('info', `setting default npm registry to ${config.npmRegistryUrl}`);
|
|
||||||
npmrcFileString += `registry=https://${config.npmRegistryUrl}\n`;
|
|
||||||
|
|
||||||
// final check
|
|
||||||
if (npmrcFileString.length > 0) {
|
|
||||||
logger.log('info', 'found one or more access tokens');
|
|
||||||
} else {
|
|
||||||
logger.log('error', 'no access token found! Exiting!');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lets save it to disk
|
|
||||||
plugins.smartfile.memory.toFsSync(npmrcFileString, '/root/.npmrc');
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* publish a package to npm
|
|
||||||
*/
|
|
||||||
const publish = async () => {
|
|
||||||
let npmAccessCliString = ``;
|
|
||||||
let npmRegistryCliString = ``;
|
|
||||||
const config = await configModule.getConfig();
|
|
||||||
|
|
||||||
// -> configure package access level
|
|
||||||
if (
|
|
||||||
config.npmAccessLevel &&
|
|
||||||
(config.npmAccessLevel === 'public' || config.npmAccessLevel === 'private')
|
|
||||||
) {
|
|
||||||
npmAccessCliString = `--access=${config.npmAccessLevel}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -> configure registry url
|
|
||||||
if (config.npmRegistryUrl) {
|
|
||||||
npmRegistryCliString = `--registry=https://${config.npmRegistryUrl}`;
|
|
||||||
} else {
|
|
||||||
logger.log('error', `no registry url specified. Can't publish!`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -> preparing
|
|
||||||
logger.log('info', `now preparing environment:`);
|
|
||||||
prepare();
|
|
||||||
await bash(`npm -v`);
|
|
||||||
|
|
||||||
// -> build it
|
|
||||||
await bash(`npm install`);
|
|
||||||
await bash(`npm run build`);
|
|
||||||
|
|
||||||
logger.log('success', `Nice!!! The build for the publication was successfull!`);
|
|
||||||
logger.log('info', `Lets clean up so we don't publish any packages that don't belong to us:`);
|
|
||||||
// -> clean up before we publish stuff
|
|
||||||
await bashNoError(`rm -r ./.npmci_cache`);
|
|
||||||
await bash(`rm -r ./node_modules`);
|
|
||||||
|
|
||||||
logger.log('success', `Cleaned up!:`);
|
|
||||||
|
|
||||||
// -> publish it
|
|
||||||
logger.log('info', `now invoking npm to publish the package!`);
|
|
||||||
await bash(`npm publish ${npmAccessCliString} ${npmRegistryCliString}`);
|
|
||||||
logger.log('success', `Package was successfully published!`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const install = async (): Promise<void> => {
|
|
||||||
logger.log('info', 'now installing dependencies:');
|
|
||||||
await bash('npm install');
|
|
||||||
};
|
|
||||||
|
|
||||||
export let test = async (): Promise<void> => {
|
|
||||||
logger.log('info', 'now starting tests:');
|
|
||||||
await bash('npm test');
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from '../npmci.plugins';
|
|
||||||
24
ts/mod_precheck/index.ts
Normal file
24
ts/mod_precheck/index.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import * as paths from '../npmci.paths.js';
|
||||||
|
import { logger } from '../npmci.logging.js';
|
||||||
|
import { Npmci } from '../npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export const handleCli = async (npmciRefArg: Npmci, argvArg: any) => {
|
||||||
|
logger.log('info', 'checking execution context');
|
||||||
|
const presentRunnerTags = process.env.CI_RUNNER_TAGS.split(',').map((stringArg) =>
|
||||||
|
stringArg.trim()
|
||||||
|
);
|
||||||
|
let allDesiredGitlabRunnerTagsPresent = true;
|
||||||
|
for (const desiredRunnerTag of npmciRefArg.npmciConfig.getConfig().gitlabRunnerTags) {
|
||||||
|
if (!presentRunnerTags.includes(desiredRunnerTag)) {
|
||||||
|
allDesiredGitlabRunnerTagsPresent = false;
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Desired runnerRag ${desiredRunnerTag} is missing in current execution context.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!allDesiredGitlabRunnerTagsPresent) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
1
ts/mod_precheck/plugins.ts
Normal file
1
ts/mod_precheck/plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../npmci.plugins.js';
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { logger } from '../npmci.logging';
|
import { logger } from '../npmci.logging.js';
|
||||||
import * as plugins from './mod.plugins';
|
import * as plugins from './mod.plugins.js';
|
||||||
let sshInstance: plugins.smartssh.SshInstance;
|
let sshInstance: plugins.smartssh.SshInstance;
|
||||||
|
|
||||||
export let handleCli = async argvArg => {
|
export let handleCli = async (argvArg: any) => {
|
||||||
if (argvArg._.length >= 2) {
|
if (argvArg._.length >= 2) {
|
||||||
const action: string = argvArg._[1];
|
const action: string = argvArg._[1];
|
||||||
switch (action) {
|
switch (action) {
|
||||||
@@ -31,7 +31,7 @@ const notUndefined = (stringArg: string) => {
|
|||||||
*/
|
*/
|
||||||
export let prepare = async () => {
|
export let prepare = async () => {
|
||||||
sshInstance = new plugins.smartssh.SshInstance(); // init ssh instance
|
sshInstance = new plugins.smartssh.SshInstance(); // init ssh instance
|
||||||
plugins.smartparam.forEachMinimatch(process.env, 'NPMCI_SSHKEY_*', evaluateSshEnv);
|
plugins.smartobject.forEachMinimatch(process.env, 'NPMCI_SSHKEY_*', evaluateSshEnv);
|
||||||
if (!process.env.NPMTS_TEST) {
|
if (!process.env.NPMTS_TEST) {
|
||||||
sshInstance.writeToDisk();
|
sshInstance.writeToDisk();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export * from '../npmci.plugins';
|
export * from '../npmci.plugins.js';
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import * as plugins from './mod.plugins';
|
import * as plugins from './mod.plugins.js';
|
||||||
import { bash } from '../npmci.bash';
|
import { bash } from '../npmci.bash.js';
|
||||||
import { logger } from '../npmci.logging';
|
import { logger } from '../npmci.logging.js';
|
||||||
|
|
||||||
const triggerValueRegex = /^([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|?([a-zA-Z0-9\.\-\/]*)/;
|
const triggerValueRegex =
|
||||||
|
/^([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|?([a-zA-Z0-9\.\-\/]*)/;
|
||||||
|
|
||||||
export let trigger = async () => {
|
export let trigger = async () => {
|
||||||
logger.log('info', 'now running triggers');
|
logger.log('info', 'now running triggers');
|
||||||
await plugins.smartparam.forEachMinimatch(process.env, 'NPMCI_TRIGGER_*', evaluateTrigger);
|
await plugins.smartobject.forEachMinimatch(process.env, 'NPMCI_TRIGGER_*', evaluateTrigger);
|
||||||
};
|
};
|
||||||
|
|
||||||
const evaluateTrigger = async triggerEnvVarArg => {
|
const evaluateTrigger = async (triggerEnvVarArg) => {
|
||||||
const triggerRegexResultArray = triggerValueRegex.exec(triggerEnvVarArg);
|
const triggerRegexResultArray = triggerValueRegex.exec(triggerEnvVarArg);
|
||||||
const regexDomain = triggerRegexResultArray[1];
|
const regexDomain = triggerRegexResultArray[1];
|
||||||
const regexProjectId = triggerRegexResultArray[2];
|
const regexProjectId = triggerRegexResultArray[2];
|
||||||
@@ -30,13 +31,13 @@ const evaluateTrigger = async triggerEnvVarArg => {
|
|||||||
{
|
{
|
||||||
name: 'token',
|
name: 'token',
|
||||||
payload: regexProjectTriggerToken,
|
payload: regexProjectTriggerToken,
|
||||||
type: 'string'
|
type: 'string',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'ref',
|
name: 'ref',
|
||||||
payload: regexRefName,
|
payload: regexRefName,
|
||||||
type: 'string'
|
type: 'string',
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export * from '../npmci.plugins';
|
export * from '../npmci.plugins.js';
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import { logger } from './npmci.logging';
|
import { logger } from './npmci.logging.js';
|
||||||
import * as plugins from './npmci.plugins';
|
import * as plugins from './npmci.plugins.js';
|
||||||
import * as paths from './npmci.paths';
|
import * as paths from './npmci.paths.js';
|
||||||
|
|
||||||
import * as smartpromise from '@pushrocks/smartpromise';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wether nvm is available or not
|
* wether nvm is available or not
|
||||||
*/
|
*/
|
||||||
export let nvmAvailable = smartpromise.defer<boolean>();
|
export let nvmAvailable = plugins.smartpromise.defer<boolean>();
|
||||||
/**
|
/**
|
||||||
* the smartshell instance for npmci
|
* the smartshell instance for npmci
|
||||||
*/
|
*/
|
||||||
const npmciSmartshell = new plugins.smartshell.Smartshell({
|
const npmciSmartshell = new plugins.smartshell.Smartshell({
|
||||||
executor: 'bash',
|
executor: 'bash',
|
||||||
sourceFilePaths: []
|
sourceFilePaths: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +82,7 @@ export let bash = async (commandArg: string, retryArg: number = 2): Promise<stri
|
|||||||
logger.log('info', 'ShellExec would be: ' + commandArg);
|
logger.log('info', 'ShellExec would be: ' + commandArg);
|
||||||
execResult = {
|
execResult = {
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
stdout: 'testOutput'
|
stdout: 'testOutput',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return execResult.stdout;
|
return execResult.stdout;
|
||||||
|
|||||||
61
ts/npmci.classes.npmci.ts
Normal file
61
ts/npmci.classes.npmci.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
|
||||||
|
|
||||||
|
// env
|
||||||
|
import { NpmciEnv } from './npmci.classes.npmcienv.js';
|
||||||
|
import { NpmciInfo } from './npmci.classes.npmciinfo.js';
|
||||||
|
import { NpmciCli } from './npmci.classes.npmcicli.js';
|
||||||
|
import { NpmciConfig } from './npmci.classes.npmciconfig.js';
|
||||||
|
|
||||||
|
// connectors
|
||||||
|
import { CloudlyConnector } from './connector.cloudly/cloudlyconnector.js';
|
||||||
|
|
||||||
|
// managers
|
||||||
|
import { NpmciCloudronManager } from './manager.cloudron/index.js';
|
||||||
|
import { NpmciDockerManager } from './manager.docker/index.js';
|
||||||
|
import { NpmciGitManager } from './manager.git/index.js';
|
||||||
|
import { NpmciNodeJsManager } from './manager.nodejs/index.js';
|
||||||
|
import { NpmciNpmManager } from './manager.npm/index.js';
|
||||||
|
|
||||||
|
export class Npmci {
|
||||||
|
public analytics: plugins.smartanalytics.Analytics;
|
||||||
|
public cloudlyConnector: CloudlyConnector;
|
||||||
|
|
||||||
|
public npmciEnv: NpmciEnv;
|
||||||
|
public npmciInfo: NpmciInfo;
|
||||||
|
public npmciConfig: NpmciConfig;
|
||||||
|
public npmciCli: NpmciCli;
|
||||||
|
|
||||||
|
// managers
|
||||||
|
public cloudronManager: NpmciCloudronManager;
|
||||||
|
public dockerManager: NpmciDockerManager;
|
||||||
|
public gitManager: NpmciGitManager;
|
||||||
|
public nodejsManager: NpmciNodeJsManager;
|
||||||
|
public npmManager: NpmciNpmManager;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.analytics = new plugins.smartanalytics.Analytics({
|
||||||
|
apiEndPoint: 'https://pubapi.lossless.one/analytics',
|
||||||
|
projectId: 'gitzone',
|
||||||
|
appName: 'npmci',
|
||||||
|
});
|
||||||
|
this.cloudlyConnector = new CloudlyConnector(this);
|
||||||
|
this.npmciEnv = new NpmciEnv(this);
|
||||||
|
this.npmciInfo = new NpmciInfo(this);
|
||||||
|
this.npmciCli = new NpmciCli(this);
|
||||||
|
this.npmciConfig = new NpmciConfig(this);
|
||||||
|
|
||||||
|
// managers
|
||||||
|
this.cloudronManager = new NpmciCloudronManager(this);
|
||||||
|
this.dockerManager = new NpmciDockerManager(this);
|
||||||
|
this.gitManager = new NpmciGitManager(this);
|
||||||
|
this.nodejsManager = new NpmciNodeJsManager(this);
|
||||||
|
this.npmManager = new NpmciNpmManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async start() {
|
||||||
|
await this.npmciInfo.printToConsole();
|
||||||
|
await this.npmciConfig.init();
|
||||||
|
this.npmciCli.startParse();
|
||||||
|
}
|
||||||
|
}
|
||||||
120
ts/npmci.classes.npmcicli.ts
Normal file
120
ts/npmci.classes.npmcicli.ts
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import { logger } from './npmci.logging.js';
|
||||||
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
import * as paths from './npmci.paths.js';
|
||||||
|
import { Npmci } from './npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciCli {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
public smartcli: plugins.smartcli.Smartcli;
|
||||||
|
|
||||||
|
constructor(npmciArg: Npmci) {
|
||||||
|
this.npmciRef = npmciArg;
|
||||||
|
this.smartcli = new plugins.smartcli.Smartcli();
|
||||||
|
this.smartcli.addVersion(this.npmciRef.npmciInfo.projectInfo.version);
|
||||||
|
|
||||||
|
// clean
|
||||||
|
this.smartcli.addCommand('clean').subscribe(
|
||||||
|
async (argv) => {
|
||||||
|
const modClean = await import('./mod_clean/index.js');
|
||||||
|
await modClean.clean();
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cloudron
|
||||||
|
this.smartcli.addCommand('cloudron').subscribe(
|
||||||
|
async (argv) => {
|
||||||
|
await this.npmciRef.cloudronManager.handleCli(argv);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// command
|
||||||
|
this.smartcli.addCommand('command').subscribe(
|
||||||
|
async (argv) => {
|
||||||
|
const modCommand = await import('./mod_command/index.js');
|
||||||
|
await modCommand.command();
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// git
|
||||||
|
this.smartcli.addCommand('git').subscribe(
|
||||||
|
async (argvArg) => {
|
||||||
|
await this.npmciRef.gitManager.handleCli(argvArg);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// build
|
||||||
|
this.smartcli.addCommand('docker').subscribe(
|
||||||
|
async (argvArg) => {
|
||||||
|
await this.npmciRef.dockerManager.handleCli(argvArg);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// node
|
||||||
|
this.smartcli.addCommand('node').subscribe(
|
||||||
|
async (argvArg) => {
|
||||||
|
await this.npmciRef.nodejsManager.handleCli(argvArg);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// npm
|
||||||
|
this.smartcli.addCommand('npm').subscribe(
|
||||||
|
async (argvArg) => {
|
||||||
|
await this.npmciRef.npmManager.handleCli(argvArg);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.smartcli.addCommand('precheck').subscribe(async (argvArg) => {
|
||||||
|
const modPrecheck = await import('./mod_precheck/index.js');
|
||||||
|
await modPrecheck.handleCli(this.npmciRef, argvArg);
|
||||||
|
});
|
||||||
|
|
||||||
|
// trigger
|
||||||
|
this.smartcli.addCommand('ssh').subscribe(async (argvArg) => {
|
||||||
|
const modSsh = await import('./mod_ssh/index.js');
|
||||||
|
await modSsh.handleCli(argvArg);
|
||||||
|
});
|
||||||
|
|
||||||
|
// trigger
|
||||||
|
this.smartcli.addCommand('trigger').subscribe(
|
||||||
|
async (argv) => {
|
||||||
|
const modTrigger = await import('./mod_trigger/index.js');
|
||||||
|
await modTrigger.trigger();
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public startParse = () => {
|
||||||
|
this.smartcli.startParse();
|
||||||
|
};
|
||||||
|
}
|
||||||
79
ts/npmci.classes.npmciconfig.ts
Normal file
79
ts/npmci.classes.npmciconfig.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
import * as paths from './npmci.paths.js';
|
||||||
|
|
||||||
|
import { logger } from './npmci.logging.js';
|
||||||
|
import { Npmci } from './npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the main config interface for npmci
|
||||||
|
*/
|
||||||
|
export interface INpmciOptions {
|
||||||
|
projectInfo: plugins.projectinfo.ProjectInfo;
|
||||||
|
|
||||||
|
// npm
|
||||||
|
npmGlobalTools: string[];
|
||||||
|
npmAccessLevel?: 'private' | 'public';
|
||||||
|
npmRegistryUrl: string;
|
||||||
|
|
||||||
|
// docker
|
||||||
|
dockerRegistries: string[];
|
||||||
|
dockerRegistryRepoMap: { [key: string]: string };
|
||||||
|
dockerBuildargEnvMap: { [key: string]: string };
|
||||||
|
|
||||||
|
// gitlab
|
||||||
|
gitlabRunnerTags: string[];
|
||||||
|
|
||||||
|
// urls
|
||||||
|
urlCloudly: string;
|
||||||
|
|
||||||
|
// cloudron
|
||||||
|
cloudronAppName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a config class for Npmci
|
||||||
|
*/
|
||||||
|
export class NpmciConfig {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
public npmciNpmextra: plugins.npmextra.Npmextra;
|
||||||
|
public kvStorage: plugins.npmextra.KeyValueStore;
|
||||||
|
public npmciQenv: plugins.qenv.Qenv;
|
||||||
|
|
||||||
|
private configObject: INpmciOptions;
|
||||||
|
|
||||||
|
constructor(npmciRefArg: Npmci) {
|
||||||
|
this.npmciRef = npmciRefArg;
|
||||||
|
|
||||||
|
this.npmciNpmextra = new plugins.npmextra.Npmextra(paths.cwd);
|
||||||
|
this.kvStorage = new plugins.npmextra.KeyValueStore(
|
||||||
|
'custom',
|
||||||
|
`${this.npmciRef.npmciEnv.repo.user}_${this.npmciRef.npmciEnv.repo.repo}`
|
||||||
|
);
|
||||||
|
this.npmciQenv = new plugins.qenv.Qenv(
|
||||||
|
paths.NpmciProjectDir,
|
||||||
|
paths.NpmciProjectNogitDir,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
this.configObject = {
|
||||||
|
projectInfo: new plugins.projectinfo.ProjectInfo(paths.cwd),
|
||||||
|
npmGlobalTools: [],
|
||||||
|
dockerRegistries: [],
|
||||||
|
dockerRegistryRepoMap: {},
|
||||||
|
npmAccessLevel: 'private',
|
||||||
|
npmRegistryUrl: 'registry.npmjs.org',
|
||||||
|
gitlabRunnerTags: [],
|
||||||
|
dockerBuildargEnvMap: {},
|
||||||
|
urlCloudly: this.npmciQenv.getEnvVarOnDemand('NPMCI_URL_CLOUDLY'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async init() {
|
||||||
|
this.configObject = this.npmciNpmextra.dataFor<INpmciOptions>('npmci', this.configObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getConfig(): INpmciOptions {
|
||||||
|
return this.configObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
ts/npmci.classes.npmcienv.ts
Normal file
23
ts/npmci.classes.npmcienv.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
import { Npmci } from './npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciEnv {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
|
||||||
|
public repoString: string;
|
||||||
|
public repo: plugins.smartstring.GitRepo;
|
||||||
|
|
||||||
|
constructor(npmciRefArg: Npmci) {
|
||||||
|
this.npmciRef = npmciRefArg;
|
||||||
|
if (process.env.GITLAB_CI) {
|
||||||
|
this.repoString = process.env.CI_REPOSITORY_URL;
|
||||||
|
}
|
||||||
|
if (process.env.NPMCI_COMPUTED_REPOURL) {
|
||||||
|
this.repoString = process.env.NPMCI_COMPUTED_REPOURL;
|
||||||
|
}
|
||||||
|
if (!this.repoString) {
|
||||||
|
this.repoString = 'https://undefined:undefined@github.com/undefined/undefined.git';
|
||||||
|
}
|
||||||
|
this.repo = new plugins.smartstring.GitRepo(this.repoString);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
ts/npmci.classes.npmciinfo.ts
Normal file
17
ts/npmci.classes.npmciinfo.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
import * as paths from './npmci.paths.js';
|
||||||
|
import { logger } from './npmci.logging.js';
|
||||||
|
import { Npmci } from './npmci.classes.npmci.js';
|
||||||
|
|
||||||
|
export class NpmciInfo {
|
||||||
|
public npmciRef: Npmci;
|
||||||
|
public projectInfo = new plugins.projectinfo.ProjectinfoNpm(paths.NpmciPackageRoot);
|
||||||
|
|
||||||
|
constructor(npmciArg: Npmci) {
|
||||||
|
this.npmciRef = npmciArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public printToConsole() {
|
||||||
|
logger.log('info', `npmci version: ${this.projectInfo.version}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
111
ts/npmci.cli.ts
111
ts/npmci.cli.ts
@@ -1,111 +0,0 @@
|
|||||||
import { logger } from './npmci.logging';
|
|
||||||
import * as plugins from './npmci.plugins';
|
|
||||||
import * as paths from './npmci.paths';
|
|
||||||
import * as npmciMonitor from './npmci.monitor';
|
|
||||||
npmciMonitor.run();
|
|
||||||
|
|
||||||
// Get Info about npmci itself
|
|
||||||
const npmciInfo = new plugins.projectinfo.ProjectinfoNpm(paths.NpmciPackageRoot);
|
|
||||||
logger.log('info', 'npmci version: ' + npmciInfo.version);
|
|
||||||
|
|
||||||
import * as NpmciEnv from './npmci.env';
|
|
||||||
|
|
||||||
const npmciSmartcli = new plugins.smartcli.Smartcli();
|
|
||||||
npmciSmartcli.addVersion(npmciInfo.version);
|
|
||||||
|
|
||||||
// clean
|
|
||||||
npmciSmartcli.addCommand('clean').subscribe(
|
|
||||||
async argv => {
|
|
||||||
const modClean = await import('./mod_clean/index');
|
|
||||||
await modClean.clean();
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// command
|
|
||||||
npmciSmartcli.addCommand('command').subscribe(
|
|
||||||
async argv => {
|
|
||||||
const modCommand = await import('./mod_command/index');
|
|
||||||
await modCommand.command();
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// command
|
|
||||||
npmciSmartcli.addCommand('git').subscribe(
|
|
||||||
async argvArg => {
|
|
||||||
const modGit = await import('./mod_git/index');
|
|
||||||
await modGit.handleCli(argvArg);
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// build
|
|
||||||
npmciSmartcli.addCommand('docker').subscribe(
|
|
||||||
async argvArg => {
|
|
||||||
const modDocker = await import('./mod_docker/index');
|
|
||||||
await modDocker.handleCli(argvArg);
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// node
|
|
||||||
npmciSmartcli.addCommand('node').subscribe(
|
|
||||||
async argvArg => {
|
|
||||||
const modNode = await import('./mod_node/index');
|
|
||||||
await modNode.handleCli(argvArg);
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// npm
|
|
||||||
npmciSmartcli.addCommand('npm').subscribe(
|
|
||||||
async argvArg => {
|
|
||||||
const modNpm = await import('./mod_npm/index');
|
|
||||||
await modNpm.handleCli(argvArg);
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// trigger
|
|
||||||
npmciSmartcli.addCommand('ssh').subscribe(
|
|
||||||
async argvArg => {
|
|
||||||
const modSsh = await import('./mod_ssh/index');
|
|
||||||
await modSsh.handleCli(argvArg);
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// trigger
|
|
||||||
npmciSmartcli.addCommand('trigger').subscribe(
|
|
||||||
async argv => {
|
|
||||||
const modTrigger = await import('./mod_trigger/index');
|
|
||||||
await modTrigger.trigger();
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
npmciSmartcli.startParse();
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import * as plugins from './npmci.plugins';
|
|
||||||
import * as paths from './npmci.paths';
|
|
||||||
|
|
||||||
import { repo } from './npmci.env';
|
|
||||||
|
|
||||||
import { KeyValueStore } from '@pushrocks/npmextra';
|
|
||||||
|
|
||||||
export interface INpmciOptions {
|
|
||||||
projectInfo: plugins.projectinfo.ProjectInfo;
|
|
||||||
npmGlobalTools: string[];
|
|
||||||
npmAccessLevel?: 'private' | 'public';
|
|
||||||
npmRegistryUrl: string;
|
|
||||||
dockerRegistryRepoMap: any;
|
|
||||||
dockerBuildargEnvMap: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// instantiate a kvStorage for the current directory
|
|
||||||
export let kvStorage = new KeyValueStore('custom', `${repo.user}_${repo.repo}`);
|
|
||||||
|
|
||||||
// handle config retrival
|
|
||||||
const npmciNpmextra = new plugins.npmextra.Npmextra(paths.cwd);
|
|
||||||
const defaultConfig: INpmciOptions = {
|
|
||||||
projectInfo: new plugins.projectinfo.ProjectInfo(paths.cwd),
|
|
||||||
npmGlobalTools: [],
|
|
||||||
dockerRegistryRepoMap: {},
|
|
||||||
npmAccessLevel: 'private',
|
|
||||||
npmRegistryUrl: 'registry.npmjs.org',
|
|
||||||
dockerBuildargEnvMap: {}
|
|
||||||
};
|
|
||||||
export let configObject = npmciNpmextra.dataFor<INpmciOptions>('npmci', defaultConfig);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the npmci portion of the npmextra.json file
|
|
||||||
*/
|
|
||||||
export let getConfig = async (): Promise<INpmciOptions> => {
|
|
||||||
return configObject;
|
|
||||||
};
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import * as plugins from './npmci.plugins';
|
|
||||||
import * as paths from './npmci.paths';
|
|
||||||
import { GitRepo } from '@pushrocks/smartstring';
|
|
||||||
import { Dockerfile } from './mod_docker/index';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a info instance about the git respoitory at cwd :)
|
|
||||||
*/
|
|
||||||
let repoString: string = process.env.CI_REPOSITORY_URL;
|
|
||||||
if (!repoString) {
|
|
||||||
repoString = 'https://undefined:undefined@github.com/undefined/undefined.git';
|
|
||||||
}
|
|
||||||
export let repo = new GitRepo(repoString);
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './npmci.plugins';
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
|
||||||
export const logger = new plugins.smartlog.Smartlog({
|
export const logger = new plugins.smartlog.Smartlog({
|
||||||
logContext: {
|
logContext: {
|
||||||
@@ -7,8 +7,8 @@ export const logger = new plugins.smartlog.Smartlog({
|
|||||||
containerName: 'Some ContainerName',
|
containerName: 'Some ContainerName',
|
||||||
environment: 'test',
|
environment: 'test',
|
||||||
runtime: 'node',
|
runtime: 'node',
|
||||||
zone: 'Some Zone'
|
zone: 'Some Zone',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.addLogDestination(new plugins.smartlogDestinationLocal.DestinationLocal());
|
logger.addLogDestination(new plugins.smartlogDestinationLocal.DestinationLocal());
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import { logger } from './npmci.logging';
|
|
||||||
import * as plugins from './npmci.plugins';
|
|
||||||
import * as env from './npmci.env';
|
|
||||||
|
|
||||||
import { Analytics } from '@pushrocks/smartanalytics';
|
|
||||||
|
|
||||||
export let npmciAnalytics = new Analytics({
|
|
||||||
apiEndPoint: 'https://pubapi.lossless.one/analytics',
|
|
||||||
projectId: 'gitzone',
|
|
||||||
appName: 'npmci'
|
|
||||||
});
|
|
||||||
|
|
||||||
export let run = async () => {
|
|
||||||
npmciAnalytics
|
|
||||||
.recordEvent('npmToolExecution', {
|
|
||||||
host: env.repo.host,
|
|
||||||
user: env.repo.user,
|
|
||||||
repo: env.repo.repo
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
logger.log('warn', 'Lossless Analytics API not available...');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
import * as plugins from './npmci.plugins';
|
import * as plugins from './npmci.plugins.js';
|
||||||
|
|
||||||
export let cwd = process.cwd();
|
export const cwd = process.cwd();
|
||||||
|
|
||||||
export let NpmciPackageRoot = plugins.path.join(__dirname, '../');
|
// package paths
|
||||||
export let NpmciPackageConfig = plugins.path.join(NpmciPackageRoot, './config.json');
|
export const NpmciPackageRoot = plugins.path.join(
|
||||||
export let NpmciProjectDir = cwd;
|
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
||||||
export let NpmciTestDir = plugins.path.join(cwd, './test');
|
'../'
|
||||||
export let NpmciCacheDir = plugins.path.join(cwd, './.npmci_cache');
|
);
|
||||||
|
export const NpmciPackageConfig = plugins.path.join(NpmciPackageRoot, './config.json');
|
||||||
|
|
||||||
|
// project paths
|
||||||
|
export const NpmciProjectDir = cwd;
|
||||||
|
export const NpmciProjectNogitDir = plugins.path.join(NpmciProjectDir, './.nogit');
|
||||||
|
export const NpmciTestDir = plugins.path.join(cwd, './test');
|
||||||
|
export const NpmciCacheDir = plugins.path.join(cwd, './.npmci_cache');
|
||||||
|
|||||||
@@ -3,39 +3,65 @@ import * as path from 'path';
|
|||||||
|
|
||||||
export { path };
|
export { path };
|
||||||
|
|
||||||
// @pushrocks
|
// @apiglobal
|
||||||
import * as projectinfo from '@pushrocks/projectinfo';
|
import * as typedrequest from '@apiglobal/typedrequest';
|
||||||
import * as npmextra from '@pushrocks/npmextra';
|
|
||||||
import * as smartdelay from '@pushrocks/smartdelay';
|
export { typedrequest };
|
||||||
import * as smartfile from '@pushrocks/smartfile';
|
|
||||||
import * as smartcli from '@pushrocks/smartcli';
|
// @servezone
|
||||||
import * as smartlog from '@pushrocks/smartlog';
|
import * as servezoneInterfaces from '@servezone/interfaces';
|
||||||
import * as smartlogDestinationLocal from '@pushrocks/smartlog-destination-local';
|
|
||||||
import * as smartparam from '@pushrocks/smartparam';
|
export { servezoneInterfaces };
|
||||||
import * as smartpromise from '@pushrocks/smartpromise';
|
|
||||||
import * as smartrequest from '@pushrocks/smartrequest';
|
// @push.rocks
|
||||||
import * as smartshell from '@pushrocks/smartshell';
|
import * as lik from '@push.rocks/lik';
|
||||||
import * as smartsocket from '@pushrocks/smartsocket';
|
import * as npmextra from '@push.rocks/npmextra';
|
||||||
import * as smartssh from '@pushrocks/smartssh';
|
import * as projectinfo from '@push.rocks/projectinfo';
|
||||||
import * as smartstring from '@pushrocks/smartstring';
|
import * as qenv from '@push.rocks/qenv';
|
||||||
|
import * as smartanalytics from '@push.rocks/smartanalytics';
|
||||||
|
import * as smartdelay from '@push.rocks/smartdelay';
|
||||||
|
import * as smartfile from '@push.rocks/smartfile';
|
||||||
|
import * as smartcli from '@push.rocks/smartcli';
|
||||||
|
import * as smartgit from '@push.rocks/smartgit';
|
||||||
|
import * as smartlog from '@push.rocks/smartlog';
|
||||||
|
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
|
||||||
|
import * as smartobject from '@push.rocks/smartobject';
|
||||||
|
import * as smartpath from '@push.rocks/smartpath';
|
||||||
|
import * as smartpromise from '@push.rocks/smartpromise';
|
||||||
|
import * as smartrequest from '@push.rocks/smartrequest';
|
||||||
|
import * as smartshell from '@push.rocks/smartshell';
|
||||||
|
import * as smartsocket from '@push.rocks/smartsocket';
|
||||||
|
import * as smartssh from '@push.rocks/smartssh';
|
||||||
|
import * as smartstring from '@push.rocks/smartstring';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
projectinfo,
|
lik,
|
||||||
npmextra,
|
npmextra,
|
||||||
|
projectinfo,
|
||||||
|
qenv,
|
||||||
|
smartanalytics,
|
||||||
smartdelay,
|
smartdelay,
|
||||||
smartfile,
|
smartfile,
|
||||||
|
smartgit,
|
||||||
smartcli,
|
smartcli,
|
||||||
smartlog,
|
smartlog,
|
||||||
smartlogDestinationLocal,
|
smartlogDestinationLocal,
|
||||||
smartparam,
|
smartobject,
|
||||||
|
smartpath,
|
||||||
smartpromise,
|
smartpromise,
|
||||||
smartrequest,
|
smartrequest,
|
||||||
smartshell,
|
smartshell,
|
||||||
smartsocket,
|
smartsocket,
|
||||||
smartssh,
|
smartssh,
|
||||||
smartstring
|
smartstring,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @tsclass scope
|
||||||
|
import * as tsclass from '@tsclass/tsclass';
|
||||||
|
|
||||||
|
export { tsclass };
|
||||||
|
|
||||||
|
// third party
|
||||||
import * as through2 from 'through2';
|
import * as through2 from 'through2';
|
||||||
|
|
||||||
export { through2 };
|
export { through2 };
|
||||||
|
|||||||
10
tsconfig.json
Normal file
10
tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"esModuleInterop": true
|
||||||
|
}
|
||||||
|
}
|
||||||
17
tslint.json
17
tslint.json
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
|
||||||
"rules": {
|
|
||||||
"semicolon": [true, "always"],
|
|
||||||
"no-console": false,
|
|
||||||
"ordered-imports": false,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"member-ordering": {
|
|
||||||
"options":{
|
|
||||||
"order": [
|
|
||||||
"static-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultSeverity": "warning"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user