Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 36f06cef09 | |||
| b0f87deb4b | |||
| 9805324746 | |||
| 808066d8c3 | |||
| 6922d19454 | |||
| e1492f8ec4 | |||
| e9a12f1c17 | |||
| 6995010a2c | |||
| e0cbc9cfec | |||
| c538e6b10b |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
name: Default (not tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags-ignore:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
IMAGE: 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
|
||||
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal 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
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -3,7 +3,6 @@
|
||||
# artifacts
|
||||
coverage/
|
||||
public/
|
||||
pages/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
@@ -15,9 +14,11 @@ node_modules/
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_web/
|
||||
dist_serve/
|
||||
dist_ts_web/
|
||||
dist_*/
|
||||
|
||||
# custom
|
||||
# AI
|
||||
.claude/
|
||||
.serena/
|
||||
|
||||
#------# custom
|
||||
test
|
||||
|
||||
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
25
.vscode/settings.json
vendored
25
.vscode/settings.json
vendored
@@ -1,3 +1,26 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM hosttoday/ht-docker-node:npmci
|
||||
RUN yarn global add @gitzone/tsdocker
|
||||
RUN yarn global add @git.zone/tsdocker
|
||||
COPY ./ /workspace
|
||||
WORKDIR /workspace
|
||||
ENV CI=true
|
||||
|
||||
114
changelog.md
114
changelog.md
@@ -1,15 +1,69 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-01-21 - 1.4.2 - fix(classes.dockerfile)
|
||||
use a single top-level fs import instead of requiring fs inside methods
|
||||
|
||||
- Added top-level import: import * as fs from 'fs' in ts/classes.dockerfile.ts
|
||||
- Removed inline require('fs') calls and replaced with the imported fs in constructor and test() to keep imports consistent
|
||||
- No behavioral change expected; this is a cleanup/refactor to standardize module usage
|
||||
|
||||
## 2026-01-20 - 1.4.1 - fix(docs)
|
||||
update README: expand usage, installation, quick start, features, troubleshooting and migration notes
|
||||
|
||||
- Expanded README content: new Quick Start, Installation examples, and detailed Features section (containerized testing, smart Docker builds, multi-registry push, multi-architecture support, zero-config start)
|
||||
- Added troubleshooting and performance tips including registry login guidance and circular dependency advice
|
||||
- Updated migration notes from legacy npmdocker to @git.zone/tsdocker (command and config key changes, ESM guidance)
|
||||
- Documentation-only change — no source code modified
|
||||
|
||||
## 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
|
||||
- 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
|
||||
@@ -18,269 +72,322 @@ Migrate to @git.zone / @push.rocks packages, replace smartfile with smartfs and
|
||||
- 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 @gitzone npm scope.
|
||||
- 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.
|
||||
@@ -288,6 +395,7 @@ Early project refinements and Docker integration.
|
||||
- Updated Docker handling and removed test artifacts.
|
||||
|
||||
## 2016-07-13 - 1.0.0 - initial
|
||||
|
||||
Initial release.
|
||||
|
||||
- Added README and initial project scaffolding.
|
||||
2
cli.js
Normal file → Executable file
2
cli.js
Normal file → Executable file
@@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
process.env.CLI_CALL = 'true';
|
||||
require('./dist/index');
|
||||
import('./dist_ts/index.js');
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
process.env.CLI_CALL = 'true';
|
||||
require('@git.zone/tsrun');
|
||||
require('./ts/index');
|
||||
@@ -3,18 +3,25 @@
|
||||
"mode": "default",
|
||||
"cli": true
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
},
|
||||
"gitzone": {
|
||||
"@git.zone/cli": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "gitzone",
|
||||
"gitrepo": "npmdocker",
|
||||
"shortDescription": "develop npm modules cross platform with docker",
|
||||
"npmPackagename": "@gitzone/npmdocker",
|
||||
"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": []
|
||||
}
|
||||
}
|
||||
28061
package-lock.json
generated
28061
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
@@ -1,27 +1,28 @@
|
||||
{
|
||||
"name": "@gitzone/tsdocker",
|
||||
"version": "1.2.42",
|
||||
"name": "@git.zone/tsdocker",
|
||||
"version": "1.4.2",
|
||||
"private": false,
|
||||
"description": "develop npm modules cross platform with docker",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"bin": {
|
||||
"tsdocker": "cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "(npm run clean && npm run setupCheck && npm run testStandard && npm run testSpeed)",
|
||||
"test": "(npm run build)",
|
||||
"build": "(tsbuild)",
|
||||
"testStandard": "(cd test/ && node ../cli.ts.js)",
|
||||
"testSpeed": "(cd test/ && node ../cli.ts.js speedtest)",
|
||||
"testClean": "(cd test/ && node ../cli.ts.js clean --all)",
|
||||
"testVscode": "(cd test/ && node ../cli.ts.js vscode)",
|
||||
"testIntegration": "(npm run clean && npm run setupCheck && npm run testStandard)",
|
||||
"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/)",
|
||||
"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": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@gitlab.com/gitzone/npmdocker.git"
|
||||
"url": "https://gitlab.com/gitzone/tsdocker.git"
|
||||
},
|
||||
"keywords": [
|
||||
"docker"
|
||||
@@ -29,22 +30,23 @@
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://gitlab.com/gitzone/npmdocker/issues"
|
||||
"url": "https://gitlab.com/gitzone/tsdocker/issues"
|
||||
},
|
||||
"homepage": "https://gitlab.com/gitzone/npmdocker#README",
|
||||
"homepage": "https://gitlab.com/gitzone/tsdocker#readme",
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^3.1.0",
|
||||
"@git.zone/tsrun": "^2.0.0",
|
||||
"@git.zone/tstest": "^3.1.3",
|
||||
"@types/node": "^22.10.2"
|
||||
"@git.zone/tsbuild": "^4.1.2",
|
||||
"@git.zone/tsrun": "^2.0.1",
|
||||
"@git.zone/tstest": "^3.1.6",
|
||||
"@types/node": "^25.0.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"@push.rocks/lik": "^6.2.2",
|
||||
"@push.rocks/npmextra": "^5.3.3",
|
||||
"@push.rocks/projectinfo": "^5.0.2",
|
||||
"@push.rocks/qenv": "^6.1.3",
|
||||
"@push.rocks/smartanalytics": "^2.0.15",
|
||||
"@push.rocks/smartcli": "^4.0.19",
|
||||
"@push.rocks/smartfs": "^1.1.0",
|
||||
"@push.rocks/smartcli": "^4.0.20",
|
||||
"@push.rocks/smartfs": "^1.3.1",
|
||||
"@push.rocks/smartlog": "^3.1.10",
|
||||
"@push.rocks/smartlog-destination-local": "^9.0.2",
|
||||
"@push.rocks/smartlog-source-ora": "^1.0.9",
|
||||
@@ -53,5 +55,21 @@
|
||||
"@push.rocks/smartshell": "^3.3.0",
|
||||
"@push.rocks/smartstring": "^4.1.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34"
|
||||
"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": {}
|
||||
}
|
||||
}
|
||||
|
||||
395
pnpm-lock.yaml
generated
395
pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@push.rocks/lik':
|
||||
specifier: ^6.2.2
|
||||
version: 6.2.2
|
||||
'@push.rocks/npmextra':
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3
|
||||
@@ -21,11 +24,11 @@ importers:
|
||||
specifier: ^2.0.15
|
||||
version: 2.0.15
|
||||
'@push.rocks/smartcli':
|
||||
specifier: ^4.0.19
|
||||
version: 4.0.19
|
||||
specifier: ^4.0.20
|
||||
version: 4.0.20
|
||||
'@push.rocks/smartfs':
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1
|
||||
'@push.rocks/smartlog':
|
||||
specifier: ^3.1.10
|
||||
version: 3.1.10
|
||||
@@ -49,17 +52,17 @@ importers:
|
||||
version: 4.1.0
|
||||
devDependencies:
|
||||
'@git.zone/tsbuild':
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
specifier: ^4.1.2
|
||||
version: 4.1.2
|
||||
'@git.zone/tsrun':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
specifier: ^2.0.1
|
||||
version: 2.0.1
|
||||
'@git.zone/tstest':
|
||||
specifier: ^3.1.3
|
||||
version: 3.1.3(socks@2.8.7)(typescript@5.9.3)
|
||||
specifier: ^3.1.6
|
||||
version: 3.1.6(socks@2.8.7)(typescript@5.9.3)
|
||||
'@types/node':
|
||||
specifier: ^22.10.2
|
||||
version: 22.19.1
|
||||
specifier: ^25.0.9
|
||||
version: 25.0.9
|
||||
|
||||
packages:
|
||||
|
||||
@@ -285,174 +288,330 @@ packages:
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.2':
|
||||
resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.2':
|
||||
resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.2':
|
||||
resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.2':
|
||||
resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.2':
|
||||
resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.2':
|
||||
resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.2':
|
||||
resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.2':
|
||||
resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.2':
|
||||
resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.2':
|
||||
resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.2':
|
||||
resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.2':
|
||||
resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.2':
|
||||
resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.2':
|
||||
resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.2':
|
||||
resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.2':
|
||||
resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.2':
|
||||
resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.2':
|
||||
resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@git.zone/tsbuild@3.1.0':
|
||||
resolution: {integrity: sha512-j8lMd84pmzWiU6NG3e+pyu0o41oo6mQVfcZv8kDsCrQwZMhoQV9Jp87MlU0i/XI5IZkqDjelG8Kx1QhOmbK+iQ==}
|
||||
'@esbuild/win32-x64@0.27.2':
|
||||
resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@git.zone/tsbuild@4.1.2':
|
||||
resolution: {integrity: sha512-S518ulKveO76pS6jrAELrnFaCw5nDAIZD9j6QzVmLYDiZuJmlRwPK3/2E8ugQ+b7ffpkwJ9MT685ooEGDcWQ4Q==}
|
||||
hasBin: true
|
||||
|
||||
'@git.zone/tsbundle@2.5.2':
|
||||
resolution: {integrity: sha512-EYTCfunqoxhxkowREZ+cJnww6eDh9cL18HJbHbSZ+vxzNeyS9x8mT9aqRlWkI7zgpvgDlGIYlyRUlUISXkQO6Q==}
|
||||
hasBin: true
|
||||
|
||||
'@git.zone/tspublish@1.10.3':
|
||||
resolution: {integrity: sha512-o2/jvNsdLC8SRdH1kQ7JjNOQNu9el0FpJ/QOW3mgiC5C9reuTp18iU4kijsVVLgvw4KZv6Z289SoKPh3HPsS0g==}
|
||||
'@git.zone/tspublish@1.11.0':
|
||||
resolution: {integrity: sha512-dkgaDBTzZJ53lAV72r7OW/W7l/KqpkncFuPojr11JO35OKAbjjDhZbAwPv4oGX9NplyXrhC5VJRPNX/orqNTHA==}
|
||||
hasBin: true
|
||||
|
||||
'@git.zone/tsrun@2.0.0':
|
||||
resolution: {integrity: sha512-yA6zCjL+kn7xfZe6sL/m4K+zYqgkznG/pF6++i/E17iwzpG6dHmW+VZmYldHe86sW4DcLMvqM6CxM+KlgaEpKw==}
|
||||
'@git.zone/tsrun@2.0.1':
|
||||
resolution: {integrity: sha512-NEcnsjvlC1o3Z6SS3VhKCf6Ev+Sh4EAinmggslrIR/ppMrvjDbXNFXoyr3PB+GLeSAR0JRZ1fGvVYjpEzjBdIg==}
|
||||
hasBin: true
|
||||
|
||||
'@git.zone/tstest@3.1.3':
|
||||
resolution: {integrity: sha512-t+/cKV21JHK8X7NGAmihs5M/eMm+V+jn4R5rzfwGG97WJFAcP5qE1Os9VYtyZw3tx/NZXA2yA4abo/ELluTuRA==}
|
||||
'@git.zone/tstest@3.1.6':
|
||||
resolution: {integrity: sha512-xRGc6wO4rJ6mohPCMIBDRH+oNjiIvX6Jeo8v/Y5o5VyKSHFmqol7FCKSBrojMcqgBpESnLHFPJAAOmT9W3JV8Q==}
|
||||
hasBin: true
|
||||
|
||||
'@happy-dom/global-registrator@15.11.7':
|
||||
@@ -624,9 +783,10 @@ packages:
|
||||
|
||||
'@push.rocks/smartchok@1.1.1':
|
||||
resolution: {integrity: sha512-WmNigGmn1muBJMANVuJb4F8x3TzgYrnn6YZm6ixTsG+0WFbYevivEwp+J4S7npobLHsR7ynf+Ky8LxRYmsL50A==}
|
||||
deprecated: This package has been renamed. Please use @push.rocks/smartwatch instead.
|
||||
|
||||
'@push.rocks/smartcli@4.0.19':
|
||||
resolution: {integrity: sha512-s1jZSgDZWi/az26AY4TJ2HPuG1qZzGC5R9fKWaECLmwnSpk6y9JXL5dnJAUohcdu50kdXCWEcRmLfYxOt81vEA==}
|
||||
'@push.rocks/smartcli@4.0.20':
|
||||
resolution: {integrity: sha512-gCo4ItvsPj8WoVAJw/6vkuoGA5FtIoACux2ktcCeH0nrFe7/xGR6waJ1aZcYAi7QN4gi52TlsgwuKz7BzXqhmQ==}
|
||||
|
||||
'@push.rocks/smartclickhouse@2.0.17':
|
||||
resolution: {integrity: sha512-IYO8Obor/Ruam2KQ2B/+5uQ+rL0exU5KZoSgOc3jkkrfjn+zZenN2xoV8lVqavAtxZVfG7MfxFrcv6I7I9ZMmA==}
|
||||
@@ -670,8 +830,11 @@ packages:
|
||||
'@push.rocks/smartfile@11.2.7':
|
||||
resolution: {integrity: sha512-8Yp7/sAgPpWJBHohV92ogHWKzRomI5MEbSG6b5W2n18tqwfAmjMed0rQvsvGrSBlnEWCKgoOrYIIZbLO61+J0Q==}
|
||||
|
||||
'@push.rocks/smartfs@1.1.0':
|
||||
resolution: {integrity: sha512-fg8JIjFUPPX5laRoBpTaGwhMfZ3Y8mFT4fUaW54Y4J/BfOBa/y0+rIFgvgvqcOZgkQlyZU+FIfL8Z6zezqxyTg==}
|
||||
'@push.rocks/smartfile@13.1.2':
|
||||
resolution: {integrity: sha512-DaEhwmnGEpX4coeeToaw4cZe3pNBhH7CY1iGr+d3pIXihozREvzzAR9/0i2r7bUXXL5+Lgy8YYIk5ZS+fwxMKA==}
|
||||
|
||||
'@push.rocks/smartfs@1.3.1':
|
||||
resolution: {integrity: sha512-ZSduVS8tM+/erbyCTvRRvc9gLWwbpqN5xdIIkMr+gub7fowSeJb7tR2rnGwySa63DyimU0q2KTp79VV9YqGLeg==}
|
||||
|
||||
'@push.rocks/smartguard@3.1.0':
|
||||
resolution: {integrity: sha512-J23q84f1O+TwFGmd4lrO9XLHUh2DaLXo9PN/9VmTWYzTkQDv5JehmifXVI0esophXcCIfbdIu6hbt7/aHlDF4A==}
|
||||
@@ -1363,6 +1526,9 @@ packages:
|
||||
'@types/node@22.19.1':
|
||||
resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==}
|
||||
|
||||
'@types/node@25.0.9':
|
||||
resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==}
|
||||
|
||||
'@types/ping@0.4.4':
|
||||
resolution: {integrity: sha512-ifvo6w2f5eJYlXm+HiVx67iJe8WZp87sfa683nlqED5Vnt9Z93onkokNoWqOG21EaE8fMxyKPobE+mkPEyxsdw==}
|
||||
|
||||
@@ -1914,6 +2080,11 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.27.2:
|
||||
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
escalade@3.2.0:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -3301,8 +3472,8 @@ packages:
|
||||
tslib@2.8.1:
|
||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||
|
||||
tsx@4.20.6:
|
||||
resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==}
|
||||
tsx@4.21.0:
|
||||
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -3353,6 +3524,9 @@ packages:
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
unified@11.0.5:
|
||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||
|
||||
@@ -4153,88 +4327,167 @@ snapshots:
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@git.zone/tsbuild@3.1.0':
|
||||
'@esbuild/win32-x64@0.27.2':
|
||||
optional: true
|
||||
|
||||
'@git.zone/tsbuild@4.1.2':
|
||||
dependencies:
|
||||
'@git.zone/tspublish': 1.10.3
|
||||
'@git.zone/tspublish': 1.11.0
|
||||
'@push.rocks/early': 4.0.4
|
||||
'@push.rocks/smartcli': 4.0.19
|
||||
'@push.rocks/smartcli': 4.0.20
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartfile': 11.2.7
|
||||
'@push.rocks/smartfile': 13.1.2
|
||||
'@push.rocks/smartfs': 1.3.1
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
'@push.rocks/smartpath': 6.0.0
|
||||
'@push.rocks/smartpromise': 4.2.3
|
||||
@@ -4251,7 +4504,7 @@ snapshots:
|
||||
'@git.zone/tsbundle@2.5.2':
|
||||
dependencies:
|
||||
'@push.rocks/early': 4.0.4
|
||||
'@push.rocks/smartcli': 4.0.19
|
||||
'@push.rocks/smartcli': 4.0.20
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartfile': 11.2.7
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
@@ -4269,16 +4522,18 @@ snapshots:
|
||||
- '@swc/helpers'
|
||||
- supports-color
|
||||
|
||||
'@git.zone/tspublish@1.10.3':
|
||||
'@git.zone/tspublish@1.11.0':
|
||||
dependencies:
|
||||
'@push.rocks/consolecolor': 2.0.3
|
||||
'@push.rocks/smartcli': 4.0.19
|
||||
'@push.rocks/npmextra': 5.3.3
|
||||
'@push.rocks/smartcli': 4.0.20
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartfile': 11.2.7
|
||||
'@push.rocks/smartfile': 13.1.2
|
||||
'@push.rocks/smartfs': 1.3.1
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
'@push.rocks/smartnpm': 2.0.6
|
||||
'@push.rocks/smartpath': 6.0.0
|
||||
'@push.rocks/smartrequest': 4.4.2
|
||||
'@push.rocks/smartrequest': 5.0.1
|
||||
'@push.rocks/smartshell': 3.3.0
|
||||
transitivePeerDependencies:
|
||||
- '@nuxt/kit'
|
||||
@@ -4289,17 +4544,17 @@ snapshots:
|
||||
- supports-color
|
||||
- vue
|
||||
|
||||
'@git.zone/tsrun@2.0.0':
|
||||
'@git.zone/tsrun@2.0.1':
|
||||
dependencies:
|
||||
'@push.rocks/smartfile': 11.2.7
|
||||
'@push.rocks/smartfile': 13.1.2
|
||||
'@push.rocks/smartshell': 3.3.0
|
||||
tsx: 4.20.6
|
||||
tsx: 4.21.0
|
||||
|
||||
'@git.zone/tstest@3.1.3(socks@2.8.7)(typescript@5.9.3)':
|
||||
'@git.zone/tstest@3.1.6(socks@2.8.7)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@api.global/typedserver': 3.0.80
|
||||
'@git.zone/tsbundle': 2.5.2
|
||||
'@git.zone/tsrun': 2.0.0
|
||||
'@git.zone/tsrun': 2.0.1
|
||||
'@push.rocks/consolecolor': 2.0.3
|
||||
'@push.rocks/qenv': 6.1.3
|
||||
'@push.rocks/smartbrowser': 2.0.8(typescript@5.9.3)
|
||||
@@ -4727,7 +4982,7 @@ snapshots:
|
||||
chokidar: 4.0.3
|
||||
picomatch: 4.0.3
|
||||
|
||||
'@push.rocks/smartcli@4.0.19':
|
||||
'@push.rocks/smartcli@4.0.20':
|
||||
dependencies:
|
||||
'@push.rocks/lik': 6.2.2
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
@@ -4870,7 +5125,24 @@ snapshots:
|
||||
glob: 11.1.0
|
||||
js-yaml: 4.1.1
|
||||
|
||||
'@push.rocks/smartfs@1.1.0':
|
||||
'@push.rocks/smartfile@13.1.2':
|
||||
dependencies:
|
||||
'@push.rocks/lik': 6.2.2
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartfile-interfaces': 1.0.7
|
||||
'@push.rocks/smartfs': 1.3.1
|
||||
'@push.rocks/smarthash': 3.2.6
|
||||
'@push.rocks/smartjson': 5.2.0
|
||||
'@push.rocks/smartmime': 2.0.4
|
||||
'@push.rocks/smartpath': 6.0.0
|
||||
'@push.rocks/smartpromise': 4.2.3
|
||||
'@push.rocks/smartrequest': 4.4.2
|
||||
'@push.rocks/smartstream': 3.2.5
|
||||
'@types/js-yaml': 4.0.9
|
||||
glob: 11.1.0
|
||||
js-yaml: 4.1.1
|
||||
|
||||
'@push.rocks/smartfs@1.3.1':
|
||||
dependencies:
|
||||
'@push.rocks/smartpath': 6.0.0
|
||||
|
||||
@@ -5936,6 +6208,10 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/node@25.0.9':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
'@types/ping@0.4.4': {}
|
||||
|
||||
'@types/qs@6.14.0': {}
|
||||
@@ -6504,6 +6780,35 @@ snapshots:
|
||||
'@esbuild/win32-ia32': 0.25.12
|
||||
'@esbuild/win32-x64': 0.25.12
|
||||
|
||||
esbuild@0.27.2:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.2
|
||||
'@esbuild/android-arm': 0.27.2
|
||||
'@esbuild/android-arm64': 0.27.2
|
||||
'@esbuild/android-x64': 0.27.2
|
||||
'@esbuild/darwin-arm64': 0.27.2
|
||||
'@esbuild/darwin-x64': 0.27.2
|
||||
'@esbuild/freebsd-arm64': 0.27.2
|
||||
'@esbuild/freebsd-x64': 0.27.2
|
||||
'@esbuild/linux-arm': 0.27.2
|
||||
'@esbuild/linux-arm64': 0.27.2
|
||||
'@esbuild/linux-ia32': 0.27.2
|
||||
'@esbuild/linux-loong64': 0.27.2
|
||||
'@esbuild/linux-mips64el': 0.27.2
|
||||
'@esbuild/linux-ppc64': 0.27.2
|
||||
'@esbuild/linux-riscv64': 0.27.2
|
||||
'@esbuild/linux-s390x': 0.27.2
|
||||
'@esbuild/linux-x64': 0.27.2
|
||||
'@esbuild/netbsd-arm64': 0.27.2
|
||||
'@esbuild/netbsd-x64': 0.27.2
|
||||
'@esbuild/openbsd-arm64': 0.27.2
|
||||
'@esbuild/openbsd-x64': 0.27.2
|
||||
'@esbuild/openharmony-arm64': 0.27.2
|
||||
'@esbuild/sunos-x64': 0.27.2
|
||||
'@esbuild/win32-arm64': 0.27.2
|
||||
'@esbuild/win32-ia32': 0.27.2
|
||||
'@esbuild/win32-x64': 0.27.2
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-html@1.0.3: {}
|
||||
@@ -8259,9 +8564,9 @@ snapshots:
|
||||
|
||||
tslib@2.8.1: {}
|
||||
|
||||
tsx@4.20.6:
|
||||
tsx@4.21.0:
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
esbuild: 0.27.2
|
||||
get-tsconfig: 4.13.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
@@ -8298,6 +8603,8 @@ snapshots:
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
unified@11.0.5:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
127
readme.hints.md
127
readme.hints.md
@@ -1,34 +1,109 @@
|
||||
# tsdocker Project Hints
|
||||
|
||||
## Module Purpose
|
||||
tsdocker is a tool for developing npm modules cross-platform using Docker. It allows testing in clean, reproducible Linux environments locally.
|
||||
|
||||
## Recent Upgrades (2025-11-22)
|
||||
- Updated all @gitzone/* dependencies to @git.zone/* scope (latest versions)
|
||||
- Updated all @pushrocks/* dependencies to @push.rocks/* scope (latest versions)
|
||||
- Migrated from smartfile v8 to smartfs v1.1.0
|
||||
- All filesystem operations now use smartfs fluent API
|
||||
- Operations are now async (smartfs is async-only)
|
||||
- Updated dev dependencies:
|
||||
- @git.zone/tsbuild: ^3.1.0
|
||||
- @git.zone/tsrun: ^2.0.0
|
||||
- @git.zone/tstest: ^3.1.3
|
||||
- Removed @pushrocks/tapbundle (now use @git.zone/tstest/tapbundle)
|
||||
- Updated @types/node to ^22.10.2
|
||||
- Removed tslint and tslint-config-prettier (no longer needed)
|
||||
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)
|
||||
|
||||
## SmartFS Migration Details
|
||||
The following operations were converted:
|
||||
- `smartfile.fs.fileExistsSync()` → Node.js `fs.existsSync()` (for sync needs)
|
||||
- `smartfile.fs.ensureDirSync()` → Node.js `fs.mkdirSync(..., { recursive: true })`
|
||||
- `smartfile.memory.toFsSync()` → `smartfs.file(path).write(content)` (async)
|
||||
- `smartfile.fs.removeSync()` → `smartfs.file(path).delete()` (async)
|
||||
## New CLI Commands (2026-01-19)
|
||||
|
||||
## Test Status
|
||||
- Build: ✅ Passes
|
||||
- The integration test requires cloning an external test repository (sandbox-npmts)
|
||||
- The external test repo uses top-level await which requires ESM module handling
|
||||
- This is not a tsdocker issue but rather the test repository's structure
|
||||
| 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
|
||||
All dependencies are now at their latest versions compatible with Node.js without introducing new Node.js-specific 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
|
||||
|
||||
599
readme.md
599
readme.md
@@ -1,6 +1,6 @@
|
||||
# @gitzone/tsdocker
|
||||
# @git.zone/tsdocker
|
||||
|
||||
> 🐳 Cross-platform npm module development with Docker — test your packages in clean, reproducible Linux environments every time.
|
||||
> 🐳 The ultimate Docker development toolkit for TypeScript projects — build, test, and ship containerized applications with ease.
|
||||
|
||||
## Issue Reporting and Security
|
||||
|
||||
@@ -8,303 +8,472 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
||||
|
||||
## What is tsdocker?
|
||||
|
||||
**tsdocker** provides containerized testing environments for npm packages, ensuring your code works consistently across different systems. It's perfect for:
|
||||
**tsdocker** is a comprehensive Docker development and building tool that handles everything from testing npm packages in clean environments to building and pushing multi-architecture Docker images across multiple registries.
|
||||
|
||||
- 🧪 **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
|
||||
### 🎯 Key Capabilities
|
||||
|
||||
## 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 async/await patterns throughout
|
||||
- 🧪 **Containerized Testing** — Run your tests in pristine Docker environments
|
||||
- 🏗️ **Smart Docker Builds** — Automatically discover, sort, and build Dockerfiles by dependency
|
||||
- 🚀 **Multi-Registry Push** — Ship to Docker Hub, GitLab, GitHub Container Registry, and more
|
||||
- 🔧 **Multi-Architecture** — Build for `amd64` and `arm64` with Docker Buildx
|
||||
- ⚡ **Zero Config Start** — Works out of the box, scales with your needs
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gitzone/tsdocker
|
||||
# or
|
||||
pnpm install --save-dev @gitzone/tsdocker
|
||||
# Global installation (recommended for CLI usage)
|
||||
npm install -g @git.zone/tsdocker
|
||||
|
||||
# Or project-local installation
|
||||
pnpm install --save-dev @git.zone/tsdocker
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Configure Your Project
|
||||
### 🧪 Run Tests in Docker
|
||||
|
||||
Create an `npmextra.json` file in your project root:
|
||||
|
||||
```json
|
||||
{
|
||||
"npmdocker": {
|
||||
"baseImage": "hosttoday/ht-docker-node:npmts",
|
||||
"command": "npmci test stable",
|
||||
"dockerSock": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Run Your Tests
|
||||
The simplest use case — run your tests in a clean container:
|
||||
|
||||
```bash
|
||||
npx tsdocker
|
||||
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
|
||||
This pulls your configured base image, mounts your project, and executes your test command in isolation.
|
||||
|
||||
## Configuration Options
|
||||
### 🏗️ Build Docker Images
|
||||
|
||||
| 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 |
|
||||
Got `Dockerfile` files? Build them all with automatic dependency ordering:
|
||||
|
||||
### Environment Variables
|
||||
```bash
|
||||
tsdocker build
|
||||
```
|
||||
|
||||
If you have a `qenv.yml` file in your project, tsdocker automatically loads and injects those environment variables into your test container.
|
||||
tsdocker will:
|
||||
1. 🔍 Discover all `Dockerfile*` files in your project
|
||||
2. 📊 Analyze `FROM` dependencies between them
|
||||
3. 🔄 Sort them topologically
|
||||
4. 🏗️ Build each image in the correct order
|
||||
|
||||
Example `qenv.yml`:
|
||||
```yaml
|
||||
demoKey: demoValue
|
||||
API_KEY: your-key-here
|
||||
### 📤 Push to Registries
|
||||
|
||||
Ship your images to one or all configured registries:
|
||||
|
||||
```bash
|
||||
# Push to all configured registries
|
||||
tsdocker push
|
||||
|
||||
# Push to a specific registry
|
||||
tsdocker push registry.gitlab.com
|
||||
```
|
||||
|
||||
## CLI Commands
|
||||
|
||||
### Standard Test Run
|
||||
```bash
|
||||
tsdocker
|
||||
```
|
||||
Runs your configured test command in a fresh Docker container.
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `tsdocker` | Run tests in a fresh Docker container |
|
||||
| `tsdocker build` | Build all Dockerfiles with dependency ordering |
|
||||
| `tsdocker push [registry]` | Push images to configured registries |
|
||||
| `tsdocker pull <registry>` | Pull images from a specific registry |
|
||||
| `tsdocker test` | Run container test scripts (test_*.sh) |
|
||||
| `tsdocker login` | Authenticate with configured registries |
|
||||
| `tsdocker list` | Display discovered Dockerfiles and their dependencies |
|
||||
| `tsdocker clean --all` | ⚠️ Aggressively clean Docker environment |
|
||||
| `tsdocker vscode` | Launch containerized VS Code in browser |
|
||||
|
||||
### 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
|
||||
## Configuration
|
||||
|
||||
Use with caution!
|
||||
|
||||
### VSCode in Docker
|
||||
```bash
|
||||
tsdocker vscode
|
||||
```
|
||||
Launches a containerized VS Code instance accessible via browser at `testing-vscode.git.zone:8443`.
|
||||
|
||||
### Speed Test
|
||||
```bash
|
||||
tsdocker speedtest
|
||||
```
|
||||
Runs a network speed test inside a Docker container.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Docker-in-Docker Testing
|
||||
|
||||
If you need to run Docker commands inside your test container (e.g., testing Docker-related tools):
|
||||
Configure tsdocker in your `package.json` or `npmextra.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"npmdocker": {
|
||||
"@git.zone/tsdocker": {
|
||||
"baseImage": "node:20",
|
||||
"command": "npm test",
|
||||
"dockerSock": false,
|
||||
"registries": ["registry.gitlab.com", "docker.io"],
|
||||
"registryRepoMap": {
|
||||
"registry.gitlab.com": "myorg/myproject"
|
||||
},
|
||||
"buildArgEnvMap": {
|
||||
"NODE_VERSION": "NODE_VERSION"
|
||||
},
|
||||
"platforms": ["linux/amd64", "linux/arm64"],
|
||||
"push": false,
|
||||
"testDir": "./test"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
#### Testing Options (Legacy)
|
||||
|
||||
| Option | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `baseImage` | `string` | Docker image for test environment (default: `hosttoday/ht-docker-node:npmdocker`) |
|
||||
| `command` | `string` | Command to run inside container (default: `npmci npm test`) |
|
||||
| `dockerSock` | `boolean` | Mount Docker socket for DinD scenarios (default: `false`) |
|
||||
|
||||
#### Build & Push Options
|
||||
|
||||
| Option | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `registries` | `string[]` | Registry URLs to push to |
|
||||
| `registryRepoMap` | `object` | Map registries to different repository paths |
|
||||
| `buildArgEnvMap` | `object` | Map Docker build ARGs to environment variables |
|
||||
| `platforms` | `string[]` | Target architectures (default: `["linux/amd64"]`) |
|
||||
| `push` | `boolean` | Auto-push after build (default: `false`) |
|
||||
| `testDir` | `string` | Directory containing test scripts |
|
||||
|
||||
## Registry Authentication
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Pipe-delimited format (supports DOCKER_REGISTRY_1 through DOCKER_REGISTRY_10)
|
||||
export DOCKER_REGISTRY_1="registry.gitlab.com|username|password"
|
||||
export DOCKER_REGISTRY_2="docker.io|username|password"
|
||||
|
||||
# Individual registry format
|
||||
export DOCKER_REGISTRY_URL="registry.gitlab.com"
|
||||
export DOCKER_REGISTRY_USER="username"
|
||||
export DOCKER_REGISTRY_PASSWORD="password"
|
||||
```
|
||||
|
||||
### Login Command
|
||||
|
||||
```bash
|
||||
tsdocker login
|
||||
```
|
||||
|
||||
Authenticates with all configured registries.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### 🔀 Multi-Architecture Builds
|
||||
|
||||
Build for multiple platforms using Docker Buildx:
|
||||
|
||||
```json
|
||||
{
|
||||
"@git.zone/tsdocker": {
|
||||
"platforms": ["linux/amd64", "linux/arm64"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
tsdocker automatically sets up a Buildx builder when multiple platforms are specified.
|
||||
|
||||
### 📦 Dockerfile Naming Conventions
|
||||
|
||||
tsdocker discovers files matching `Dockerfile*`:
|
||||
|
||||
| File Name | Version Tag |
|
||||
|-----------|-------------|
|
||||
| `Dockerfile` | `latest` |
|
||||
| `Dockerfile_v1.0.0` | `v1.0.0` |
|
||||
| `Dockerfile_alpine` | `alpine` |
|
||||
| `Dockerfile_##version##` | Uses `package.json` version |
|
||||
|
||||
### 🔗 Dependency-Aware Builds
|
||||
|
||||
If you have multiple Dockerfiles that depend on each other:
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile_base
|
||||
FROM node:20-alpine
|
||||
RUN npm install -g typescript
|
||||
|
||||
# Dockerfile_app
|
||||
FROM myproject:base
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
```
|
||||
|
||||
tsdocker automatically detects that `Dockerfile_app` depends on `Dockerfile_base` and builds them in the correct order.
|
||||
|
||||
### 🧪 Container Test Scripts
|
||||
|
||||
Create test scripts in your test directory:
|
||||
|
||||
```bash
|
||||
# test/test_latest.sh
|
||||
#!/bin/bash
|
||||
node --version
|
||||
npm --version
|
||||
echo "Container tests passed!"
|
||||
```
|
||||
|
||||
Run with:
|
||||
|
||||
```bash
|
||||
tsdocker test
|
||||
```
|
||||
|
||||
### 🔧 Build Args from Environment
|
||||
|
||||
Pass environment variables as Docker build arguments:
|
||||
|
||||
```json
|
||||
{
|
||||
"@git.zone/tsdocker": {
|
||||
"buildArgEnvMap": {
|
||||
"NPM_TOKEN": "NPM_TOKEN",
|
||||
"NODE_VERSION": "NODE_VERSION"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```dockerfile
|
||||
ARG NPM_TOKEN
|
||||
ARG NODE_VERSION=20
|
||||
FROM node:${NODE_VERSION}
|
||||
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
||||
```
|
||||
|
||||
### 🐳 Docker-in-Docker Testing
|
||||
|
||||
Test Docker-related tools by mounting the Docker socket:
|
||||
|
||||
```json
|
||||
{
|
||||
"@git.zone/tsdocker": {
|
||||
"baseImage": "docker:latest",
|
||||
"command": "docker run hello-world",
|
||||
"command": "docker version && docker ps",
|
||||
"dockerSock": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Setting `"dockerSock": true` mounts the host's Docker socket into the container.
|
||||
### 📋 Listing Dockerfiles
|
||||
|
||||
### Custom Base Images
|
||||
Inspect your project's Dockerfiles and their relationships:
|
||||
|
||||
You can use any Docker image as your base:
|
||||
```bash
|
||||
tsdocker list
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
Discovered Dockerfiles:
|
||||
========================
|
||||
|
||||
1. Dockerfile_base
|
||||
Tag: myproject:base
|
||||
Base Image: node:20-alpine
|
||||
Version: base
|
||||
|
||||
2. Dockerfile_app
|
||||
Tag: myproject:app
|
||||
Base Image: myproject:base
|
||||
Version: app
|
||||
Depends on: myproject:base
|
||||
```
|
||||
|
||||
### 🗺️ Registry Repo Mapping
|
||||
|
||||
Use different repository names for different registries:
|
||||
|
||||
```json
|
||||
{
|
||||
"npmdocker": {
|
||||
"baseImage": "node:20-alpine",
|
||||
"command": "npm test"
|
||||
"@git.zone/tsdocker": {
|
||||
"registries": ["registry.gitlab.com", "docker.io"],
|
||||
"registryRepoMap": {
|
||||
"registry.gitlab.com": "mygroup/myproject",
|
||||
"docker.io": "myuser/myproject"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Popular choices:
|
||||
- `node:20` — Official Node.js images
|
||||
- `node:20-alpine` — Lightweight Alpine-based images
|
||||
- `hosttoday/ht-docker-node:npmts` — Pre-configured with npmts tooling
|
||||
## Environment Variables
|
||||
|
||||
### CI Integration
|
||||
### qenv Integration
|
||||
|
||||
tsdocker automatically detects CI environments (via `CI=true` env var) and adjusts behavior:
|
||||
- Skips mounting project directory in CI (assumes code is already in container)
|
||||
- Optimizes for CI execution patterns
|
||||
tsdocker automatically loads environment variables from `qenv.yml`:
|
||||
|
||||
## 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 { IConfig } from '@gitzone/tsdocker/dist/tsdocker.config';
|
||||
|
||||
const config: IConfig = {
|
||||
baseImage: 'node:20',
|
||||
command: 'npm test',
|
||||
dockerSock: false,
|
||||
keyValueObject: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
};
|
||||
```yaml
|
||||
# qenv.yml
|
||||
API_KEY: your-api-key
|
||||
DATABASE_URL: postgres://localhost/test
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Docker**: Docker must be installed and accessible via CLI
|
||||
- **Node.js**: Version 14 or higher recommended
|
||||
|
||||
## 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
|
||||
```
|
||||
These are injected into your test container automatically.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic npm test
|
||||
### Basic Test Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"npmdocker": {
|
||||
"@git.zone/tsdocker": {
|
||||
"baseImage": "node:20",
|
||||
"command": "npm test"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using npmci for multiple Node versions
|
||||
### Full Production Setup
|
||||
|
||||
```json
|
||||
{
|
||||
"npmdocker": {
|
||||
"baseImage": "hosttoday/ht-docker-node:npmts",
|
||||
"command": "npmci test stable"
|
||||
"@git.zone/tsdocker": {
|
||||
"baseImage": "node:20-alpine",
|
||||
"command": "pnpm test",
|
||||
"registries": ["registry.gitlab.com", "ghcr.io", "docker.io"],
|
||||
"registryRepoMap": {
|
||||
"registry.gitlab.com": "myorg/myapp",
|
||||
"ghcr.io": "myorg/myapp",
|
||||
"docker.io": "myuser/myapp"
|
||||
},
|
||||
"buildArgEnvMap": {
|
||||
"NPM_TOKEN": "NPM_TOKEN"
|
||||
},
|
||||
"platforms": ["linux/amd64", "linux/arm64"],
|
||||
"testDir": "./docker-tests"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Docker-based tools
|
||||
```json
|
||||
{
|
||||
"npmdocker": {
|
||||
"baseImage": "docker:latest",
|
||||
"command": "sh -c 'docker version && docker ps'",
|
||||
"dockerSock": true
|
||||
}
|
||||
}
|
||||
### CI/CD Integration
|
||||
|
||||
```yaml
|
||||
# .gitlab-ci.yml
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- npm install -g @git.zone/tsdocker
|
||||
- tsdocker build
|
||||
- tsdocker push
|
||||
|
||||
# GitHub Actions
|
||||
- name: Build and Push
|
||||
run: |
|
||||
npm install -g @git.zone/tsdocker
|
||||
tsdocker login
|
||||
tsdocker build
|
||||
tsdocker push
|
||||
env:
|
||||
DOCKER_REGISTRY_1: "ghcr.io|${{ github.actor }}|${{ secrets.GITHUB_TOKEN }}"
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Docker** — Docker Engine or Docker Desktop must be installed
|
||||
- **Node.js** — Version 18 or higher (ESM support required)
|
||||
- **Docker Buildx** — Required for multi-architecture builds (included in Docker Desktop)
|
||||
|
||||
## Why tsdocker?
|
||||
|
||||
### 🎯 The Problem
|
||||
|
||||
Managing Docker workflows manually is tedious:
|
||||
- Remembering build order for dependent images
|
||||
- Pushing to multiple registries with different credentials
|
||||
- Setting up Buildx for multi-arch builds
|
||||
- Ensuring consistent test environments
|
||||
|
||||
### ✨ The Solution
|
||||
|
||||
tsdocker automates the entire workflow:
|
||||
- **One command** to build all images in dependency order
|
||||
- **One command** to push to all registries
|
||||
- **Automatic** Buildx setup for multi-platform builds
|
||||
- **Consistent** containerized test environments
|
||||
|
||||
## TypeScript API
|
||||
|
||||
tsdocker exposes its types for programmatic use:
|
||||
|
||||
```typescript
|
||||
import type { ITsDockerConfig } from '@git.zone/tsdocker/dist_ts/interfaces/index.js';
|
||||
import { TsDockerManager } from '@git.zone/tsdocker/dist_ts/classes.tsdockermanager.js';
|
||||
|
||||
const config: ITsDockerConfig = {
|
||||
baseImage: 'node:20',
|
||||
command: 'npm test',
|
||||
dockerSock: false,
|
||||
keyValueObject: {},
|
||||
registries: ['docker.io'],
|
||||
platforms: ['linux/amd64'],
|
||||
};
|
||||
|
||||
const manager = new TsDockerManager(config);
|
||||
await manager.prepare();
|
||||
await manager.build();
|
||||
await manager.push();
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "docker not found"
|
||||
|
||||
Ensure Docker is installed and in your PATH:
|
||||
|
||||
```bash
|
||||
docker --version
|
||||
```
|
||||
|
||||
### Multi-arch build fails
|
||||
|
||||
Make sure Docker Buildx is available:
|
||||
|
||||
```bash
|
||||
docker buildx version
|
||||
docker buildx create --use
|
||||
```
|
||||
|
||||
### Registry authentication fails
|
||||
|
||||
Check your environment variables are set correctly:
|
||||
|
||||
```bash
|
||||
echo $DOCKER_REGISTRY_1
|
||||
tsdocker login
|
||||
```
|
||||
|
||||
### Circular dependency detected
|
||||
|
||||
Review your Dockerfiles' `FROM` statements — you have images depending on each other in a loop.
|
||||
|
||||
## 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
|
||||
🚀 **Use specific tags**: `node:20-alpine` is smaller and faster than `node:latest`
|
||||
|
||||
## Migration from @gitzone/npmdocker
|
||||
🚀 **Leverage caching**: Docker layers are cached — your builds get faster over time
|
||||
|
||||
This package was previously published as `@gitzone/npmdocker`. The scope has been updated to `@gitzone/tsdocker` for better naming consistency. Functionality remains the same.
|
||||
🚀 **Prune regularly**: `docker system prune` reclaims disk space
|
||||
|
||||
🚀 **Use .dockerignore**: Exclude `node_modules`, `.git`, etc. from build context
|
||||
|
||||
## Migration from Legacy
|
||||
|
||||
Previously published as `npmdocker`, now `@git.zone/tsdocker`:
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `npmdocker` command | `tsdocker` command |
|
||||
| `"npmdocker"` config key | `"@git.zone/tsdocker"` config key |
|
||||
| CommonJS | ESM with `.js` imports |
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
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 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, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
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
|
||||
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@gitzone/tsdocker',
|
||||
version: '1.2.42',
|
||||
name: '@git.zone/tsdocker',
|
||||
version: '1.4.2',
|
||||
description: 'develop npm modules cross platform with docker'
|
||||
}
|
||||
|
||||
461
ts/classes.dockerfile.ts
Normal file
461
ts/classes.dockerfile.ts
Normal file
@@ -0,0 +1,461 @@
|
||||
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';
|
||||
import * as fs from 'fs';
|
||||
|
||||
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) {
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
91
ts/classes.dockerregistry.ts
Normal file
91
ts/classes.dockerregistry.ts
Normal 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}`);
|
||||
}
|
||||
}
|
||||
83
ts/classes.registrystorage.ts
Normal file
83
ts/classes.registrystorage.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
254
ts/classes.tsdockermanager.ts
Normal file
254
ts/classes.tsdockermanager.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
import * as cli from './tsdocker.cli';
|
||||
import * as plugins from './tsdocker.plugins.js';
|
||||
import * as cli from './tsdocker.cli.js';
|
||||
|
||||
cli.run();
|
||||
|
||||
70
ts/interfaces/index.ts
Normal file
70
ts/interfaces/index.ts
Normal 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;
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
import * as paths from './tsdocker.paths';
|
||||
import * as plugins from './tsdocker.plugins.js';
|
||||
import * as paths from './tsdocker.paths.js';
|
||||
|
||||
// modules
|
||||
import * as ConfigModule from './tsdocker.config';
|
||||
import * as DockerModule from './tsdocker.docker';
|
||||
import * as ConfigModule from './tsdocker.config.js';
|
||||
import * as DockerModule from './tsdocker.docker.js';
|
||||
|
||||
import { logger, ora } from './tsdocker.logging';
|
||||
import { logger, ora } from './tsdocker.logging.js';
|
||||
import { TsDockerManager } from './classes.tsdockermanager.js';
|
||||
|
||||
const tsdockerCli = new plugins.smartcli.Smartcli();
|
||||
|
||||
export let run = () => {
|
||||
tsdockerCli.standardTask().subscribe(async argvArg => {
|
||||
// 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!');
|
||||
@@ -20,6 +22,127 @@ export let run = () => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -62,16 +185,6 @@ export let run = () => {
|
||||
ora.finishSuccess('docker environment now is clean!');
|
||||
});
|
||||
|
||||
tsdockerCli.addCommand('speedtest').subscribe(async argvArg => {
|
||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||
executor: 'bash'
|
||||
});
|
||||
logger.log('ok', 'Starting speedtest');
|
||||
await smartshellInstance.exec(
|
||||
`docker pull tianon/speedtest && docker run --rm tianon/speedtest --accept-license --accept-gdpr`
|
||||
);
|
||||
});
|
||||
|
||||
tsdockerCli.addCommand('vscode').subscribe(async argvArg => {
|
||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||
executor: 'bash'
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
import * as paths from './tsdocker.paths';
|
||||
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';
|
||||
|
||||
export interface IConfig {
|
||||
baseImage: string;
|
||||
command: string;
|
||||
dockerSock: boolean;
|
||||
// Re-export ITsDockerConfig as IConfig for backward compatibility
|
||||
export type IConfig = ITsDockerConfig & {
|
||||
exitCode?: number;
|
||||
keyValueObject: {[key: string]: any};
|
||||
}
|
||||
};
|
||||
|
||||
const getQenvKeyValueObject = async () => {
|
||||
let qenvKeyValueObjectArray: { [key: string]: string | number };
|
||||
@@ -22,12 +20,21 @@ const getQenvKeyValueObject = async () => {
|
||||
|
||||
const buildConfig = async (qenvKeyValueObjectArg: { [key: string]: string | number }) => {
|
||||
const npmextra = new plugins.npmextra.Npmextra(paths.cwd);
|
||||
const config = npmextra.dataFor<IConfig>('npmdocker', {
|
||||
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
|
||||
keyValueObject: qenvKeyValueObjectArg,
|
||||
|
||||
// New Docker build options
|
||||
registries: [],
|
||||
registryRepoMap: {},
|
||||
buildArgEnvMap: {},
|
||||
platforms: ['linux/amd64'],
|
||||
push: false,
|
||||
testDir: undefined,
|
||||
});
|
||||
return config;
|
||||
};
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
import * as paths from './tsdocker.paths';
|
||||
import * as snippets from './tsdocker.snippets';
|
||||
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';
|
||||
import { logger, ora } from './tsdocker.logging.js';
|
||||
|
||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||
executor: 'bash'
|
||||
});
|
||||
|
||||
// interfaces
|
||||
import { IConfig } from './tsdocker.config';
|
||||
import type { IConfig } from './tsdocker.config.js';
|
||||
|
||||
let config: IConfig;
|
||||
|
||||
@@ -67,7 +67,7 @@ const buildDockerImage = async () => {
|
||||
await smartshellInstance.exec(`docker pull ${config.baseImage}`);
|
||||
ora.text('building Dockerimage...');
|
||||
const execResult = await smartshellInstance.execSilent(
|
||||
`docker build -f npmdocker -t ${dockerData.imageTag} ${paths.cwd}`
|
||||
`docker build --load -f npmdocker -t ${dockerData.imageTag} ${paths.cwd}`
|
||||
);
|
||||
if (execResult.exitCode !== 0) {
|
||||
console.log(execResult.stdout);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
import * as plugins from './tsdocker.plugins.js';
|
||||
|
||||
export const logger = new plugins.smartlog.Smartlog({
|
||||
logContext: {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
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();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// 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';
|
||||
@@ -17,6 +18,7 @@ import * as smartstring from '@push.rocks/smartstring';
|
||||
export const smartfs = new SmartFs(new SmartFsProviderNode());
|
||||
|
||||
export {
|
||||
lik,
|
||||
npmextra,
|
||||
path,
|
||||
projectinfo,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as plugins from './tsdocker.plugins';
|
||||
import * as plugins from './tsdocker.plugins.js';
|
||||
|
||||
export interface IDockerfileSnippet {
|
||||
baseImage: string;
|
||||
@@ -14,23 +14,20 @@ let getMountSolutionString = (optionsArg: IDockerfileSnippet) => {
|
||||
};
|
||||
|
||||
let getGlobalPreparationString = (optionsArg: IDockerfileSnippet) => {
|
||||
if (optionsArg.baseImage !== 'hosttoday/ht-docker-node:npmdocker') {
|
||||
return 'RUN npm install -g npmdocker';
|
||||
} else {
|
||||
return '# not installing npmdocker since it is included in the base image';
|
||||
}
|
||||
// Always install tsdocker to ensure the latest version is available
|
||||
return 'RUN npm install -g @git.zone/tsdocker';
|
||||
};
|
||||
|
||||
export let dockerfileSnippet = (optionsArg: IDockerfileSnippet): string => {
|
||||
return plugins.smartstring.indent.normalize(
|
||||
`
|
||||
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)}
|
||||
${getMountSolutionString(optionsArg)}
|
||||
WORKDIR /workspace
|
||||
ENV CI=true
|
||||
ENTRYPOINT ["npmdocker"]
|
||||
ENTRYPOINT ["tsdocker"]
|
||||
CMD ["runinside"]
|
||||
`
|
||||
);
|
||||
|
||||
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {}
|
||||
},
|
||||
"exclude": ["dist_*/**/*.d.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user