Compare commits

...

52 Commits

Author SHA1 Message Date
6922d19454 v1.4.0 2026-01-20 09:33:31 +00:00
e1492f8ec4 feat(tsdocker): add multi-registry and multi-arch Docker build/push/pull manager, registry storage, Dockerfile handling, and new CLI commands 2026-01-20 09:33:31 +00:00
e9a12f1c17 v1.3.0 2026-01-19 22:08:59 +00:00
6995010a2c feat(packaging): Rename package scope to @git.zone and migrate to ESM; rename CLI/config keys, update entrypoints and imports, bump Node requirement to 18, and adjust scripts/dependencies 2026-01-19 22:08:59 +00:00
e0cbc9cfec v1.2.43 2025-12-13 09:44:37 +00:00
c538e6b10b fix(packaging): Rename package scope to @git.zone and migrate deps/CI; pin pnpm and enable ESM packaging 2025-12-13 09:44:37 +00:00
c31df766fc v1.2.42 2025-11-22 18:08:31 +00:00
0c626c20e7 fix(package.json): Add packageManager field to package.json to pin pnpm version 2025-11-22 18:08:31 +00:00
c07f10b97b v1.2.41 2025-11-22 18:07:39 +00:00
08d32f0370 fix(core): Migrate to @git.zone / @push.rocks packages, replace smartfile with smartfs and adapt filesystem usage; update dev deps and remove CI/lint config 2025-11-22 18:07:39 +00:00
ac386f01e0 1.2.40 2021-09-30 11:14:44 +02:00
08ead4258f fix(core): update 2021-09-30 11:14:43 +02:00
f930f3a6a7 1.2.39 2019-05-28 11:31:40 +02:00
b6d4a76c70 fix(core): update 2019-05-28 11:31:39 +02:00
9a7ecd27e5 1.2.38 2019-05-27 15:50:38 +02:00
11b70b0ddf fix(core): update 2019-05-27 15:50:38 +02:00
79f8cb5e0e 1.2.37 2019-05-27 13:14:12 +02:00
3e1286b9ac fix(core): update 2019-05-27 13:14:12 +02:00
a8ae886959 1.2.36 2019-05-21 17:43:38 +02:00
da1c977a62 fix(core): update 2019-05-21 17:43:37 +02:00
b99b55a05b 1.2.35 2019-05-21 17:41:25 +02:00
133bf0abe5 fix(core): update 2019-05-21 17:41:25 +02:00
df260bbab9 1.2.34 2019-05-21 17:35:37 +02:00
080bd2bc48 fix(core): update 2019-05-21 17:35:36 +02:00
a0032b8168 1.2.33 2019-05-12 18:52:23 +02:00
a09efd1125 fix(core): update 2019-05-12 18:52:23 +02:00
4ce28c7979 1.2.32 2019-05-12 18:30:33 +02:00
415eaea56e fix(bin name): change from npmdocker to tsdocker 2019-05-12 18:30:32 +02:00
bde4597dd9 1.2.31 2019-05-10 17:09:51 +02:00
80946d4f0c fix(core): update 2019-05-10 17:09:50 +02:00
2155e886ef 1.2.30 2019-05-10 11:46:38 +02:00
8b61a90b5f fix(core): update 2019-05-10 11:46:37 +02:00
f48eadc814 1.2.29 2019-05-10 11:46:00 +02:00
9bdaaa0c30 fix(core): update 2019-05-10 11:45:59 +02:00
5f681ff237 fix(core): update 2019-05-10 11:45:20 +02:00
889a3fdc5a 1.2.28 2019-05-09 10:06:59 +02:00
565c002127 fix(core): update 2019-05-09 10:06:59 +02:00
6fec1a00ea 1.2.27 2018-10-29 01:09:46 +01:00
e1f2c28718 fix(ci): remove npmts from build process 2018-10-29 01:09:45 +01:00
9efab07424 1.2.26 2018-10-29 01:07:40 +01:00
18d16feaa9 fix(core): update 2018-10-29 01:07:39 +01:00
df09ff0f9b 1.2.25 2018-10-28 21:40:32 +01:00
7b50ceb69f fix(clean): images are now cleaned in a more thorough way 2018-10-28 21:40:31 +01:00
d1fd76e8d0 1.2.24 2018-09-16 23:14:33 +02:00
b71fa1bc36 fix(core): update 2018-09-16 23:14:33 +02:00
068d28b95d 1.2.23 2018-09-16 21:08:14 +02:00
ecb458f5cd fix(dependencies): update 2018-09-16 21:08:13 +02:00
9f6fb8aedd 1.2.22 2018-07-21 13:32:51 +02:00
f21df13b7c fix(update to latest standards): update 2018-07-21 13:32:51 +02:00
9c56942739 1.2.21 2018-05-18 13:22:08 +02:00
5f4ab33069 1.2.20 2018-05-18 13:17:52 +02:00
14761a442e fix(ci): add build command to package.json 2018-05-18 13:17:52 +02:00
53 changed files with 11364 additions and 2154 deletions

View File

@@ -0,0 +1,66 @@
name: Default (not tags)
on:
push:
tags-ignore:
- '**'
env:
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
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 @ship.zone/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

View File

@@ -0,0 +1,124 @@
name: Default (tags)
on:
push:
tags:
- '*'
env:
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
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: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
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: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- 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: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- 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: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Code quality
run: |
npmci command npm install -g typescript
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 @git.zone/tsdoc
npmci command tsdoc
continue-on-error: true

26
.gitignore vendored
View File

@@ -1,8 +1,24 @@
node_modules/ .nogit/
# artifacts
coverage/ coverage/
pages/
public/ public/
test/ # installs
assets/ node_modules/
.nogit/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_*/
# AI
.claude/
.serena/
#------# custom
test

View File

@@ -1,69 +0,0 @@
image: hosttoday/ht-docker-dbase:npmci
services:
- docker:dind
stages:
- mirror
- test
- release
- trigger
- pages
mirror:
image: hosttoday/ht-docker-node:npmci
stage: mirror
script:
- npmci git mirror
tags:
- docker
test:
stage: test
script:
- npmci node install stable
- npmci npm install
- npmci npm test
tags:
- docker
- lossless
- priv
release:
stage: release
environment: npmjs-com_registry
script:
- npmci npm prepare
- npmci npm publish
only:
- tags
tags:
- docker
- lossless
- priv
trigger:
stage: trigger
script:
- npmci trigger
only:
- tags
tags:
- docker
- lossless
- priv
pages:
image: hosttoday/ht-docker-node:npmci
stage: pages
script:
- npmci command yarn global add npmpage
- npmci command npmpage
only:
- tags
tags:
- docker
artifacts:
expire_in: 1 week
paths:
- public

11
.vscode/launch.json vendored Normal file
View 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
View 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"]
}
}
}
}
}
}
]
}

View File

@@ -1,67 +0,0 @@
# npmdocker
develop npm modules cross platform with docker
## Availabililty
[![npm](https://gitzone.gitlab.io/assets/repo-button-npm.svg)](https://www.npmjs.com/package/npmdocker)
[![git](https://gitzone.gitlab.io/assets/repo-button-git.svg)](https://GitLab.com/gitzone/npmdocker)
[![git](https://gitzone.gitlab.io/assets/repo-button-mirror.svg)](https://github.com/gitzone/npmdocker)
[![docs](https://gitzone.gitlab.io/assets/repo-button-docs.svg)](https://gitzone.gitlab.io/npmdocker/)
## Status for master
[![build status](https://GitLab.com/gitzone/npmdocker/badges/master/build.svg)](https://GitLab.com/gitzone/npmdocker/commits/master)
[![coverage report](https://GitLab.com/gitzone/npmdocker/badges/master/coverage.svg)](https://GitLab.com/gitzone/npmdocker/commits/master)
[![npm downloads per month](https://img.shields.io/npm/dm/npmdocker.svg)](https://www.npmjs.com/package/npmdocker)
[![Dependency Status](https://david-dm.org/gitzonetools/npmdocker.svg)](https://david-dm.org/gitzonetools/npmdocker)
[![bitHound Dependencies](https://www.bithound.io/github/gitzonetools/npmdocker/badges/dependencies.svg)](https://www.bithound.io/github/gitzonetools/npmdocker/master/dependencies/npm)
[![bitHound Code](https://www.bithound.io/github/gitzonetools/npmdocker/badges/code.svg)](https://www.bithound.io/github/gitzonetools/npmdocker)
[![TypeScript](https://img.shields.io/badge/TypeScript-2.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%206.x.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
## Usage
Use TypeScript for best in class instellisense.
### Why does this package exist?
Sometimes you want a clean and fresh linux environment everytime you test your package.
Usually this is the default i CI, but locally behaviour tends to defer.
### Where does it work
The npmdocker package works in everywhere where the docker cli is available. e.g.:
* docker toolbox
* native docker application
* docker in docker
* mounted docker.sock
### How do I use it?
create a npmextra.json in the project's root directory
```json
{
"npmdocker": {
"baseImage": "hosttoday/ht-docker-node:npmts",
"command": "npmci test stable",
"dockerSock": false
}
}
```
| option | description |
| ----------- | ------------------------------------------------------------------------------------- |
| baseImage | the base image that is the context for your project |
| command | the cli command to run within the the project's directory inside the docker container |
| dockersSock | wether or not the testcontainer will have access to the docker.sock of the host |
For further information read the linked docs at the top of this README.
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
> | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html)
[![repo-footer](https://gitzone.gitlab.io/assets/repo-footer.svg)](https://git.zone)

View File

@@ -1,6 +1,6 @@
FROM hosttoday/ht-docker-node:npmci FROM hosttoday/ht-docker-node:npmci
RUN yarn global add npmdocker RUN yarn global add @git.zone/tsdocker
COPY ./ /workspace COPY ./ /workspace
WORKDIR /workspace WORKDIR /workspace
ENV CI=true ENV CI=true
CMD ["npmdocker","runinside"]; CMD ["tsdocker","runinside"];

386
changelog.md Normal file
View File

@@ -0,0 +1,386 @@
# Changelog
## 2026-01-20 - 1.4.0 - feat(tsdocker)
add multi-registry and multi-arch Docker build/push/pull manager, registry storage, Dockerfile handling, and new CLI commands
- Introduce TsDockerManager orchestrator to discover, sort, build, test, push and pull Dockerfiles
- Add Dockerfile class with dependency-aware build order, buildx support, push/pull and test flows (new large module)
- Add DockerRegistry and RegistryStorage classes to manage registry credentials, login/logout and environment loading
- Add CLI commands: build, push, pull, test, login, list (and integrate TsDockerManager into CLI)
- Extend configuration (ITsDockerConfig) with registries, registryRepoMap, buildArgEnvMap, platforms, push and testDir; re-export as IConfig for backwards compatibility
- Add @push.rocks/lik to dependencies and import it in tsdocker.plugins
- Remove legacy speedtest command and related package.json script
- Update README and readme.hints with new features, configuration examples and command list
## 2026-01-19 - 1.3.0 - feat(packaging)
Rename package scope to @git.zone and migrate to ESM; rename CLI/config keys, update entrypoints and imports, bump Node requirement to 18, and adjust scripts/dependencies
- Package renamed to @git.zone/tsdocker (scope change) — consumers must update package reference.
- Configuration key changed from 'npmdocker' to '@git.zone/tsdocker' in npmextra.json; update project config accordingly.
- CLI command renamed from 'npmdocker' to 'tsdocker' and entrypoint/entrypoint binary references updated.
- Project migrated to ESM: imports now use .js extensions, package main/typings point to dist_ts, and ts source uses ESM patterns — Node >=18 required.
- Build/test scripts changed to use tsx and updated test task names; CI/workflow and npmextra release registries updated.
- Dependencies/devDependencies bumped; smartfs, smartcli and tsbuild versions updated.
- Docker build command now uses '--load' and default base images/installation behavior adjusted (global install of tsdocker in image).
## 2025-12-13 - 1.2.43 - fix(packaging)
Rename package scope to @git.zone and migrate deps/CI; pin pnpm and enable ESM packaging
- Rename npm package scope from @gitzone/tsdocker to @git.zone/tsdocker (package.json, commitinfo, README, npmextra)
- Migrate devDependencies from @gitzone/_ to @git.zone/_ and ensure runtime packages use @push.rocks/\* where applicable
- Replace smartfile usage with smartfs and update code to use async smartfs.file(...).write()/delete() patterns
- Add packageManager pin for pnpm, set type: "module", add files array and pnpm.overrides in package.json
- Add tsconfig.json with NodeNext/ES2022 settings and other ESM-related adjustments
- Add Gitea CI workflows (.gitea/workflows/default_tags.yaml and default_nottags.yaml) for test, audit and release flows
- Update assets Dockerfile to reference @git.zone/tsdocker and other packaging/CI related scripts
- Update .gitignore to consolidate dist patterns and add AI/tooling excludes (.claude/, .serena/)
- Update README, readme.hints.md and changelog to document the scope rename, dependency migrations and SmartFS migration
## 2025-11-22 - 1.2.42 - fix(package.json)
Add packageManager field to package.json to pin pnpm version
- Add packageManager: "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34" to package.json to lock pnpm CLI version and integrity
## 2025-11-22 - 1.2.41 - fix(core)
Migrate to @git.zone / @push.rocks packages, replace smartfile with smartfs and adapt filesystem usage; update dev deps and remove CI/lint config
- Updated devDependencies from @gitzone/_ to @git.zone/_ (tsbuild, tsrun, tstest) and bumped versions
- Re-scoped runtime dependencies from @pushrocks/_ to @push.rocks/_ and updated package versions
- Replaced deprecated smartfile usage with new async smartfs API; added SmartFs instance in ts/tsdocker.plugins.ts
- Switched sync filesystem calls to Node fs where appropriate (fs.existsSync, fs.mkdirSync) and updated code to await smartfs.file(...).write()/delete()
- Made buildDockerFile async and awaited file write/delete operations to ensure correct async flow
- Updated CLI bootstrap to require @git.zone/tsrun in cli.ts.js
- Removed tslint.json and cleaned up CI configuration (.gitlab-ci.yml content removed)
- Added readme.hints.md describing the migration and dependency changes
## 2021-09-30 - 1.2.40 - release (no code changes)
Routine release tag with no recorded source changes.
- Tagged release only (no changelogged changes).
## 2021-09-30 - 1.2.39 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-28 - 1.2.38 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-27 - 1.2.37 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-27 - 1.2.36 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-21 - 1.2.35 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-21 - 1.2.34 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-12 - 1.2.33 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-12 - 1.2.32 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-12 - 1.2.31 - fix(bin name)
Rename of the published CLI binary.
- Changed published binary name from "npmdocker" to "tsdocker".
## 2019-05-10 - 1.2.30 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-10 - 1.2.29 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-10 - 1.2.28 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2019-05-09 - 1.2.27 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2018-10-29 - 1.2.26 - fix(ci)
CI build process change.
- Removed "npmts" from the build process.
## 2018-10-29 - 1.2.25 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2018-10-28 - 1.2.24 - fix(clean)
Improved image cleanup.
- Images are now cleaned in a more thorough way.
## 2018-09-16 - 1.2.23 - fix(core)
Core maintenance updates.
- Internal core updates and maintenance.
## 2018-09-16 - 1.2.22 - fix(dependencies)
Dependency updates.
- Updated dependencies (maintenance).
## 2018-07-21 - 1.2.21 - fix(update to latest standards)
Standards/update alignment.
- Updated codebase to latest standards (general maintenance).
## 2018-05-18 - 1.2.20 - release (no code changes)
Tagged release with no recorded source changes.
- Tagged release only (no changelogged changes).
## 2018-05-18 - 1.2.19 - fix(ci)
CI improvements.
- Added a build command to package.json to support CI builds.
## 2018-05-18 - 1.2.18 - fix(package)
Packaging change for scoped publish.
- Include npmdocker under the @git.zone npm scope.
## 2018-01-24 - 1.2.18 - update
Documentation update.
- Updated package description.
## 2017-10-13 - 1.2.17 - fix(cleanup)
Cleanup behavior fix.
- Now cleans up correctly after operations.
## 2017-10-13 - 1.2.16 - update
Miscellaneous updates.
- General maintenance and updates.
## 2017-10-13 - 1.2.15 - fix(test)
Testing improvements.
- Fixed Docker testing.
## 2017-10-07 - 1.2.14 - ci
CI improvements.
- Updated CI configuration.
## 2017-10-07 - 1.2.13 - update(analytics)
Analytics integration.
- Updated Analytics integration.
## 2017-10-07 - 1.2.12 - update(dependencies)
Dependency updates.
- Updated dependencies.
## 2017-07-16 - 1.2.11 - update
Dependency and greeting update.
- Updated dependencies and changed greeting text.
## 2017-04-21 - 1.2.10 - feature
Added analytics.
- Now includes SmartAnalytics.
## 2017-04-02 - 1.2.8 - docs & ci
Docs and CI updates.
- Updated README and CI configuration.
## 2017-04-02 - 1.2.7 - fix(command)
Command execution fix.
- Fixed command execution behavior.
## 2017-03-28 - 1.2.6 - ci
CI configuration update.
- Updated .gitlab-ci.yml for correct images/steps.
## 2017-03-28 - 1.2.5 - ci
CI improvements.
- Further CI updates.
## 2017-03-28 - 1.2.4 - perf
Performance improvements.
- Now runs asynchronously and is significantly faster.
## 2017-02-12 - 1.2.3 - feature
New cleanup and diagnostics features.
- Added speedtest utility.
- Added removal of volumes.
## 2017-02-11 - 1.2.2 - feature
Cleanup enhancement.
- Added "clean --all" option to remove more artifacts.
## 2017-02-11 - 1.2.1 - maintenance
Docs and dependency updates.
- Updated README and dependencies.
## 2016-08-04 - 1.2.0 - maintenance
Dependency cleanup.
- Removed unnecessary dependencies.
## 2016-07-29 - 1.1.6 - feature
Environment support.
- Added support for qenv.
## 2016-07-29 - 1.1.5 - fix
Container cleanup improvements.
- Now also removes old running containers.
## 2016-07-29 - 1.1.4 - fix
Namespace conflict avoidance.
- Removes previous containers to avoid name-space conflicts after errors.
## 2016-07-29 - 1.1.3 - ci
CI image configuration.
- Added correct images for GitLab CI.
## 2016-07-29 - 1.1.2 - ci
CI fixes.
- Fixed GitLab CI configuration.
## 2016-07-28 - 1.1.1 - ci
CI fixes and configuration.
- Fixed gitlab.yml and CI issues.
## 2016-07-28 - 1.1.0 - feature
Docker-in-Docker support.
- Improved support for Docker-in-Docker scenarios.
## 2016-07-28 - 1.0.5 - feature & ci
Docker socket option and CI update.
- Added dockerSock option.
- Updated .gitlab-ci.yml.
## 2016-07-19 - 1.0.4 - release (no code changes)
Tagged release with no recorded source changes.
- Tagged release only (no changelogged changes).
## 2016-07-19 - 1.0.3 - feature
Environment tagging.
- Added environment tag support.
## 2016-07-19 - 1.0.2 - milestone
CLI and stability improvements.
- Wired up CLI usage.
- Marked as fully working.
## 2016-07-19 - 1.0.1 - initial improvements
Early project refinements and Docker integration.
- Added/updated Docker integration and configuration.
- Improved config handling and path management.
- Updated Docker handling and removed test artifacts.
## 2016-07-13 - 1.0.0 - initial
Initial release.
- Added README and initial project scaffolding.

3
cli.js Normal file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
import('./dist_ts/index.js');

3
dist/cli.js vendored
View File

@@ -1,3 +0,0 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true'
var index = require("../dist/index.js");

1
dist/index.d.ts vendored
View File

@@ -1 +0,0 @@
export {};

5
dist/index.js vendored
View File

@@ -1,5 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const cli = require("./npmdocker.cli");
cli.run();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLHVDQUF1QztBQUV2QyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMifQ==

View File

@@ -1 +0,0 @@
export declare let run: () => void;

83
dist/npmdocker.cli.js vendored
View File

@@ -1,83 +0,0 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const plugins = require("./npmdocker.plugins");
// modules
const ConfigModule = require("./npmdocker.config");
const DockerModule = require("./npmdocker.docker");
/**
* smartanalytics
* this data is fully anonymized (no Ips or any other personal information is tracked).
* It just keeps track which of our tools are really used...
* ... so we know where to spend our limited resources for improving them.
* Since yarn is out and there is heavy caching going on,
* pure download stats are just not reliable enough for us anymore
* Feel free to dig into the smartanalytics package, if you are interested in how it works.
* Our privacy policy can be found here: https://lossless.gmbh/privacy.html
*/
let npmdockerAnalytics = new plugins.smartanalytics.Analytics({
apiEndPoint: 'https://pubapi.lossless.one',
appName: 'npmdocker',
projectId: 'gitzone'
});
npmdockerAnalytics.recordEvent('npmtoolexecution', {
somedata: 'somedata'
});
let npmdockerCli = new plugins.smartcli.Smartcli();
exports.run = () => {
npmdockerCli.standardTask().then((argvArg) => __awaiter(this, void 0, void 0, function* () {
plugins.beautylog.figletSync('npmdocker');
let configArg = yield ConfigModule.run().then(DockerModule.run);
if (configArg.exitCode === 0) {
plugins.beautylog.success('container ended all right!');
}
else {
plugins.beautylog.error(`container ended with error! Exit Code is ${configArg.exitCode}`);
process.exit(1);
}
}));
/**
* this command is executed inside docker and meant for use from outside docker
*/
npmdockerCli.addCommand('runinside').then((argvArg) => __awaiter(this, void 0, void 0, function* () {
plugins.beautylog.ok('Allright. We are now in Docker!');
plugins.beautylog.log('now trying to run your specified command');
let configArg = yield ConfigModule.run();
yield plugins.smartshell.exec(configArg.command).then(response => {
if (response.exitCode !== 0) {
process.exit(1);
}
});
}));
npmdockerCli.addCommand('clean').then((argvArg) => __awaiter(this, void 0, void 0, function* () {
plugins.beautylog.ora.start();
plugins.beautylog.ora.text('cleaning up docker env...');
if (argvArg.all) {
plugins.beautylog.ora.text('killing any running docker containers...');
yield plugins.smartshell.exec(`docker kill $(docker ps -q)`);
plugins.beautylog.ora.text('removing stopped containers...');
yield plugins.smartshell.exec(`docker rm $(docker ps -a -q)`);
plugins.beautylog.ora.text('removing images...');
yield plugins.smartshell.exec(`docker rmi $(docker images -q -f dangling=true)`);
plugins.beautylog.ora.text('removing all other images...');
yield plugins.smartshell.exec(`docker rmi $(docker images -a -q)`);
plugins.beautylog.ora.text('removing all volumes...');
yield plugins.smartshell.exec(`docker volume rm $(docker volume ls -f dangling=true -q)`);
}
plugins.beautylog.ora.endOk('docker environment now is clean!');
}));
npmdockerCli.addCommand('speedtest').then((argvArg) => __awaiter(this, void 0, void 0, function* () {
plugins.beautylog.figletSync('npmdocker');
plugins.beautylog.ok('Starting speedtest');
yield plugins.smartshell.exec(`docker pull tianon/speedtest && docker run --rm tianon/speedtest`);
}));
npmdockerCli.startParse();
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnBtZG9ja2VyLmNsaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL25wbWRvY2tlci5jbGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUFBLCtDQUErQztBQUcvQyxVQUFVO0FBQ1YsbURBQW1EO0FBQ25ELG1EQUFtRDtBQUVuRDs7Ozs7Ozs7O0dBU0c7QUFDSCxJQUFJLGtCQUFrQixHQUFHLElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUM7SUFDNUQsV0FBVyxFQUFFLDZCQUE2QjtJQUMxQyxPQUFPLEVBQUUsV0FBVztJQUNwQixTQUFTLEVBQUUsU0FBUztDQUNyQixDQUFDLENBQUM7QUFDSCxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsa0JBQWtCLEVBQUU7SUFDakQsUUFBUSxFQUFFLFVBQVU7Q0FDckIsQ0FBQyxDQUFDO0FBRUgsSUFBSSxZQUFZLEdBQUcsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDO0FBRXhDLFFBQUEsR0FBRyxHQUFHLEdBQUcsRUFBRTtJQUNwQixZQUFZLENBQUMsWUFBWSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQU0sT0FBTyxFQUFDLEVBQUU7UUFDL0MsT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDMUMsSUFBSSxTQUFTLEdBQUcsTUFBTSxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNoRSxJQUFJLFNBQVMsQ0FBQyxRQUFRLEtBQUssQ0FBQyxFQUFFO1lBQzVCLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLDRCQUE0QixDQUFDLENBQUM7U0FDekQ7YUFBTTtZQUNMLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLDRDQUE0QyxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUMxRixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2pCO0lBQ0gsQ0FBQyxDQUFBLENBQUMsQ0FBQztJQUVIOztPQUVHO0lBQ0gsWUFBWSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBTSxPQUFPLEVBQUMsRUFBRTtRQUN4RCxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3hELE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDbEUsSUFBSSxTQUFTLEdBQUcsTUFBTSxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDekMsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQy9ELElBQUksUUFBUSxDQUFDLFFBQVEsS0FBSyxDQUFDLEVBQUU7Z0JBQzNCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDakI7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQSxDQUFDLENBQUM7SUFFSCxZQUFZLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFNLE9BQU8sRUFBQyxFQUFFO1FBQ3BELE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzlCLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1FBQ3hELElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNmLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1lBQ3ZFLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUMsQ0FBQztZQUU3RCxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztZQUM3RCxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLDhCQUE4QixDQUFDLENBQUM7WUFFOUQsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDakQsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxpREFBaUQsQ0FBQyxDQUFDO1lBRWpGLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1lBQzNELE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsbUNBQW1DLENBQUMsQ0FBQztZQUVuRSxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztZQUN0RCxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLDBEQUEwRCxDQUFDLENBQUM7U0FDM0Y7UUFDRCxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsa0NBQWtDLENBQUMsQ0FBQztJQUNsRSxDQUFDLENBQUEsQ0FBQyxDQUFDO0lBRUgsWUFBWSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBTSxPQUFPLEVBQUMsRUFBRTtRQUN4RCxPQUFPLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMxQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQzNDLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQzNCLGtFQUFrRSxDQUNuRSxDQUFDO0lBQ0osQ0FBQyxDQUFBLENBQUMsQ0FBQztJQUVILFlBQVksQ0FBQyxVQUFVLEVBQUUsQ0FBQztBQUM1QixDQUFDLENBQUMifQ==

View File

@@ -1,9 +0,0 @@
import { IKeyValueObject } from 'qenv';
export interface IConfig {
baseImage: string;
command: string;
dockerSock: boolean;
exitCode?: number;
keyValueObjectArray: IKeyValueObject[];
}
export declare let run: () => Promise<IConfig>;

View File

@@ -1,38 +0,0 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const plugins = require("./npmdocker.plugins");
const paths = require("./npmdocker.paths");
let getQenvKeyValueObject = () => __awaiter(this, void 0, void 0, function* () {
let qenvKeyValueObjectArray;
if (plugins.smartfile.fs.fileExistsSync(plugins.path.join(paths.cwd, 'qenv.yml'))) {
qenvKeyValueObjectArray = new plugins.qenv.Qenv(paths.cwd, '.nogit/').keyValueObjectArray;
}
else {
qenvKeyValueObjectArray = [];
}
return qenvKeyValueObjectArray;
});
let buildConfig = (qenvKeyValueObjectArrayArg) => __awaiter(this, void 0, void 0, function* () {
let npmextra = new plugins.npmextra.Npmextra(paths.cwd);
let config = npmextra.dataFor('npmdocker', {
baseImage: 'hosttoday/ht-docker-node:npmdocker',
init: 'rm -rf node_nodules/ && yarn install',
command: 'npmci npm test',
dockerSock: false,
keyValueObjectArray: qenvKeyValueObjectArrayArg
});
return config;
});
exports.run = () => __awaiter(this, void 0, void 0, function* () {
let config = yield getQenvKeyValueObject().then(buildConfig);
return config;
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnBtZG9ja2VyLmNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL25wbWRvY2tlci5jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUFBLCtDQUErQztBQUMvQywyQ0FBMkM7QUFhM0MsSUFBSSxxQkFBcUIsR0FBRyxHQUFTLEVBQUU7SUFDckMsSUFBSSx1QkFBMEMsQ0FBQztJQUMvQyxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDLEVBQUU7UUFDakYsdUJBQXVCLEdBQUcsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxDQUFDLG1CQUFtQixDQUFDO0tBQzNGO1NBQU07UUFDTCx1QkFBdUIsR0FBRyxFQUFFLENBQUM7S0FDOUI7SUFDRCxPQUFPLHVCQUF1QixDQUFDO0FBQ2pDLENBQUMsQ0FBQSxDQUFDO0FBRUYsSUFBSSxXQUFXLEdBQUcsQ0FBTywwQkFBNkMsRUFBRSxFQUFFO0lBQ3hFLElBQUksUUFBUSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3hELElBQUksTUFBTSxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQVUsV0FBVyxFQUFFO1FBQ2xELFNBQVMsRUFBRSxvQ0FBb0M7UUFDL0MsSUFBSSxFQUFFLHNDQUFzQztRQUM1QyxPQUFPLEVBQUUsZ0JBQWdCO1FBQ3pCLFVBQVUsRUFBRSxLQUFLO1FBQ2pCLG1CQUFtQixFQUFFLDBCQUEwQjtLQUNoRCxDQUFDLENBQUM7SUFDSCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUEsQ0FBQztBQUVTLFFBQUEsR0FBRyxHQUFHLEdBQTJCLEVBQUU7SUFDNUMsSUFBSSxNQUFNLEdBQUcsTUFBTSxxQkFBcUIsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUM3RCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUEsQ0FBQyJ9

View File

@@ -1,2 +0,0 @@
import { IConfig } from './npmdocker.config';
export declare let run: (configArg: IConfig) => Promise<IConfig>;

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
export declare let cwd: string;
export declare let packageBase: string;
export declare let assets: string;
export declare let npmdockerFile: string;

View File

@@ -1,10 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const plugins = require("./npmdocker.plugins");
// directories
exports.cwd = process.cwd();
exports.packageBase = plugins.path.join(__dirname, '../');
exports.assets = plugins.path.join(exports.packageBase, 'assets/');
plugins.smartfile.fs.ensureDirSync(exports.assets);
exports.npmdockerFile = plugins.path.join(exports.cwd, 'npmdocker');
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnBtZG9ja2VyLnBhdGhzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbnBtZG9ja2VyLnBhdGhzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsK0NBQStDO0FBRS9DLGNBQWM7QUFDSCxRQUFBLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDcEIsUUFBQSxXQUFXLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQ2xELFFBQUEsTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFXLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDOUQsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLGNBQU0sQ0FBQyxDQUFDO0FBQ2hDLFFBQUEsYUFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyJ9

View File

@@ -1,12 +0,0 @@
import * as beautylog from 'beautylog';
import * as npmextra from 'npmextra';
import * as path from 'path';
import * as projectinfo from 'projectinfo';
import * as q from 'smartq';
import * as qenv from 'qenv';
import * as smartanalytics from 'smartanalytics';
import * as smartcli from 'smartcli';
import * as smartfile from 'smartfile';
import * as smartshell from 'smartshell';
import * as smartstring from 'smartstring';
export { beautylog, npmextra, path, projectinfo, q, qenv, smartanalytics, smartcli, smartfile, smartshell, smartstring };

View File

@@ -1,25 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const beautylog = require("beautylog");
exports.beautylog = beautylog;
const npmextra = require("npmextra");
exports.npmextra = npmextra;
const path = require("path");
exports.path = path;
const projectinfo = require("projectinfo");
exports.projectinfo = projectinfo;
const q = require("smartq");
exports.q = q;
const qenv = require("qenv");
exports.qenv = qenv;
const smartanalytics = require("smartanalytics");
exports.smartanalytics = smartanalytics;
const smartcli = require("smartcli");
exports.smartcli = smartcli;
const smartfile = require("smartfile");
exports.smartfile = smartfile;
const smartshell = require("smartshell");
exports.smartshell = smartshell;
const smartstring = require("smartstring");
exports.smartstring = smartstring;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnBtZG9ja2VyLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9ucG1kb2NrZXIucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHVDQUF1QztBQWFyQyw4QkFBUztBQVpYLHFDQUFxQztBQWFuQyw0QkFBUTtBQVpWLDZCQUE2QjtBQWEzQixvQkFBSTtBQVpOLDJDQUEyQztBQWF6QyxrQ0FBVztBQVpiLDRCQUE0QjtBQWExQixjQUFDO0FBWkgsNkJBQTZCO0FBYTNCLG9CQUFJO0FBWk4saURBQWlEO0FBYS9DLHdDQUFjO0FBWmhCLHFDQUFxQztBQWFuQyw0QkFBUTtBQVpWLHVDQUF1QztBQWFyQyw4QkFBUztBQVpYLHlDQUF5QztBQWF2QyxnQ0FBVTtBQVpaLDJDQUEyQztBQWF6QyxrQ0FBVyJ9

View File

@@ -1,5 +0,0 @@
export interface IDockerfileSnippet {
baseImage: string;
command: string;
}
export declare let dockerfileSnippet: (optionsArg: IDockerfileSnippet) => string;

View File

@@ -1,32 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const plugins = require("./npmdocker.plugins");
let getMountSolutionString = (optionsArg) => {
if (process.env.CI) {
return 'COPY ./ /workspace';
}
else {
return '# not copying workspcae since not in CI';
}
};
let getGlobalPreparationString = (optionsArg) => {
if (optionsArg.baseImage !== 'hosttoday/ht-docker-node:npmdocker') {
return 'RUN yarn global add npmdocker';
}
else {
return '# not installing npmdocker since it is included in the base image';
}
};
exports.dockerfileSnippet = (optionsArg) => {
return plugins.smartstring.indent.normalize(`
FROM ${optionsArg.baseImage}
# For info about what npmdocker does read the docs at https://gitzone.github.io/npmdocker
${getGlobalPreparationString(optionsArg)}
${getMountSolutionString(optionsArg)}
WORKDIR /workspace
ENV CI=true
ENTRYPOINT ["npmdocker"]
CMD ["runinside"]
`);
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnBtZG9ja2VyLnNuaXBwZXRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbnBtZG9ja2VyLnNuaXBwZXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsK0NBQStDO0FBTy9DLElBQUksc0JBQXNCLEdBQUcsQ0FBQyxVQUE4QixFQUFFLEVBQUU7SUFDOUQsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRTtRQUNsQixPQUFPLG9CQUFvQixDQUFDO0tBQzdCO1NBQU07UUFDTCxPQUFPLHlDQUF5QyxDQUFDO0tBQ2xEO0FBQ0gsQ0FBQyxDQUFDO0FBRUYsSUFBSSwwQkFBMEIsR0FBRyxDQUFDLFVBQThCLEVBQUUsRUFBRTtJQUNsRSxJQUFJLFVBQVUsQ0FBQyxTQUFTLEtBQUssb0NBQW9DLEVBQUU7UUFDakUsT0FBTywrQkFBK0IsQ0FBQztLQUN4QztTQUFNO1FBQ0wsT0FBTyxtRUFBbUUsQ0FBQztLQUM1RTtBQUNILENBQUMsQ0FBQztBQUVTLFFBQUEsaUJBQWlCLEdBQUcsQ0FBQyxVQUE4QixFQUFVLEVBQUU7SUFDeEUsT0FBTyxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQ3pDO09BQ0csVUFBVSxDQUFDLFNBQVM7O0VBRXpCLDBCQUEwQixDQUFDLFVBQVUsQ0FBQztFQUN0QyxzQkFBc0IsQ0FBQyxVQUFVLENBQUM7Ozs7O0NBS25DLENBQ0UsQ0FBQztBQUNKLENBQUMsQ0FBQyJ9

View File

@@ -1 +0,0 @@
Docs for npmpage coming soon.

View File

@@ -3,11 +3,25 @@
"mode": "default", "mode": "default",
"cli": true "cli": true
}, },
"npmci": { "@git.zone/cli": {
"npmGlobalTools": [ "projectType": "npm",
"@gitzone/npmts", "module": {
"ts-node" "githost": "gitlab.com",
], "gitscope": "gitzone",
"npmAccessLevel": "public" "gitrepo": "tsdocker",
"description": "develop npm modules cross platform with docker",
"npmPackagename": "@git.zone/tsdocker",
"license": "MIT"
},
"release": {
"accessLevel": "public",
"registries": [
"https://verdaccio.lossless.digital",
"https://registry.npmjs.org"
]
}
},
"@ship.zone/szci": {
"npmGlobalTools": []
} }
} }

View File

@@ -1,27 +1,28 @@
{ {
"name": "@gitzone/npmdocker", "name": "@git.zone/tsdocker",
"version": "1.2.19", "version": "1.4.0",
"private": false,
"description": "develop npm modules cross platform with docker", "description": "develop npm modules cross platform with docker",
"main": "dist/index.js", "main": "dist_ts/index.js",
"typings": "dist/index.d.ts", "typings": "dist_ts/index.d.ts",
"bin": { "bin": {
"npmdocker": "dist/cli.js" "tsdocker": "cli.js"
},
"directories": {
"test": "test"
}, },
"scripts": { "scripts": {
"test": "(npm run clean && npm run compile && npm run setupCheck && npm run testStandard && npm run testSpeed)", "test": "(npm run build)",
"testStandard": "(cd test/ && node ../dist/index.js)", "build": "(tsbuild)",
"testSpeed": "(cd test/ && node ../dist/index.js speedtest)", "testIntegration": "(npm run clean && npm run setupCheck && npm run testStandard)",
"testClean": "(cd test/ && node ../dist/index.js clean --all)", "testStandard": "(cd test/ && tsx ../ts/index.ts)",
"testClean": "(cd test/ && tsx ../ts/index.ts clean --all)",
"testVscode": "(cd test/ && tsx ../ts/index.ts vscode)",
"clean": "(rm -rf test/)", "clean": "(rm -rf test/)",
"compile": "(npmts --notest)", "compile": "(npmts --notest)",
"setupCheck": "(git clone https://gitlab.com/sandboxzone/sandbox-npmts.git test/)" "setupCheck": "(git clone https://gitlab.com/sandboxzone/sandbox-npmts.git test/)",
"buildDocs": "tsdoc"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+ssh://git@gitlab.com/gitzone/npmdocker.git" "url": "https://gitlab.com/gitzone/tsdocker.git"
}, },
"keywords": [ "keywords": [
"docker" "docker"
@@ -29,22 +30,46 @@
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://gitlab.com/gitzone/npmdocker/issues" "url": "https://gitlab.com/gitzone/tsdocker/issues"
},
"homepage": "https://gitlab.com/gitzone/tsdocker#readme",
"devDependencies": {
"@git.zone/tsbuild": "^4.1.2",
"@git.zone/tsrun": "^2.0.1",
"@git.zone/tstest": "^3.1.6",
"@types/node": "^25.0.9"
}, },
"homepage": "https://gitlab.com/gitzone/npmdocker#README",
"devDependencies": {},
"dependencies": { "dependencies": {
"@types/shelljs": "0.x.x", "@push.rocks/lik": "^6.2.2",
"beautylog": "^6.1.10", "@push.rocks/npmextra": "^5.3.3",
"npmextra": "^2.0.9", "@push.rocks/projectinfo": "^5.0.2",
"projectinfo": "^3.0.4", "@push.rocks/qenv": "^6.1.3",
"qenv": "^1.1.7", "@push.rocks/smartanalytics": "^2.0.15",
"smartanalytics": "^2.0.9", "@push.rocks/smartcli": "^4.0.20",
"smartcli": "^2.0.7", "@push.rocks/smartfs": "^1.3.1",
"smartfile": "^4.2.26", "@push.rocks/smartlog": "^3.1.10",
"smartq": "^1.1.6", "@push.rocks/smartlog-destination-local": "^9.0.2",
"smartshell": "^1.0.18", "@push.rocks/smartlog-source-ora": "^1.0.9",
"smartstring": "^2.0.24", "@push.rocks/smartopen": "^2.0.0",
"typings-global": "^1.0.20" "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartshell": "^3.3.0",
"@push.rocks/smartstring": "^4.1.0"
},
"packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34",
"type": "module",
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"pnpm": {
"overrides": {}
} }
} }

8743
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

109
readme.hints.md Normal file
View File

@@ -0,0 +1,109 @@
# tsdocker Project Hints
## Module Purpose
tsdocker is a comprehensive Docker development and building tool. It provides:
- Testing npm modules in clean Docker environments (legacy feature)
- Building Dockerfiles with dependency ordering
- Multi-registry push/pull support
- Multi-architecture builds (amd64/arm64)
## New CLI Commands (2026-01-19)
| Command | Description |
|---------|-------------|
| `tsdocker` | Run tests in container (legacy default behavior) |
| `tsdocker build` | Build all Dockerfiles with dependency ordering |
| `tsdocker push [registry]` | Push images to configured registries |
| `tsdocker pull <registry>` | Pull images from registry |
| `tsdocker test` | Run container tests (test scripts) |
| `tsdocker login` | Login to configured registries |
| `tsdocker list` | List discovered Dockerfiles and dependencies |
| `tsdocker clean --all` | Clean up Docker environment |
| `tsdocker vscode` | Start VS Code in Docker |
## Configuration
Configure in `package.json` under `@git.zone/tsdocker`:
```json
{
"@git.zone/tsdocker": {
"registries": ["registry.gitlab.com", "docker.io"],
"registryRepoMap": {
"registry.gitlab.com": "host.today/ht-docker-node"
},
"buildArgEnvMap": {
"NODE_VERSION": "NODE_VERSION"
},
"platforms": ["linux/amd64", "linux/arm64"],
"push": false,
"testDir": "./test"
}
}
```
### Configuration Options
- `baseImage`: Base Docker image for testing (legacy)
- `command`: Command to run in container (legacy)
- `dockerSock`: Mount Docker socket (legacy)
- `registries`: Array of registry URLs to push to
- `registryRepoMap`: Map registry URLs to different repo paths
- `buildArgEnvMap`: Map Docker build ARGs to environment variables
- `platforms`: Target architectures for buildx
- `push`: Auto-push after build
- `testDir`: Directory containing test scripts
## Registry Authentication
Set environment variables for registry login:
```bash
# Pipe-delimited format (numbered 1-10)
export DOCKER_REGISTRY_1="registry.gitlab.com|username|password"
export DOCKER_REGISTRY_2="docker.io|username|password"
# Or individual registry format
export DOCKER_REGISTRY_URL="registry.gitlab.com"
export DOCKER_REGISTRY_USER="username"
export DOCKER_REGISTRY_PASSWORD="password"
```
## File Structure
```
ts/
├── index.ts (entry point)
├── tsdocker.cli.ts (CLI commands)
├── tsdocker.config.ts (configuration)
├── tsdocker.plugins.ts (plugin imports)
├── tsdocker.docker.ts (legacy test runner)
├── tsdocker.snippets.ts (Dockerfile generation)
├── classes.dockerfile.ts (Dockerfile management)
├── classes.dockerregistry.ts (registry authentication)
├── classes.registrystorage.ts (registry storage)
├── classes.tsdockermanager.ts (orchestrator)
└── interfaces/
└── index.ts (type definitions)
```
## Dependencies
- `@push.rocks/lik`: Object mapping utilities
- `@push.rocks/smartfs`: Filesystem operations
- `@push.rocks/smartshell`: Shell command execution
- `@push.rocks/smartcli`: CLI framework
- `@push.rocks/projectinfo`: Project metadata
## Build Status
- Build: ✅ Passes
- Legacy test functionality preserved
- New Docker build functionality added
## Previous Upgrades (2025-11-22)
- Updated all @git.zone/_ dependencies to @git.zone/_ scope
- Updated all @pushrocks/_ dependencies to @push.rocks/_ scope
- Migrated from smartfile v8 to smartfs v1.1.0

330
readme.md Normal file
View File

@@ -0,0 +1,330 @@
# @git.zone/tsdocker
> 🐳 Cross-platform npm module development with Docker — test your packages in clean, reproducible Linux environments every time.
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## What is tsdocker?
**tsdocker** provides containerized testing environments for npm packages, ensuring your code works consistently across different systems. It's perfect for:
- 🧪 **Testing in clean environments** — Every test run starts fresh, just like CI
- 🔄 **Reproducing CI behavior locally** — No more "works on my machine" surprises
- 🐧 **Cross-platform development** — Develop on macOS/Windows, test on Linux
- 🚀 **Quick validation** — Spin up isolated containers for testing without polluting your system
## Features
**Works Everywhere Docker Does**
- Docker Toolbox
- Native Docker Desktop
- Docker-in-Docker (DinD)
- Mounted docker.sock scenarios
🔧 **Flexible Configuration**
- Custom base images
- Configurable test commands
- Environment variable injection via qenv
- Optional docker.sock mounting for nested container tests
📦 **TypeScript-First**
- Full TypeScript support with excellent IntelliSense
- Type-safe configuration
- Modern ESM with async/await patterns throughout
## Installation
```bash
npm install -g @git.zone/tsdocker
# or for project-local installation
pnpm install --save-dev @git.zone/tsdocker
```
## Quick Start
### 1. Configure Your Project
Create an `npmextra.json` file in your project root:
```json
{
"@git.zone/tsdocker": {
"baseImage": "node:20",
"command": "npm test",
"dockerSock": false
}
}
```
### 2. Run Your Tests
```bash
tsdocker
```
That's it! tsdocker will:
1. ✅ Verify Docker is available
2. 🏗️ Build a test container with your specified base image
3. 📂 Mount your project directory
4. 🚀 Execute your test command
5. 🧹 Clean up automatically
## Configuration Options
| Option | Type | Description |
| ------------ | --------- | ---------------------------------------------------------------------- |
| `baseImage` | `string` | Docker image to use as the test environment base |
| `command` | `string` | CLI command to execute inside the container |
| `dockerSock` | `boolean` | Whether to mount `/var/run/docker.sock` for Docker-in-Docker scenarios |
### Environment Variables
If you have a `qenv.yml` file in your project, tsdocker automatically loads and injects those environment variables into your test container.
Example `qenv.yml`:
```yaml
demoKey: demoValue
API_KEY: your-key-here
```
## CLI Commands
### Standard Test Run
```bash
tsdocker
```
Runs your configured test command in a fresh Docker container.
### Clean Docker Environment
```bash
tsdocker clean --all
```
⚠️ **WARNING**: This aggressively cleans your Docker environment by:
- Killing all running containers
- Removing all stopped containers
- Removing dangling images
- Removing all images
- Removing dangling volumes
Use with caution!
### VSCode in Docker
```bash
tsdocker vscode
```
Launches a containerized VS Code instance accessible via browser at `testing-vscode.git.zone:8443`.
## Advanced Usage
### Docker-in-Docker Testing
If you need to run Docker commands inside your test container (e.g., testing Docker-related tools):
```json
{
"@git.zone/tsdocker": {
"baseImage": "docker:latest",
"command": "docker run hello-world",
"dockerSock": true
}
}
```
Setting `"dockerSock": true` mounts the host's Docker socket into the container.
### Custom Base Images
You can use any Docker image as your base:
```json
{
"@git.zone/tsdocker": {
"baseImage": "node:20-alpine",
"command": "npm test"
}
}
```
Popular choices:
- `node:20` — Official Node.js images
- `node:20-alpine` — Lightweight Alpine-based images
- `node:lts` — Long-term support Node.js version
### CI Integration
tsdocker automatically detects CI environments (via `CI=true` env var) and adjusts behavior:
- Copies project files into container in CI (instead of mounting)
- Optimizes for CI execution patterns
## Why tsdocker?
### The Problem
Local development environments drift over time. You might have:
- Stale global packages
- Modified system configurations
- Cached dependencies
- Different Node.js versions
Your tests pass locally but fail in CI — or vice versa.
### The Solution
tsdocker ensures every test run happens in a **clean, reproducible environment**, just like your CI pipeline. This means:
✅ Consistent behavior between local and CI
✅ No dependency pollution between test runs
✅ Easy cross-platform testing
✅ Reproducible bug investigations
## TypeScript Usage
tsdocker is built with TypeScript and provides full type definitions:
```typescript
import type { IConfig } from '@git.zone/tsdocker/dist_ts/tsdocker.config.js';
const config: IConfig = {
baseImage: 'node:20',
command: 'npm test',
dockerSock: false,
keyValueObject: {
NODE_ENV: 'test',
},
};
```
## Requirements
- **Docker**: Docker must be installed and accessible via CLI
- **Node.js**: Version 18 or higher (ESM support required)
## How It Works
Under the hood, tsdocker:
1. 📋 Reads your `npmextra.json` configuration
2. 🔍 Optionally loads environment variables from `qenv.yml`
3. 🐳 Generates a temporary Dockerfile
4. 🏗️ Builds a Docker image with your base image
5. 📦 Mounts your project directory (unless in CI)
6. ▶️ Runs your test command inside the container
7. 📊 Captures the exit code
8. 🧹 Cleans up containers and images
9. ✅ Exits with the same code as your tests
## Troubleshooting
### "docker not found on this machine"
Make sure Docker is installed and the `docker` command is in your PATH:
```bash
docker --version
```
### Tests fail in container but work locally
This often indicates environment-specific issues. Check:
- Are all dependencies in `package.json`? (not relying on global packages)
- Does your code have hardcoded paths?
- Are environment variables set correctly?
### Permission errors with docker.sock
If using `dockerSock: true`, ensure your user has permissions to access `/var/run/docker.sock`:
```bash
sudo usermod -aG docker $USER
# Then log out and back in
```
## Examples
### Basic npm test
```json
{
"@git.zone/tsdocker": {
"baseImage": "node:20",
"command": "npm test"
}
}
```
### Running pnpm tests
```json
{
"@git.zone/tsdocker": {
"baseImage": "node:20",
"command": "corepack enable && pnpm install && pnpm test"
}
}
```
### Testing Docker-based tools
```json
{
"@git.zone/tsdocker": {
"baseImage": "docker:latest",
"command": "sh -c 'docker version && docker ps'",
"dockerSock": true
}
}
```
## Performance Tips
🚀 **Use specific base images**: `node:20-alpine` is much faster to pull than `node:latest`
🚀 **Layer caching**: Docker caches image layers — your base image only downloads once
🚀 **Prune regularly**: Run `docker system prune` periodically to reclaim disk space
## Migration from legacy npmdocker
This package was previously published under the `npmdocker` name. It is now available as `@git.zone/tsdocker` with modernized ESM support and updated dependencies.
Key changes:
- Configuration key changed from `npmdocker` to `@git.zone/tsdocker` in `npmextra.json`
- CLI command is now `tsdocker` instead of `npmdocker`
- Full ESM support with `.js` extensions in imports
## License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
### Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

8
ts/00_commitinfo_data.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@git.zone/tsdocker',
version: '1.4.0',
description: 'develop npm modules cross platform with docker'
}

462
ts/classes.dockerfile.ts Normal file
View File

@@ -0,0 +1,462 @@
import * as plugins from './tsdocker.plugins.js';
import * as paths from './tsdocker.paths.js';
import { logger } from './tsdocker.logging.js';
import { DockerRegistry } from './classes.dockerregistry.js';
import type { IDockerfileOptions, ITsDockerConfig } from './interfaces/index.js';
import type { TsDockerManager } from './classes.tsdockermanager.js';
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
/**
* Class Dockerfile represents a Dockerfile on disk
*/
export class Dockerfile {
// STATIC METHODS
/**
* Creates instances of class Dockerfile for all Dockerfiles in cwd
*/
public static async readDockerfiles(managerRef: TsDockerManager): Promise<Dockerfile[]> {
const entries = await plugins.smartfs.directory(paths.cwd).filter('Dockerfile*').list();
const fileTree = entries
.filter(entry => entry.isFile)
.map(entry => plugins.path.join(paths.cwd, entry.name));
const readDockerfilesArray: Dockerfile[] = [];
logger.log('info', `found ${fileTree.length} Dockerfiles:`);
console.log(fileTree);
for (const dockerfilePath of fileTree) {
const myDockerfile = new Dockerfile(managerRef, {
filePath: dockerfilePath,
read: true,
});
readDockerfilesArray.push(myDockerfile);
}
return readDockerfilesArray;
}
/**
* Sorts Dockerfiles into a build order based on dependencies (topological sort)
*/
public static async sortDockerfiles(dockerfiles: Dockerfile[]): Promise<Dockerfile[]> {
logger.log('info', 'Sorting Dockerfiles based on dependencies...');
// Map from cleanTag to Dockerfile instance for quick lookup
const tagToDockerfile = new Map<string, Dockerfile>();
dockerfiles.forEach((dockerfile) => {
tagToDockerfile.set(dockerfile.cleanTag, dockerfile);
});
// Build the dependency graph
const graph = new Map<Dockerfile, Dockerfile[]>();
dockerfiles.forEach((dockerfile) => {
const dependencies: Dockerfile[] = [];
const baseImage = dockerfile.baseImage;
// Check if the baseImage is among the local Dockerfiles
if (tagToDockerfile.has(baseImage)) {
const baseDockerfile = tagToDockerfile.get(baseImage)!;
dependencies.push(baseDockerfile);
dockerfile.localBaseImageDependent = true;
dockerfile.localBaseDockerfile = baseDockerfile;
}
graph.set(dockerfile, dependencies);
});
// Perform topological sort
const sortedDockerfiles: Dockerfile[] = [];
const visited = new Set<Dockerfile>();
const tempMarked = new Set<Dockerfile>();
const visit = (dockerfile: Dockerfile) => {
if (tempMarked.has(dockerfile)) {
throw new Error(`Circular dependency detected involving ${dockerfile.cleanTag}`);
}
if (!visited.has(dockerfile)) {
tempMarked.add(dockerfile);
const dependencies = graph.get(dockerfile) || [];
dependencies.forEach((dep) => visit(dep));
tempMarked.delete(dockerfile);
visited.add(dockerfile);
sortedDockerfiles.push(dockerfile);
}
};
try {
dockerfiles.forEach((dockerfile) => {
if (!visited.has(dockerfile)) {
visit(dockerfile);
}
});
} catch (error) {
logger.log('error', (error as Error).message);
throw error;
}
// Log the sorted order
sortedDockerfiles.forEach((dockerfile, index) => {
logger.log(
'info',
`Build order ${index + 1}: ${dockerfile.cleanTag} with base image ${dockerfile.baseImage}`
);
});
return sortedDockerfiles;
}
/**
* Maps local Dockerfiles dependencies to the corresponding 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 corresponding real docker image for each Dockerfile class instance
*/
public static async buildDockerfiles(sortedArrayArg: Dockerfile[]): Promise<Dockerfile[]> {
for (const dockerfileArg of sortedArrayArg) {
await dockerfileArg.build();
}
return sortedArrayArg;
}
/**
* Tests all Dockerfiles by calling Dockerfile.test()
*/
public static async testDockerfiles(sortedArrayArg: Dockerfile[]): Promise<Dockerfile[]> {
for (const dockerfileArg of sortedArrayArg) {
await dockerfileArg.test();
}
return sortedArrayArg;
}
/**
* Returns a version for a docker file
* Dockerfile_latest -> latest
* Dockerfile_v1.0.0 -> v1.0.0
* Dockerfile -> latest
*/
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';
}
// Replace ##version## placeholder with actual package version if available
if (dockerfileInstanceArg.managerRef?.projectInfo?.npm?.version) {
versionString = versionString.replace(
'##version##',
dockerfileInstanceArg.managerRef.projectInfo.npm.version
);
}
return versionString;
}
/**
* Extracts the base image from a Dockerfile content
* Handles ARG substitution for variable base images
*/
public static dockerBaseImage(dockerfileContentArg: string): string {
const lines = dockerfileContentArg.split(/\r?\n/);
const args: { [key: string]: string } = {};
for (const line of lines) {
const trimmedLine = line.trim();
// Skip empty lines and comments
if (trimmedLine === '' || trimmedLine.startsWith('#')) {
continue;
}
// Match ARG instructions
const argMatch = trimmedLine.match(/^ARG\s+([^\s=]+)(?:=(.*))?$/i);
if (argMatch) {
const argName = argMatch[1];
const argValue = argMatch[2] !== undefined ? argMatch[2] : process.env[argName] || '';
args[argName] = argValue;
continue;
}
// Match FROM instructions
const fromMatch = trimmedLine.match(/^FROM\s+(.+?)(?:\s+AS\s+[^\s]+)?$/i);
if (fromMatch) {
let baseImage = fromMatch[1].trim();
// Substitute variables in the base image name
baseImage = Dockerfile.substituteVariables(baseImage, args);
return baseImage;
}
}
throw new Error('No FROM instruction found in Dockerfile');
}
/**
* Substitutes variables in a string, supporting default values like ${VAR:-default}
*/
private static substituteVariables(str: string, vars: { [key: string]: string }): string {
return str.replace(/\${([^}:]+)(:-([^}]+))?}/g, (_, varName, __, defaultValue) => {
if (vars[varName] !== undefined) {
return vars[varName];
} else if (defaultValue !== undefined) {
return defaultValue;
} else {
return '';
}
});
}
/**
* Returns the docker tag string for a given registry and repo
*/
public static getDockerTagString(
managerRef: TsDockerManager,
registryArg: string,
repoArg: string,
versionArg: string,
suffixArg?: string
): string {
// Determine whether the repo should be mapped according to the registry
const config = managerRef.config;
const mappedRepo = config.registryRepoMap?.[registryArg];
const repo = mappedRepo || repoArg;
// Determine whether the version contains a suffix
let version = versionArg;
if (suffixArg) {
version = versionArg + '_' + suffixArg;
}
const tagString = `${registryArg}/${repo}:${version}`;
return tagString;
}
/**
* Gets build args from environment variable mapping
*/
public static async getDockerBuildArgs(managerRef: TsDockerManager): Promise<string> {
logger.log('info', 'checking for env vars to be supplied to the docker build');
let buildArgsString: string = '';
const config = managerRef.config;
if (config.buildArgEnvMap) {
for (const dockerArgKey of Object.keys(config.buildArgEnvMap)) {
const dockerArgOuterEnvVar = config.buildArgEnvMap[dockerArgKey];
logger.log(
'note',
`docker ARG "${dockerArgKey}" maps to outer env var "${dockerArgOuterEnvVar}"`
);
const targetValue = process.env[dockerArgOuterEnvVar];
if (targetValue) {
buildArgsString = `${buildArgsString} --build-arg ${dockerArgKey}="${targetValue}"`;
}
}
}
return buildArgsString;
}
// INSTANCE PROPERTIES
public managerRef: TsDockerManager;
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(managerRefArg: TsDockerManager, options: IDockerfileOptions) {
this.managerRef = managerRefArg;
this.filePath = options.filePath!;
// Build repo name from project info or directory name
const projectInfo = this.managerRef.projectInfo;
if (projectInfo?.npm?.name) {
// Use package name, removing scope if present
const packageName = projectInfo.npm.name.replace(/^@[^/]+\//, '');
this.repo = packageName;
} else {
// Fallback to directory name
this.repo = plugins.path.basename(paths.cwd);
}
this.version = Dockerfile.dockerFileVersion(this, plugins.path.parse(this.filePath).base);
this.cleanTag = this.repo + ':' + this.version;
this.buildTag = this.cleanTag;
this.containerName = 'dockerfile-' + this.version;
if (options.filePath && options.read) {
const fs = require('fs');
this.content = fs.readFileSync(plugins.path.resolve(options.filePath), 'utf-8');
} else if (options.fileContents) {
this.content = options.fileContents;
}
this.baseImage = Dockerfile.dockerBaseImage(this.content);
this.localBaseImageDependent = false;
}
/**
* Builds the Dockerfile
*/
public async build(): Promise<void> {
logger.log('info', 'now building Dockerfile for ' + this.cleanTag);
const buildArgsString = await Dockerfile.getDockerBuildArgs(this.managerRef);
const config = this.managerRef.config;
let buildCommand: string;
// Check if multi-platform build is needed
if (config.platforms && config.platforms.length > 1) {
// Multi-platform build using buildx
const platformString = config.platforms.join(',');
buildCommand = `docker buildx build --platform ${platformString} -t ${this.buildTag} -f ${this.filePath} ${buildArgsString} .`;
if (config.push) {
buildCommand += ' --push';
} else {
buildCommand += ' --load';
}
} else {
// Standard build
const versionLabel = this.managerRef.projectInfo?.npm?.version || 'unknown';
buildCommand = `docker build --label="version=${versionLabel}" -t ${this.buildTag} -f ${this.filePath} ${buildArgsString} .`;
}
const result = await smartshellInstance.exec(buildCommand);
if (result.exitCode !== 0) {
logger.log('error', `Build failed for ${this.cleanTag}`);
console.log(result.stdout);
throw new Error(`Build failed for ${this.cleanTag}`);
}
logger.log('ok', `Built ${this.cleanTag}`);
}
/**
* Pushes the Dockerfile to a registry
*/
public async push(dockerRegistryArg: DockerRegistry, versionSuffix?: string): Promise<void> {
this.pushTag = Dockerfile.getDockerTagString(
this.managerRef,
dockerRegistryArg.registryUrl,
this.repo,
this.version,
versionSuffix
);
await smartshellInstance.exec(`docker tag ${this.buildTag} ${this.pushTag}`);
const pushResult = await smartshellInstance.exec(`docker push ${this.pushTag}`);
if (pushResult.exitCode !== 0) {
logger.log('error', `Push failed for ${this.pushTag}`);
throw new Error(`Push failed for ${this.pushTag}`);
}
// Get image digest
const inspectResult = await smartshellInstance.exec(
`docker inspect --format="{{index .RepoDigests 0}}" ${this.pushTag}`
);
if (inspectResult.exitCode === 0 && inspectResult.stdout.includes('@')) {
const imageDigest = inspectResult.stdout.split('@')[1]?.trim();
console.log(`The image ${this.pushTag} has digest ${imageDigest}`);
}
logger.log('ok', `Pushed ${this.pushTag}`);
}
/**
* Pulls the Dockerfile from a registry
*/
public async pull(registryArg: DockerRegistry, versionSuffixArg?: string): Promise<void> {
const pullTag = Dockerfile.getDockerTagString(
this.managerRef,
registryArg.registryUrl,
this.repo,
this.version,
versionSuffixArg
);
await smartshellInstance.exec(`docker pull ${pullTag}`);
await smartshellInstance.exec(`docker tag ${pullTag} ${this.buildTag}`);
logger.log('ok', `Pulled and tagged ${pullTag} as ${this.buildTag}`);
}
/**
* Tests the Dockerfile by running a test script if it exists
*/
public async test(): Promise<void> {
const testDir = this.managerRef.config.testDir || plugins.path.join(paths.cwd, 'test');
const testFile = plugins.path.join(testDir, 'test_' + this.version + '.sh');
const fs = require('fs');
const testFileExists = fs.existsSync(testFile);
if (testFileExists) {
logger.log('info', `Running tests for ${this.cleanTag}`);
// Run tests in container
await smartshellInstance.exec(
`docker run --name tsdocker_test_container --entrypoint="bash" ${this.buildTag} -c "mkdir /tsdocker_test"`
);
await smartshellInstance.exec(`docker cp ${testFile} tsdocker_test_container:/tsdocker_test/test.sh`);
await smartshellInstance.exec(`docker commit tsdocker_test_container tsdocker_test_image`);
const testResult = await smartshellInstance.exec(
`docker run --entrypoint="bash" tsdocker_test_image -x /tsdocker_test/test.sh`
);
// Cleanup
await smartshellInstance.exec(`docker rm tsdocker_test_container`);
await smartshellInstance.exec(`docker rmi --force tsdocker_test_image`);
if (testResult.exitCode !== 0) {
throw new Error(`Tests failed for ${this.cleanTag}`);
}
logger.log('ok', `Tests passed for ${this.cleanTag}`);
} else {
logger.log('warn', `Skipping tests for ${this.cleanTag} because no test file was found at ${testFile}`);
}
}
/**
* Gets the ID of a built Docker image
*/
public async getId(): Promise<string> {
const result = await smartshellInstance.exec(
'docker inspect --type=image --format="{{.Id}}" ' + this.buildTag
);
return result.stdout.trim();
}
}

View File

@@ -0,0 +1,91 @@
import * as plugins from './tsdocker.plugins.js';
import { logger } from './tsdocker.logging.js';
import type { IDockerRegistryOptions } from './interfaces/index.js';
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
/**
* Represents a Docker registry with authentication capabilities
*/
export class DockerRegistry {
public registryUrl: string;
public username: string;
public password: string;
constructor(optionsArg: IDockerRegistryOptions) {
this.registryUrl = optionsArg.registryUrl;
this.username = optionsArg.username;
this.password = optionsArg.password;
logger.log('info', `created DockerRegistry for ${this.registryUrl}`);
}
/**
* Creates a DockerRegistry instance from a pipe-delimited environment string
* Format: "registryUrl|username|password"
*/
public static fromEnvString(envString: string): DockerRegistry {
const dockerRegexResultArray = envString.split('|');
if (dockerRegexResultArray.length !== 3) {
logger.log('error', 'malformed docker env var...');
throw new Error('malformed docker env var, expected format: registryUrl|username|password');
}
const registryUrl = dockerRegexResultArray[0].replace('https://', '').replace('http://', '');
const username = dockerRegexResultArray[1];
const password = dockerRegexResultArray[2];
return new DockerRegistry({
registryUrl: registryUrl,
username: username,
password: password,
});
}
/**
* Creates a DockerRegistry from environment variables
* Looks for DOCKER_REGISTRY, DOCKER_REGISTRY_USER, DOCKER_REGISTRY_PASSWORD
* Or for a specific registry: DOCKER_REGISTRY_<NAME>, etc.
*/
public static fromEnv(registryName?: string): DockerRegistry | null {
const prefix = registryName ? `DOCKER_REGISTRY_${registryName.toUpperCase()}_` : 'DOCKER_REGISTRY_';
const registryUrl = process.env[`${prefix}URL`] || process.env['DOCKER_REGISTRY'];
const username = process.env[`${prefix}USER`] || process.env['DOCKER_REGISTRY_USER'];
const password = process.env[`${prefix}PASSWORD`] || process.env['DOCKER_REGISTRY_PASSWORD'];
if (!registryUrl || !username || !password) {
return null;
}
return new DockerRegistry({
registryUrl: registryUrl.replace('https://', '').replace('http://', ''),
username,
password,
});
}
/**
* Logs in to the Docker registry
*/
public async login(): Promise<void> {
if (this.registryUrl === 'docker.io') {
await smartshellInstance.exec(`docker login -u ${this.username} -p ${this.password}`);
logger.log('info', 'Logged in to standard docker hub');
} else {
await smartshellInstance.exec(`docker login -u ${this.username} -p ${this.password} ${this.registryUrl}`);
}
logger.log('ok', `docker authenticated for ${this.registryUrl}!`);
}
/**
* Logs out from the Docker registry
*/
public async logout(): Promise<void> {
if (this.registryUrl === 'docker.io') {
await smartshellInstance.exec('docker logout');
} else {
await smartshellInstance.exec(`docker logout ${this.registryUrl}`);
}
logger.log('info', `logged out from ${this.registryUrl}`);
}
}

View File

@@ -0,0 +1,83 @@
import * as plugins from './tsdocker.plugins.js';
import { logger } from './tsdocker.logging.js';
import { DockerRegistry } from './classes.dockerregistry.js';
/**
* Storage class for managing multiple Docker registries
*/
export class RegistryStorage {
public objectMap = new plugins.lik.ObjectMap<DockerRegistry>();
constructor() {
// Nothing here
}
/**
* Adds a registry to the storage
*/
public addRegistry(registryArg: DockerRegistry): void {
this.objectMap.add(registryArg);
}
/**
* Gets a registry by its URL
*/
public getRegistryByUrl(registryUrlArg: string): DockerRegistry | undefined {
return this.objectMap.findSync((registryArg) => {
return registryArg.registryUrl === registryUrlArg;
});
}
/**
* Gets all registries
*/
public getAllRegistries(): DockerRegistry[] {
return this.objectMap.getArray();
}
/**
* Logs in to all registries
*/
public async loginAll(): Promise<void> {
await this.objectMap.forEach(async (registryArg) => {
await registryArg.login();
});
logger.log('success', 'logged in successfully into all available DockerRegistries!');
}
/**
* Logs out from all registries
*/
public async logoutAll(): Promise<void> {
await this.objectMap.forEach(async (registryArg) => {
await registryArg.logout();
});
logger.log('info', 'logged out from all DockerRegistries');
}
/**
* Loads registries from environment variables
* Looks for DOCKER_REGISTRY_1, DOCKER_REGISTRY_2, etc. (pipe-delimited format)
* Or individual registries like DOCKER_REGISTRY_GITLAB_URL, etc.
*/
public loadFromEnv(): void {
// Check for numbered registry env vars (pipe-delimited format)
for (let i = 1; i <= 10; i++) {
const envVar = process.env[`DOCKER_REGISTRY_${i}`];
if (envVar) {
try {
const registry = DockerRegistry.fromEnvString(envVar);
this.addRegistry(registry);
} catch (err) {
logger.log('warn', `Failed to parse DOCKER_REGISTRY_${i}: ${(err as Error).message}`);
}
}
}
// Check for default registry
const defaultRegistry = DockerRegistry.fromEnv();
if (defaultRegistry) {
this.addRegistry(defaultRegistry);
}
}
}

View File

@@ -0,0 +1,254 @@
import * as plugins from './tsdocker.plugins.js';
import * as paths from './tsdocker.paths.js';
import { logger } from './tsdocker.logging.js';
import { Dockerfile } from './classes.dockerfile.js';
import { DockerRegistry } from './classes.dockerregistry.js';
import { RegistryStorage } from './classes.registrystorage.js';
import type { ITsDockerConfig } from './interfaces/index.js';
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
});
/**
* Main orchestrator class for Docker operations
*/
export class TsDockerManager {
public registryStorage: RegistryStorage;
public config: ITsDockerConfig;
public projectInfo: any;
private dockerfiles: Dockerfile[] = [];
constructor(config: ITsDockerConfig) {
this.config = config;
this.registryStorage = new RegistryStorage();
}
/**
* Prepares the manager by loading project info and registries
*/
public async prepare(): Promise<void> {
// Load project info
try {
const projectinfoInstance = new plugins.projectinfo.ProjectInfo(paths.cwd);
this.projectInfo = {
npm: {
name: projectinfoInstance.npm.name,
version: projectinfoInstance.npm.version,
},
};
} catch (err) {
logger.log('warn', 'Could not load project info');
this.projectInfo = null;
}
// Load registries from environment
this.registryStorage.loadFromEnv();
// Add registries from config if specified
if (this.config.registries) {
for (const registryUrl of this.config.registries) {
// Check if already loaded from env
if (!this.registryStorage.getRegistryByUrl(registryUrl)) {
// Try to load credentials for this registry from env
const envVarName = registryUrl.replace(/\./g, '_').toUpperCase();
const envString = process.env[`DOCKER_REGISTRY_${envVarName}`];
if (envString) {
try {
const registry = DockerRegistry.fromEnvString(envString);
this.registryStorage.addRegistry(registry);
} catch (err) {
logger.log('warn', `Could not load credentials for registry ${registryUrl}`);
}
}
}
}
}
logger.log('info', `Prepared TsDockerManager with ${this.registryStorage.getAllRegistries().length} registries`);
}
/**
* Logs in to all configured registries
*/
public async login(): Promise<void> {
if (this.registryStorage.getAllRegistries().length === 0) {
logger.log('warn', 'No registries configured');
return;
}
await this.registryStorage.loginAll();
}
/**
* Discovers and sorts Dockerfiles in the current directory
*/
public async discoverDockerfiles(): Promise<Dockerfile[]> {
this.dockerfiles = await Dockerfile.readDockerfiles(this);
this.dockerfiles = await Dockerfile.sortDockerfiles(this.dockerfiles);
this.dockerfiles = await Dockerfile.mapDockerfiles(this.dockerfiles);
return this.dockerfiles;
}
/**
* Builds all discovered Dockerfiles in dependency order
*/
public async build(): Promise<Dockerfile[]> {
if (this.dockerfiles.length === 0) {
await this.discoverDockerfiles();
}
if (this.dockerfiles.length === 0) {
logger.log('warn', 'No Dockerfiles found');
return [];
}
// Check if buildx is needed
if (this.config.platforms && this.config.platforms.length > 1) {
await this.ensureBuildx();
}
logger.log('info', `Building ${this.dockerfiles.length} Dockerfiles...`);
await Dockerfile.buildDockerfiles(this.dockerfiles);
logger.log('success', 'All Dockerfiles built successfully');
return this.dockerfiles;
}
/**
* Ensures Docker buildx is set up for multi-architecture builds
*/
private async ensureBuildx(): Promise<void> {
logger.log('info', 'Setting up Docker buildx for multi-platform builds...');
// Check if a buildx builder exists
const inspectResult = await smartshellInstance.exec('docker buildx inspect tsdocker-builder 2>/dev/null');
if (inspectResult.exitCode !== 0) {
// Create a new buildx builder
logger.log('info', 'Creating new buildx builder...');
await smartshellInstance.exec('docker buildx create --name tsdocker-builder --use');
await smartshellInstance.exec('docker buildx inspect --bootstrap');
} else {
// Use existing builder
await smartshellInstance.exec('docker buildx use tsdocker-builder');
}
logger.log('ok', 'Docker buildx ready');
}
/**
* Pushes all built images to specified registries
*/
public async push(registryUrls?: string[]): Promise<void> {
if (this.dockerfiles.length === 0) {
await this.discoverDockerfiles();
}
if (this.dockerfiles.length === 0) {
logger.log('warn', 'No Dockerfiles found to push');
return;
}
// Determine which registries to push to
let registriesToPush: DockerRegistry[] = [];
if (registryUrls && registryUrls.length > 0) {
// Push to specified registries
for (const url of registryUrls) {
const registry = this.registryStorage.getRegistryByUrl(url);
if (registry) {
registriesToPush.push(registry);
} else {
logger.log('warn', `Registry ${url} not found in storage`);
}
}
} else {
// Push to all configured registries
registriesToPush = this.registryStorage.getAllRegistries();
}
if (registriesToPush.length === 0) {
logger.log('warn', 'No registries available to push to');
return;
}
// Push each Dockerfile to each registry
for (const dockerfile of this.dockerfiles) {
for (const registry of registriesToPush) {
await dockerfile.push(registry);
}
}
logger.log('success', 'All images pushed successfully');
}
/**
* Pulls images from a specified registry
*/
public async pull(registryUrl: string): Promise<void> {
if (this.dockerfiles.length === 0) {
await this.discoverDockerfiles();
}
const registry = this.registryStorage.getRegistryByUrl(registryUrl);
if (!registry) {
throw new Error(`Registry ${registryUrl} not found`);
}
for (const dockerfile of this.dockerfiles) {
await dockerfile.pull(registry);
}
logger.log('success', 'All images pulled successfully');
}
/**
* Runs tests for all Dockerfiles
*/
public async test(): Promise<void> {
if (this.dockerfiles.length === 0) {
await this.discoverDockerfiles();
}
if (this.dockerfiles.length === 0) {
logger.log('warn', 'No Dockerfiles found to test');
return;
}
await Dockerfile.testDockerfiles(this.dockerfiles);
logger.log('success', 'All tests completed');
}
/**
* Lists all discovered Dockerfiles and their info
*/
public async list(): Promise<Dockerfile[]> {
if (this.dockerfiles.length === 0) {
await this.discoverDockerfiles();
}
console.log('\nDiscovered Dockerfiles:');
console.log('========================\n');
for (let i = 0; i < this.dockerfiles.length; i++) {
const df = this.dockerfiles[i];
console.log(`${i + 1}. ${df.filePath}`);
console.log(` Tag: ${df.cleanTag}`);
console.log(` Base Image: ${df.baseImage}`);
console.log(` Version: ${df.version}`);
if (df.localBaseImageDependent) {
console.log(` Depends on: ${df.localBaseDockerfile?.cleanTag}`);
}
console.log('');
}
return this.dockerfiles;
}
/**
* Gets the cached Dockerfiles (after discovery)
*/
public getDockerfiles(): Dockerfile[] {
return this.dockerfiles;
}
}

View File

@@ -1,4 +1,4 @@
import * as plugins from './npmdocker.plugins'; import * as plugins from './tsdocker.plugins.js';
import * as cli from './npmdocker.cli'; import * as cli from './tsdocker.cli.js';
cli.run(); cli.run();

70
ts/interfaces/index.ts Normal file
View File

@@ -0,0 +1,70 @@
/**
* Configuration interface for tsdocker
* Extends legacy config with new Docker build capabilities
*/
export interface ITsDockerConfig {
// Legacy (backward compatible)
baseImage: string;
command: string;
dockerSock: boolean;
keyValueObject: { [key: string]: any };
// New Docker build config
registries?: string[];
registryRepoMap?: { [registry: string]: string };
buildArgEnvMap?: { [dockerArg: string]: string };
platforms?: string[]; // ['linux/amd64', 'linux/arm64']
push?: boolean;
testDir?: string;
}
/**
* Options for constructing a DockerRegistry
*/
export interface IDockerRegistryOptions {
registryUrl: string;
username: string;
password: string;
}
/**
* Information about a discovered Dockerfile
*/
export interface IDockerfileInfo {
filePath: string;
fileName: string;
version: string;
baseImage: string;
buildTag: string;
localBaseImageDependent: boolean;
}
/**
* Options for creating a Dockerfile instance
*/
export interface IDockerfileOptions {
filePath?: string;
fileContents?: string;
read?: boolean;
}
/**
* Result from a Docker build operation
*/
export interface IBuildResult {
success: boolean;
tag: string;
duration?: number;
error?: string;
}
/**
* Result from a Docker push operation
*/
export interface IPushResult {
success: boolean;
registry: string;
tag: string;
digest?: string;
error?: string;
}

View File

@@ -1,86 +0,0 @@
import * as plugins from './npmdocker.plugins';
import * as paths from './npmdocker.paths';
// modules
import * as ConfigModule from './npmdocker.config';
import * as DockerModule from './npmdocker.docker';
/**
* smartanalytics
* this data is fully anonymized (no Ips or any other personal information is tracked).
* It just keeps track which of our tools are really used...
* ... so we know where to spend our limited resources for improving them.
* Since yarn is out and there is heavy caching going on,
* pure download stats are just not reliable enough for us anymore
* Feel free to dig into the smartanalytics package, if you are interested in how it works.
* Our privacy policy can be found here: https://lossless.gmbh/privacy.html
*/
let npmdockerAnalytics = new plugins.smartanalytics.Analytics({
apiEndPoint: 'https://pubapi.lossless.one',
appName: 'npmdocker',
projectId: 'gitzone'
});
npmdockerAnalytics.recordEvent('npmtoolexecution', {
somedata: 'somedata'
});
let npmdockerCli = new plugins.smartcli.Smartcli();
export let run = () => {
npmdockerCli.standardTask().then(async argvArg => {
plugins.beautylog.figletSync('npmdocker');
let configArg = await ConfigModule.run().then(DockerModule.run);
if (configArg.exitCode === 0) {
plugins.beautylog.success('container ended all right!');
} else {
plugins.beautylog.error(`container ended with error! Exit Code is ${configArg.exitCode}`);
process.exit(1);
}
});
/**
* this command is executed inside docker and meant for use from outside docker
*/
npmdockerCli.addCommand('runinside').then(async argvArg => {
plugins.beautylog.ok('Allright. We are now in Docker!');
plugins.beautylog.log('now trying to run your specified command');
let configArg = await ConfigModule.run();
await plugins.smartshell.exec(configArg.command).then(response => {
if (response.exitCode !== 0) {
process.exit(1);
}
});
});
npmdockerCli.addCommand('clean').then(async argvArg => {
plugins.beautylog.ora.start();
plugins.beautylog.ora.text('cleaning up docker env...');
if (argvArg.all) {
plugins.beautylog.ora.text('killing any running docker containers...');
await plugins.smartshell.exec(`docker kill $(docker ps -q)`);
plugins.beautylog.ora.text('removing stopped containers...');
await plugins.smartshell.exec(`docker rm $(docker ps -a -q)`);
plugins.beautylog.ora.text('removing images...');
await plugins.smartshell.exec(`docker rmi $(docker images -q -f dangling=true)`);
plugins.beautylog.ora.text('removing all other images...');
await plugins.smartshell.exec(`docker rmi $(docker images -a -q)`);
plugins.beautylog.ora.text('removing all volumes...');
await plugins.smartshell.exec(`docker volume rm $(docker volume ls -f dangling=true -q)`);
}
plugins.beautylog.ora.endOk('docker environment now is clean!');
});
npmdockerCli.addCommand('speedtest').then(async argvArg => {
plugins.beautylog.figletSync('npmdocker');
plugins.beautylog.ok('Starting speedtest');
await plugins.smartshell.exec(
`docker pull tianon/speedtest && docker run --rm tianon/speedtest`
);
});
npmdockerCli.startParse();
};

View File

@@ -1,40 +0,0 @@
import * as plugins from './npmdocker.plugins';
import * as paths from './npmdocker.paths';
// interfaces
import { IKeyValueObject } from 'qenv';
export interface IConfig {
baseImage: string;
command: string;
dockerSock: boolean;
exitCode?: number;
keyValueObjectArray: IKeyValueObject[];
}
let getQenvKeyValueObject = async () => {
let qenvKeyValueObjectArray: IKeyValueObject[];
if (plugins.smartfile.fs.fileExistsSync(plugins.path.join(paths.cwd, 'qenv.yml'))) {
qenvKeyValueObjectArray = new plugins.qenv.Qenv(paths.cwd, '.nogit/').keyValueObjectArray;
} else {
qenvKeyValueObjectArray = [];
}
return qenvKeyValueObjectArray;
};
let buildConfig = async (qenvKeyValueObjectArrayArg: IKeyValueObject[]) => {
let npmextra = new plugins.npmextra.Npmextra(paths.cwd);
let config = npmextra.dataFor<IConfig>('npmdocker', {
baseImage: 'hosttoday/ht-docker-node:npmdocker',
init: 'rm -rf node_nodules/ && yarn install',
command: 'npmci npm test',
dockerSock: false,
keyValueObjectArray: qenvKeyValueObjectArrayArg
});
return config;
};
export let run = async (): Promise<IConfig> => {
let config = await getQenvKeyValueObject().then(buildConfig);
return config;
};

View File

@@ -1,163 +0,0 @@
import * as plugins from './npmdocker.plugins';
import * as paths from './npmdocker.paths';
import * as snippets from './npmdocker.snippets';
// interfaces
import { IConfig } from './npmdocker.config';
let config: IConfig;
/**
* the docker data used to build the internal testing container
*/
let dockerData = {
imageTag: 'npmdocker-temp-image:latest',
containerName: 'npmdocker-temp-container',
dockerProjectMountString: '',
dockerSockString: '',
dockerEnvString: ''
};
/**
* check if docker is available
*/
let checkDocker = () => {
let done = plugins.q.defer();
plugins.beautylog.ora.text('checking docker...');
if (plugins.smartshell.which('docker')) {
plugins.beautylog.ok('Docker found!');
done.resolve();
} else {
done.reject(new Error('docker not found on this machine'));
}
return done.promise;
};
/**
* builds the Dockerfile according to the config in the project
*/
let buildDockerFile = () => {
let done = plugins.q.defer();
plugins.beautylog.ora.text('building Dockerfile...');
let dockerfile: string = snippets.dockerfileSnippet({
baseImage: config.baseImage,
command: config.command
});
plugins.beautylog.info(`Base image is: ${config.baseImage}`);
plugins.beautylog.info(`Command is: ${config.command}`);
plugins.smartfile.memory.toFsSync(dockerfile, plugins.path.join(paths.cwd, 'npmdocker'));
plugins.beautylog.ok('Dockerfile created!');
plugins.beautylog.ora.stop();
done.resolve();
return done.promise;
};
/**
* builds the Dockerimage from the built Dockerfile
*/
let buildDockerImage = async () => {
plugins.beautylog.info('pulling latest base image from registry...');
await plugins.smartshell.exec(`docker pull ${config.baseImage}`);
plugins.beautylog.ora.text('building Dockerimage...');
let execResult = await plugins.smartshell.execSilent(
`docker build -f npmdocker -t ${dockerData.imageTag} ${paths.cwd}`
);
if (execResult.exitCode !== 0) {
console.log(execResult.stdout);
process.exit(1);
}
plugins.beautylog.ok('Dockerimage built!');
};
let buildDockerProjectMountString = async () => {
if (process.env.CI !== 'true') {
dockerData.dockerProjectMountString = `-v ${paths.cwd}:/workspace`;
}
};
/**
* builds an environment string that docker cli understands
*/
let buildDockerEnvString = async () => {
for (let keyValueObjectArg of config.keyValueObjectArray) {
let envString = (dockerData.dockerEnvString =
dockerData.dockerEnvString + `-e ${keyValueObjectArg.key}=${keyValueObjectArg.value} `);
}
};
/**
* creates string to mount the docker.sock inside the testcontainer
*/
let buildDockerSockString = async () => {
if (config.dockerSock) {
dockerData.dockerSockString = `-v /var/run/docker.sock:/var/run/docker.sock`;
}
};
/**
* creates a container by running the built Dockerimage
*/
let runDockerImage = async () => {
let done = plugins.q.defer();
plugins.beautylog.ora.text('starting Container...');
plugins.beautylog.ora.end();
plugins.beautylog.log('now running Dockerimage');
config.exitCode = (await plugins.smartshell.exec(
`docker run ${dockerData.dockerProjectMountString} ${dockerData.dockerSockString} ${
dockerData.dockerEnvString
} --name ${dockerData.containerName} ${dockerData.imageTag}`
)).exitCode;
};
/**
* cleans up: deletes the test container
*/
let deleteDockerContainer = async () => {
await plugins.smartshell.execSilent(`docker rm -f ${dockerData.containerName}`);
};
/**
* cleans up deletes the test image
*/
let deleteDockerImage = async () => {
await plugins.smartshell.execSilent(`docker rmi ${dockerData.imageTag}`).then(async response => {
if (response.exitCode !== 0) {
console.log(response.stdout);
}
});
};
let preClean = async () => {
await deleteDockerImage()
.then(deleteDockerContainer)
.then(async () => {
plugins.beautylog.ok('ensured clean Docker environment!');
});
};
let postClean = async () => {
await deleteDockerContainer()
.then(deleteDockerImage)
.then(async () => {
plugins.beautylog.ok('cleaned up!');
});
plugins.smartfile.fs.removeSync(paths.npmdockerFile);
};
export let run = async (configArg: IConfig): Promise<IConfig> => {
plugins.beautylog.ora.start();
config = configArg;
let resultConfig = await checkDocker()
.then(preClean)
.then(buildDockerFile)
.then(buildDockerImage)
.then(buildDockerProjectMountString)
.then(buildDockerEnvString)
.then(buildDockerSockString)
.then(runDockerImage)
.then(postClean)
.catch(err => {
console.log(err);
});
return config;
};

View File

@@ -1,8 +0,0 @@
import * as plugins from './npmdocker.plugins';
// directories
export let cwd = process.cwd();
export let packageBase = plugins.path.join(__dirname, '../');
export let assets = plugins.path.join(packageBase, 'assets/');
plugins.smartfile.fs.ensureDirSync(assets);
export let npmdockerFile = plugins.path.join(cwd, 'npmdocker');

View File

@@ -1,25 +0,0 @@
import * as beautylog from 'beautylog';
import * as npmextra from 'npmextra';
import * as path from 'path';
import * as projectinfo from 'projectinfo';
import * as q from 'smartq';
import * as qenv from 'qenv';
import * as smartanalytics from 'smartanalytics';
import * as smartcli from 'smartcli';
import * as smartfile from 'smartfile';
import * as smartshell from 'smartshell';
import * as smartstring from 'smartstring';
export {
beautylog,
npmextra,
path,
projectinfo,
q,
qenv,
smartanalytics,
smartcli,
smartfile,
smartshell,
smartstring
};

203
ts/tsdocker.cli.ts Normal file
View File

@@ -0,0 +1,203 @@
import * as plugins from './tsdocker.plugins.js';
import * as paths from './tsdocker.paths.js';
// modules
import * as ConfigModule from './tsdocker.config.js';
import * as DockerModule from './tsdocker.docker.js';
import { logger, ora } from './tsdocker.logging.js';
import { TsDockerManager } from './classes.tsdockermanager.js';
const tsdockerCli = new plugins.smartcli.Smartcli();
export let run = () => {
// Default command: run tests in container (legacy behavior)
tsdockerCli.standardCommand().subscribe(async argvArg => {
const configArg = await ConfigModule.run().then(DockerModule.run);
if (configArg.exitCode === 0) {
logger.log('success', 'container ended all right!');
} else {
logger.log('error', `container ended with error! Exit Code is ${configArg.exitCode}`);
process.exit(1);
}
});
/**
* Build all Dockerfiles in dependency order
*/
tsdockerCli.addCommand('build').subscribe(async argvArg => {
try {
const config = await ConfigModule.run();
const manager = new TsDockerManager(config);
await manager.prepare();
await manager.build();
logger.log('success', 'Build completed successfully');
} catch (err) {
logger.log('error', `Build failed: ${(err as Error).message}`);
process.exit(1);
}
});
/**
* Push built images to configured registries
*/
tsdockerCli.addCommand('push').subscribe(async argvArg => {
try {
const config = await ConfigModule.run();
const manager = new TsDockerManager(config);
await manager.prepare();
// Login first
await manager.login();
// Build images first (if not already built)
await manager.build();
// Get registry from arguments if specified
const registryArg = argvArg._[1]; // e.g., tsdocker push registry.gitlab.com
const registries = registryArg ? [registryArg] : undefined;
await manager.push(registries);
logger.log('success', 'Push completed successfully');
} catch (err) {
logger.log('error', `Push failed: ${(err as Error).message}`);
process.exit(1);
}
});
/**
* Pull images from a specified registry
*/
tsdockerCli.addCommand('pull').subscribe(async argvArg => {
try {
const registryArg = argvArg._[1]; // e.g., tsdocker pull registry.gitlab.com
if (!registryArg) {
logger.log('error', 'Registry URL required. Usage: tsdocker pull <registry-url>');
process.exit(1);
}
const config = await ConfigModule.run();
const manager = new TsDockerManager(config);
await manager.prepare();
// Login first
await manager.login();
await manager.pull(registryArg);
logger.log('success', 'Pull completed successfully');
} catch (err) {
logger.log('error', `Pull failed: ${(err as Error).message}`);
process.exit(1);
}
});
/**
* Run container tests for all Dockerfiles
*/
tsdockerCli.addCommand('test').subscribe(async argvArg => {
try {
const config = await ConfigModule.run();
const manager = new TsDockerManager(config);
await manager.prepare();
// Build images first
await manager.build();
// Run tests
await manager.test();
logger.log('success', 'Tests completed successfully');
} catch (err) {
logger.log('error', `Tests failed: ${(err as Error).message}`);
process.exit(1);
}
});
/**
* Login to configured registries
*/
tsdockerCli.addCommand('login').subscribe(async argvArg => {
try {
const config = await ConfigModule.run();
const manager = new TsDockerManager(config);
await manager.prepare();
await manager.login();
logger.log('success', 'Login completed successfully');
} catch (err) {
logger.log('error', `Login failed: ${(err as Error).message}`);
process.exit(1);
}
});
/**
* List discovered Dockerfiles and their dependencies
*/
tsdockerCli.addCommand('list').subscribe(async argvArg => {
try {
const config = await ConfigModule.run();
const manager = new TsDockerManager(config);
await manager.prepare();
await manager.list();
} catch (err) {
logger.log('error', `List failed: ${(err as Error).message}`);
process.exit(1);
}
});
/**
* this command is executed inside docker and meant for use from outside docker
*/
tsdockerCli.addCommand('runinside').subscribe(async argvArg => {
logger.log('ok', 'Allright. We are now in Docker!');
ora.text('now trying to run your specified command');
const configArg = await ConfigModule.run();
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash'
});
ora.stop();
await smartshellInstance.exec(configArg.command).then(response => {
if (response.exitCode !== 0) {
process.exit(1);
}
});
});
tsdockerCli.addCommand('clean').subscribe(async argvArg => {
ora.text('cleaning up docker env...');
if (argvArg.all) {
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash'
});
ora.text('killing any running docker containers...');
await smartshellInstance.exec(`docker kill $(docker ps -q)`);
ora.text('removing stopped containers...');
await smartshellInstance.exec(`docker rm $(docker ps -a -q)`);
ora.text('removing images...');
await smartshellInstance.exec(`docker rmi -f $(docker images -q -f dangling=true)`);
ora.text('removing all other images...');
await smartshellInstance.exec(`docker rmi $(docker images -a -q)`);
ora.text('removing all volumes...');
await smartshellInstance.exec(`docker volume rm $(docker volume ls -f dangling=true -q)`);
}
ora.finishSuccess('docker environment now is clean!');
});
tsdockerCli.addCommand('vscode').subscribe(async argvArg => {
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash'
});
logger.log('ok', `Starting vscode in cwd ${paths.cwd}`);
await smartshellInstance.execAndWaitForLine(
`docker run -p 127.0.0.1:8443:8443 -v "${
paths.cwd
}:/home/coder/project" registry.gitlab.com/hosttoday/ht-docker-vscode --allow-http --no-auth`,
/Connected to shared process/
);
await plugins.smartopen.openUrl('testing-vscode.git.zone:8443');
});
tsdockerCli.startParse();
};

45
ts/tsdocker.config.ts Normal file
View File

@@ -0,0 +1,45 @@
import * as plugins from './tsdocker.plugins.js';
import * as paths from './tsdocker.paths.js';
import * as fs from 'fs';
import type { ITsDockerConfig } from './interfaces/index.js';
// Re-export ITsDockerConfig as IConfig for backward compatibility
export type IConfig = ITsDockerConfig & {
exitCode?: number;
};
const getQenvKeyValueObject = async () => {
let qenvKeyValueObjectArray: { [key: string]: string | number };
if (fs.existsSync(plugins.path.join(paths.cwd, 'qenv.yml'))) {
qenvKeyValueObjectArray = new plugins.qenv.Qenv(paths.cwd, '.nogit/').keyValueObject;
} else {
qenvKeyValueObjectArray = {};
}
return qenvKeyValueObjectArray;
};
const buildConfig = async (qenvKeyValueObjectArg: { [key: string]: string | number }) => {
const npmextra = new plugins.npmextra.Npmextra(paths.cwd);
const config = npmextra.dataFor<IConfig>('@git.zone/tsdocker', {
// Legacy options (backward compatible)
baseImage: 'hosttoday/ht-docker-node:npmdocker',
init: 'rm -rf node_nodules/ && yarn install',
command: 'npmci npm test',
dockerSock: false,
keyValueObject: qenvKeyValueObjectArg,
// New Docker build options
registries: [],
registryRepoMap: {},
buildArgEnvMap: {},
platforms: ['linux/amd64'],
push: false,
testDir: undefined,
});
return config;
};
export let run = async (): Promise<IConfig> => {
const config = await getQenvKeyValueObject().then(buildConfig);
return config;
};

169
ts/tsdocker.docker.ts Normal file
View File

@@ -0,0 +1,169 @@
import * as plugins from './tsdocker.plugins.js';
import * as paths from './tsdocker.paths.js';
import * as snippets from './tsdocker.snippets.js';
import { logger, ora } from './tsdocker.logging.js';
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash'
});
// interfaces
import type { IConfig } from './tsdocker.config.js';
let config: IConfig;
/**
* the docker data used to build the internal testing container
*/
const dockerData = {
imageTag: 'npmdocker-temp-image:latest',
containerName: 'npmdocker-temp-container',
dockerProjectMountString: '',
dockerSockString: '',
dockerEnvString: ''
};
/**
* check if docker is available
*/
const checkDocker = () => {
const done = plugins.smartpromise.defer();
ora.text('checking docker...');
if (smartshellInstance.exec('which docker')) {
logger.log('ok', 'Docker found!');
done.resolve();
} else {
done.reject(new Error('docker not found on this machine'));
}
return done.promise;
};
/**
* builds the Dockerfile according to the config in the project
*/
const buildDockerFile = async () => {
const done = plugins.smartpromise.defer();
ora.text('building Dockerfile...');
const dockerfile: string = snippets.dockerfileSnippet({
baseImage: config.baseImage,
command: config.command
});
logger.log('info', `Base image is: ${config.baseImage}`);
logger.log('info', `Command is: ${config.command}`);
await plugins.smartfs.file(plugins.path.join(paths.cwd, 'npmdocker')).write(dockerfile);
logger.log('ok', 'Dockerfile created!');
ora.stop();
done.resolve();
return done.promise;
};
/**
* builds the Dockerimage from the built Dockerfile
*/
const buildDockerImage = async () => {
logger.log('info', 'pulling latest base image from registry...');
await smartshellInstance.exec(`docker pull ${config.baseImage}`);
ora.text('building Dockerimage...');
const execResult = await smartshellInstance.execSilent(
`docker build --load -f npmdocker -t ${dockerData.imageTag} ${paths.cwd}`
);
if (execResult.exitCode !== 0) {
console.log(execResult.stdout);
process.exit(1);
}
logger.log('ok', 'Dockerimage built!');
};
const buildDockerProjectMountString = async () => {
if (process.env.CI !== 'true') {
dockerData.dockerProjectMountString = `-v ${paths.cwd}:/workspace`;
}
};
/**
* builds an environment string that docker cli understands
*/
const buildDockerEnvString = async () => {
for (const key of Object.keys(config.keyValueObject)) {
const envString = (dockerData.dockerEnvString =
dockerData.dockerEnvString + `-e ${key}=${config.keyValueObject[key]} `);
}
};
/**
* creates string to mount the docker.sock inside the testcontainer
*/
const buildDockerSockString = async () => {
if (config.dockerSock) {
dockerData.dockerSockString = `-v /var/run/docker.sock:/var/run/docker.sock`;
}
};
/**
* creates a container by running the built Dockerimage
*/
const runDockerImage = async () => {
const done = plugins.smartpromise.defer();
ora.text('starting Container...');
ora.stop();
logger.log('info', 'now running Dockerimage');
config.exitCode = (await smartshellInstance.exec(
`docker run ${dockerData.dockerProjectMountString} ${dockerData.dockerSockString} ${
dockerData.dockerEnvString
} --name ${dockerData.containerName} ${dockerData.imageTag}`
)).exitCode;
};
/**
* cleans up: deletes the test container
*/
const deleteDockerContainer = async () => {
await smartshellInstance.execSilent(`docker rm -f ${dockerData.containerName}`);
};
/**
* cleans up deletes the test image
*/
const deleteDockerImage = async () => {
await smartshellInstance.execSilent(`docker rmi ${dockerData.imageTag}`).then(async response => {
if (response.exitCode !== 0) {
console.log(response.stdout);
}
});
};
const preClean = async () => {
await deleteDockerImage()
.then(deleteDockerContainer)
.then(async () => {
logger.log('ok', 'ensured clean Docker environment!');
});
};
const postClean = async () => {
await deleteDockerContainer()
.then(deleteDockerImage)
.then(async () => {
logger.log('ok', 'cleaned up!');
});
await plugins.smartfs.file(paths.npmdockerFile).delete();
};
export let run = async (configArg: IConfig): Promise<IConfig> => {
config = configArg;
const resultConfig = await checkDocker()
.then(preClean)
.then(buildDockerFile)
.then(buildDockerImage)
.then(buildDockerProjectMountString)
.then(buildDockerEnvString)
.then(buildDockerSockString)
.then(runDockerImage)
.then(postClean)
.catch(err => {
console.log(err);
});
return config;
};

17
ts/tsdocker.logging.ts Normal file
View File

@@ -0,0 +1,17 @@
import * as plugins from './tsdocker.plugins.js';
export const logger = new plugins.smartlog.Smartlog({
logContext: {
company: 'Some Company',
companyunit: 'Some CompanyUnit',
containerName: 'Some Containername',
environment: 'local',
runtime: 'node',
zone: 'gitzone'
},
minimumLogLevel: 'silly'
});
logger.addLogDestination(new plugins.smartlogDestinationLocal.DestinationLocal());
export const ora = new plugins.smartlogSouceOra.SmartlogSourceOra();

14
ts/tsdocker.paths.ts Normal file
View File

@@ -0,0 +1,14 @@
import * as plugins from './tsdocker.plugins.js';
import * as fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// directories
export let cwd = process.cwd();
export let packageBase = plugins.path.join(__dirname, '../');
export let assets = plugins.path.join(packageBase, 'assets/');
fs.mkdirSync(assets, { recursive: true });
export let npmdockerFile = plugins.path.join(cwd, 'npmdocker');

34
ts/tsdocker.plugins.ts Normal file
View File

@@ -0,0 +1,34 @@
// push.rocks scope
import * as lik from '@push.rocks/lik';
import * as npmextra from '@push.rocks/npmextra';
import * as path from 'path';
import * as projectinfo from '@push.rocks/projectinfo';
import * as smartpromise from '@push.rocks/smartpromise';
import * as qenv from '@push.rocks/qenv';
import * as smartcli from '@push.rocks/smartcli';
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
import * as smartlog from '@push.rocks/smartlog';
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
import * as smartlogSouceOra from '@push.rocks/smartlog-source-ora';
import * as smartopen from '@push.rocks/smartopen';
import * as smartshell from '@push.rocks/smartshell';
import * as smartstring from '@push.rocks/smartstring';
// Create smartfs instance
export const smartfs = new SmartFs(new SmartFsProviderNode());
export {
lik,
npmextra,
path,
projectinfo,
smartpromise,
qenv,
smartcli,
smartlog,
smartlogDestinationLocal,
smartlogSouceOra,
smartopen,
smartshell,
smartstring
};

View File

@@ -1,4 +1,4 @@
import * as plugins from './npmdocker.plugins'; import * as plugins from './tsdocker.plugins.js';
export interface IDockerfileSnippet { export interface IDockerfileSnippet {
baseImage: string; baseImage: string;
@@ -14,23 +14,20 @@ let getMountSolutionString = (optionsArg: IDockerfileSnippet) => {
}; };
let getGlobalPreparationString = (optionsArg: IDockerfileSnippet) => { let getGlobalPreparationString = (optionsArg: IDockerfileSnippet) => {
if (optionsArg.baseImage !== 'hosttoday/ht-docker-node:npmdocker') { // Always install tsdocker to ensure the latest version is available
return 'RUN yarn global add npmdocker'; return 'RUN npm install -g @git.zone/tsdocker';
} else {
return '# not installing npmdocker since it is included in the base image';
}
}; };
export let dockerfileSnippet = (optionsArg: IDockerfileSnippet): string => { export let dockerfileSnippet = (optionsArg: IDockerfileSnippet): string => {
return plugins.smartstring.indent.normalize( return plugins.smartstring.indent.normalize(
` `
FROM ${optionsArg.baseImage} FROM ${optionsArg.baseImage}
# For info about what npmdocker does read the docs at https://gitzone.github.io/npmdocker # For info about what tsdocker does read the docs at https://gitzone.github.io/tsdocker
${getGlobalPreparationString(optionsArg)} ${getGlobalPreparationString(optionsArg)}
${getMountSolutionString(optionsArg)} ${getMountSolutionString(optionsArg)}
WORKDIR /workspace WORKDIR /workspace
ENV CI=true ENV CI=true
ENTRYPOINT ["npmdocker"] ENTRYPOINT ["tsdocker"]
CMD ["runinside"] CMD ["runinside"]
` `
); );

12
tsconfig.json Normal file
View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"baseUrl": ".",
"paths": {}
},
"exclude": ["dist_*/**/*.d.ts"]
}

View File

@@ -1,3 +0,0 @@
{
"extends": "tslint-config-standard"
}

1258
yarn.lock

File diff suppressed because it is too large Load Diff