Compare commits

...

4 Commits

Author SHA1 Message Date
6c8095260d 6.0.1
Some checks failed
Default (tags) / security (push) Failing after 22s
Default (tags) / test (push) Failing after 12s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-10-26 17:44:43 +00:00
95c4ae3b16 fix(tests): Migrate tests to Deno native runner and update Deno config 2025-10-26 17:44:43 +00:00
536ebca6ab 6.0.0
Some checks failed
Default (tags) / security (push) Failing after 22s
Default (tags) / test (push) Failing after 12s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-10-26 15:23:56 +00:00
88f64536c2 BREAKING CHANGE(szci): Rename project from npmci to szci and migrate runtime to Deno; add compiled binaries, installer and wrapper; update imports, env handling and package metadata 2025-10-26 15:23:56 +00:00
59 changed files with 1632 additions and 958 deletions

4
.gitignore vendored
View File

@@ -17,4 +17,8 @@ node_modules/
dist/
dist_*/
# deno
deno.lock
.deno/
# custom

1
.serena/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/cache

71
.serena/project.yml Normal file
View File

@@ -0,0 +1,71 @@
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
# * For C, use cpp
# * For JavaScript, use typescript
# Special requirements:
# * csharp: Requires the presence of a .sln file in the project folder.
language: typescript
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# whether to use the project's gitignore file to ignore files
# Added on 2025-04-07
ignore_all_files_in_gitignore: true
# list of additional paths to ignore
# same syntax as gitignore, so you can use * and **
# Was previously called `ignored_dirs`, please update your config if you are using that.
# Added (renamed) on 2025-04-07
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
project_name: "npmci"

108
bin/szci-wrapper.js Executable file
View File

@@ -0,0 +1,108 @@
#!/usr/bin/env node
/**
* SZCI npm wrapper
* This script executes the appropriate pre-compiled binary based on the current platform
*/
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { existsSync } from 'fs';
import { platform, arch } from 'os';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
/**
* Get the binary name for the current platform
*/
function getBinaryName() {
const plat = platform();
const architecture = arch();
// Map Node's platform/arch to our binary naming
const platformMap = {
'darwin': 'macos',
'linux': 'linux',
'win32': 'windows'
};
const archMap = {
'x64': 'x64',
'arm64': 'arm64'
};
const mappedPlatform = platformMap[plat];
const mappedArch = archMap[architecture];
if (!mappedPlatform || !mappedArch) {
console.error(`Error: Unsupported platform/architecture: ${plat}/${architecture}`);
console.error('Supported platforms: Linux, macOS, Windows');
console.error('Supported architectures: x64, arm64');
process.exit(1);
}
// Construct binary name
let binaryName = `szci-${mappedPlatform}-${mappedArch}`;
if (plat === 'win32') {
binaryName += '.exe';
}
return binaryName;
}
/**
* Execute the binary
*/
function executeBinary() {
const binaryName = getBinaryName();
const binaryPath = join(__dirname, '..', 'dist', 'binaries', binaryName);
// Check if binary exists
if (!existsSync(binaryPath)) {
console.error(`Error: Binary not found at ${binaryPath}`);
console.error('This might happen if:');
console.error('1. The postinstall script failed to run');
console.error('2. The platform is not supported');
console.error('3. The package was not installed correctly');
console.error('');
console.error('Try reinstalling the package:');
console.error(' npm uninstall -g @ship.zone/szci');
console.error(' npm install -g @ship.zone/szci');
process.exit(1);
}
// Spawn the binary with all arguments passed through
const child = spawn(binaryPath, process.argv.slice(2), {
stdio: 'inherit',
shell: false
});
// Handle child process events
child.on('error', (err) => {
console.error(`Error executing szci: ${err.message}`);
process.exit(1);
});
child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code || 0);
}
});
// Forward signals to child process
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
signals.forEach(signal => {
process.on(signal, () => {
if (!child.killed) {
child.kill(signal);
}
});
});
}
// Execute
executeBinary();

View File

@@ -1,5 +1,27 @@
# Changelog
## 2025-10-26 - 6.0.1 - fix(tests)
Migrate tests to Deno native runner and update Deno config
- Convert test suites from tap/tapbundle to Deno.test and @std/assert
- Replace CommonJS-style runtime imports with .ts module imports for Deno (test files updated)
- Use Deno.env.set to configure test environment variables and restore working directory after tests
- Update test/test.cloudly.ts to import CloudlyConnector directly and disable TLS verification for tests
- Adjust deno.json version field (6.0.0 -> 5.0.0) as part of Deno configuration changes
- Add local project .claude/settings.local.json for tooling permissions
## 2025-10-26 - 6.0.0 - BREAKING CHANGE(szci)
Rename project from npmci to szci and migrate runtime to Deno; add compiled binaries, installer and wrapper; update imports, env handling and package metadata
- Major rename/refactor: Npmci -> Szci across the codebase (classes, filenames, modules and exports).
- Migrate runtime to Deno: add deno.json, mod.ts entry point, use Deno.std imports and .ts module imports throughout.
- Add compilation and distribution tooling: scripts/compile-all.sh, scripts/install-binary.js, bin/szci-wrapper.js and dist/binaries layout for prebuilt executables.
- Package metadata updated: package.json renamed/rewritten for @ship.zone/szci and bumped to 5.0.0, updated publishConfig, files and scripts.
- Environment API changes: replaced process.env usages with Deno.env accessors and updated path constants (Szci paths).
- Refactored helper modules: npmci.bash -> szci.bash, updated smartshell/bash wrappers and other manager modules to Deno patterns.
- Tests and imports updated to new module paths and package layout; .gitignore updated to ignore deno artifacts.
- Breaking changes to callers: CLI name, class names, programmatic API, binary installation and environment handling have changed and may require updates in integrations and CI configurations.
## 2024-11-17 - 4.1.37 - fix(docker)
Enhanced base image extraction logic from Dockerfile

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
import * as cliTool from './ts/index.js';
cliTool.runCli();

4
cli.js
View File

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

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
import * as tsrun from '@git.zone/tsrun';
tsrun.runPath('./cli.child.js', import.meta.url);

67
deno.json Normal file
View File

@@ -0,0 +1,67 @@
{
"name": "@ship.zone/szci",
"version": "6.0.1",
"exports": "./mod.ts",
"nodeModulesDir": "auto",
"tasks": {
"dev": "deno run --allow-all mod.ts",
"compile": "deno task compile:all",
"compile:all": "bash scripts/compile-all.sh",
"test": "deno test --allow-all test/",
"test:watch": "deno test --allow-all --watch test/",
"check": "deno check mod.ts",
"fmt": "deno fmt",
"lint": "deno lint"
},
"lint": {
"rules": {
"tags": [
"recommended"
]
}
},
"fmt": {
"useTabs": false,
"lineWidth": 100,
"indentWidth": 2,
"semiColons": true,
"singleQuote": true
},
"compilerOptions": {
"lib": [
"deno.window"
],
"strict": true
},
"imports": {
"@std/path": "jsr:@std/path@^1.0.0",
"@std/fmt": "jsr:@std/fmt@^1.0.0",
"@std/cli": "jsr:@std/cli@^1.0.0",
"@std/assert": "jsr:@std/assert@^1.0.0",
"@api.global/typedrequest": "npm:@api.global/typedrequest@^3.1.10",
"@push.rocks/lik": "npm:@push.rocks/lik@^6.1.0",
"@push.rocks/npmextra": "npm:@push.rocks/npmextra@^5.1.2",
"@push.rocks/projectinfo": "npm:@push.rocks/projectinfo@^5.0.2",
"@push.rocks/qenv": "npm:@push.rocks/qenv@^6.0.2",
"@push.rocks/smartanalytics": "npm:@push.rocks/smartanalytics@^2.0.15",
"@push.rocks/smartcli": "npm:@push.rocks/smartcli@^4.0.11",
"@push.rocks/smartdelay": "npm:@push.rocks/smartdelay@^3.0.5",
"@push.rocks/smartenv": "npm:@push.rocks/smartenv@^5.0.5",
"@push.rocks/smartfile": "npm:@push.rocks/smartfile@^11.0.21",
"@push.rocks/smartgit": "npm:@push.rocks/smartgit@^3.1.1",
"@push.rocks/smartlog": "npm:@push.rocks/smartlog@^3.0.7",
"@push.rocks/smartlog-destination-local": "npm:@push.rocks/smartlog-destination-local@^9.0.0",
"@push.rocks/smartobject": "npm:@push.rocks/smartobject@^1.0.12",
"@push.rocks/smartpath": "npm:@push.rocks/smartpath@^5.0.11",
"@push.rocks/smartpromise": "npm:@push.rocks/smartpromise@^4.0.4",
"@push.rocks/smartrequest": "npm:@push.rocks/smartrequest@^2.0.23",
"@push.rocks/smartshell": "npm:@push.rocks/smartshell@^3.0.6",
"@push.rocks/smartsocket": "npm:@push.rocks/smartsocket@^2.0.22",
"@push.rocks/smartssh": "npm:@push.rocks/smartssh@^2.0.1",
"@push.rocks/smartstring": "npm:@push.rocks/smartstring@^4.0.8",
"@push.rocks/smartexpect": "npm:@push.rocks/smartexpect@^1.0.15",
"@serve.zone/api": "npm:@serve.zone/api@^4.3.11",
"@tsclass/tsclass": "npm:@tsclass/tsclass@^4.1.2",
"through2": "npm:through2@^4.0.2"
}
}

257
install.sh Executable file
View File

@@ -0,0 +1,257 @@
#!/bin/bash
# SZCI Installer Script (v5.0+)
# Downloads and installs pre-compiled SZCI binary from Gitea releases
#
# Usage:
# Direct piped installation (recommended):
# curl -sSL https://code.foss.global/ship.zone/szci/raw/branch/master/install.sh | sudo bash
#
# With version specification:
# curl -sSL https://code.foss.global/ship.zone/szci/raw/branch/master/install.sh | sudo bash -s -- --version v5.0.0
#
# Options:
# -h, --help Show this help message
# --version VERSION Install specific version (e.g., v5.0.0)
# --install-dir DIR Installation directory (default: /opt/szci)
set -e
# Default values
SHOW_HELP=0
SPECIFIED_VERSION=""
INSTALL_DIR="/opt/szci"
GITEA_BASE_URL="https://code.foss.global"
GITEA_REPO="ship.zone/szci"
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
SHOW_HELP=1
shift
;;
--version)
SPECIFIED_VERSION="$2"
shift 2
;;
--install-dir)
INSTALL_DIR="$2"
shift 2
;;
*)
echo "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
esac
done
if [ $SHOW_HELP -eq 1 ]; then
echo "SZCI Installer Script (v5.0+)"
echo "Downloads and installs pre-compiled SZCI binary"
echo ""
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " -h, --help Show this help message"
echo " --version VERSION Install specific version (e.g., v5.0.0)"
echo " --install-dir DIR Installation directory (default: /opt/szci)"
echo ""
echo "Examples:"
echo " # Install latest version"
echo " curl -sSL https://code.foss.global/ship.zone/szci/raw/branch/master/install.sh | sudo bash"
echo ""
echo " # Install specific version"
echo " curl -sSL https://code.foss.global/ship.zone/szci/raw/branch/master/install.sh | sudo bash -s -- --version v5.0.0"
exit 0
fi
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root (sudo bash install.sh or pipe to sudo bash)"
exit 1
fi
# Helper function to detect OS and architecture
detect_platform() {
local os=$(uname -s)
local arch=$(uname -m)
# Map OS
case "$os" in
Linux)
os_name="linux"
;;
Darwin)
os_name="macos"
;;
MINGW*|MSYS*|CYGWIN*)
os_name="windows"
;;
*)
echo "Error: Unsupported operating system: $os"
echo "Supported: Linux, macOS, Windows"
exit 1
;;
esac
# Map architecture
case "$arch" in
x86_64|amd64)
arch_name="x64"
;;
aarch64|arm64)
arch_name="arm64"
;;
*)
echo "Error: Unsupported architecture: $arch"
echo "Supported: x86_64/amd64 (x64), aarch64/arm64 (arm64)"
exit 1
;;
esac
# Construct binary name
if [ "$os_name" = "windows" ]; then
echo "szci-${os_name}-${arch_name}.exe"
else
echo "szci-${os_name}-${arch_name}"
fi
}
# Get latest release version from Gitea API
get_latest_version() {
echo "Fetching latest release version from Gitea..." >&2
local api_url="${GITEA_BASE_URL}/api/v1/repos/${GITEA_REPO}/releases/latest"
local response=$(curl -sSL "$api_url" 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$response" ]; then
echo "Error: Failed to fetch latest release information from Gitea API" >&2
echo "URL: $api_url" >&2
exit 1
fi
# Extract tag_name from JSON response
local version=$(echo "$response" | grep -o '"tag_name":"[^"]*"' | cut -d'"' -f4)
if [ -z "$version" ]; then
echo "Error: Could not determine latest version from API response" >&2
exit 1
fi
echo "$version"
}
# Main installation process
echo "================================================"
echo " SZCI Installation Script (v5.0+)"
echo " Serve Zone CI/CD Tool"
echo "================================================"
echo ""
# Detect platform
BINARY_NAME=$(detect_platform)
echo "Detected platform: $BINARY_NAME"
echo ""
# Determine version to install
if [ -n "$SPECIFIED_VERSION" ]; then
VERSION="$SPECIFIED_VERSION"
echo "Installing specified version: $VERSION"
else
VERSION=$(get_latest_version)
echo "Installing latest version: $VERSION"
fi
echo ""
# Construct download URL
DOWNLOAD_URL="${GITEA_BASE_URL}/${GITEA_REPO}/releases/download/${VERSION}/${BINARY_NAME}"
echo "Download URL: $DOWNLOAD_URL"
echo ""
# Clean installation directory - ensure only binary exists
if [ -d "$INSTALL_DIR" ]; then
echo "Cleaning installation directory: $INSTALL_DIR"
rm -rf "$INSTALL_DIR"
fi
# Create fresh installation directory
echo "Creating installation directory: $INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
# Download binary
echo "Downloading SZCI binary..."
TEMP_FILE="$INSTALL_DIR/szci.download"
curl -sSL "$DOWNLOAD_URL" -o "$TEMP_FILE"
if [ $? -ne 0 ]; then
echo "Error: Failed to download binary from $DOWNLOAD_URL"
echo ""
echo "Please check:"
echo " 1. Your internet connection"
echo " 2. The specified version exists: ${GITEA_BASE_URL}/${GITEA_REPO}/releases"
echo " 3. The platform binary is available for this release"
rm -f "$TEMP_FILE"
exit 1
fi
# Check if download was successful (file exists and not empty)
if [ ! -s "$TEMP_FILE" ]; then
echo "Error: Downloaded file is empty or does not exist"
rm -f "$TEMP_FILE"
exit 1
fi
# Move to final location
BINARY_PATH="$INSTALL_DIR/szci"
mv "$TEMP_FILE" "$BINARY_PATH"
if [ $? -ne 0 ] || [ ! -f "$BINARY_PATH" ]; then
echo "Error: Failed to move binary to $BINARY_PATH"
rm -f "$TEMP_FILE" 2>/dev/null
exit 1
fi
# Make executable
chmod +x "$BINARY_PATH"
if [ $? -ne 0 ]; then
echo "Error: Failed to make binary executable"
exit 1
fi
echo "Binary installed successfully to: $BINARY_PATH"
echo ""
# Check if /usr/local/bin is in PATH
if [[ ":$PATH:" == *":/usr/local/bin:"* ]]; then
BIN_DIR="/usr/local/bin"
else
BIN_DIR="/usr/bin"
fi
# Create symlink for global access
ln -sf "$BINARY_PATH" "$BIN_DIR/szci"
echo "Symlink created: $BIN_DIR/szci -> $BINARY_PATH"
echo ""
echo "================================================"
echo " SZCI Installation Complete!"
echo "================================================"
echo ""
echo "Installation details:"
echo " Binary location: $BINARY_PATH"
echo " Symlink location: $BIN_DIR/szci"
echo " Version: $VERSION"
echo ""
echo "Get started:"
echo " szci --version"
echo " szci --help"
echo " szci node install stable # Install Node.js"
echo " szci docker build # Build Docker images"
echo " szci npm test # Run tests"
echo ""
echo "For CI/CD integration examples, visit:"
echo " https://code.foss.global/ship.zone/szci"
echo ""

48
mod.ts Normal file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env -S deno run --allow-all
/**
* SZCI - Serve Zone CI/CD Tool
*
* A command-line tool for streamlining Node.js and Docker workflows
* within CI environments, particularly GitLab CI, GitHub CI, and Gitea CI.
*
* Required Permissions:
* - --allow-net: Network access for Docker registries, npm, git operations
* - --allow-read: Read configuration files, Dockerfiles, package.json
* - --allow-write: Write configuration files, build artifacts
* - --allow-run: Execute system commands (docker, git, npm, ssh)
* - --allow-sys: Access system information (OS details)
* - --allow-env: Read/write environment variables
*
* @module
*/
import { Szci } from './ts/szci.classes.szci.ts';
/**
* Main entry point for the SZCI application
* Parses command-line arguments and executes the requested command
*/
async function main(): Promise<void> {
// Create Szci instance
const szciInstance = new Szci();
// Start the CLI
// Deno.args is already 0-indexed (unlike Node's process.argv which starts at index 2)
// The smartcli library may expect process.argv format, so we might need to prepend placeholders
await szciInstance.start();
}
// Execute main and handle errors
if (import.meta.main) {
try {
await main();
} catch (error) {
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
Deno.exit(1);
}
}
// Export for programmatic use
export { Szci } from './ts/szci.classes.szci.ts';
export { Dockerfile } from './ts/manager.docker/mod.classes.dockerfile.ts';

View File

@@ -1,79 +1,7 @@
{
"name": "@ship.zone/npmci",
"version": "4.1.37",
"private": false,
"description": "A tool to streamline Node.js and Docker workflows within CI environments, particularly GitLab CI, providing various CI/CD utilities.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"type": "module",
"bin": {
"npmci": "cli.js"
},
"scripts": {
"test": "tstest test/",
"build": "tsbuild --allowimplicitany && (npm run testVersion)",
"testVersion": "(cd test/assets/ && node ../../cli.js -v)",
"buildDocs": "tsdoc"
},
"repository": {
"type": "git",
"url": "git+ssh://git@gitlab.com/gitzone/npmci.git"
},
"author": "Lossless GmbH",
"license": "MIT",
"bugs": {
"url": "https://gitlab.com/gitzone/npmci/issues"
},
"homepage": "https://gitlab.com/gitzone/npmci#README",
"devDependencies": {
"@git.zone/tsbuild": "^2.2.0",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^1.0.77",
"@push.rocks/tapbundle": "^5.5.0",
"@types/node": "^22.9.0"
},
"dependencies": {
"@api.global/typedrequest": "^3.1.10",
"@push.rocks/lik": "^6.1.0",
"@push.rocks/npmextra": "^5.1.2",
"@push.rocks/projectinfo": "^5.0.2",
"@push.rocks/qenv": "^6.0.2",
"@push.rocks/smartanalytics": "^2.0.15",
"@push.rocks/smartcli": "^4.0.11",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartenv": "^5.0.5",
"@push.rocks/smartfile": "^11.0.21",
"@push.rocks/smartgit": "^3.1.1",
"@push.rocks/smartlog": "^3.0.7",
"@push.rocks/smartlog-destination-local": "^9.0.0",
"@push.rocks/smartobject": "^1.0.12",
"@push.rocks/smartpath": "^5.0.11",
"@push.rocks/smartpromise": "^4.0.4",
"@push.rocks/smartrequest": "^2.0.23",
"@push.rocks/smartshell": "^3.0.6",
"@push.rocks/smartsocket": "^2.0.22",
"@push.rocks/smartssh": "^2.0.1",
"@push.rocks/smartstring": "^4.0.8",
"@serve.zone/api": "^4.3.11",
"@tsclass/tsclass": "^4.1.2",
"@types/through2": "^2.0.38",
"through2": "^4.0.2"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"browserslist": [
"last 1 chrome versions"
],
"name": "@ship.zone/szci",
"version": "6.0.1",
"description": "Serve Zone CI - A tool to streamline Node.js and Docker workflows within CI environments, particularly GitLab CI, providing various CI/CD utilities. Powered by Deno with standalone executables.",
"keywords": [
"Node.js",
"Docker",
@@ -84,11 +12,56 @@
"automation",
"npm",
"TypeScript",
"Deno",
"cloud",
"SSH",
"registry",
"container management",
"continuous integration",
"continuous deployment"
]
],
"homepage": "https://code.foss.global/ship.zone/szci",
"bugs": {
"url": "https://code.foss.global/ship.zone/szci/issues"
},
"repository": {
"type": "git",
"url": "git+https://code.foss.global/ship.zone/szci.git"
},
"author": "Lossless GmbH",
"license": "MIT",
"type": "module",
"bin": {
"szci": "./bin/szci-wrapper.js"
},
"scripts": {
"postinstall": "node scripts/install-binary.js",
"prepublishOnly": "echo 'Publishing SZCI binaries to npm...'",
"test": "echo 'Tests are run with Deno: deno task test'",
"build": "echo 'no build needed'"
},
"files": [
"bin/",
"scripts/install-binary.js",
"readme.md",
"license",
"changelog.md"
],
"engines": {
"node": ">=14.0.0"
},
"os": [
"darwin",
"linux",
"win32"
],
"cpu": [
"x64",
"arm64"
],
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34"
}

4
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,4 @@
onlyBuiltDependencies:
- esbuild
- mongodb-memory-server
- puppeteer

689
readme.md
View File

@@ -1,30 +1,115 @@
# @ship.zone/npmci
A tool to enhance Node.js and Docker workflows within GitLab CI, providing various CI/CD utilities.
# @ship.zone/szci
## Install
**Serve Zone CI** - A powerful CI/CD tool for streamlining Node.js and Docker workflows within CI environments (GitLab CI, GitHub CI, Gitea CI). Now powered by Deno with standalone executables.
To install `@ship.zone/npmci`, you can use npm or yarn:
## ✨ Features
- 🚀 **Standalone Executables** - No Node.js installation required
- 🐳 **Docker Integration** - Build, tag, and push Docker images
- 📦 **NPM Management** - Install, test, and publish npm packages
- 🔧 **Node.js Version Management** - Install and switch between Node versions
- 🔐 **SSH Key Management** - Deploy SSH keys from environment variables
- ☁️ **Multi-Registry Support** - Push to multiple Docker registries
- 🎯 **Cross-Platform** - Binaries for Linux, macOS, and Windows
## 📥 Installation
### NPM (Recommended)
```sh
# Using npm
npm install @ship.zone/npmci
# Using yarn
yarn add @ship.zone/npmci
npm install -g @ship.zone/szci
```
## Usage
The package will automatically download the appropriate pre-compiled binary for your platform.
`npmci` is designed to streamline CI/CD processes, particularly in Docker and Node.js environments. The following sections illustrate its usage in various scenarios, from handling Node versions to building Docker images and more.
### From Source (Deno Required)
### 1. Integration with GitLab CI, GitHub CI, and Gitea CI
```sh
git clone https://code.foss.global/ship.zone/szci.git
cd szci
deno task compile
```
#### GitLab CI
## 🚀 Quick Start
An example of integrating `npmci` into a GitLab CI configuration could look like this:
```sh
# Install Node.js
szci node install stable
# Install dependencies
szci npm install
# Build Docker images
szci docker build
# Run tests
szci npm test
# Push Docker images
szci docker push registry.example.com
```
## 📖 Usage
### Node.js Management
```sh
# Install specific Node.js version
szci node install lts
szci node install stable
szci node install 18
# Install from .nvmrc
szci node install legacy
```
### NPM Commands
```sh
# Install dependencies
szci npm install
# Run tests
szci npm test
# Publish package
szci npm publish
```
### Docker Workflows
```sh
# Prepare Docker environment
szci docker prepare
# Build all Dockerfiles
szci docker build
# Push to registry
szci docker push registry.example.com
# Pull from registry
szci docker pull registry.example.com
# Test Dockerfiles
szci docker test
```
### SSH Key Management
```sh
# Deploy SSH keys from environment
szci ssh prepare
```
Set environment variables like `NPMCI_SSHKEY_1`, `NPMCI_SSHKEY_2`, etc.
## 🔧 CI/CD Integration
### GitLab CI
```yaml
image: hosttoday/ht-docker-node:npmci
image: denoland/deno:alpine
stages:
- prepare
@@ -32,463 +117,191 @@ stages:
- test
- deploy
default:
before_script:
- npmci node install stable
- npmci npm install
variables:
SZCI_VERSION: "latest"
before_script:
- deno install --allow-all --global --name szci https://code.foss.global/ship.zone/szci/raw/branch/master/mod.ts
# OR use the npm package:
# - npm install -g @ship.zone/szci
prepare:
stage: prepare
script:
- npmci prepare npm
- npmci prepare docker
- szci node install stable
- szci npm install
build:
stage: build
script:
- npmci docker build
- szci docker build
test:
stage: test
script:
- npmci npm test
- szci npm test
deploy:
stage: deploy
script:
- npmci publish npm
- npmci docker push
environment:
name: production
url: http://example.com
- szci docker push $CI_REGISTRY
only:
- master
```
#### GitHub Actions
Similarly, you can set up `npmci` in GitHub Actions:
### GitHub Actions
```yaml
name: CI Pipeline
on:
push:
branches:
- main
branches: [main]
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install -g @ship.zone/npmci
- run: npmci node install stable
- run: npmci npm install
build:
runs-on: ubuntu-latest
needs: prepare
steps:
- run: npmci docker build
- uses: actions/checkout@v3
test:
runs-on: ubuntu-latest
needs: build
steps:
- run: npmci npm test
- name: Install SZCI
run: npm install -g @ship.zone/szci
deploy:
runs-on: ubuntu-latest
needs: test
steps:
- run: npmci publish npm
- run: npmci docker push
- name: Setup Node.js
run: szci node install stable
- name: Install Dependencies
run: szci npm install
- name: Build Docker Images
run: szci docker build
- name: Run Tests
run: szci npm test
- name: Push Images
if: github.ref == 'refs/heads/main'
run: szci docker push ghcr.io
```
#### Gitea CI
Lastly, for Gitea CI:
```yaml
image: hosttoday/ht-docker-node:npmci
pipelines:
default:
- step:
name: Prepare
image: hosttoday/ht-docker-node:npmci
commands:
- npmci node install stable
- npmci npm install
- npmci prepare npm
- npmci prepare docker
- step:
name: Build
image: hosttoday/ht-docker-node:npmci
commands:
- npmci docker build
- step:
name: Test
image: hosttoday/ht-docker-node:npmci
commands:
- npmci npm test
- step:
name: Deploy
image: hosttoday/ht-docker-node:npmci
commands:
- npmci publish npm
- npmci docker push
```
### 2. Handle Node Versions
One of the core features of `npmci` is managing Node versions in your CI environment. You can specify which version of Node to install:
```typescript
import { Npmci } from '@ship.zone/npmci';
async function manageNodeVersions() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.nodejsManager.handleCli({
_: ['node', 'install', 'stable'] // Installs the latest stable version
});
await npmciInstance.nodejsManager.handleCli({
_: ['node', 'install', 'lts'] // Installs the Long-Term Support (LTS) version
});
await npmciInstance.nodejsManager.handleCli({
_: ['node', 'install', 'legacy'] // Installs a legacy version
});
await npmciInstance.nodejsManager.handleCli({
_: ['node', 'install', '14.17.0'] // Install a specific version of Node
});
}
manageNodeVersions().then(() => console.log('Node versions managed successfully.'));
```
### 3. Handling npm and Yarn Tasks
`npmci` provides numerous utilities to streamline npm and yarn workflow tasks within a CI/CD pipeline.
```typescript
import { Npmci } from '@ship.zone/npmci';
async function manageNpmTasks() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.npmManager.handleCli({ _: ['npm', 'install'] }); // Installs dependencies
await npmciInstance.npmManager.handleCli({ _: ['npm', 'test'] }); // Runs tests
await npmciInstance.npmManager.handleCli({ _: ['npm', 'publish'] }); // Publishes the package
}
manageNpmTasks().then(() => console.log('Npm tasks handled successfully.'));
```
### 4. Docker Task Handling
`npmci` simplifies Docker operations, particularly in building, testing, and publishing Docker images.
**Prepare Docker Environment:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function prepareDocker() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'prepare'] }); // Prepares Docker environment
}
prepareDocker().then(() => console.log('Docker environment prepared successfully.'));
```
**Building Docker Images:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function buildDockerImages() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'build'] }); // Builds Docker images
}
buildDockerImages().then(() => console.log('Docker images built successfully.'));
```
**Testing Docker Images:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function testDockerImages() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'test'] }); // Tests Docker images
}
testDockerImages().then(() => console.log('Docker images tested successfully.'));
```
**Publishing Docker Images:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function pushDockerImages() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'push'] }); // Pushes Docker images to registry
}
pushDockerImages().then(() => console.log('Docker images pushed successfully.'));
```
### 5. Managing Docker Registries
`npmci` can handle multiple Docker registries and allows for easy integration within your CI pipeline.
**Logging in to Docker Registries:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function loginToDockerRegistries() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'login'] }); // Logs into all configured Docker registries
}
loginToDockerRegistries().then(() => console.log('Logged into Docker registries.'));
```
**Pulling Docker Images:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function pullDockerImages() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'pull', 'registry.gitlab.com/mygroup/myrepo'] }); // Pulls Docker images from a registry
}
pullDockerImages().then(() => console.log('Docker images pulled successfully.'));
```
### 6. SSH Key Management
`npmci` also simplifies the management of SSH keys, which is crucial for accessing private repositories and servers.
**Preparing SSH Keys:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function prepareSshKeys() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.sshManager.handleCli({ _: ['ssh', 'prepare'] }); // Prepares SSH keys from environment variables
}
prepareSshKeys().then(() => console.log('SSH keys prepared successfully.'));
```
### 7. Cloudron Integration
For users deploying applications on Cloudron, `npmci` provides a set of utilities for automating Cloudron tasks.
**Deploying to Cloudron:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function deployToCloudron() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.cloudronManager.handleCli({
_: ['cloudron', 'deploy']
}); // Deploys application to Cloudron platform
}
deployToCloudron().then(() => console.log('Deployment to Cloudron completed.'));
```
**Preparing Cloudron Manifest:**
Before deployment, replace version placeholders in the Cloudron Manifest:
```typescript
import { Npmci } from '@ship.zone/npmci';
import * as fs from 'fs';
import * as path from 'path';
async function prepareCloudronManifest(version: string) {
const manifestPath = path.join(process.cwd(), "CloudronManifest.json");
let manifestFile = fs.readFileSync(manifestPath, { encoding: 'utf-8' });
manifestFile = manifestFile.replace(/##version##/g, version);
fs.writeFileSync(manifestPath, manifestFile);
console.log('CloudronManifest prepared');
}
async function deployWithPreparedManifest() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await prepareCloudronManifest('1.0.0');
await npmciInstance.cloudronManager.handleCli({
_: ['cloudron', 'deploy']
}); // Deploys application to Cloudron platform
}
deployWithPreparedManifest().then(() => console.log('Deployment to Cloudron with manifest preparation completed.'));
```
### 8. Webhook Triggers
`npmci` supports webhook triggers, allowing you to trigger builds and other activities based on various conditions.
**Triggering Webhooks:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function triggerWebhooks() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.triggerManager.handleCli({
_: ['trigger']
}); // Triggers webhooks based on environment variables
}
triggerWebhooks().then(() => console.log('Webhooks triggered successfully.'));
```
### 9. Using the bash Helper
`npmci` includes a bash helper for executing commands within a bash shell, useful for various custom tasks.
**Using bash to Execute Commands:**
```typescript
import { bash } from '@ship.zone/npmci';
async function runCustomBashCommand(command: string) {
const output = await bash(command);
console.log('Command output:', output);
}
runCustomBashCommand('echo Hello World').then(() => console.log('Custom command executed successfully.'));
```
### Full Features and Use Cases
Below is a comprehensive set of features and use cases supported by `npmci`. This section ensures you can take full advantage of the library's capabilities in multiple scenarios.
### Comprehensive Docker Workflow
**Step-by-step Docker Image Handling:**
1. **Detect and Build All Dockerfiles:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function detectAndBuildDockerfiles() {
const npmciInstance = new Npmci();
await npmciInstance.start();
const dockerfiles = await npmciInstance.dockerManager.getDockerfiles();
console.log('Dockerfiles detected:', dockerfiles.map(d => d.filePath));
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'build'] });
console.log('Dockerfiles built successfully.');
}
detectAndBuildDockerfiles().then(() => console.log('Docker detection and build process completed.'));
```
2. **Test All Dockerfiles:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function testAllDockerfiles() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'test'] });
console.log('Dockerfiles tested successfully.');
}
testAllDockerfiles().then(() => console.log('Docker testing process completed.'));
```
3. **Push Dockerfiles to a Registry:**
```typescript
import { Npmci } from '@ship.zone/npmci';
async function pushDockerfilesToRegistry() {
const npmciInstance = new Npmci();
await npmciInstance.start();
await npmciInstance.dockerManager.handleCli({ _: ['docker', 'push'] });
console.log('Dockerfiles pushed to registry successfully.');
}
pushDockerfilesToRegistry().then(() => console.log('Docker push process completed.'));
```
**Dockerfile Class Example:**
Here's a snippet showcasing how the `Dockerfile` class can be used to handle Dockerfile-specific operations:
```typescript
import { Dockerfile } from '@ship.zone/npmci';
async function handleDockerfileOperations() {
// Initialize Dockerfile instances
const dockerfile1 = new Dockerfile(/* required parameters */);
const dockerfile2 = new Dockerfile(/* required parameters */);
// Read and sort Dockerfiles
const dockerfiles = await Dockerfile.readDockerfiles(/* required parameters */);
const sortedDockerfiles = await Dockerfile.sortDockerfiles(dockerfiles);
// Build and Test Dockerfiles
await Dockerfile.buildDockerfiles(sortedDockerfiles);
await Dockerfile.testDockerfiles(sortedDockerfiles);
// Push Dockerfile images to a registry
for (const dockerfile of sortedDockerfiles) {
await dockerfile.push(/* registry and tag parameters */);
## ⚙️ Configuration
Create an `npmextra.json` file in your project root:
```json
{
"npmci": {
"npmGlobalTools": [],
"npmAccessLevel": "public",
"npmRegistryUrl": "registry.npmjs.org",
"dockerRegistries": [
"registry.gitlab.com"
],
"dockerRegistryRepoMap": {
"registry.gitlab.com": "mygroup/myrepo"
},
"dockerBuildargEnvMap": {
"ARG_NAME": "ENV_VAR_NAME"
}
}
console.log('Dockerfile operations completed successfully.');
}
handleDockerfileOperations().then(() => console.log('Dockerfile processing flow completed.'));
```
This completes the comprehensive guide to `@ship.zone/npmci`. With the examples and explanations provided, you should be able to harness the full power and flexibility of the library to streamline your CI/CD processes effectively.
undefined
## 🐳 Docker Registry Authentication
SZCI supports automatic authentication with:
- GitLab CI Registry (via `CI_JOB_TOKEN`)
- Custom registries via environment variables
Set `NPMCI_LOGIN_DOCKER*` environment variables:
```sh
NPMCI_LOGIN_DOCKER_1="registry.example.com|username|password"
NPMCI_LOGIN_DOCKER_2="another-registry.com|user2|pass2"
```
## 🏗️ Development
### Prerequisites
- Deno 1.40+ installed
### Building from Source
```sh
# Clone the repository
git clone https://code.foss.global/ship.zone/szci.git
cd szci
# Compile for all platforms
deno task compile
# Compile for current platform only
deno compile --allow-all --output szci mod.ts
# Run tests
deno task test
# Development mode
deno task dev --help
```
### Testing
SZCI uses Deno's native test framework:
```sh
# Run all tests
deno task test
# Run tests in watch mode
deno task test:watch
# Run specific test file
deno test --allow-all test/test.cloudly.ts
```
## 📦 Binary Sizes
The standalone executables are approximately:
- Linux x64: ~800MB
- Linux ARM64: ~800MB
- macOS x64: ~796MB
- macOS ARM64: ~796MB
- Windows x64: ~804MB
Sizes include all dependencies and the Deno runtime.
## 🔄 Migration from npmci
If you're upgrading from the old `@ship.zone/npmci` package:
1. Update package references:
```sh
npm uninstall -g @ship.zone/npmci
npm install -g @ship.zone/szci
```
2. Update CI configuration files - replace `npmci` with `szci`
3. The command interface remains the same, only the binary name changed
## 📝 License
MIT © Lossless GmbH
## 🔗 Links
- [Repository](https://code.foss.global/ship.zone/szci)
- [Issues](https://code.foss.global/ship.zone/szci/issues)
- [Changelog](./changelog.md)
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
---
**Built with Deno 🦕**

66
scripts/compile-all.sh Executable file
View File

@@ -0,0 +1,66 @@
#!/bin/bash
set -e
# Get version from deno.json
VERSION=$(cat deno.json | grep -o '"version": *"[^"]*"' | cut -d'"' -f4)
BINARY_DIR="dist/binaries"
echo "================================================"
echo " SZCI Compilation Script"
echo " Version: ${VERSION}"
echo "================================================"
echo ""
echo "Compiling for all supported platforms..."
echo ""
# Clean up old binaries and create fresh directory
rm -rf "$BINARY_DIR"
mkdir -p "$BINARY_DIR"
echo "→ Cleaned old binaries from $BINARY_DIR"
echo ""
# Linux x86_64
echo "→ Compiling for Linux x86_64..."
deno compile --allow-all --no-check --output "$BINARY_DIR/szci-linux-x64" \
--target x86_64-unknown-linux-gnu mod.ts
echo " ✓ Linux x86_64 complete"
echo ""
# Linux ARM64
echo "→ Compiling for Linux ARM64..."
deno compile --allow-all --no-check --output "$BINARY_DIR/szci-linux-arm64" \
--target aarch64-unknown-linux-gnu mod.ts
echo " ✓ Linux ARM64 complete"
echo ""
# macOS x86_64
echo "→ Compiling for macOS x86_64..."
deno compile --allow-all --no-check --output "$BINARY_DIR/szci-macos-x64" \
--target x86_64-apple-darwin mod.ts
echo " ✓ macOS x86_64 complete"
echo ""
# macOS ARM64
echo "→ Compiling for macOS ARM64..."
deno compile --allow-all --no-check --output "$BINARY_DIR/szci-macos-arm64" \
--target aarch64-apple-darwin mod.ts
echo " ✓ macOS ARM64 complete"
echo ""
# Windows x86_64
echo "→ Compiling for Windows x86_64..."
deno compile --allow-all --no-check --output "$BINARY_DIR/szci-windows-x64.exe" \
--target x86_64-pc-windows-msvc mod.ts
echo " ✓ Windows x86_64 complete"
echo ""
echo "================================================"
echo " Compilation Summary"
echo "================================================"
echo ""
ls -lh "$BINARY_DIR/" | tail -n +2
echo ""
echo "✓ All binaries compiled successfully!"
echo ""
echo "Binary location: $BINARY_DIR/"
echo ""

228
scripts/install-binary.js Normal file
View File

@@ -0,0 +1,228 @@
#!/usr/bin/env node
/**
* SZCI npm postinstall script
* Downloads the appropriate binary for the current platform from repository releases
*/
import { platform, arch } from 'os';
import { existsSync, mkdirSync, writeFileSync, chmodSync, unlinkSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import https from 'https';
import { pipeline } from 'stream';
import { promisify } from 'util';
import { createWriteStream } from 'fs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const streamPipeline = promisify(pipeline);
// Configuration
const REPO_BASE = 'https://code.foss.global/ship.zone/szci';
const VERSION = process.env.npm_package_version || '4.1.37';
function getBinaryInfo() {
const plat = platform();
const architecture = arch();
const platformMap = {
'darwin': 'macos',
'linux': 'linux',
'win32': 'windows'
};
const archMap = {
'x64': 'x64',
'arm64': 'arm64'
};
const mappedPlatform = platformMap[plat];
const mappedArch = archMap[architecture];
if (!mappedPlatform || !mappedArch) {
return { supported: false, platform: plat, arch: architecture };
}
let binaryName = `szci-${mappedPlatform}-${mappedArch}`;
if (plat === 'win32') {
binaryName += '.exe';
}
return {
supported: true,
platform: mappedPlatform,
arch: mappedArch,
binaryName,
originalPlatform: plat
};
}
function downloadFile(url, destination) {
return new Promise((resolve, reject) => {
console.log(`Downloading from: ${url}`);
// Follow redirects
const download = (url, redirectCount = 0) => {
if (redirectCount > 5) {
reject(new Error('Too many redirects'));
return;
}
https.get(url, (response) => {
if (response.statusCode === 301 || response.statusCode === 302) {
console.log(`Following redirect to: ${response.headers.location}`);
download(response.headers.location, redirectCount + 1);
return;
}
if (response.statusCode !== 200) {
reject(new Error(`Failed to download: ${response.statusCode} ${response.statusMessage}`));
return;
}
const totalSize = parseInt(response.headers['content-length'], 10);
let downloadedSize = 0;
let lastProgress = 0;
response.on('data', (chunk) => {
downloadedSize += chunk.length;
const progress = Math.round((downloadedSize / totalSize) * 100);
// Only log every 10% to reduce noise
if (progress >= lastProgress + 10) {
console.log(`Download progress: ${progress}%`);
lastProgress = progress;
}
});
const file = createWriteStream(destination);
pipeline(response, file, (err) => {
if (err) {
reject(err);
} else {
console.log('Download complete!');
resolve();
}
});
}).on('error', reject);
};
download(url);
});
}
async function main() {
console.log('===========================================');
console.log(' SZCI - Binary Installation');
console.log('===========================================');
console.log('');
const binaryInfo = getBinaryInfo();
if (!binaryInfo.supported) {
console.error(`❌ Error: Unsupported platform/architecture: ${binaryInfo.platform}/${binaryInfo.arch}`);
console.error('');
console.error('Supported platforms:');
console.error(' • Linux (x64, arm64)');
console.error(' • macOS (x64, arm64)');
console.error(' • Windows (x64)');
console.error('');
console.error('If you believe your platform should be supported, please file an issue:');
console.error(' https://code.foss.global/ship.zone/szci/issues');
process.exit(1);
}
console.log(`Platform: ${binaryInfo.platform} (${binaryInfo.originalPlatform})`);
console.log(`Architecture: ${binaryInfo.arch}`);
console.log(`Binary: ${binaryInfo.binaryName}`);
console.log(`Version: ${VERSION}`);
console.log('');
// Create dist/binaries directory if it doesn't exist
const binariesDir = join(__dirname, '..', 'dist', 'binaries');
if (!existsSync(binariesDir)) {
console.log('Creating binaries directory...');
mkdirSync(binariesDir, { recursive: true });
}
const binaryPath = join(binariesDir, binaryInfo.binaryName);
// Check if binary already exists and skip download
if (existsSync(binaryPath)) {
console.log('✓ Binary already exists, skipping download');
} else {
// Construct download URL
// Try release URL first, fall back to raw branch if needed
const releaseUrl = `${REPO_BASE}/releases/download/v${VERSION}/${binaryInfo.binaryName}`;
const fallbackUrl = `${REPO_BASE}/raw/branch/master/dist/binaries/${binaryInfo.binaryName}`;
console.log('Downloading platform-specific binary...');
console.log('This may take a moment depending on your connection speed.');
console.log('');
try {
// Try downloading from release
await downloadFile(releaseUrl, binaryPath);
} catch (err) {
console.log(`Release download failed: ${err.message}`);
console.log('Trying fallback URL...');
try {
// Try fallback URL
await downloadFile(fallbackUrl, binaryPath);
} catch (fallbackErr) {
console.error(`❌ Error: Failed to download binary`);
console.error(` Primary URL: ${releaseUrl}`);
console.error(` Fallback URL: ${fallbackUrl}`);
console.error('');
console.error('This might be because:');
console.error('1. The release has not been created yet');
console.error('2. Network connectivity issues');
console.error('3. The version specified does not exist');
console.error('');
console.error('You can try:');
console.error('1. Installing from source: https://code.foss.global/ship.zone/szci');
console.error('2. Downloading the binary manually from the releases page');
console.error('3. Building from source with: deno task compile');
// Clean up partial download
if (existsSync(binaryPath)) {
unlinkSync(binaryPath);
}
process.exit(1);
}
}
console.log(`✓ Binary downloaded successfully`);
}
// On Unix-like systems, ensure the binary is executable
if (binaryInfo.originalPlatform !== 'win32') {
try {
console.log('Setting executable permissions...');
chmodSync(binaryPath, 0o755);
console.log('✓ Binary permissions updated');
} catch (err) {
console.error(`⚠️ Warning: Could not set executable permissions: ${err.message}`);
console.error(' You may need to manually run:');
console.error(` chmod +x ${binaryPath}`);
}
}
console.log('');
console.log('✅ SZCI installation completed successfully!');
console.log('');
console.log('You can now use SZCI by running:');
console.log(' szci --help');
console.log('');
console.log('===========================================');
}
// Run the installation
main().catch(err => {
console.error(`❌ Installation failed: ${err.message}`);
process.exit(1);
});

View File

@@ -1,10 +1,10 @@
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
import { tap, expect } from '@push.rocks/tapbundle';
// Disable TLS certificate validation for testing
Deno.env.set('NODE_TLS_REJECT_UNAUTHORIZED', '0');
import * as cloudlyConnectorMod from '../ts/connector.cloudly/cloudlyconnector.js';
import { CloudlyConnector } from '../ts/connector.cloudly/cloudlyconnector.ts';
tap.test('should be able to announce a container to cloudly', async () => {
const cloudlyConnector = new cloudlyConnectorMod.CloudlyConnector(null);
Deno.test('should be able to announce a container to cloudly', async () => {
const cloudlyConnector = new CloudlyConnector(null);
await cloudlyConnector.announceDockerContainer(
{
registryUrl: 'registry.losssless.com',
@@ -15,12 +15,3 @@ tap.test('should be able to announce a container to cloudly', async () => {
'cloudly.lossless.one'
);
});
tap.test('should close the program despite socket timeout', async (toolsArg) => {
// TODO: remove when unreffed timeouts in webrequest have been solved.
toolsArg.delayFor(0).then(() => {
process.exit();
});
});
tap.start();

View File

@@ -1,97 +1,84 @@
import { tap, expect } from '@push.rocks/tapbundle';
import * as path from 'path';
import { assertEquals } from '@std/assert';
import * as path from '@std/path';
import * as smartpath from '@push.rocks/smartpath';
process.env.NPMTS_TEST = 'true';
process.env.NPMCI_URL_CLOUDLY = 'localhost';
// Set up test environment
Deno.env.set('NPMTS_TEST', 'true');
Deno.env.set('NPMCI_URL_CLOUDLY', 'localhost');
Deno.env.set('CI_REPOSITORY_URL', 'https://yyyyyy:xxxxxxxx@gitlab.com/mygroup/myrepo.git');
Deno.env.set('CI_BUILD_TOKEN', 'kjlkjfiudofiufs');
Deno.env.set('NPMCI_LOGIN_DOCKER', 'docker.io|someuser|somepass');
Deno.env.set('NPMCI_SSHKEY_1', 'hostString|somePrivKey|##');
// set up environment
process.env.CI_REPOSITORY_URL = 'https://yyyyyy:xxxxxxxx@gitlab.com/mygroup/myrepo.git';
process.env.CI_BUILD_TOKEN = 'kjlkjfiudofiufs';
// Get the test assets directory
const testAssetsDir = path.join(smartpath.get.dirnameFromImportMetaUrl(import.meta.url), 'assets/');
// Docker
process.env.NPMCI_LOGIN_DOCKER = 'docker.io|someuser|somepass';
// Save original cwd and change to test assets
const originalCwd = Deno.cwd();
Deno.chdir(testAssetsDir);
// SSH env
process.env.NPMCI_SSHKEY_1 = 'hostString|somePrivKey|##';
process.cwd = () => {
return path.join(smartpath.get.dirnameFromImportMetaUrl(import.meta.url), 'assets/');
};
import type * as npmciTypes from '../ts/index.js';
const npmci = await import('../ts/index.js');
import type { Dockerfile } from '../ts/manager.docker/mod.classes.dockerfile.ts';
import { Szci } from '../ts/szci.classes.szci.ts';
import * as DockerfileModule from '../ts/manager.docker/mod.classes.dockerfile.ts';
// ======
// Docker
// ======
let dockerfile1: npmciTypes.Dockerfile;
let dockerfile2: npmciTypes.Dockerfile;
let sortableArray: npmciTypes.Dockerfile[];
let dockerfile1: Dockerfile;
let dockerfile2: Dockerfile;
let sortableArray: Dockerfile[];
tap.test('should return valid Dockerfiles', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
dockerfile1 = new npmci.Dockerfile(npmciInstance.dockerManager, {
Deno.test('should return valid Dockerfiles', async () => {
const szciInstance = new Szci();
await szciInstance.start();
dockerfile1 = new DockerfileModule.Dockerfile(szciInstance.dockerManager, {
filePath: './Dockerfile',
read: true,
});
dockerfile2 = new npmci.Dockerfile(npmciInstance.dockerManager, {
dockerfile2 = new DockerfileModule.Dockerfile(szciInstance.dockerManager, {
filePath: './Dockerfile_sometag1',
read: true,
});
expect(dockerfile1.version).toEqual('latest');
return expect(dockerfile2.version).toEqual('sometag1');
assertEquals(dockerfile1.version, 'latest');
assertEquals(dockerfile2.version, 'sometag1');
});
tap.test('should read a directory of Dockerfiles', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
return npmci.Dockerfile.readDockerfiles(npmciInstance.dockerManager).then(
async (readDockerfilesArrayArg: npmciTypes.Dockerfile[]) => {
sortableArray = readDockerfilesArrayArg;
return expect(readDockerfilesArrayArg[1].version).toEqual('sometag1');
}
Deno.test('should read a directory of Dockerfiles', async () => {
const szciInstance = new Szci();
await szciInstance.start();
const readDockerfilesArray = await DockerfileModule.Dockerfile.readDockerfiles(
szciInstance.dockerManager
);
sortableArray = readDockerfilesArray;
assertEquals(readDockerfilesArray[1].version, 'sometag1');
});
tap.test('should sort an array of Dockerfiles', async () => {
return npmci.Dockerfile.sortDockerfiles(sortableArray).then(
async (sortedArrayArg: npmciTypes.Dockerfile[]) => {
console.log(sortedArrayArg);
}
);
Deno.test('should sort an array of Dockerfiles', async () => {
const sortedArray = await DockerfileModule.Dockerfile.sortDockerfiles(sortableArray);
console.log(sortedArray);
});
tap.test('should build all Dockerfiles', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
return npmciInstance.dockerManager.handleCli({
Deno.test('should build all Dockerfiles', async () => {
const szciInstance = new Szci();
await szciInstance.start();
await szciInstance.dockerManager.handleCli({
_: ['docker', 'build'],
});
});
tap.test('should test all Dockerfiles', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
return npmciInstance.dockerManager.handleCli({
Deno.test('should test all Dockerfiles', async () => {
const szciInstance = new Szci();
await szciInstance.start();
await szciInstance.dockerManager.handleCli({
_: ['docker', 'test'],
});
});
tap.test('should test dockerfiles', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
return npmciInstance.dockerManager.handleCli({
_: ['docker', 'test'],
});
});
tap.test('should login docker daemon', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
return npmciInstance.dockerManager.handleCli({
Deno.test('should login docker daemon', async () => {
const szciInstance = new Szci();
await szciInstance.start();
await szciInstance.dockerManager.handleCli({
_: ['docker', 'login'],
});
});
@@ -99,9 +86,9 @@ tap.test('should login docker daemon', async () => {
// ===
// SSH
// ===
tap.test('should prepare SSH keys', async () => {
const npmciModSsh = await import('../ts/mod_ssh/index.js');
return await npmciModSsh.handleCli({
Deno.test('should prepare SSH keys', async () => {
const npmciModSsh = await import('../ts/mod_ssh/index.ts');
await npmciModSsh.handleCli({
_: ['ssh', 'prepare'],
});
});
@@ -109,25 +96,21 @@ tap.test('should prepare SSH keys', async () => {
// ====
// node
// ====
tap.test('should install a certain version of node', async () => {
const npmciInstance = new npmci.Npmci();
await npmciInstance.start();
await npmciInstance.nodejsManager.handleCli({
Deno.test('should install a certain version of node', async () => {
const szciInstance = new Szci();
await szciInstance.start();
await szciInstance.nodejsManager.handleCli({
_: ['node', 'install', 'stable'],
});
await npmciInstance.nodejsManager.handleCli({
await szciInstance.nodejsManager.handleCli({
_: ['node', 'install', 'lts'],
});
await npmciInstance.nodejsManager.handleCli({
await szciInstance.nodejsManager.handleCli({
_: ['node', 'install', 'legacy'],
});
});
// make sure test ends all right
tap.test('reset paths', async () => {
process.cwd = () => {
return path.join(__dirname, '../');
};
// Restore original working directory after all tests
Deno.test('reset paths', () => {
Deno.chdir(originalCwd);
});
tap.start();

View File

@@ -2,7 +2,7 @@
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@ship.zone/npmci',
version: '4.1.37',
description: 'A tool to streamline Node.js and Docker workflows within CI environments, particularly GitLab CI, providing various CI/CD utilities.'
name: '@ship.zone/szci',
version: '6.0.1',
description: 'Serve Zone CI - A tool to streamline Node.js and Docker workflows within CI environments, particularly GitLab CI, providing various CI/CD utilities. Powered by Deno with standalone executables.'
}

View File

@@ -1,23 +1,23 @@
import * as plugins from '../npmci.plugins.js';
import * as plugins from '../szci.plugins.ts';
import { Npmci } from '../npmci.classes.npmci.js';
import { logger } from '../npmci.logging.js';
import { Szci } from '../szci.classes.szci.ts';
import { logger } from '../szci.logging.ts';
/**
* connects to cloudly
*/
export class CloudlyConnector {
public npmciRef: Npmci;
public szciRef: Szci;
constructor(npmciRefArg: Npmci) {
this.npmciRef = npmciRefArg;
constructor(szciRefArg: Szci) {
this.szciRef = szciRefArg;
}
public async announceDockerContainer(
optionsArg: plugins.tsclass.container.IContainer,
testCloudlyUrlArg?: string
) {
const cloudlyUrl = testCloudlyUrlArg || this.npmciRef.npmciConfig.getConfig().urlCloudly;
const cloudlyUrl = testCloudlyUrlArg || this.szciRef.npmciConfig.getConfig().urlCloudly;
if (!cloudlyUrl) {
logger.log(
'warn',

View File

@@ -1,10 +1,10 @@
import { Npmci } from './npmci.classes.npmci.js';
import { Dockerfile } from './manager.docker/mod.classes.dockerfile.js';
import { Szci } from './szci.classes.szci.ts';
import { Dockerfile } from './manager.docker/mod.classes.dockerfile.ts';
export const npmciInstance = new Npmci();
export const szciInstance = new Npmci();
export { Dockerfile, Npmci };
export const runCli = async () => {
await npmciInstance.start();
await szciInstance.start();
};

View File

@@ -1,14 +1,14 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import * as paths from '../npmci.paths.js';
import { bash } from '../npmci.bash.js';
import { Npmci } from '../npmci.classes.npmci.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
import * as paths from '../szci.paths.ts';
import { bash } from '../szci.bash.ts';
import { Szci } from '../szci.classes.szci.ts';
export class NpmciCloudronManager {
public npmciRef: Npmci;
export class SzciCloudronManager {
public szciRef: Szci;
constructor(npmciArg: Npmci) {
this.npmciRef = npmciArg;
constructor(szciArg: Szci) {
this.szciRef = szciArg;
}
/**
@@ -44,14 +44,14 @@ export class NpmciCloudronManager {
logger.log('ok', 'cloudron cli installed');
// lets set the version in the CloudronManifest file
await this.prepareCloudronManifest(this.npmciRef.npmciConfig.getConfig().projectInfo.npm.version);
await this.prepareCloudronManifest(this.szciRef.npmciConfig.getConfig().projectInfo.npm.version);
logger.log('ok', 'CloudronManifest prepared');
// lets figure out the docker image tag
const dockerImageTag = await this.npmciRef.npmciConfig.kvStorage.readKey('latestPushedDockerTag');
const appName = this.npmciRef.npmciConfig.getConfig().cloudronAppName;
const dockerImageTag = await this.szciRef.npmciConfig.kvStorage.readKey('latestPushedDockerTag');
const appName = this.szciRef.npmciConfig.getConfig().cloudronAppName;
const cloudronEnvVar = process.env.NPMCI_LOGIN_CLOUDRON;
const cloudronEnvVar = Deno.env.get("NPMCI_LOGIN_CLOUDRON");
const cloudronServer = cloudronEnvVar.split('|')[0];
const cloudronToken = cloudronEnvVar.split('|')[1];
await bash(`cloudron update --server ${cloudronServer} --token ${cloudronToken} --image ${dockerImageTag} --app ${appName}`);

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,20 +1,20 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import * as paths from '../npmci.paths.js';
import { bash } from '../npmci.bash.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
import * as paths from '../szci.paths.ts';
import { bash } from '../szci.bash.ts';
// classes
import { Npmci } from '../npmci.classes.npmci.js';
import { Dockerfile } from './mod.classes.dockerfile.js';
import { DockerRegistry } from './mod.classes.dockerregistry.js';
import { RegistryStorage } from './mod.classes.registrystorage.js';
import { Szci } from '../szci.classes.szci.ts';
import { Dockerfile } from './mod.classes.dockerfile.ts';
import { DockerRegistry } from './mod.classes.dockerregistry.ts';
import { RegistryStorage } from './mod.classes.registrystorage.ts';
export class NpmciDockerManager {
public npmciRef: Npmci;
export class SzciDockerManager {
public szciRef: Szci;
public npmciRegistryStorage = new RegistryStorage();
constructor(npmciArg: Npmci) {
this.npmciRef = npmciArg;
constructor(szciArg: Szci) {
this.szciRef = szciArg;
}
/**
@@ -77,24 +77,24 @@ export class NpmciDockerManager {
*/
public prepare = async () => {
// Always login to GitLab Registry
if (process.env.GITLAB_CI) {
if (Deno.env.get("GITLAB_CI")) {
console.log('gitlab ci detected');
if (!process.env.CI_JOB_TOKEN || process.env.CI_JOB_TOKEN === '') {
if (!Deno.env.get("CI_JOB_TOKEN") || Deno.env.get("CI_JOB_TOKEN") === '') {
logger.log('error', 'Running in Gitlab CI, but no registry token specified by gitlab!');
process.exit(1);
Deno.exit(1);
}
this.npmciRegistryStorage.addRegistry(
new DockerRegistry({
registryUrl: 'registry.gitlab.com',
username: 'gitlab-ci-token',
password: process.env.CI_JOB_TOKEN,
password: Deno.env.get("CI_JOB_TOKEN"),
})
);
}
// handle registries
await plugins.smartobject.forEachMinimatch(
process.env,
Deno.env.toObject(),
'NPMCI_LOGIN_DOCKER*',
async (envString: string) => {
this.npmciRegistryStorage.addRegistry(DockerRegistry.fromEnvString(envString));
@@ -115,14 +115,14 @@ export class NpmciDockerManager {
if (argvArg._.length >= 3 && argvArg._[2] !== 'npmextra') {
dockerRegistryUrls.push(argvArg._[2]);
} else {
if (this.npmciRef.npmciConfig.getConfig().dockerRegistries.length === 0) {
if (this.szciRef.npmciConfig.getConfig().dockerRegistries.length === 0) {
logger.log(
'warn',
`There are no docker registries listed in npmextra.json! This is strange!`
);
}
dockerRegistryUrls = dockerRegistryUrls.concat(
this.npmciRef.npmciConfig.getConfig().dockerRegistries
this.szciRef.npmciConfig.getConfig().dockerRegistries
);
}
@@ -145,7 +145,7 @@ export class NpmciDockerManager {
'error',
`Cannot push to registry ${dockerRegistryUrl}, because it was not found in the authenticated registry list.`
);
process.exit(1);
Deno.exit(1);
}
for (const dockerfile of dockerfileArray) {
await dockerfile.push(dockerRegistryToPushTo, suffix);

View File

@@ -1,13 +1,13 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../npmci.paths.js';
import * as plugins from './mod.plugins.ts';
import * as paths from '../szci.paths.ts';
import { logger } from '../npmci.logging.js';
import { bash } from '../npmci.bash.js';
import { logger } from '../szci.logging.ts';
import { bash } from '../szci.bash.ts';
import { DockerRegistry } from './mod.classes.dockerregistry.js';
import * as helpers from './mod.helpers.js';
import { NpmciDockerManager } from './index.js';
import { Npmci } from '../npmci.classes.npmci.js';
import { DockerRegistry } from './mod.classes.dockerregistry.ts';
import * as helpers from './mod.helpers.ts';
import { SzciDockerManager } from './index.ts';
import { Szci } from '../szci.classes.szci.ts';
/**
* class Dockerfile represents a Dockerfile on disk in npmci
@@ -20,7 +20,7 @@ export class Dockerfile {
* @returns Promise<Dockerfile[]>
*/
public static async readDockerfiles(
npmciDockerManagerRefArg: NpmciDockerManager
npmciDockerManagerRefArg: SzciDockerManager
): Promise<Dockerfile[]> {
const fileTree = await plugins.smartfile.fs.listFileTree(paths.cwd, 'Dockerfile*');
@@ -167,7 +167,7 @@ export class Dockerfile {
}
versionString = versionString.replace(
'##version##',
dockerfileInstanceArg.npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().projectInfo.npm
dockerfileInstanceArg.npmciDockerManagerRef.szciRef.npmciConfig.getConfig().projectInfo.npm
.version
);
return versionString;
@@ -194,7 +194,7 @@ export class Dockerfile {
const argMatch = trimmedLine.match(/^ARG\s+([^\s=]+)(?:=(.*))?$/i);
if (argMatch) {
const argName = argMatch[1];
const argValue = argMatch[2] !== undefined ? argMatch[2] : process.env[argName] || '';
const argValue = argMatch[2] !== undefined ? argMatch[2] : Deno.env.get(argName) || '';
args[argName] = argValue;
continue;
}
@@ -236,7 +236,7 @@ export class Dockerfile {
* returns the docker tag
*/
public static getDockerTagString(
npmciDockerManagerRef: NpmciDockerManager,
npmciDockerManagerRef: SzciDockerManager,
registryArg: string,
repoArg: string,
versionArg: string,
@@ -244,7 +244,7 @@ export class Dockerfile {
): string {
// determine wether the repo should be mapped accordingly to the registry
const mappedRepo =
npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().dockerRegistryRepoMap[registryArg];
npmciDockerManagerRef.szciRef.npmciConfig.getConfig().dockerRegistryRepoMap[registryArg];
const repo = (() => {
if (mappedRepo) {
return mappedRepo;
@@ -264,27 +264,27 @@ export class Dockerfile {
}
public static async getDockerBuildArgs(
npmciDockerManagerRef: NpmciDockerManager
npmciDockerManagerRef: SzciDockerManager
): Promise<string> {
logger.log('info', 'checking for env vars to be supplied to the docker build');
let buildArgsString: string = '';
for (const dockerArgKey of Object.keys(
npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().dockerBuildargEnvMap
npmciDockerManagerRef.szciRef.npmciConfig.getConfig().dockerBuildargEnvMap
)) {
const dockerArgOuterEnvVar =
npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().dockerBuildargEnvMap[dockerArgKey];
npmciDockerManagerRef.szciRef.npmciConfig.getConfig().dockerBuildargEnvMap[dockerArgKey];
logger.log(
'note',
`docker ARG "${dockerArgKey}" maps to outer env var "${dockerArgOuterEnvVar}"`
);
const targetValue = process.env[dockerArgOuterEnvVar];
const targetValue = Deno.env.get(dockerArgOuterEnvVar);
buildArgsString = `${buildArgsString} --build-arg ${dockerArgKey}="${targetValue}"`;
}
return buildArgsString;
}
// INSTANCE
public npmciDockerManagerRef: NpmciDockerManager;
public npmciDockerManagerRef: SzciDockerManager;
public filePath: string;
public repo: string;
@@ -299,15 +299,15 @@ export class Dockerfile {
public localBaseDockerfile: Dockerfile;
constructor(
dockerManagerRefArg: NpmciDockerManager,
dockerManagerRefArg: SzciDockerManager,
options: { filePath?: string; fileContents?: string | Buffer; read?: boolean }
) {
this.npmciDockerManagerRef = dockerManagerRefArg;
this.filePath = options.filePath;
this.repo =
this.npmciDockerManagerRef.npmciRef.npmciEnv.repo.user +
this.npmciDockerManagerRef.szciRef.npmciEnv.repo.user +
'/' +
this.npmciDockerManagerRef.npmciRef.npmciEnv.repo.repo;
this.npmciDockerManagerRef.szciRef.npmciEnv.repo.repo;
this.version = Dockerfile.dockerFileVersion(this, plugins.path.parse(options.filePath).base);
this.cleanTag = this.repo + ':' + this.version;
this.buildTag = this.cleanTag;
@@ -327,7 +327,7 @@ export class Dockerfile {
logger.log('info', 'now building Dockerfile for ' + this.cleanTag);
const buildArgsString = await Dockerfile.getDockerBuildArgs(this.npmciDockerManagerRef);
const buildCommand = `docker build --label="version=${
this.npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().projectInfo.npm.version
this.npmciDockerManagerRef.szciRef.npmciConfig.getConfig().projectInfo.npm.version
}" -t ${this.buildTag} -f ${this.filePath} ${buildArgsString} .`;
await bash(buildCommand);
return;
@@ -350,13 +350,13 @@ export class Dockerfile {
await bash(`docker inspect --format="{{index .RepoDigests 0}}" ${this.pushTag}`)
).split('@')[1];
console.log(`The image ${this.pushTag} has digest ${imageDigest}`);
await this.npmciDockerManagerRef.npmciRef.cloudlyConnector.announceDockerContainer({
await this.npmciDockerManagerRef.szciRef.cloudlyConnector.announceDockerContainer({
registryUrl: this.pushTag,
tag: this.buildTag,
labels: [],
version: this.npmciDockerManagerRef.npmciRef.npmciConfig.getConfig().projectInfo.npm.version,
version: this.npmciDockerManagerRef.szciRef.npmciConfig.getConfig().projectInfo.npm.version,
});
await this.npmciDockerManagerRef.npmciRef.npmciConfig.kvStorage.writeKey(
await this.npmciDockerManagerRef.szciRef.npmciConfig.kvStorage.writeKey(
'latestPushedDockerTag',
this.pushTag
);
@@ -381,7 +381,7 @@ export class Dockerfile {
* tests the Dockerfile;
*/
public async test() {
const testFile: string = plugins.path.join(paths.NpmciTestDir, 'test_' + this.version + '.sh');
const testFile: string = plugins.path.join(paths.SzciTestDir, 'test_' + this.version + '.sh');
const testFileExists: boolean = plugins.smartfile.fs.fileExistsSync(testFile);
if (testFileExists) {
// run tests

View File

@@ -1,6 +1,6 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import { bash } from '../npmci.bash.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
import { bash } from '../szci.bash.ts';
export interface IDockerRegistryConstructorOptions {
registryUrl: string;
@@ -23,7 +23,7 @@ export class DockerRegistry {
const dockerRegexResultArray = envString.split('|');
if (dockerRegexResultArray.length !== 3) {
logger.log('error', 'malformed docker env var...');
process.exit(1);
Deno.exit(1);
return;
}
const registryUrl = dockerRegexResultArray[0].replace('https://', '').replace('http://', '');

View File

@@ -1,7 +1,7 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
import { DockerRegistry } from './mod.classes.dockerregistry.js';
import { DockerRegistry } from './mod.classes.dockerregistry.ts';
export class RegistryStorage {
objectMap = new plugins.lik.ObjectMap<DockerRegistry>();

View File

@@ -1,5 +1,5 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import * as paths from '../npmci.paths.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
import * as paths from '../szci.paths.ts';
import { Dockerfile } from './mod.classes.dockerfile.js';
import { Dockerfile } from './mod.classes.dockerfile.ts';

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,13 +1,13 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import { bash, bashNoError } from '../npmci.bash.js';
import { Npmci } from '../npmci.classes.npmci.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
import { bash, bashNoError } from '../szci.bash.ts';
import { Szci } from '../szci.classes.szci.ts';
export class NpmciGitManager {
public npmciRef: Npmci;
export class SzciGitManager {
public szciRef: Szci;
constructor(npmciRefArg: Npmci) {
this.npmciRef = npmciRefArg;
constructor(szciRefArg: Szci) {
this.szciRef = szciRefArg;
}
/**
@@ -30,12 +30,12 @@ export class NpmciGitManager {
};
public mirror = async () => {
const githubToken = process.env.NPMCI_GIT_GITHUBTOKEN;
const githubUser = process.env.NPMCI_GIT_GITHUBGROUP || this.npmciRef.npmciEnv.repo.user;
const githubRepo = process.env.NPMCI_GIT_GITHUB || this.npmciRef.npmciEnv.repo.repo;
const githubToken = Deno.env.get("NPMCI_GIT_GITHUBTOKEN");
const githubUser = Deno.env.get("NPMCI_GIT_GITHUBGROUP") || this.szciRef.npmciEnv.repo.user;
const githubRepo = Deno.env.get("NPMCI_GIT_GITHUB") || this.szciRef.npmciEnv.repo.repo;
if (
this.npmciRef.npmciConfig.getConfig().projectInfo.npm.packageJson.private === true ||
this.npmciRef.npmciConfig.getConfig().npmAccessLevel === 'private'
this.szciRef.npmciConfig.getConfig().projectInfo.npm.packageJson.private === true ||
this.szciRef.npmciConfig.getConfig().npmAccessLevel === 'private'
) {
logger.log(
'warn',
@@ -65,7 +65,7 @@ export class NpmciGitManager {
await bashNoError('git remote rm mirror');
} else {
logger.log('error', `cannot find NPMCI_GIT_GITHUBTOKEN env var!`);
process.exit(1);
Deno.exit(1);
}
};
}

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,15 +1,15 @@
import * as plugins from '../npmci.plugins.js';
import * as paths from '../npmci.paths.js';
import * as plugins from '../szci.plugins.ts';
import * as paths from '../szci.paths.ts';
import { logger } from '../npmci.logging.js';
import { bash, bashNoError, nvmAvailable } from '../npmci.bash.js';
import { Npmci } from '../npmci.classes.npmci.js';
import { logger } from '../szci.logging.ts';
import { bash, bashNoError, nvmAvailable } from '../szci.bash.ts';
import { Szci } from '../szci.classes.szci.ts';
export class NpmciNodeJsManager {
public npmciRef: Npmci;
export class SzciNodeJsManager {
public szciRef: Szci;
constructor(npmciRefArg: Npmci) {
this.npmciRef = npmciRefArg;
constructor(szciRefArg: Szci) {
this.szciRef = szciRefArg;
}
/**
@@ -25,14 +25,14 @@ export class NpmciNodeJsManager {
break;
default:
logger.log('error', `>>npmci node ...<< action >>${action}<< not supported`);
process.exit(1);
Deno.exit(1);
}
} else {
logger.log(
'error',
`>>npmci node ...<< cli arguments invalid... Please read the documentation.`
);
process.exit(1);
Deno.exit(1);
}
}
@@ -64,7 +64,7 @@ export class NpmciNodeJsManager {
await bash('npm -v');
// lets look for further config
const config = await this.npmciRef.npmciConfig.getConfig();
const config = await this.szciRef.npmciConfig.getConfig();
logger.log('info', 'Now checking for needed global npm tools...');
for (const npmTool of config.npmGlobalTools) {
logger.log('info', `Checking for global "${npmTool}"`);

View File

@@ -1,15 +1,15 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../npmci.paths.js';
import * as plugins from './mod.plugins.ts';
import * as paths from '../szci.paths.ts';
import { logger } from '../npmci.logging.js';
import { bash, bashNoError, nvmAvailable } from '../npmci.bash.js';
import { Npmci } from '../npmci.classes.npmci.js';
import { logger } from '../szci.logging.ts';
import { bash, bashNoError, nvmAvailable } from '../szci.bash.ts';
import { Szci } from '../szci.classes.szci.ts';
export class NpmciNpmManager {
public npmciRef: Npmci;
export class SzciNpmManager {
public szciRef: Szci;
constructor(npmciRefArg: Npmci) {
this.npmciRef = npmciRefArg;
constructor(szciRefArg: Szci) {
this.szciRef = szciRefArg;
}
/**
@@ -37,14 +37,14 @@ export class NpmciNpmManager {
break;
default:
logger.log('error', `>>npmci npm ...<< action >>${action}<< not supported`);
process.exit(1);
Deno.exit(1);
}
} else {
logger.log(
'info',
`>>npmci npm ...<< cli arguments invalid... Please read the documentation.`
);
process.exit(1);
Deno.exit(1);
}
}
@@ -53,10 +53,10 @@ export class NpmciNpmManager {
*/
public async prepare() {
logger.log('info', 'running >>npm prepare<<');
const config = this.npmciRef.npmciConfig.getConfig();
const config = this.szciRef.npmciConfig.getConfig();
let npmrcFileString: string = '';
await plugins.smartobject.forEachMinimatch(
process.env,
Deno.env.toObject(),
'NPMCI_TOKEN_NPM*',
(npmEnvArg: string) => {
if (!npmEnvArg) {
@@ -83,14 +83,14 @@ export class NpmciNpmManager {
logger.log('info', 'found one or more access tokens');
} else {
logger.log('error', 'no access token found! Exiting!');
process.exit(1);
Deno.exit(1);
}
// lets save it to disk
plugins.smartfile.memory.toFsSync(npmrcFileString, '/root/.npmrc');
// lets set the cache directory
await bash(`npm config set cache ${paths.NpmciCacheDir} --global `);
await bash(`npm config set cache ${paths.SzciCacheDir} --global `);
return;
}
@@ -103,10 +103,10 @@ export class NpmciNpmManager {
let npmAccessCliString = ``;
let npmRegistryCliString = ``;
let publishVerdaccioAsWell = false;
const config = this.npmciRef.npmciConfig.getConfig();
const config = this.szciRef.npmciConfig.getConfig();
const availableRegistries: string[] = [];
await plugins.smartobject.forEachMinimatch(
process.env,
Deno.env.toObject(),
'NPMCI_TOKEN_NPM*',
(npmEnvArg: string) => {
availableRegistries.push(npmEnvArg.split('|')[0]);
@@ -127,7 +127,7 @@ export class NpmciNpmManager {
npmRegistryCliString = `--registry=https://${config.npmRegistryUrl}`;
} else {
logger.log('error', `no registry url specified. Can't publish!`);
process.exit(1);
Deno.exit(1);
}
let publishCommand = `npm publish ${npmAccessCliString} ${npmRegistryCliString} `;

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,10 +1,10 @@
import * as plugins from './mod.plugins.js';
import * as paths from '../npmci.paths.js';
import * as plugins from './mod.plugins.ts';
import * as paths from '../szci.paths.ts';
/**
* cleans npmci config files
*/
export let clean = async (): Promise<void> => {
plugins.smartfile.fs.removeSync(paths.NpmciPackageConfig);
plugins.smartfile.fs.removeSync(paths.SzciPackageConfig);
return;
};

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,9 +1,9 @@
import * as plugins from './mod.plugins.js';
import { bash } from '../npmci.bash.js';
import * as plugins from './mod.plugins.ts';
import { bash } from '../szci.bash.ts';
export let command = async () => {
let wrappedCommand: string = '';
let argvArray = process.argv;
let argvArray = ['deno', 'mod.ts', ...Deno.args];
for (let i = 3; i < argvArray.length; i++) {
wrappedCommand = wrappedCommand + argvArray[i];
if (i + 1 !== argvArray.length) {

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,15 +1,15 @@
import * as plugins from './plugins.js';
import * as paths from '../npmci.paths.js';
import { logger } from '../npmci.logging.js';
import { Npmci } from '../npmci.classes.npmci.js';
import * as plugins from './plugins.ts';
import * as paths from '../szci.paths.ts';
import { logger } from '../szci.logging.ts';
import { Szci } from '../szci.classes.szci.ts';
export const handleCli = async (npmciRefArg: Npmci, argvArg: any) => {
export const handleCli = async (szciRefArg: Szci, argvArg: any) => {
logger.log('info', 'checking execution context');
const presentRunnerTags = process.env.CI_RUNNER_TAGS.split(',').map((stringArg) =>
const presentRunnerTags = Deno.env.get("CI_RUNNER_TAGS").split(',').map((stringArg) =>
stringArg.trim()
);
let allDesiredGitlabRunnerTagsPresent = true;
for (const desiredRunnerTag of npmciRefArg.npmciConfig.getConfig().gitlabRunnerTags) {
for (const desiredRunnerTag of szciRefArg.npmciConfig.getConfig().gitlabRunnerTags) {
if (!presentRunnerTags.includes(desiredRunnerTag)) {
allDesiredGitlabRunnerTagsPresent = false;
logger.log(
@@ -19,6 +19,6 @@ export const handleCli = async (npmciRefArg: Npmci, argvArg: any) => {
}
}
if (!allDesiredGitlabRunnerTagsPresent) {
process.exit(1);
Deno.exit(1);
}
};

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,5 +1,5 @@
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.js';
import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.ts';
let sshInstance: plugins.smartssh.SshInstance;
export let handleCli = async (argvArg: any) => {
@@ -11,11 +11,11 @@ export let handleCli = async (argvArg: any) => {
break;
default:
logger.log('error', `action >>${action}<< not supported`);
process.exit(1);
Deno.exit(1);
}
} else {
logger.log('error', `>>npmci ssh ...<< please specify an action!`);
process.exit(1);
Deno.exit(1);
}
};
@@ -31,8 +31,8 @@ const notUndefined = (stringArg: string) => {
*/
export let prepare = async () => {
sshInstance = new plugins.smartssh.SshInstance(); // init ssh instance
plugins.smartobject.forEachMinimatch(process.env, 'NPMCI_SSHKEY_*', evaluateSshEnv);
if (!process.env.NPMTS_TEST) {
plugins.smartobject.forEachMinimatch(Deno.env.toObject(), 'NPMCI_SSHKEY_*', evaluateSshEnv);
if (!Deno.env.get("NPMTS_TEST")) {
sshInstance.writeToDisk();
} else {
logger.log('info', 'In test mode, so not storing SSH keys to disk!');

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,13 +1,13 @@
import * as plugins from './mod.plugins.js';
import { bash } from '../npmci.bash.js';
import { logger } from '../npmci.logging.js';
import * as plugins from './mod.plugins.ts';
import { bash } from '../szci.bash.ts';
import { logger } from '../szci.logging.ts';
const triggerValueRegex =
/^([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|?([a-zA-Z0-9\.\-\/]*)/;
export let trigger = async () => {
logger.log('info', 'now running triggers');
await plugins.smartobject.forEachMinimatch(process.env, 'NPMCI_TRIGGER_*', evaluateTrigger);
await plugins.smartobject.forEachMinimatch(Deno.env.toObject(), 'NPMCI_TRIGGER_*', evaluateTrigger);
};
const evaluateTrigger = async (triggerEnvVarArg) => {

View File

@@ -1 +1 @@
export * from '../npmci.plugins.js';
export * from '../szci.plugins.ts';

View File

@@ -1,61 +0,0 @@
import * as plugins from './npmci.plugins.js';
// env
import { NpmciEnv } from './npmci.classes.npmcienv.js';
import { NpmciInfo } from './npmci.classes.npmciinfo.js';
import { NpmciCli } from './npmci.classes.npmcicli.js';
import { NpmciConfig } from './npmci.classes.npmciconfig.js';
// connectors
import { CloudlyConnector } from './connector.cloudly/cloudlyconnector.js';
// managers
import { NpmciCloudronManager } from './manager.cloudron/index.js';
import { NpmciDockerManager } from './manager.docker/index.js';
import { NpmciGitManager } from './manager.git/index.js';
import { NpmciNodeJsManager } from './manager.nodejs/index.js';
import { NpmciNpmManager } from './manager.npm/index.js';
export class Npmci {
public analytics: plugins.smartanalytics.Analytics;
public cloudlyConnector: CloudlyConnector;
public npmciEnv: NpmciEnv;
public npmciInfo: NpmciInfo;
public npmciConfig: NpmciConfig;
public npmciCli: NpmciCli;
// managers
public cloudronManager: NpmciCloudronManager;
public dockerManager: NpmciDockerManager;
public gitManager: NpmciGitManager;
public nodejsManager: NpmciNodeJsManager;
public npmManager: NpmciNpmManager;
constructor() {
this.analytics = new plugins.smartanalytics.Analytics({
apiEndPoint: 'https://pubapi.lossless.one/analytics',
projectId: 'gitzone',
appName: 'npmci',
});
}
public async start() {
this.cloudlyConnector = new CloudlyConnector(this);
this.npmciEnv = new NpmciEnv(this);
this.npmciInfo = new NpmciInfo(this);
await this.npmciInfo.printToConsole();
this.npmciCli = new NpmciCli(this);
this.npmciConfig = new NpmciConfig(this);
await this.npmciConfig.init();
// managers
this.cloudronManager = new NpmciCloudronManager(this);
this.dockerManager = new NpmciDockerManager(this);
this.gitManager = new NpmciGitManager(this);
this.nodejsManager = new NpmciNodeJsManager(this);
this.npmManager = new NpmciNpmManager(this);
this.npmciCli.startParse();
}
}

View File

@@ -1,23 +0,0 @@
import * as plugins from './npmci.plugins.js';
import { Npmci } from './npmci.classes.npmci.js';
export class NpmciEnv {
public npmciRef: Npmci;
public repoString: string;
public repo: plugins.smartstring.GitRepo;
constructor(npmciRefArg: Npmci) {
this.npmciRef = npmciRefArg;
if (!this.repoString && process.env.GITLAB_CI) {
this.repoString = process.env.CI_REPOSITORY_URL;
}
if (!this.repoString && process.env.NPMCI_COMPUTED_REPOURL) {
this.repoString = process.env.NPMCI_COMPUTED_REPOURL;
}
if (!this.repoString) {
this.repoString = 'https://undefined:undefined@github.com/undefined/undefined.git';
}
this.repo = new plugins.smartstring.GitRepo(this.repoString);
}
}

View File

@@ -1,17 +0,0 @@
import * as plugins from './npmci.plugins.js';
import * as paths from './npmci.paths.js';
import { logger } from './npmci.logging.js';
import { Npmci } from './npmci.classes.npmci.js';
export class NpmciInfo {
public npmciRef: Npmci;
public projectInfo = new plugins.projectinfo.ProjectinfoNpm(paths.NpmciPackageRoot);
constructor(npmciArg: Npmci) {
this.npmciRef = npmciArg;
}
public async printToConsole() {
await logger.log('info', `npmci version: ${this.projectInfo.version}`);
}
}

View File

@@ -1,16 +0,0 @@
import * as plugins from './npmci.plugins.js';
export const cwd = process.cwd();
// package paths
export const NpmciPackageRoot = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../'
);
export const NpmciPackageConfig = plugins.path.join(NpmciPackageRoot, './config.json');
// project paths
export const NpmciProjectDir = cwd;
export const NpmciProjectNogitDir = plugins.path.join(NpmciProjectDir, './.nogit');
export const NpmciTestDir = plugins.path.join(cwd, './test');
export const NpmciCacheDir = plugins.path.join(cwd, './.npmci_cache');

View File

@@ -1,6 +1,6 @@
import { logger } from './npmci.logging.js';
import * as plugins from './npmci.plugins.js';
import * as paths from './npmci.paths.js';
import { logger } from './szci.logging.ts';
import * as plugins from './szci.plugins.ts';
import * as paths from './szci.paths.ts';
/**
* wether nvm is available or not
@@ -19,7 +19,7 @@ const npmciSmartshell = new plugins.smartshell.Smartshell({
*/
const checkToolsAvailable = async () => {
// check for nvm
if (!process.env.NPMTS_TEST) {
if (!Deno.env.get('NPMTS_TEST')) {
if (
(await npmciSmartshell.execSilent(`bash -c "source /usr/local/nvm/nvm.sh"`)).exitCode === 0
) {
@@ -55,10 +55,10 @@ export let bash = async (commandArg: string, retryArg: number = 2): Promise<stri
retryArg = 0;
}
if (!process.env.NPMTS_TEST) {
if (!Deno.env.get('NPMTS_TEST')) {
// NPMTS_TEST is used during testing
for (let i = 0; i <= retryArg; i++) {
if (process.env.DEBUG_NPMCI === 'true') {
if (Deno.env.get('DEBUG_NPMCI') === 'true') {
console.log(commandArg);
}
execResult = await npmciSmartshell.exec(commandArg);
@@ -68,7 +68,7 @@ export let bash = async (commandArg: string, retryArg: number = 2): Promise<stri
// something went wrong and retries are exhausted
if (failOnError) {
logger.log('error', 'something went wrong and retries are exhausted');
process.exit(1);
Deno.exit(1);
}
} else if (execResult.exitCode === 0) {
// everything went fine, or no error wanted

61
ts/szci.classes.szci.ts Normal file
View File

@@ -0,0 +1,61 @@
import * as plugins from './szci.plugins.ts';
// env
import { SzciEnv } from './szci.classes.szcienv.ts';
import { SzciInfo } from './szci.classes.szciinfo.ts';
import { SzciCli } from './szci.classes.szcicli.ts';
import { SzciConfig } from './szci.classes.szciconfig.ts';
// connectors
import { CloudlyConnector } from './connector.cloudly/cloudlyconnector.ts';
// managers
import { SzciCloudronManager } from './manager.cloudron/index.ts';
import { SzciDockerManager } from './manager.docker/index.ts';
import { SzciGitManager } from './manager.git/index.ts';
import { SzciNodeJsManager } from './manager.nodejs/index.ts';
import { SzciNpmManager } from './manager.npm/index.ts';
export class Szci {
public analytics: plugins.smartanalytics.Analytics;
public cloudlyConnector: CloudlyConnector;
public npmciEnv: SzciEnv;
public npmciInfo: SzciInfo;
public npmciConfig: SzciConfig;
public npmciCli: SzciCli;
// managers
public cloudronManager: SzciCloudronManager;
public dockerManager: SzciDockerManager;
public gitManager: SzciGitManager;
public nodejsManager: SzciNodeJsManager;
public npmManager: SzciNpmManager;
constructor() {
this.analytics = new plugins.smartanalytics.Analytics({
apiEndPoint: 'https://pubapi.lossless.one/analytics',
projectId: 'gitzone',
appName: 'szci',
});
}
public async start() {
this.cloudlyConnector = new CloudlyConnector(this);
this.npmciEnv = new SzciEnv(this);
this.npmciInfo = new SzciInfo(this);
await this.npmciInfo.printToConsole();
this.npmciCli = new SzciCli(this);
this.npmciConfig = new SzciConfig(this);
await this.npmciConfig.init();
// managers
this.cloudronManager = new SzciCloudronManager(this);
this.dockerManager = new SzciDockerManager(this);
this.gitManager = new SzciGitManager(this);
this.nodejsManager = new SzciNodeJsManager(this);
this.npmManager = new SzciNpmManager(this);
this.npmciCli.startParse();
}
}

View File

@@ -1,16 +1,16 @@
import { logger } from './npmci.logging.js';
import * as plugins from './npmci.plugins.js';
import * as paths from './npmci.paths.js';
import { Npmci } from './npmci.classes.npmci.js';
import { logger } from './szci.logging.ts';
import * as plugins from './szci.plugins.ts';
import * as paths from './szci.paths.ts';
import { Szci } from './szci.classes.szci.ts';
export class NpmciCli {
public npmciRef: Npmci;
export class SzciCli {
public szciRef: Szci;
public smartcli: plugins.smartcli.Smartcli;
constructor(npmciArg: Npmci) {
this.npmciRef = npmciArg;
constructor(szciArg: Szci) {
this.szciRef = szciArg;
this.smartcli = new plugins.smartcli.Smartcli();
this.smartcli.addVersion(this.npmciRef.npmciInfo.projectInfo.version);
this.smartcli.addVersion(this.szciRef.npmciInfo.version);
// clean
this.smartcli.addCommand('clean').subscribe(
@@ -20,18 +20,18 @@ export class NpmciCli {
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
// cloudron
this.smartcli.addCommand('cloudron').subscribe(
async (argv) => {
await this.npmciRef.cloudronManager.handleCli(argv);
await this.szciRef.cloudronManager.handleCli(argv);
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
@@ -43,47 +43,47 @@ export class NpmciCli {
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
// git
this.smartcli.addCommand('git').subscribe(
async (argvArg) => {
await this.npmciRef.gitManager.handleCli(argvArg);
await this.szciRef.gitManager.handleCli(argvArg);
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
// build
this.smartcli.addCommand('docker').subscribe(
async (argvArg) => {
await this.npmciRef.dockerManager.handleCli(argvArg);
await this.szciRef.dockerManager.handleCli(argvArg);
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
// node
this.smartcli.addCommand('node').subscribe(
async (argvArg) => {
await this.npmciRef.nodejsManager.handleCli(argvArg);
await this.szciRef.nodejsManager.handleCli(argvArg);
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
// npm
this.smartcli.addCommand('npm').subscribe(
async (argvArg) => {
await this.npmciRef.npmManager.handleCli(argvArg);
await this.szciRef.npmManager.handleCli(argvArg);
},
(err) => {
console.log(err);
@@ -92,7 +92,7 @@ export class NpmciCli {
this.smartcli.addCommand('precheck').subscribe(async (argvArg) => {
const modPrecheck = await import('./mod_precheck/index.js');
await modPrecheck.handleCli(this.npmciRef, argvArg);
await modPrecheck.handleCli(this.szciRef, argvArg);
});
// trigger
@@ -109,7 +109,7 @@ export class NpmciCli {
},
(err) => {
console.log(err);
process.exit(1);
Deno.exit(1);
}
);
}

View File

@@ -1,13 +1,13 @@
import * as plugins from './npmci.plugins.js';
import * as paths from './npmci.paths.js';
import * as plugins from './szci.plugins.ts';
import * as paths from './szci.paths.ts';
import { logger } from './npmci.logging.js';
import { Npmci } from './npmci.classes.npmci.js';
import { logger } from './szci.logging.ts';
import { Szci } from './szci.classes.szci.ts';
/**
* the main config interface for npmci
*/
export interface INpmciOptions {
export interface ISzciOptions {
projectInfo: plugins.projectinfo.ProjectInfo;
// npm
@@ -33,28 +33,28 @@ export interface INpmciOptions {
/**
* a config class for Npmci
*/
export class NpmciConfig {
public npmciRef: Npmci;
export class SzciConfig {
public szciRef: Szci;
public npmciNpmextra: plugins.npmextra.Npmextra;
public kvStorage: plugins.npmextra.KeyValueStore;
public npmciQenv: plugins.qenv.Qenv;
private configObject: INpmciOptions;
private configObject: ISzciOptions;
constructor(npmciRefArg: Npmci) {
this.npmciRef = npmciRefArg;
constructor(szciRefArg: Szci) {
this.szciRef = szciRefArg;
}
public async init() {
this.npmciNpmextra = new plugins.npmextra.Npmextra(paths.cwd);
this.kvStorage = new plugins.npmextra.KeyValueStore({
typeArg: 'userHomeDir',
identityArg: `.npmci_${this.npmciRef.npmciEnv.repo.user}_${this.npmciRef.npmciEnv.repo.repo}`,
identityArg: `.npmci_${this.szciRef.npmciEnv.repo.user}_${this.szciRef.npmciEnv.repo.repo}`,
});
this.npmciQenv = new plugins.qenv.Qenv(
paths.NpmciProjectDir,
paths.NpmciProjectNogitDir,
paths.SzciProjectDir,
paths.SzciProjectNogitDir,
false
);
@@ -69,10 +69,10 @@ export class NpmciConfig {
dockerBuildargEnvMap: {},
urlCloudly: await this.npmciQenv.getEnvVarOnDemand('NPMCI_URL_CLOUDLY'),
};
this.configObject = this.npmciNpmextra.dataFor<INpmciOptions>('npmci', this.configObject);
this.configObject = this.npmciNpmextra.dataFor<ISzciOptions>('szci', this.configObject);
}
public getConfig(): INpmciOptions {
public getConfig(): ISzciOptions {
return this.configObject;
}
}

View File

@@ -0,0 +1,23 @@
import * as plugins from './szci.plugins.ts';
import { Szci } from './szci.classes.szci.ts';
export class SzciEnv {
public szciRef: Szci;
public repoString: string;
public repo: plugins.smartstring.GitRepo;
constructor(szciRefArg: Szci) {
this.szciRef = szciRefArg;
if (!this.repoString && Deno.env.get("GITLAB_CI")) {
this.repoString = Deno.env.get("CI_REPOSITORY_URL");
}
if (!this.repoString && Deno.env.get("NPMCI_COMPUTED_REPOURL")) {
this.repoString = Deno.env.get("NPMCI_COMPUTED_REPOURL");
}
if (!this.repoString) {
this.repoString = 'https://undefined:undefined@github.com/undefined/undefined.git';
}
this.repo = new plugins.smartstring.GitRepo(this.repoString);
}
}

View File

@@ -0,0 +1,18 @@
import * as plugins from './szci.plugins.ts';
import * as paths from './szci.paths.ts';
import { logger } from './szci.logging.ts';
import { Szci } from './szci.classes.szci.ts';
import denoConfig from '../deno.json' with { type: 'json' };
export class SzciInfo {
public szciRef: Szci;
public version = denoConfig.version;
constructor(szciArg: Szci) {
this.szciRef = szciArg;
}
public async printToConsole() {
await logger.log('info', `szci version: ${this.version}`);
}
}

View File

@@ -1,4 +1,4 @@
import * as plugins from './npmci.plugins.js';
import * as plugins from './szci.plugins.ts';
export const logger = new plugins.smartlog.Smartlog({
logContext: {

16
ts/szci.paths.ts Normal file
View File

@@ -0,0 +1,16 @@
import * as plugins from './szci.plugins.ts';
export const cwd = Deno.cwd();
// package paths
export const SzciPackageRoot = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../'
);
export const SzciPackageConfig = plugins.path.join(SzciPackageRoot, './config.json');
// project paths
export const SzciProjectDir = cwd;
export const SzciProjectNogitDir = plugins.path.join(SzciProjectDir, './.nogit');
export const SzciTestDir = plugins.path.join(cwd, './test');
export const SzciCacheDir = plugins.path.join(cwd, './.npmci_cache');

View File

@@ -1,5 +1,5 @@
// node native
import * as path from 'path';
// Deno std libraries
import * as path from '@std/path';
export { path };

View File

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

64
uninstall.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/bin/bash
# SZCI Uninstaller Script
# Removes SZCI from the system (installed via install.sh)
#
# Usage:
# sudo bash uninstall.sh
set -e
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root (sudo bash uninstall.sh)"
exit 1
fi
echo "================================================"
echo " SZCI Uninstaller"
echo " Serve Zone CI/CD Tool Removal"
echo "================================================"
echo ""
# Default installation directory
INSTALL_DIR="/opt/szci"
# Step 1: Remove global symlinks
echo "Checking for global symlinks..."
if [ -L "/usr/local/bin/szci" ]; then
echo "Removing symlink: /usr/local/bin/szci"
rm -f /usr/local/bin/szci
fi
if [ -L "/usr/bin/szci" ]; then
echo "Removing symlink: /usr/bin/szci"
rm -f /usr/bin/szci
fi
# Step 2: Remove installation directory
if [ -d "$INSTALL_DIR" ]; then
echo "Removing installation directory: $INSTALL_DIR"
rm -rf "$INSTALL_DIR"
else
echo "Installation directory not found: $INSTALL_DIR"
fi
echo ""
echo "================================================"
echo " SZCI Uninstallation Complete!"
echo "================================================"
echo ""
# Check for npm global installation
NODE_PATH=$(which node 2>/dev/null || true)
if [ -n "$NODE_PATH" ]; then
NPM_PATH=$(dirname "$NODE_PATH")/npm
if [ -x "$NPM_PATH" ]; then
echo "If you installed SZCI via npm, you may want to uninstall it with:"
echo " npm uninstall -g @ship.zone/szci"
echo ""
fi
fi
echo "SZCI has been removed from your system."
echo ""