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

This commit is contained in:
2025-10-26 15:23:56 +00:00
parent 4854d27a19
commit 88f64536c2
58 changed files with 1550 additions and 867 deletions

4
.gitignore vendored
View File

@@ -17,4 +17,8 @@ node_modules/
dist/ dist/
dist_*/ dist_*/
# deno
deno.lock
.deno/
# custom # 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,17 @@
# Changelog # Changelog
## 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) ## 2024-11-17 - 4.1.37 - fix(docker)
Enhanced base image extraction logic from Dockerfile 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": "5.0.0",
"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", "name": "@ship.zone/szci",
"version": "4.1.37", "version": "5.0.0",
"private": false, "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.",
"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"
],
"keywords": [ "keywords": [
"Node.js", "Node.js",
"Docker", "Docker",
@@ -84,11 +12,56 @@
"automation", "automation",
"npm", "npm",
"TypeScript", "TypeScript",
"Deno",
"cloud", "cloud",
"SSH", "SSH",
"registry", "registry",
"container management", "container management",
"continuous integration", "continuous integration",
"continuous deployment" "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

682
readme.md
View File

@@ -1,30 +1,115 @@
# @ship.zone/npmci # @ship.zone/szci
A tool to enhance Node.js and Docker workflows within GitLab CI, providing various CI/CD utilities.
## 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 ```sh
# Using npm npm install -g @ship.zone/szci
npm install @ship.zone/npmci
# Using yarn
yarn add @ship.zone/npmci
``` ```
## 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 ```yaml
image: hosttoday/ht-docker-node:npmci image: denoland/deno:alpine
stages: stages:
- prepare - prepare
@@ -32,463 +117,184 @@ stages:
- test - test
- deploy - deploy
default: variables:
before_script: SZCI_VERSION: "latest"
- npmci node install stable
- npmci npm install 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: prepare:
stage: prepare stage: prepare
script: script:
- npmci prepare npm - szci node install stable
- npmci prepare docker - szci npm install
build: build:
stage: build stage: build
script: script:
- npmci docker build - szci docker build
test: test:
stage: test stage: test
script: script:
- npmci npm test - szci npm test
deploy: deploy:
stage: deploy stage: deploy
script: script:
- npmci publish npm - szci docker push $CI_REGISTRY
- npmci docker push only:
- master
environment:
name: production
url: http://example.com
``` ```
#### GitHub Actions ### GitHub Actions
Similarly, you can set up `npmci` in GitHub Actions:
```yaml ```yaml
name: CI Pipeline name: CI Pipeline
on: on:
push: push:
branches: branches: [main]
- main
jobs: 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: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: prepare
steps: steps:
- run: npmci docker build - uses: actions/checkout@v3
test: - name: Install SZCI
runs-on: ubuntu-latest run: npm install -g @ship.zone/szci
needs: build
steps:
- run: npmci npm test
deploy: - name: Setup Node.js
runs-on: ubuntu-latest run: szci node install stable
needs: test
steps: - name: Install Dependencies
- run: npmci publish npm run: szci npm install
- run: npmci docker push
- 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 ## ⚙️ Configuration
Lastly, for Gitea CI: Create an `npmextra.json` file in your project root:
```yaml ```json
image: hosttoday/ht-docker-node:npmci {
"npmci": {
pipelines: "npmGlobalTools": [],
default: "npmAccessLevel": "public",
- step: "npmRegistryUrl": "registry.npmjs.org",
name: Prepare "dockerRegistries": [
image: hosttoday/ht-docker-node:npmci "registry.gitlab.com"
commands: ],
- npmci node install stable "dockerRegistryRepoMap": {
- npmci npm install "registry.gitlab.com": "mygroup/myrepo"
- npmci prepare npm },
- npmci prepare docker "dockerBuildargEnvMap": {
"ARG_NAME": "ENV_VAR_NAME"
- 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 */);
} }
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. ## 🐳 Docker Registry Authentication
undefined
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
Tests will be migrated to Deno's native test framework:
```sh
deno task test
```
## 📦 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,4 +1,4 @@
import { tap, expect } from '@push.rocks/tapbundle'; import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as path from 'path'; import * as path from 'path';
import * as smartpath from '@push.rocks/smartpath'; import * as smartpath from '@push.rocks/smartpath';

View File

@@ -2,7 +2,7 @@
* autocreated commitinfo by @push.rocks/commitinfo * autocreated commitinfo by @push.rocks/commitinfo
*/ */
export const commitinfo = { export const commitinfo = {
name: '@ship.zone/npmci', name: '@ship.zone/szci',
version: '4.1.37', version: '6.0.0',
description: 'A tool to streamline Node.js and Docker workflows within CI environments, particularly GitLab CI, providing various CI/CD utilities.' 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 { Szci } from '../szci.classes.szci.ts';
import { logger } from '../npmci.logging.js'; import { logger } from '../szci.logging.ts';
/** /**
* connects to cloudly * connects to cloudly
*/ */
export class CloudlyConnector { export class CloudlyConnector {
public npmciRef: Npmci; public szciRef: Szci;
constructor(npmciRefArg: Npmci) { constructor(szciRefArg: Szci) {
this.npmciRef = npmciRefArg; this.szciRef = szciRefArg;
} }
public async announceDockerContainer( public async announceDockerContainer(
optionsArg: plugins.tsclass.container.IContainer, optionsArg: plugins.tsclass.container.IContainer,
testCloudlyUrlArg?: string testCloudlyUrlArg?: string
) { ) {
const cloudlyUrl = testCloudlyUrlArg || this.npmciRef.npmciConfig.getConfig().urlCloudly; const cloudlyUrl = testCloudlyUrlArg || this.szciRef.npmciConfig.getConfig().urlCloudly;
if (!cloudlyUrl) { if (!cloudlyUrl) {
logger.log( logger.log(
'warn', 'warn',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
import { logger } from '../npmci.logging.js'; import { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.js'; import * as plugins from './mod.plugins.ts';
import * as paths from '../npmci.paths.js'; 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 { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.js'; import * as plugins from './mod.plugins.ts';
import { bash, bashNoError } from '../npmci.bash.js'; import { bash, bashNoError } from '../szci.bash.ts';
import { Npmci } from '../npmci.classes.npmci.js'; import { Szci } from '../szci.classes.szci.ts';
export class NpmciGitManager { export class SzciGitManager {
public npmciRef: Npmci; public szciRef: Szci;
constructor(npmciRefArg: Npmci) { constructor(szciRefArg: Szci) {
this.npmciRef = npmciRefArg; this.szciRef = szciRefArg;
} }
/** /**
@@ -30,12 +30,12 @@ export class NpmciGitManager {
}; };
public mirror = async () => { public mirror = async () => {
const githubToken = process.env.NPMCI_GIT_GITHUBTOKEN; const githubToken = Deno.env.get("NPMCI_GIT_GITHUBTOKEN");
const githubUser = process.env.NPMCI_GIT_GITHUBGROUP || this.npmciRef.npmciEnv.repo.user; const githubUser = Deno.env.get("NPMCI_GIT_GITHUBGROUP") || this.szciRef.npmciEnv.repo.user;
const githubRepo = process.env.NPMCI_GIT_GITHUB || this.npmciRef.npmciEnv.repo.repo; const githubRepo = Deno.env.get("NPMCI_GIT_GITHUB") || this.szciRef.npmciEnv.repo.repo;
if ( if (
this.npmciRef.npmciConfig.getConfig().projectInfo.npm.packageJson.private === true || this.szciRef.npmciConfig.getConfig().projectInfo.npm.packageJson.private === true ||
this.npmciRef.npmciConfig.getConfig().npmAccessLevel === 'private' this.szciRef.npmciConfig.getConfig().npmAccessLevel === 'private'
) { ) {
logger.log( logger.log(
'warn', 'warn',
@@ -65,7 +65,7 @@ export class NpmciGitManager {
await bashNoError('git remote rm mirror'); await bashNoError('git remote rm mirror');
} else { } else {
logger.log('error', `cannot find NPMCI_GIT_GITHUBTOKEN env var!`); 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 plugins from '../szci.plugins.ts';
import * as paths from '../npmci.paths.js'; import * as paths from '../szci.paths.ts';
import { logger } from '../npmci.logging.js'; import { logger } from '../szci.logging.ts';
import { bash, bashNoError, nvmAvailable } from '../npmci.bash.js'; import { bash, bashNoError, nvmAvailable } from '../szci.bash.ts';
import { Npmci } from '../npmci.classes.npmci.js'; import { Szci } from '../szci.classes.szci.ts';
export class NpmciNodeJsManager { export class SzciNodeJsManager {
public npmciRef: Npmci; public szciRef: Szci;
constructor(npmciRefArg: Npmci) { constructor(szciRefArg: Szci) {
this.npmciRef = npmciRefArg; this.szciRef = szciRefArg;
} }
/** /**
@@ -25,14 +25,14 @@ export class NpmciNodeJsManager {
break; break;
default: default:
logger.log('error', `>>npmci node ...<< action >>${action}<< not supported`); logger.log('error', `>>npmci node ...<< action >>${action}<< not supported`);
process.exit(1); Deno.exit(1);
} }
} else { } else {
logger.log( logger.log(
'error', 'error',
`>>npmci node ...<< cli arguments invalid... Please read the documentation.` `>>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'); await bash('npm -v');
// lets look for further config // 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...'); logger.log('info', 'Now checking for needed global npm tools...');
for (const npmTool of config.npmGlobalTools) { for (const npmTool of config.npmGlobalTools) {
logger.log('info', `Checking for global "${npmTool}"`); logger.log('info', `Checking for global "${npmTool}"`);

View File

@@ -1,15 +1,15 @@
import * as plugins from './mod.plugins.js'; import * as plugins from './mod.plugins.ts';
import * as paths from '../npmci.paths.js'; import * as paths from '../szci.paths.ts';
import { logger } from '../npmci.logging.js'; import { logger } from '../szci.logging.ts';
import { bash, bashNoError, nvmAvailable } from '../npmci.bash.js'; import { bash, bashNoError, nvmAvailable } from '../szci.bash.ts';
import { Npmci } from '../npmci.classes.npmci.js'; import { Szci } from '../szci.classes.szci.ts';
export class NpmciNpmManager { export class SzciNpmManager {
public npmciRef: Npmci; public szciRef: Szci;
constructor(npmciRefArg: Npmci) { constructor(szciRefArg: Szci) {
this.npmciRef = npmciRefArg; this.szciRef = szciRefArg;
} }
/** /**
@@ -37,14 +37,14 @@ export class NpmciNpmManager {
break; break;
default: default:
logger.log('error', `>>npmci npm ...<< action >>${action}<< not supported`); logger.log('error', `>>npmci npm ...<< action >>${action}<< not supported`);
process.exit(1); Deno.exit(1);
} }
} else { } else {
logger.log( logger.log(
'info', 'info',
`>>npmci npm ...<< cli arguments invalid... Please read the documentation.` `>>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() { public async prepare() {
logger.log('info', 'running >>npm prepare<<'); logger.log('info', 'running >>npm prepare<<');
const config = this.npmciRef.npmciConfig.getConfig(); const config = this.szciRef.npmciConfig.getConfig();
let npmrcFileString: string = ''; let npmrcFileString: string = '';
await plugins.smartobject.forEachMinimatch( await plugins.smartobject.forEachMinimatch(
process.env, Deno.env.toObject(),
'NPMCI_TOKEN_NPM*', 'NPMCI_TOKEN_NPM*',
(npmEnvArg: string) => { (npmEnvArg: string) => {
if (!npmEnvArg) { if (!npmEnvArg) {
@@ -83,14 +83,14 @@ export class NpmciNpmManager {
logger.log('info', 'found one or more access tokens'); logger.log('info', 'found one or more access tokens');
} else { } else {
logger.log('error', 'no access token found! Exiting!'); logger.log('error', 'no access token found! Exiting!');
process.exit(1); Deno.exit(1);
} }
// lets save it to disk // lets save it to disk
plugins.smartfile.memory.toFsSync(npmrcFileString, '/root/.npmrc'); plugins.smartfile.memory.toFsSync(npmrcFileString, '/root/.npmrc');
// lets set the cache directory // lets set the cache directory
await bash(`npm config set cache ${paths.NpmciCacheDir} --global `); await bash(`npm config set cache ${paths.SzciCacheDir} --global `);
return; return;
} }
@@ -103,10 +103,10 @@ export class NpmciNpmManager {
let npmAccessCliString = ``; let npmAccessCliString = ``;
let npmRegistryCliString = ``; let npmRegistryCliString = ``;
let publishVerdaccioAsWell = false; let publishVerdaccioAsWell = false;
const config = this.npmciRef.npmciConfig.getConfig(); const config = this.szciRef.npmciConfig.getConfig();
const availableRegistries: string[] = []; const availableRegistries: string[] = [];
await plugins.smartobject.forEachMinimatch( await plugins.smartobject.forEachMinimatch(
process.env, Deno.env.toObject(),
'NPMCI_TOKEN_NPM*', 'NPMCI_TOKEN_NPM*',
(npmEnvArg: string) => { (npmEnvArg: string) => {
availableRegistries.push(npmEnvArg.split('|')[0]); availableRegistries.push(npmEnvArg.split('|')[0]);
@@ -127,7 +127,7 @@ export class NpmciNpmManager {
npmRegistryCliString = `--registry=https://${config.npmRegistryUrl}`; npmRegistryCliString = `--registry=https://${config.npmRegistryUrl}`;
} else { } else {
logger.log('error', `no registry url specified. Can't publish!`); logger.log('error', `no registry url specified. Can't publish!`);
process.exit(1); Deno.exit(1);
} }
let publishCommand = `npm publish ${npmAccessCliString} ${npmRegistryCliString} `; 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 plugins from './mod.plugins.ts';
import * as paths from '../npmci.paths.js'; import * as paths from '../szci.paths.ts';
/** /**
* cleans npmci config files * cleans npmci config files
*/ */
export let clean = async (): Promise<void> => { export let clean = async (): Promise<void> => {
plugins.smartfile.fs.removeSync(paths.NpmciPackageConfig); plugins.smartfile.fs.removeSync(paths.SzciPackageConfig);
return; 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 * as plugins from './mod.plugins.ts';
import { bash } from '../npmci.bash.js'; import { bash } from '../szci.bash.ts';
export let command = async () => { export let command = async () => {
let wrappedCommand: string = ''; let wrappedCommand: string = '';
let argvArray = process.argv; let argvArray = ['deno', 'mod.ts', ...Deno.args];
for (let i = 3; i < argvArray.length; i++) { for (let i = 3; i < argvArray.length; i++) {
wrappedCommand = wrappedCommand + argvArray[i]; wrappedCommand = wrappedCommand + argvArray[i];
if (i + 1 !== argvArray.length) { 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 plugins from './plugins.ts';
import * as paths from '../npmci.paths.js'; import * as paths from '../szci.paths.ts';
import { logger } from '../npmci.logging.js'; import { logger } from '../szci.logging.ts';
import { Npmci } from '../npmci.classes.npmci.js'; 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'); 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() stringArg.trim()
); );
let allDesiredGitlabRunnerTagsPresent = true; let allDesiredGitlabRunnerTagsPresent = true;
for (const desiredRunnerTag of npmciRefArg.npmciConfig.getConfig().gitlabRunnerTags) { for (const desiredRunnerTag of szciRefArg.npmciConfig.getConfig().gitlabRunnerTags) {
if (!presentRunnerTags.includes(desiredRunnerTag)) { if (!presentRunnerTags.includes(desiredRunnerTag)) {
allDesiredGitlabRunnerTagsPresent = false; allDesiredGitlabRunnerTagsPresent = false;
logger.log( logger.log(
@@ -19,6 +19,6 @@ export const handleCli = async (npmciRefArg: Npmci, argvArg: any) => {
} }
} }
if (!allDesiredGitlabRunnerTagsPresent) { 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 { logger } from '../szci.logging.ts';
import * as plugins from './mod.plugins.js'; import * as plugins from './mod.plugins.ts';
let sshInstance: plugins.smartssh.SshInstance; let sshInstance: plugins.smartssh.SshInstance;
export let handleCli = async (argvArg: any) => { export let handleCli = async (argvArg: any) => {
@@ -11,11 +11,11 @@ export let handleCli = async (argvArg: any) => {
break; break;
default: default:
logger.log('error', `action >>${action}<< not supported`); logger.log('error', `action >>${action}<< not supported`);
process.exit(1); Deno.exit(1);
} }
} else { } else {
logger.log('error', `>>npmci ssh ...<< please specify an action!`); 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 () => { export let prepare = async () => {
sshInstance = new plugins.smartssh.SshInstance(); // init ssh instance sshInstance = new plugins.smartssh.SshInstance(); // init ssh instance
plugins.smartobject.forEachMinimatch(process.env, 'NPMCI_SSHKEY_*', evaluateSshEnv); plugins.smartobject.forEachMinimatch(Deno.env.toObject(), 'NPMCI_SSHKEY_*', evaluateSshEnv);
if (!process.env.NPMTS_TEST) { if (!Deno.env.get("NPMTS_TEST")) {
sshInstance.writeToDisk(); sshInstance.writeToDisk();
} else { } else {
logger.log('info', 'In test mode, so not storing SSH keys to disk!'); 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 * as plugins from './mod.plugins.ts';
import { bash } from '../npmci.bash.js'; import { bash } from '../szci.bash.ts';
import { logger } from '../npmci.logging.js'; import { logger } from '../szci.logging.ts';
const triggerValueRegex = const triggerValueRegex =
/^([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|?([a-zA-Z0-9\.\-\/]*)/; /^([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|([a-zA-Z0-9\.]*)\|?([a-zA-Z0-9\.\-\/]*)/;
export let trigger = async () => { export let trigger = async () => {
logger.log('info', 'now running triggers'); logger.log('info', 'now running triggers');
await plugins.smartobject.forEachMinimatch(process.env, 'NPMCI_TRIGGER_*', evaluateTrigger); await plugins.smartobject.forEachMinimatch(Deno.env.toObject(), 'NPMCI_TRIGGER_*', evaluateTrigger);
}; };
const evaluateTrigger = async (triggerEnvVarArg) => { 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 { logger } from './szci.logging.ts';
import * as plugins from './npmci.plugins.js'; import * as plugins from './szci.plugins.ts';
import * as paths from './npmci.paths.js'; import * as paths from './szci.paths.ts';
/** /**
* wether nvm is available or not * wether nvm is available or not
@@ -19,7 +19,7 @@ const npmciSmartshell = new plugins.smartshell.Smartshell({
*/ */
const checkToolsAvailable = async () => { const checkToolsAvailable = async () => {
// check for nvm // check for nvm
if (!process.env.NPMTS_TEST) { if (!Deno.env.get('NPMTS_TEST')) {
if ( if (
(await npmciSmartshell.execSilent(`bash -c "source /usr/local/nvm/nvm.sh"`)).exitCode === 0 (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; retryArg = 0;
} }
if (!process.env.NPMTS_TEST) { if (!Deno.env.get('NPMTS_TEST')) {
// NPMTS_TEST is used during testing // NPMTS_TEST is used during testing
for (let i = 0; i <= retryArg; i++) { for (let i = 0; i <= retryArg; i++) {
if (process.env.DEBUG_NPMCI === 'true') { if (Deno.env.get('DEBUG_NPMCI') === 'true') {
console.log(commandArg); console.log(commandArg);
} }
execResult = await npmciSmartshell.exec(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 // something went wrong and retries are exhausted
if (failOnError) { if (failOnError) {
logger.log('error', 'something went wrong and retries are exhausted'); logger.log('error', 'something went wrong and retries are exhausted');
process.exit(1); Deno.exit(1);
} }
} else if (execResult.exitCode === 0) { } else if (execResult.exitCode === 0) {
// everything went fine, or no error wanted // 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 { logger } from './szci.logging.ts';
import * as plugins from './npmci.plugins.js'; import * as plugins from './szci.plugins.ts';
import * as paths from './npmci.paths.js'; import * as paths from './szci.paths.ts';
import { Npmci } from './npmci.classes.npmci.js'; import { Szci } from './szci.classes.szci.ts';
export class NpmciCli { export class SzciCli {
public npmciRef: Npmci; public szciRef: Szci;
public smartcli: plugins.smartcli.Smartcli; public smartcli: plugins.smartcli.Smartcli;
constructor(npmciArg: Npmci) { constructor(szciArg: Szci) {
this.npmciRef = npmciArg; this.szciRef = szciArg;
this.smartcli = new plugins.smartcli.Smartcli(); this.smartcli = new plugins.smartcli.Smartcli();
this.smartcli.addVersion(this.npmciRef.npmciInfo.projectInfo.version); this.smartcli.addVersion(this.szciRef.npmciInfo.version);
// clean // clean
this.smartcli.addCommand('clean').subscribe( this.smartcli.addCommand('clean').subscribe(
@@ -20,18 +20,18 @@ export class NpmciCli {
}, },
(err) => { (err) => {
console.log(err); console.log(err);
process.exit(1); Deno.exit(1);
} }
); );
// cloudron // cloudron
this.smartcli.addCommand('cloudron').subscribe( this.smartcli.addCommand('cloudron').subscribe(
async (argv) => { async (argv) => {
await this.npmciRef.cloudronManager.handleCli(argv); await this.szciRef.cloudronManager.handleCli(argv);
}, },
(err) => { (err) => {
console.log(err); console.log(err);
process.exit(1); Deno.exit(1);
} }
); );
@@ -43,47 +43,47 @@ export class NpmciCli {
}, },
(err) => { (err) => {
console.log(err); console.log(err);
process.exit(1); Deno.exit(1);
} }
); );
// git // git
this.smartcli.addCommand('git').subscribe( this.smartcli.addCommand('git').subscribe(
async (argvArg) => { async (argvArg) => {
await this.npmciRef.gitManager.handleCli(argvArg); await this.szciRef.gitManager.handleCli(argvArg);
}, },
(err) => { (err) => {
console.log(err); console.log(err);
process.exit(1); Deno.exit(1);
} }
); );
// build // build
this.smartcli.addCommand('docker').subscribe( this.smartcli.addCommand('docker').subscribe(
async (argvArg) => { async (argvArg) => {
await this.npmciRef.dockerManager.handleCli(argvArg); await this.szciRef.dockerManager.handleCli(argvArg);
}, },
(err) => { (err) => {
console.log(err); console.log(err);
process.exit(1); Deno.exit(1);
} }
); );
// node // node
this.smartcli.addCommand('node').subscribe( this.smartcli.addCommand('node').subscribe(
async (argvArg) => { async (argvArg) => {
await this.npmciRef.nodejsManager.handleCli(argvArg); await this.szciRef.nodejsManager.handleCli(argvArg);
}, },
(err) => { (err) => {
console.log(err); console.log(err);
process.exit(1); Deno.exit(1);
} }
); );
// npm // npm
this.smartcli.addCommand('npm').subscribe( this.smartcli.addCommand('npm').subscribe(
async (argvArg) => { async (argvArg) => {
await this.npmciRef.npmManager.handleCli(argvArg); await this.szciRef.npmManager.handleCli(argvArg);
}, },
(err) => { (err) => {
console.log(err); console.log(err);
@@ -92,7 +92,7 @@ export class NpmciCli {
this.smartcli.addCommand('precheck').subscribe(async (argvArg) => { this.smartcli.addCommand('precheck').subscribe(async (argvArg) => {
const modPrecheck = await import('./mod_precheck/index.js'); const modPrecheck = await import('./mod_precheck/index.js');
await modPrecheck.handleCli(this.npmciRef, argvArg); await modPrecheck.handleCli(this.szciRef, argvArg);
}); });
// trigger // trigger
@@ -109,7 +109,7 @@ export class NpmciCli {
}, },
(err) => { (err) => {
console.log(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 plugins from './szci.plugins.ts';
import * as paths from './npmci.paths.js'; import * as paths from './szci.paths.ts';
import { logger } from './npmci.logging.js'; import { logger } from './szci.logging.ts';
import { Npmci } from './npmci.classes.npmci.js'; import { Szci } from './szci.classes.szci.ts';
/** /**
* the main config interface for npmci * the main config interface for npmci
*/ */
export interface INpmciOptions { export interface ISzciOptions {
projectInfo: plugins.projectinfo.ProjectInfo; projectInfo: plugins.projectinfo.ProjectInfo;
// npm // npm
@@ -33,28 +33,28 @@ export interface INpmciOptions {
/** /**
* a config class for Npmci * a config class for Npmci
*/ */
export class NpmciConfig { export class SzciConfig {
public npmciRef: Npmci; public szciRef: Szci;
public npmciNpmextra: plugins.npmextra.Npmextra; public npmciNpmextra: plugins.npmextra.Npmextra;
public kvStorage: plugins.npmextra.KeyValueStore; public kvStorage: plugins.npmextra.KeyValueStore;
public npmciQenv: plugins.qenv.Qenv; public npmciQenv: plugins.qenv.Qenv;
private configObject: INpmciOptions; private configObject: ISzciOptions;
constructor(npmciRefArg: Npmci) { constructor(szciRefArg: Szci) {
this.npmciRef = npmciRefArg; this.szciRef = szciRefArg;
} }
public async init() { public async init() {
this.npmciNpmextra = new plugins.npmextra.Npmextra(paths.cwd); this.npmciNpmextra = new plugins.npmextra.Npmextra(paths.cwd);
this.kvStorage = new plugins.npmextra.KeyValueStore({ this.kvStorage = new plugins.npmextra.KeyValueStore({
typeArg: 'userHomeDir', 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( this.npmciQenv = new plugins.qenv.Qenv(
paths.NpmciProjectDir, paths.SzciProjectDir,
paths.NpmciProjectNogitDir, paths.SzciProjectNogitDir,
false false
); );
@@ -69,10 +69,10 @@ export class NpmciConfig {
dockerBuildargEnvMap: {}, dockerBuildargEnvMap: {},
urlCloudly: await this.npmciQenv.getEnvVarOnDemand('NPMCI_URL_CLOUDLY'), 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; 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({ export const logger = new plugins.smartlog.Smartlog({
logContext: { 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 // Deno std libraries
import * as path from 'path'; import * as path from '@std/path';
export { 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 ""