Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
cef31cf1ff | |||
74ecdde1ac | |||
74a8229e43 | |||
859cbc733d | |||
d32d47b706 | |||
fd90cfe895 | |||
c48f48fc8b | |||
e21e7f0850 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -17,3 +17,5 @@ dist/
|
|||||||
dist_*/
|
dist_*/
|
||||||
|
|
||||||
#------# custom
|
#------# custom
|
||||||
|
.serena
|
||||||
|
test-output.json
|
||||||
|
1
assets/overrides.json
Normal file
1
assets/overrides.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
102
changelog.md
102
changelog.md
@@ -1,6 +1,42 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-08-08 - 1.16.9 - fix(format)
|
||||||
|
Improve concurrency control in cache and rollback modules, refine gitignore custom section handling, and enhance Prettier file processing
|
||||||
|
|
||||||
|
- Added mutex locking in ChangeCache and RollbackManager to prevent race conditions during manifest updates
|
||||||
|
- Updated gitignore logic to detect and preserve existing custom sections from various markers
|
||||||
|
- Simplified Prettier formatter to process files sequentially, skip files without extensions, and log detailed status
|
||||||
|
- Minor refactoring in base formatter and tsconfig file updates for improved reliability
|
||||||
|
|
||||||
|
## 2025-08-08 - 1.16.8 - fix(format)
|
||||||
|
|
||||||
|
Improve concurrency control in cache and rollback management with mutex locking and refine formatting details
|
||||||
|
|
||||||
|
- Added 'withMutex' functions in ChangeCache and RollbackManager to synchronize file I/O operations
|
||||||
|
- Introduced static mutex maps to prevent race conditions during manifest updates
|
||||||
|
- Fixed minor formatting issues in commit info and package.json
|
||||||
|
|
||||||
|
## 2025-08-08 - 1.16.7 - fix(core)
|
||||||
|
|
||||||
|
Improve formatting, logging, and rollback integrity in core modules
|
||||||
|
|
||||||
|
- Add .claude/settings.local.json with defined permissions for allowed commands
|
||||||
|
- Standardize formatting in package.json, commit info, and configuration files
|
||||||
|
- Refactor rollback manager to use atomic manifest writes and validate manifest structure
|
||||||
|
- Enhance logging messages and overall code clarity in CLI and commit modules
|
||||||
|
|
||||||
|
## 2025-08-08 - 1.16.6 - fix(changecache)
|
||||||
|
|
||||||
|
Improve cache manifest validation and atomic file writes; add local settings and overrides
|
||||||
|
|
||||||
|
- Add manifest structure validation and default fallback in getManifest
|
||||||
|
- Implement atomic write in saveManifest using a temporary file and rename strategy
|
||||||
|
- Enhance error handling and cleanup for corrupted manifest files
|
||||||
|
- Introduce new .claude/settings.local.json for project-specific permission configuration
|
||||||
|
- Add an empty assets/overrides.json file for future overrides
|
||||||
|
|
||||||
## 2025-08-08 - 1.16.5 - fix(prettier)
|
## 2025-08-08 - 1.16.5 - fix(prettier)
|
||||||
|
|
||||||
Improve file selection in Prettier formatter, remove legacy package overrides, and update CI template indentation
|
Improve file selection in Prettier formatter, remove legacy package overrides, and update CI template indentation
|
||||||
|
|
||||||
- Added .claude/settings.local.json with updated permission settings for local commands
|
- Added .claude/settings.local.json with updated permission settings for local commands
|
||||||
@@ -9,12 +45,14 @@ Improve file selection in Prettier formatter, remove legacy package overrides, a
|
|||||||
- Refined Prettier formatter logic by defining include directories, root config files, and filtering duplicates instead of manual exclusion
|
- Refined Prettier formatter logic by defining include directories, root config files, and filtering duplicates instead of manual exclusion
|
||||||
|
|
||||||
## 2025-08-08 - 1.16.4 - fix(prettier)
|
## 2025-08-08 - 1.16.4 - fix(prettier)
|
||||||
|
|
||||||
Improve file exclusion in the Prettier formatter to skip unnecessary files and directories.
|
Improve file exclusion in the Prettier formatter to skip unnecessary files and directories.
|
||||||
|
|
||||||
- Added exclusion patterns for node_modules, .git, dist, .nogit, coverage, .nyc_output, vendor, bower_components, jspm_packages, and minified files.
|
- Added exclusion patterns for node_modules, .git, dist, .nogit, coverage, .nyc_output, vendor, bower_components, jspm_packages, and minified files.
|
||||||
- Optimized filtering logic to ensure only valid files are processed.
|
- Optimized filtering logic to ensure only valid files are processed.
|
||||||
|
|
||||||
## 2025-08-08 - 1.16.3 - fix(changecache/prettier)
|
## 2025-08-08 - 1.16.3 - fix(changecache/prettier)
|
||||||
|
|
||||||
Skip directories during file processing to prevent errors in changecache and prettier formatting
|
Skip directories during file processing to prevent errors in changecache and prettier formatting
|
||||||
|
|
||||||
- Removed unnecessary await on synchronous file reads in changecache
|
- Removed unnecessary await on synchronous file reads in changecache
|
||||||
@@ -22,18 +60,21 @@ Skip directories during file processing to prevent errors in changecache and pre
|
|||||||
- Filtered out directories in prettier formatter to avoid processing non-files
|
- Filtered out directories in prettier formatter to avoid processing non-files
|
||||||
|
|
||||||
## 2025-08-07 - 1.16.2 - fix(format)
|
## 2025-08-07 - 1.16.2 - fix(format)
|
||||||
|
|
||||||
Fix format command confirmation prompt to correctly check user response
|
Fix format command confirmation prompt to correctly check user response
|
||||||
|
|
||||||
- Fixed bug where format command always showed "cancelled" even when user confirmed
|
- Fixed bug where format command always showed "cancelled" even when user confirmed
|
||||||
- Changed response check from `response.proceed` to `response.value` for SmartInteract compatibility
|
- Changed response check from `response.proceed` to `response.value` for SmartInteract compatibility
|
||||||
|
|
||||||
## 2025-08-04 - 1.16.1 - fix(package/config)
|
## 2025-08-04 - 1.16.1 - fix(package/config)
|
||||||
|
|
||||||
Move smartdiff dependency to runtime and add local bash permissions settings
|
Move smartdiff dependency to runtime and add local bash permissions settings
|
||||||
|
|
||||||
- Moved '@push.rocks/smartdiff' from devDependencies to dependencies in package.json
|
- Moved '@push.rocks/smartdiff' from devDependencies to dependencies in package.json
|
||||||
- Added .claude/settings.local.json with allowed bash commands (grep, mkdir, find, ls)
|
- Added .claude/settings.local.json with allowed bash commands (grep, mkdir, find, ls)
|
||||||
|
|
||||||
## 2025-05-19 - 1.16.0 - feat(format)
|
## 2025-05-19 - 1.16.0 - feat(format)
|
||||||
|
|
||||||
Enhance format module with rollback, diff reporting, and improved parallel execution
|
Enhance format module with rollback, diff reporting, and improved parallel execution
|
||||||
|
|
||||||
- Implemented rollback functionality with backup management and automatic rollback on error
|
- Implemented rollback functionality with backup management and automatic rollback on error
|
||||||
@@ -44,12 +85,14 @@ Enhance format module with rollback, diff reporting, and improved parallel execu
|
|||||||
- Updated package.json to include new dependency '@push.rocks/smartdiff'
|
- Updated package.json to include new dependency '@push.rocks/smartdiff'
|
||||||
|
|
||||||
## 2025-05-14 - 1.15.5 - fix(dependencies)
|
## 2025-05-14 - 1.15.5 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc to ^1.5.0 and @types/node to ^22.15.18
|
Update @git.zone/tsdoc to ^1.5.0 and @types/node to ^22.15.18
|
||||||
|
|
||||||
- Bumped @git.zone/tsdoc from ^1.4.5 to ^1.5.0
|
- Bumped @git.zone/tsdoc from ^1.4.5 to ^1.5.0
|
||||||
- Bumped @types/node from ^22.15.17 to ^22.15.18
|
- Bumped @types/node from ^22.15.17 to ^22.15.18
|
||||||
|
|
||||||
## 2025-05-13 - 1.15.4 - fix(package.json)
|
## 2025-05-13 - 1.15.4 - fix(package.json)
|
||||||
|
|
||||||
Update dependency versions: bump @git.zone/tsdoc, @push.rocks/lik, @push.rocks/smartlog, and @types/node to their latest releases
|
Update dependency versions: bump @git.zone/tsdoc, @push.rocks/lik, @push.rocks/smartlog, and @types/node to their latest releases
|
||||||
|
|
||||||
- Upgrade @git.zone/tsdoc from ^1.4.4 to ^1.4.5
|
- Upgrade @git.zone/tsdoc from ^1.4.4 to ^1.4.5
|
||||||
@@ -58,6 +101,7 @@ Update dependency versions: bump @git.zone/tsdoc, @push.rocks/lik, @push.rocks/s
|
|||||||
- Upgrade @types/node from ^22.14.1 to ^22.15.17
|
- Upgrade @types/node from ^22.14.1 to ^22.15.17
|
||||||
|
|
||||||
## 2025-04-15 - 1.15.3 - fix(deps)
|
## 2025-04-15 - 1.15.3 - fix(deps)
|
||||||
|
|
||||||
update dependency versions and improve website template variable handling
|
update dependency versions and improve website template variable handling
|
||||||
|
|
||||||
- Bumped @git.zone/tsbuild from ^2.2.1 to ^2.3.2 and @types/node to ^22.14.1
|
- Bumped @git.zone/tsbuild from ^2.2.1 to ^2.3.2 and @types/node to ^22.14.1
|
||||||
@@ -65,56 +109,65 @@ update dependency versions and improve website template variable handling
|
|||||||
- Refactored website template update to correctly supply variables with added logging
|
- Refactored website template update to correctly supply variables with added logging
|
||||||
|
|
||||||
## 2025-04-15 - 1.15.2 - fix(website_update)
|
## 2025-04-15 - 1.15.2 - fix(website_update)
|
||||||
|
|
||||||
Await supplyVariables call in website update template
|
Await supplyVariables call in website update template
|
||||||
|
|
||||||
- Changed website template update to properly await the supplyVariables method
|
- Changed website template update to properly await the supplyVariables method
|
||||||
- Ensured asynchronous consistency in updating website template variables
|
- Ensured asynchronous consistency in updating website template variables
|
||||||
|
|
||||||
## 2025-04-15 - 1.15.1 - fix(cli)
|
## 2025-04-15 - 1.15.1 - fix(cli)
|
||||||
|
|
||||||
Refresh internal CLI tooling and configuration for consistency.
|
Refresh internal CLI tooling and configuration for consistency.
|
||||||
|
|
||||||
|
|
||||||
## 2025-04-15 - 1.15.0 - feat(config/template)
|
## 2025-04-15 - 1.15.0 - feat(config/template)
|
||||||
|
|
||||||
Add assetbrokerUrl and legalUrl fields to module config and update website template to supply these values
|
Add assetbrokerUrl and legalUrl fields to module config and update website template to supply these values
|
||||||
|
|
||||||
- Added assetbrokerUrl and legalUrl properties in ts/classes.gitzoneconfig.ts
|
- Added assetbrokerUrl and legalUrl properties in ts/classes.gitzoneconfig.ts
|
||||||
- Updated ts/mod_format/format.templates.ts to pass assetbrokerUrl and legalUrl to website template
|
- Updated ts/mod_format/format.templates.ts to pass assetbrokerUrl and legalUrl to website template
|
||||||
|
|
||||||
## 2025-04-15 - 1.14.1 - fix(package.json)
|
## 2025-04-15 - 1.14.1 - fix(package.json)
|
||||||
|
|
||||||
Add packageManager field to specify pnpm version for consistent package management
|
Add packageManager field to specify pnpm version for consistent package management
|
||||||
|
|
||||||
- Inserted packageManager property in package.json with pnpm version info to ensure reproducible dependency installs
|
- Inserted packageManager property in package.json with pnpm version info to ensure reproducible dependency installs
|
||||||
|
|
||||||
## 2025-04-15 - 1.14.0 - feat(tsconfig_update)
|
## 2025-04-15 - 1.14.0 - feat(tsconfig_update)
|
||||||
|
|
||||||
Add runafter directive to trigger gitzone format after tsconfig update
|
Add runafter directive to trigger gitzone format after tsconfig update
|
||||||
|
|
||||||
- Added runafter configuration in assets/templates/tsconfig_update/.smartscaf.yml to automate formatting task
|
- Added runafter configuration in assets/templates/tsconfig_update/.smartscaf.yml to automate formatting task
|
||||||
|
|
||||||
## 2025-03-07 - 1.13.1 - fix(cli)
|
## 2025-03-07 - 1.13.1 - fix(cli)
|
||||||
|
|
||||||
Improve commit message logging
|
Improve commit message logging
|
||||||
|
|
||||||
- Updated logging to display recommended next commit details.
|
- Updated logging to display recommended next commit details.
|
||||||
- Enabled interactive prompt for choosing commit type and scope.
|
- Enabled interactive prompt for choosing commit type and scope.
|
||||||
|
|
||||||
## 2025-02-28 - 1.13.0 - feat(templates)
|
## 2025-02-28 - 1.13.0 - feat(templates)
|
||||||
|
|
||||||
Updated and added new TypeScript template files for npm projects
|
Updated and added new TypeScript template files for npm projects
|
||||||
|
|
||||||
- Added new paths.ts and plugins.ts template files for npm projects.
|
- Added new paths.ts and plugins.ts template files for npm projects.
|
||||||
- Removed outdated some.plugins.ts template file.
|
- Removed outdated some.plugins.ts template file.
|
||||||
|
|
||||||
## 2025-02-25 - 1.12.8 - fix(metadata)
|
## 2025-02-25 - 1.12.8 - fix(metadata)
|
||||||
|
|
||||||
Updated package and npmextra json description and keywords for enhanced development workflow clarity
|
Updated package and npmextra json description and keywords for enhanced development workflow clarity
|
||||||
|
|
||||||
- Updated the description in package.json to focus on project setup and management.
|
- Updated the description in package.json to focus on project setup and management.
|
||||||
- Aligned the keywords in both package.json and npmextra.json to include more relevant terms such as gitzone utilities, template management, and CI/CD.
|
- Aligned the keywords in both package.json and npmextra.json to include more relevant terms such as gitzone utilities, template management, and CI/CD.
|
||||||
|
|
||||||
## 2025-02-25 - 1.12.7 - fix(meta)
|
## 2025-02-25 - 1.12.7 - fix(meta)
|
||||||
|
|
||||||
Fix issues in project metadata and configuration.
|
Fix issues in project metadata and configuration.
|
||||||
|
|
||||||
- Updated package metadata to ensure accurate project description and licensing.
|
- Updated package metadata to ensure accurate project description and licensing.
|
||||||
- Ensured npm access level configuration consistency within npmextra.json.
|
- Ensured npm access level configuration consistency within npmextra.json.
|
||||||
|
|
||||||
## 2025-02-25 - 1.12.7 - fix(ci)
|
## 2025-02-25 - 1.12.7 - fix(ci)
|
||||||
|
|
||||||
Updated dependencies and added CI/CD workflows.
|
Updated dependencies and added CI/CD workflows.
|
||||||
|
|
||||||
- Updated several dependencies in package.json for compatibility and security.
|
- Updated several dependencies in package.json for compatibility and security.
|
||||||
@@ -123,6 +176,7 @@ Updated dependencies and added CI/CD workflows.
|
|||||||
- Ensured consistent formatting with Prettier and TypeScript configurations.
|
- Ensured consistent formatting with Prettier and TypeScript configurations.
|
||||||
|
|
||||||
## 2025-01-29 - 1.12.6 - fix(project)
|
## 2025-01-29 - 1.12.6 - fix(project)
|
||||||
|
|
||||||
Minor fixes and cleanup
|
Minor fixes and cleanup
|
||||||
|
|
||||||
- Removed outdated pages/ directory entry in .gitignore.
|
- Removed outdated pages/ directory entry in .gitignore.
|
||||||
@@ -131,6 +185,7 @@ Minor fixes and cleanup
|
|||||||
- Fixed formatting issues across various TypeScript files.
|
- Fixed formatting issues across various TypeScript files.
|
||||||
|
|
||||||
## 2025-01-29 - 1.12.5 - fix(cli)
|
## 2025-01-29 - 1.12.5 - fix(cli)
|
||||||
|
|
||||||
Initial implementation of CLI utility with project management features
|
Initial implementation of CLI utility with project management features
|
||||||
|
|
||||||
- Integration of various plugins for logging, command-line interactions, and project management.
|
- Integration of various plugins for logging, command-line interactions, and project management.
|
||||||
@@ -138,34 +193,40 @@ Initial implementation of CLI utility with project management features
|
|||||||
- Implement commands for packaging, versioning, and deprecating npm packages.
|
- Implement commands for packaging, versioning, and deprecating npm packages.
|
||||||
|
|
||||||
## 2025-01-29 - 1.12.2 - fix(format)
|
## 2025-01-29 - 1.12.2 - fix(format)
|
||||||
|
|
||||||
Add overrides for peek-readable in package.json formatting
|
Add overrides for peek-readable in package.json formatting
|
||||||
|
|
||||||
- Added a URL correction in the packageJson repository information.
|
- Added a URL correction in the packageJson repository information.
|
||||||
- Introduced support for pnpm overrides by including an `overrides.json` file.
|
- Introduced support for pnpm overrides by including an `overrides.json` file.
|
||||||
|
|
||||||
## 2025-01-18 - 1.12.1 - fix(dependencies)
|
## 2025-01-18 - 1.12.1 - fix(dependencies)
|
||||||
|
|
||||||
Update various package dependencies and Dockerfile base image
|
Update various package dependencies and Dockerfile base image
|
||||||
|
|
||||||
- Updated Dockerfile base image from 'alpinenpmci' to 'alpine_npmci'.
|
- Updated Dockerfile base image from 'alpinenpmci' to 'alpine_npmci'.
|
||||||
- Upgraded @git.zone/tsbuild, @git.zone/tsrun, @git.zone/tsdoc, and other dependencies to their latest versions.
|
- Upgraded @git.zone/tsbuild, @git.zone/tsrun, @git.zone/tsdoc, and other dependencies to their latest versions.
|
||||||
|
|
||||||
## 2025-01-17 - 1.12.0 - feat(build)
|
## 2025-01-17 - 1.12.0 - feat(build)
|
||||||
|
|
||||||
Update TypeScript configuration to support emit decorator metadata
|
Update TypeScript configuration to support emit decorator metadata
|
||||||
|
|
||||||
- Added emitDecoratorMetadata to the tsconfig.json template in assets/templates/tsconfig_update.
|
- Added emitDecoratorMetadata to the tsconfig.json template in assets/templates/tsconfig_update.
|
||||||
|
|
||||||
## 2025-01-08 - 1.11.0 - feat(cli)
|
## 2025-01-08 - 1.11.0 - feat(cli)
|
||||||
|
|
||||||
Add Docker command for cleaning up Docker system and extend deprecation command for multiple registries
|
Add Docker command for cleaning up Docker system and extend deprecation command for multiple registries
|
||||||
|
|
||||||
- Added a new command 'docker' to handle Docker system cleanup operations.
|
- Added a new command 'docker' to handle Docker system cleanup operations.
|
||||||
- Improved the 'deprecate' command to support deprecating packages across multiple npm registry URLs.
|
- Improved the 'deprecate' command to support deprecating packages across multiple npm registry URLs.
|
||||||
|
|
||||||
## 2025-01-01 - 1.10.10 - fix(templates)
|
## 2025-01-01 - 1.10.10 - fix(templates)
|
||||||
|
|
||||||
Corrected typo in template file comment
|
Corrected typo in template file comment
|
||||||
|
|
||||||
- Fixed repeated comment in the template file for services under 'assets/templates/service/ts/some.plugins.ts'.
|
- Fixed repeated comment in the template file for services under 'assets/templates/service/ts/some.plugins.ts'.
|
||||||
|
|
||||||
## 2025-01-01 - 1.10.9 - fix(templates)
|
## 2025-01-01 - 1.10.9 - fix(templates)
|
||||||
|
|
||||||
Correct template file paths and organization for service projects
|
Correct template file paths and organization for service projects
|
||||||
|
|
||||||
- Moved 'some.classes.some.ts' to 'classes.some.ts'
|
- Moved 'some.classes.some.ts' to 'classes.some.ts'
|
||||||
@@ -173,60 +234,70 @@ Correct template file paths and organization for service projects
|
|||||||
- Resolved incorrect import paths in service templates
|
- Resolved incorrect import paths in service templates
|
||||||
|
|
||||||
## 2025-01-01 - 1.10.8 - fix(assets/templates)
|
## 2025-01-01 - 1.10.8 - fix(assets/templates)
|
||||||
|
|
||||||
Update CI template configurations to use module.githost
|
Update CI template configurations to use module.githost
|
||||||
|
|
||||||
- Replaced occurrences of {{git.host}} with {{module.githost}} in CI workflow files
|
- Replaced occurrences of {{git.host}} with {{module.githost}} in CI workflow files
|
||||||
- Updated package dependencies for service template
|
- Updated package dependencies for service template
|
||||||
|
|
||||||
## 2024-12-26 - 1.10.7 - fix(assets)
|
## 2024-12-26 - 1.10.7 - fix(assets)
|
||||||
|
|
||||||
Correct URLs in templates and fix TypeScript declaration
|
Correct URLs in templates and fix TypeScript declaration
|
||||||
|
|
||||||
- Updated incorrect URLs in Dockerfile templates to 'host.today'.
|
- Updated incorrect URLs in Dockerfile templates to 'host.today'.
|
||||||
- Fixed type declaration for 'TemplateResult' in header.ts file.
|
- Fixed type declaration for 'TemplateResult' in header.ts file.
|
||||||
|
|
||||||
## 2024-12-08 - 1.10.6 - fix(ci)
|
## 2024-12-08 - 1.10.6 - fix(ci)
|
||||||
|
|
||||||
Corrected Docker image URL in CI templates
|
Corrected Docker image URL in CI templates
|
||||||
|
|
||||||
- Updated Docker image URL from 'code.foss.global/hosttoday' to 'code.foss.global/host.today' in default_nottags.yaml and default_tags.yaml.
|
- Updated Docker image URL from 'code.foss.global/hosttoday' to 'code.foss.global/host.today' in default_nottags.yaml and default_tags.yaml.
|
||||||
- Adjusted gitignore template to include a custom section delineation.
|
- Adjusted gitignore template to include a custom section delineation.
|
||||||
|
|
||||||
## 2024-12-02 - 1.10.5 - fix(assets)
|
## 2024-12-02 - 1.10.5 - fix(assets)
|
||||||
|
|
||||||
Update .gitignore template to remove pages directory
|
Update .gitignore template to remove pages directory
|
||||||
|
|
||||||
- Removed 'pages/' from the ignored directories in the .gitignore template.
|
- Removed 'pages/' from the ignored directories in the .gitignore template.
|
||||||
|
|
||||||
## 2024-11-05 - 1.10.4 - fix(mod_format)
|
## 2024-11-05 - 1.10.4 - fix(mod_format)
|
||||||
|
|
||||||
Correct file extension for TypeScript path configuration
|
Correct file extension for TypeScript path configuration
|
||||||
|
|
||||||
- Fixed the TypeScript configuration to use correct file extensions for module subdirectories.
|
- Fixed the TypeScript configuration to use correct file extensions for module subdirectories.
|
||||||
|
|
||||||
## 2024-10-27 - 1.10.3 - fix(mod_format)
|
## 2024-10-27 - 1.10.3 - fix(mod_format)
|
||||||
|
|
||||||
Reorder TypeScript formatting steps in mod_format module
|
Reorder TypeScript formatting steps in mod_format module
|
||||||
|
|
||||||
- Moved TypeScript configuration formatting earlier in the sequence for better logical consistency.
|
- Moved TypeScript configuration formatting earlier in the sequence for better logical consistency.
|
||||||
|
|
||||||
## 2024-10-27 - 1.10.2 - fix(format)
|
## 2024-10-27 - 1.10.2 - fix(format)
|
||||||
|
|
||||||
Add logging for tsconfig.json formatting
|
Add logging for tsconfig.json formatting
|
||||||
|
|
||||||
- Added an info log message for tsconfig.json formatting in format.tsconfig.ts.
|
- Added an info log message for tsconfig.json formatting in format.tsconfig.ts.
|
||||||
|
|
||||||
## 2024-10-27 - 1.10.1 - fix(format)
|
## 2024-10-27 - 1.10.1 - fix(format)
|
||||||
|
|
||||||
Fixed async issue in tsconfig module lookup and corrected property access
|
Fixed async issue in tsconfig module lookup and corrected property access
|
||||||
|
|
||||||
|
|
||||||
## 2024-10-27 - 1.10.0 - feat(mod_format)
|
## 2024-10-27 - 1.10.0 - feat(mod_format)
|
||||||
|
|
||||||
Add support for tsconfig.json formatting
|
Add support for tsconfig.json formatting
|
||||||
|
|
||||||
- Added a new script to format tsconfig.json.
|
- Added a new script to format tsconfig.json.
|
||||||
- Updated package.json to include `@git.zone/tspublish` as a dependency.
|
- Updated package.json to include `@git.zone/tspublish` as a dependency.
|
||||||
|
|
||||||
## 2024-10-23 - 1.9.126 - fix(format)
|
## 2024-10-23 - 1.9.126 - fix(format)
|
||||||
|
|
||||||
Remove redundant package.json property checks
|
Remove redundant package.json property checks
|
||||||
|
|
||||||
- Removed property checks for `main`, `typings`, and `browserslist` from format.packagejson.ts
|
- Removed property checks for `main`, `typings`, and `browserslist` from format.packagejson.ts
|
||||||
- This change streamlines the formatting process by removing unnecessary exits
|
- This change streamlines the formatting process by removing unnecessary exits
|
||||||
|
|
||||||
## 2024-09-29 - 1.9.125 - fix(cli)
|
## 2024-09-29 - 1.9.125 - fix(cli)
|
||||||
|
|
||||||
Fix package version configuration and formatting issues
|
Fix package version configuration and formatting issues
|
||||||
|
|
||||||
- Updated metadata fields in package.json (repository URL, bugs URL, and homepage).
|
- Updated metadata fields in package.json (repository URL, bugs URL, and homepage).
|
||||||
@@ -234,15 +305,17 @@ Fix package version configuration and formatting issues
|
|||||||
- Added missing Prettier default TypeScript and Markdown configurations.
|
- Added missing Prettier default TypeScript and Markdown configurations.
|
||||||
|
|
||||||
## 2024-09-27 - 1.9.124 - fix(cli)
|
## 2024-09-27 - 1.9.124 - fix(cli)
|
||||||
|
|
||||||
Ensured proper existence and initialization of readme files
|
Ensured proper existence and initialization of readme files
|
||||||
|
|
||||||
- Ensured readme.md and readme.hints.md files are created and initialized if they do not exist.
|
- Ensured readme.md and readme.hints.md files are created and initialized if they do not exist.
|
||||||
|
|
||||||
## 2024-09-27 - 1.9.123 - fix(core)
|
## 2024-09-27 - 1.9.123 - fix(core)
|
||||||
|
|
||||||
No changes detected
|
No changes detected
|
||||||
|
|
||||||
|
|
||||||
## 2024-09-27 - 1.9.123 - fix(core)
|
## 2024-09-27 - 1.9.123 - fix(core)
|
||||||
|
|
||||||
Update dependencies and improve build configurations
|
Update dependencies and improve build configurations
|
||||||
|
|
||||||
- Updated several dependencies in package.json for better compatibility
|
- Updated several dependencies in package.json for better compatibility
|
||||||
@@ -253,88 +326,111 @@ Update dependencies and improve build configurations
|
|||||||
- Provided initial structure for readme and readme hints
|
- Provided initial structure for readme and readme hints
|
||||||
|
|
||||||
## 2024-06-24 - 1.9.122 - fix(mod_commit)
|
## 2024-06-24 - 1.9.122 - fix(mod_commit)
|
||||||
|
|
||||||
Update package.json dependencies: @git.zone/tsdoc and @push.rocks/smartpromise to latest versions.
|
Update package.json dependencies: @git.zone/tsdoc and @push.rocks/smartpromise to latest versions.
|
||||||
|
|
||||||
- - Updated @git.zone/tsdoc to ^1.3.12
|
- - Updated @git.zone/tsdoc to ^1.3.12
|
||||||
- - Updated @push.rocks/smartfile to ^11.0.21
|
- - Updated @push.rocks/smartfile to ^11.0.21
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.121 - fix(mod_commit)
|
## 2024-06-23 - 1.9.121 - fix(mod_commit)
|
||||||
|
|
||||||
Fix changelog template rendering by removing extra new line when no version details are provided.
|
Fix changelog template rendering by removing extra new line when no version details are provided.
|
||||||
|
|
||||||
- Update package.json dependencies: @git.zone/tsdoc and @push.rocks/smartpromise to latest versions.
|
- Update package.json dependencies: @git.zone/tsdoc and @push.rocks/smartpromise to latest versions.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.120 - fix(mod_commit)
|
## 2024-06-23 - 1.9.120 - fix(mod_commit)
|
||||||
|
|
||||||
Handle edge case for empty version details in changelog formatting
|
Handle edge case for empty version details in changelog formatting
|
||||||
|
|
||||||
- Added check for the length of the recommendedNextVersionDetails array
|
- Added check for the length of the recommendedNextVersionDetails array
|
||||||
- Ensure no extra newline in changelog if there are no version details
|
- Ensure no extra newline in changelog if there are no version details
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.119 - fix(dependencies)
|
## 2024-06-23 - 1.9.119 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc to v1.3.8
|
Update @git.zone/tsdoc to v1.3.8
|
||||||
|
|
||||||
- Updated @git.zone/tsdoc from v1.3.7 to v1.3.8 in package.json
|
- Updated @git.zone/tsdoc from v1.3.7 to v1.3.8 in package.json
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.118 - fix(dependencies)
|
## 2024-06-23 - 1.9.118 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc to version 1.3.7
|
Update @git.zone/tsdoc to version 1.3.7
|
||||||
|
|
||||||
- Bump @git.zone/tsdoc from 1.3.6 to 1.3.7 in both package.json and pnpm-lock.yaml
|
- Bump @git.zone/tsdoc from 1.3.6 to 1.3.7 in both package.json and pnpm-lock.yaml
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.117 - fix(dependencies)
|
## 2024-06-23 - 1.9.117 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc dependency to v1.3.6
|
Update @git.zone/tsdoc dependency to v1.3.6
|
||||||
|
|
||||||
- Updated @git.zone/tsdoc version from 1.3.5 to 1.3.6 in package.json
|
- Updated @git.zone/tsdoc version from 1.3.5 to 1.3.6 in package.json
|
||||||
- Updated pnpm-lock.yaml to reflect the new version of @git.zone/tsdoc
|
- Updated pnpm-lock.yaml to reflect the new version of @git.zone/tsdoc
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.116 - fix(dependencies)
|
## 2024-06-23 - 1.9.116 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc to version 1.3.5
|
Update @git.zone/tsdoc to version 1.3.5
|
||||||
|
|
||||||
- Updated the @git.zone/tsdoc dependency in package.json and pnpm-lock.yaml from version 1.3.4 to 1.3.5
|
- Updated the @git.zone/tsdoc dependency in package.json and pnpm-lock.yaml from version 1.3.4 to 1.3.5
|
||||||
- Removed the outdated changelog.md file.
|
- Removed the outdated changelog.md file.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.114 - fix(format)
|
## 2024-06-23 - 1.9.114 - fix(format)
|
||||||
|
|
||||||
Fixed formatting issues across multiple TypeScript files.
|
Fixed formatting issues across multiple TypeScript files.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.113 - fix(mod_commit)
|
## 2024-06-23 - 1.9.113 - fix(mod_commit)
|
||||||
|
|
||||||
Remove extra new lines in changelog.
|
Remove extra new lines in changelog.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.112 - fix(core)
|
## 2024-06-23 - 1.9.112 - fix(core)
|
||||||
|
|
||||||
Update changelog formatting and remove outdated entries.
|
Update changelog formatting and remove outdated entries.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.111 - fix(changelog)
|
## 2024-06-23 - 1.9.111 - fix(changelog)
|
||||||
|
|
||||||
Remove outdated changelog entries and update formatting.
|
Remove outdated changelog entries and update formatting.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.110 - fix(dependencies)
|
## 2024-06-23 - 1.9.110 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc to version 1.3.4.
|
Update @git.zone/tsdoc to version 1.3.4.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.109 - fix(changelog)
|
## 2024-06-23 - 1.9.109 - fix(changelog)
|
||||||
|
|
||||||
Remove outdated entries and adjust formatting in changelog.
|
Remove outdated entries and adjust formatting in changelog.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.108 - fix(dependencies)
|
## 2024-06-23 - 1.9.108 - fix(dependencies)
|
||||||
|
|
||||||
Update @git.zone/tsdoc dependency to version 1.3.2.
|
Update @git.zone/tsdoc dependency to version 1.3.2.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.107 - fix(changelog)
|
## 2024-06-23 - 1.9.107 - fix(changelog)
|
||||||
|
|
||||||
Remove placeholder entries and adjust formatting in changelog.
|
Remove placeholder entries and adjust formatting in changelog.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.106 - fix(dependencies)
|
## 2024-06-23 - 1.9.106 - fix(dependencies)
|
||||||
|
|
||||||
Updated @git.zone/tsdoc from version 1.3.0 to 1.3.1.
|
Updated @git.zone/tsdoc from version 1.3.0 to 1.3.1.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.105 - fix(dependencies)
|
## 2024-06-23 - 1.9.105 - fix(dependencies)
|
||||||
|
|
||||||
Updated @git.zone/tsdoc dependency from 1.2.2 to 1.3.0 in package.json and pnpm-lock.yaml.
|
Updated @git.zone/tsdoc dependency from 1.2.2 to 1.3.0 in package.json and pnpm-lock.yaml.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.104 - fix(changelog)
|
## 2024-06-23 - 1.9.104 - fix(changelog)
|
||||||
|
|
||||||
Remove placeholder entries and adjust formatting in changelog.
|
Remove placeholder entries and adjust formatting in changelog.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.103 - fix(changelog)
|
## 2024-06-23 - 1.9.103 - fix(changelog)
|
||||||
|
|
||||||
Fix changelog to remove placeholder entries and adjust formatting.
|
Fix changelog to remove placeholder entries and adjust formatting.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.102 - fix(logging)
|
## 2024-06-23 - 1.9.102 - fix(logging)
|
||||||
|
|
||||||
Optimize logger instantiation and configuration.
|
Optimize logger instantiation and configuration.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.101 - fix(metadata)
|
## 2024-06-23 - 1.9.101 - fix(metadata)
|
||||||
|
|
||||||
Ensure accurate project metadata in package.json.
|
Ensure accurate project metadata in package.json.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.100 - fix(dependencies)
|
## 2024-06-23 - 1.9.100 - fix(dependencies)
|
||||||
|
|
||||||
Updated @git.zone/tsdoc dependency version to ^1.2.2 in package.json and pnpm-lock.yaml.
|
Updated @git.zone/tsdoc dependency version to ^1.2.2 in package.json and pnpm-lock.yaml.
|
||||||
|
|
||||||
## 2024-06-23 - 1.9.99 - fix(mod_commit)
|
## 2024-06-23 - 1.9.99 - fix(mod_commit)
|
||||||
|
|
||||||
Fix variable reassignment issue in changelog writing step.
|
Fix variable reassignment issue in changelog writing step.
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@git.zone/cli",
|
"name": "@git.zone/cli",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.16.5",
|
"version": "1.16.9",
|
||||||
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
|
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
|
||||||
"main": "dist_ts/index.ts",
|
"main": "dist_ts/index.ts",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
# Gitzone CLI - Development Hints
|
# Gitzone CLI - Development Hints
|
||||||
|
|
||||||
* the cli of the git.zone project.
|
- the cli of the git.zone project.
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
Gitzone CLI (`@git.zone/cli`) is a comprehensive toolbelt for streamlining local development cycles. It provides utilities for:
|
Gitzone CLI (`@git.zone/cli`) is a comprehensive toolbelt for streamlining local development cycles. It provides utilities for:
|
||||||
|
|
||||||
- Project initialization and templating (via smartscaf)
|
- Project initialization and templating (via smartscaf)
|
||||||
- Code formatting and standardization
|
- Code formatting and standardization
|
||||||
- Version control and commit management
|
- Version control and commit management
|
||||||
@@ -14,12 +15,14 @@ Gitzone CLI (`@git.zone/cli`) is a comprehensive toolbelt for streamlining local
|
|||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### Core Structure
|
### Core Structure
|
||||||
|
|
||||||
- Main CLI entry: `cli.ts` / `cli.child.ts`
|
- Main CLI entry: `cli.ts` / `cli.child.ts`
|
||||||
- Modular architecture with separate modules in `ts/mod_*` directories
|
- Modular architecture with separate modules in `ts/mod_*` directories
|
||||||
- Each module handles specific functionality (format, commit, docker, etc.)
|
- Each module handles specific functionality (format, commit, docker, etc.)
|
||||||
- Extensive use of plugins pattern via `plugins.ts` files
|
- Extensive use of plugins pattern via `plugins.ts` files
|
||||||
|
|
||||||
### Configuration Management
|
### Configuration Management
|
||||||
|
|
||||||
- Uses `npmextra.json` for all tool configuration
|
- Uses `npmextra.json` for all tool configuration
|
||||||
- Configuration stored under `gitzone` key in npmextra
|
- Configuration stored under `gitzone` key in npmextra
|
||||||
- No separate `.gitzonerc` file - everything in npmextra.json
|
- No separate `.gitzonerc` file - everything in npmextra.json
|
||||||
@@ -30,6 +33,7 @@ Gitzone CLI (`@git.zone/cli`) is a comprehensive toolbelt for streamlining local
|
|||||||
The format module is responsible for project standardization:
|
The format module is responsible for project standardization:
|
||||||
|
|
||||||
#### Current Modules:
|
#### Current Modules:
|
||||||
|
|
||||||
1. **cleanup** - Removes obsolete files (yarn.lock, tslint.json, etc.)
|
1. **cleanup** - Removes obsolete files (yarn.lock, tslint.json, etc.)
|
||||||
2. **copy** - File copying with glob patterns (fully implemented)
|
2. **copy** - File copying with glob patterns (fully implemented)
|
||||||
3. **gitignore** - Creates/updates .gitignore from templates
|
3. **gitignore** - Creates/updates .gitignore from templates
|
||||||
@@ -42,6 +46,7 @@ The format module is responsible for project standardization:
|
|||||||
10. **tsconfig** - Formats TypeScript configuration
|
10. **tsconfig** - Formats TypeScript configuration
|
||||||
|
|
||||||
#### Execution Order (Dependency-Based):
|
#### Execution Order (Dependency-Based):
|
||||||
|
|
||||||
- Modules are now executed in parallel groups based on dependencies
|
- Modules are now executed in parallel groups based on dependencies
|
||||||
- Independent modules run concurrently for better performance
|
- Independent modules run concurrently for better performance
|
||||||
- Dependency analyzer ensures correct execution order
|
- Dependency analyzer ensures correct execution order
|
||||||
@@ -182,7 +187,7 @@ gitzone format --clean-backups
|
|||||||
|
|
||||||
## API Changes
|
## API Changes
|
||||||
|
|
||||||
- smartfile API updated to use fs.* and memory.* namespaces
|
- smartfile API updated to use fs._ and memory._ namespaces
|
||||||
- smartnpm requires instance creation: `new NpmRegistry()`
|
- smartnpm requires instance creation: `new NpmRegistry()`
|
||||||
- All file operations now use updated APIs
|
- All file operations now use updated APIs
|
||||||
- Type imports use `import type` for proper verbatim module syntax
|
- Type imports use `import type` for proper verbatim module syntax
|
27
readme.md
27
readme.md
@@ -47,12 +47,14 @@ gitzone template [template-name]
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Available templates:**
|
**Available templates:**
|
||||||
|
|
||||||
- **`npm`** - TypeScript npm package with testing, CI/CD, and full tooling
|
- **`npm`** - TypeScript npm package with testing, CI/CD, and full tooling
|
||||||
- **`service`** - Microservice architecture with Docker support
|
- **`service`** - Microservice architecture with Docker support
|
||||||
- **`website`** - Modern web application with LitElement and service workers
|
- **`website`** - Modern web application with LitElement and service workers
|
||||||
- **`wcc`** - Web Component Collection for reusable UI components
|
- **`wcc`** - Web Component Collection for reusable UI components
|
||||||
|
|
||||||
Each template comes pre-configured with:
|
Each template comes pre-configured with:
|
||||||
|
|
||||||
- ✅ TypeScript with modern configurations
|
- ✅ TypeScript with modern configurations
|
||||||
- ✅ Automated testing setup
|
- ✅ Automated testing setup
|
||||||
- ✅ CI/CD pipelines (GitLab/GitHub)
|
- ✅ CI/CD pipelines (GitLab/GitHub)
|
||||||
@@ -81,6 +83,7 @@ gitzone format --verbose
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Format features:**
|
**Format features:**
|
||||||
|
|
||||||
- 🔄 **Smart caching** - Only processes changed files
|
- 🔄 **Smart caching** - Only processes changed files
|
||||||
- 🛡️ **Rollback support** - Undo formatting changes if needed
|
- 🛡️ **Rollback support** - Undo formatting changes if needed
|
||||||
- 📊 **Detailed reporting** - See exactly what changed
|
- 📊 **Detailed reporting** - See exactly what changed
|
||||||
@@ -88,6 +91,7 @@ gitzone format --verbose
|
|||||||
- 🎯 **Module-specific formatting** - Target specific formatters
|
- 🎯 **Module-specific formatting** - Target specific formatters
|
||||||
|
|
||||||
**Rollback capabilities:**
|
**Rollback capabilities:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# List all available backups
|
# List all available backups
|
||||||
gitzone format --list-backups
|
gitzone format --list-backups
|
||||||
@@ -103,6 +107,7 @@ gitzone format --clean-backups
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Formatters included:**
|
**Formatters included:**
|
||||||
|
|
||||||
- **Prettier** - JavaScript/TypeScript code formatting
|
- **Prettier** - JavaScript/TypeScript code formatting
|
||||||
- **License** - Ensure proper licensing
|
- **License** - Ensure proper licensing
|
||||||
- **Package.json** - Standardize package configurations
|
- **Package.json** - Standardize package configurations
|
||||||
@@ -121,6 +126,7 @@ gitzone commit
|
|||||||
```
|
```
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
- 📝 Interactive commit message builder
|
- 📝 Interactive commit message builder
|
||||||
- 🏷️ Automatic version bumping (major/minor/patch)
|
- 🏷️ Automatic version bumping (major/minor/patch)
|
||||||
- 📜 Changelog generation
|
- 📜 Changelog generation
|
||||||
@@ -128,6 +134,7 @@ Features:
|
|||||||
- 🎯 Conventional commit compliance
|
- 🎯 Conventional commit compliance
|
||||||
|
|
||||||
The commit wizard guides you through:
|
The commit wizard guides you through:
|
||||||
|
|
||||||
1. **Type selection** (feat/fix/docs/style/refactor/perf/test/chore)
|
1. **Type selection** (feat/fix/docs/style/refactor/perf/test/chore)
|
||||||
2. **Scope definition** (component/module affected)
|
2. **Scope definition** (component/module affected)
|
||||||
3. **Description crafting**
|
3. **Description crafting**
|
||||||
@@ -153,6 +160,7 @@ gitzone meta remove [name]
|
|||||||
```
|
```
|
||||||
|
|
||||||
Perfect for:
|
Perfect for:
|
||||||
|
|
||||||
- Monorepo management
|
- Monorepo management
|
||||||
- Multi-package projects
|
- Multi-package projects
|
||||||
- Coordinated deployments
|
- Coordinated deployments
|
||||||
@@ -168,6 +176,7 @@ gitzone docker prune
|
|||||||
```
|
```
|
||||||
|
|
||||||
This command removes:
|
This command removes:
|
||||||
|
|
||||||
- Stopped containers
|
- Stopped containers
|
||||||
- Unused images
|
- Unused images
|
||||||
- Dangling volumes
|
- Dangling volumes
|
||||||
@@ -196,6 +205,7 @@ gitzone deprecate
|
|||||||
```
|
```
|
||||||
|
|
||||||
Interactive wizard for:
|
Interactive wizard for:
|
||||||
|
|
||||||
- Setting deprecation notices
|
- Setting deprecation notices
|
||||||
- Guiding users to replacements
|
- Guiding users to replacements
|
||||||
- Updating registry metadata
|
- Updating registry metadata
|
||||||
@@ -210,6 +220,7 @@ gitzone start
|
|||||||
```
|
```
|
||||||
|
|
||||||
Automatically:
|
Automatically:
|
||||||
|
|
||||||
- Checks out master branch
|
- Checks out master branch
|
||||||
- Pulls latest changes
|
- Pulls latest changes
|
||||||
- Installs dependencies
|
- Installs dependencies
|
||||||
@@ -266,18 +277,21 @@ Customize gitzone behavior through `npmextra.json`:
|
|||||||
## 🏆 Best Practices
|
## 🏆 Best Practices
|
||||||
|
|
||||||
### For New Projects
|
### For New Projects
|
||||||
|
|
||||||
1. Start with a template: `gitzone template npm`
|
1. Start with a template: `gitzone template npm`
|
||||||
2. Customize the generated structure
|
2. Customize the generated structure
|
||||||
3. Run initial format: `gitzone format`
|
3. Run initial format: `gitzone format`
|
||||||
4. Set up CI/CD: `gitzone open ci`
|
4. Set up CI/CD: `gitzone open ci`
|
||||||
|
|
||||||
### For Existing Projects
|
### For Existing Projects
|
||||||
|
|
||||||
1. Initialize: `gitzone start`
|
1. Initialize: `gitzone start`
|
||||||
2. Format codebase: `gitzone format --dry-run` (preview first!)
|
2. Format codebase: `gitzone format --dry-run` (preview first!)
|
||||||
3. Apply formatting: `gitzone format --yes`
|
3. Apply formatting: `gitzone format --yes`
|
||||||
4. Commit changes: `gitzone commit`
|
4. Commit changes: `gitzone commit`
|
||||||
|
|
||||||
### For Teams
|
### For Teams
|
||||||
|
|
||||||
1. Document format preferences in `npmextra.json`
|
1. Document format preferences in `npmextra.json`
|
||||||
2. Use `--save-plan` for reviewable format changes
|
2. Use `--save-plan` for reviewable format changes
|
||||||
3. Enable rollback for safety
|
3. Enable rollback for safety
|
||||||
@@ -286,6 +300,7 @@ Customize gitzone behavior through `npmextra.json`:
|
|||||||
## 🎯 Common Workflows
|
## 🎯 Common Workflows
|
||||||
|
|
||||||
### Clean Development Cycle
|
### Clean Development Cycle
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Start fresh
|
# 1. Start fresh
|
||||||
gitzone start
|
gitzone start
|
||||||
@@ -304,6 +319,7 @@ gitzone commit
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Multi-Repository Management
|
### Multi-Repository Management
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Set up meta repository
|
# 1. Set up meta repository
|
||||||
gitzone meta init
|
gitzone meta init
|
||||||
@@ -318,6 +334,7 @@ gitzone meta update
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Safe Formatting with Rollback
|
### Safe Formatting with Rollback
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Preview changes
|
# 1. Preview changes
|
||||||
gitzone format --dry-run
|
gitzone format --dry-run
|
||||||
@@ -335,17 +352,20 @@ gitzone format --rollback
|
|||||||
## 🔌 Integrations
|
## 🔌 Integrations
|
||||||
|
|
||||||
### CI/CD Platforms
|
### CI/CD Platforms
|
||||||
|
|
||||||
- **GitLab CI** - Full pipeline support with templates
|
- **GitLab CI** - Full pipeline support with templates
|
||||||
- **GitHub Actions** - Automated workflows
|
- **GitHub Actions** - Automated workflows
|
||||||
- **Docker** - Container-based deployments
|
- **Docker** - Container-based deployments
|
||||||
|
|
||||||
### Development Tools
|
### Development Tools
|
||||||
|
|
||||||
- **TypeScript** - First-class support
|
- **TypeScript** - First-class support
|
||||||
- **Prettier** - Code formatting
|
- **Prettier** - Code formatting
|
||||||
- **ESLint** - Linting (via format modules)
|
- **ESLint** - Linting (via format modules)
|
||||||
- **npm/pnpm** - Package management
|
- **npm/pnpm** - Package management
|
||||||
|
|
||||||
### Version Control
|
### Version Control
|
||||||
|
|
||||||
- **Git** - Deep integration
|
- **Git** - Deep integration
|
||||||
- **Semantic Versioning** - Automatic version bumping
|
- **Semantic Versioning** - Automatic version bumping
|
||||||
- **Conventional Commits** - Standardized commit messages
|
- **Conventional Commits** - Standardized commit messages
|
||||||
@@ -361,19 +381,25 @@ gitzone format --rollback
|
|||||||
## 🐛 Troubleshooting
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
### Format Command Shows "Cancelled"
|
### Format Command Shows "Cancelled"
|
||||||
|
|
||||||
If the format command shows cancelled even after confirming:
|
If the format command shows cancelled even after confirming:
|
||||||
|
|
||||||
- Check your `npmextra.json` configuration
|
- Check your `npmextra.json` configuration
|
||||||
- Try with `--yes` flag to skip confirmation
|
- Try with `--yes` flag to skip confirmation
|
||||||
- Use `--verbose` for detailed output
|
- Use `--verbose` for detailed output
|
||||||
|
|
||||||
### Docker Commands Fail
|
### Docker Commands Fail
|
||||||
|
|
||||||
Ensure Docker daemon is running:
|
Ensure Docker daemon is running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker info
|
docker info
|
||||||
```
|
```
|
||||||
|
|
||||||
### Template Creation Issues
|
### Template Creation Issues
|
||||||
|
|
||||||
Verify npm/pnpm is properly configured:
|
Verify npm/pnpm is properly configured:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm config get registry
|
npm config get registry
|
||||||
```
|
```
|
||||||
@@ -381,6 +407,7 @@ npm config get registry
|
|||||||
## 📈 Performance
|
## 📈 Performance
|
||||||
|
|
||||||
gitzone is optimized for speed:
|
gitzone is optimized for speed:
|
||||||
|
|
||||||
- **Parallel processing** for format operations
|
- **Parallel processing** for format operations
|
||||||
- **Smart caching** to avoid redundant work
|
- **Smart caching** to avoid redundant work
|
||||||
- **Incremental updates** for meta repositories
|
- **Incremental updates** for meta repositories
|
||||||
|
@@ -3,11 +3,13 @@
|
|||||||
Please reread /home/philkunz/.claude/CLAUDE.md before proceeding with any implementation.
|
Please reread /home/philkunz/.claude/CLAUDE.md before proceeding with any implementation.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
This plan outlines improvements for the gitzone format module to enhance its functionality, reliability, and maintainability.
|
This plan outlines improvements for the gitzone format module to enhance its functionality, reliability, and maintainability.
|
||||||
|
|
||||||
## Phase 1: Core Improvements (High Priority) - COMPLETED ✅
|
## Phase 1: Core Improvements (High Priority) - COMPLETED ✅
|
||||||
|
|
||||||
### 1. Enhanced Error Handling & Recovery ✅
|
### 1. Enhanced Error Handling & Recovery ✅
|
||||||
|
|
||||||
- [x] Implement rollback mechanism for failed format operations
|
- [x] Implement rollback mechanism for failed format operations
|
||||||
- [x] Add detailed error messages with recovery suggestions
|
- [x] Add detailed error messages with recovery suggestions
|
||||||
- [x] Create a `--dry-run` flag to preview changes before applying
|
- [x] Create a `--dry-run` flag to preview changes before applying
|
||||||
@@ -15,12 +17,14 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
- [x] Implement plan → action workflow as default behavior
|
- [x] Implement plan → action workflow as default behavior
|
||||||
|
|
||||||
### 2. Complete Missing Functionality ✅
|
### 2. Complete Missing Functionality ✅
|
||||||
|
|
||||||
- [x] Implement the `ensureDependency` function in format.packagejson.ts
|
- [x] Implement the `ensureDependency` function in format.packagejson.ts
|
||||||
- [x] Develop the copy module for file pattern-based copying
|
- [x] Develop the copy module for file pattern-based copying
|
||||||
- [x] Add dependency version constraint management
|
- [x] Add dependency version constraint management
|
||||||
- [x] Support workspace/monorepo configurations (via configuration)
|
- [x] Support workspace/monorepo configurations (via configuration)
|
||||||
|
|
||||||
### 3. Configuration & Flexibility ✅
|
### 3. Configuration & Flexibility ✅
|
||||||
|
|
||||||
- [x] Extend npmextra.json gitzone configuration section
|
- [x] Extend npmextra.json gitzone configuration section
|
||||||
- [x] Allow custom license exclusion/inclusion lists
|
- [x] Allow custom license exclusion/inclusion lists
|
||||||
- [x] Make format steps configurable (skip/include specific modules)
|
- [x] Make format steps configurable (skip/include specific modules)
|
||||||
@@ -28,6 +32,7 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
- [x] Add format profiles for different project types
|
- [x] Add format profiles for different project types
|
||||||
|
|
||||||
### 4. Architecture Changes ✅
|
### 4. Architecture Changes ✅
|
||||||
|
|
||||||
- [x] Introduce a `FormatContext` class to manage state across modules
|
- [x] Introduce a `FormatContext` class to manage state across modules
|
||||||
- [x] Create abstract `BaseFormatter` class for consistent module structure
|
- [x] Create abstract `BaseFormatter` class for consistent module structure
|
||||||
- [x] Implement event system for inter-module communication (via context)
|
- [x] Implement event system for inter-module communication (via context)
|
||||||
@@ -37,12 +42,14 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
## Phase 2: Performance & Reporting (Medium Priority) - COMPLETED ✅
|
## Phase 2: Performance & Reporting (Medium Priority) - COMPLETED ✅
|
||||||
|
|
||||||
### 5. Performance Optimizations ✅
|
### 5. Performance Optimizations ✅
|
||||||
|
|
||||||
- [x] Implement parallel execution for independent format modules
|
- [x] Implement parallel execution for independent format modules
|
||||||
- [x] Add file change detection to skip unchanged files
|
- [x] Add file change detection to skip unchanged files
|
||||||
- [x] Create format cache to track last formatted state
|
- [x] Create format cache to track last formatted state
|
||||||
- [x] Optimize Prettier runs by batching files
|
- [x] Optimize Prettier runs by batching files
|
||||||
|
|
||||||
### 6. Enhanced Reporting & Visibility ✅
|
### 6. Enhanced Reporting & Visibility ✅
|
||||||
|
|
||||||
- [x] Generate comprehensive format report showing all changes
|
- [x] Generate comprehensive format report showing all changes
|
||||||
- [x] Add diff view for file modifications
|
- [x] Add diff view for file modifications
|
||||||
- [x] Create verbose logging option
|
- [x] Create verbose logging option
|
||||||
@@ -51,30 +58,35 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
## Phase 3: Advanced Features (Lower Priority) - PARTIALLY COMPLETED
|
## Phase 3: Advanced Features (Lower Priority) - PARTIALLY COMPLETED
|
||||||
|
|
||||||
### 7. Better Integration & Extensibility ⏳
|
### 7. Better Integration & Extensibility ⏳
|
||||||
|
|
||||||
- [ ] Create plugin system for custom format modules
|
- [ ] Create plugin system for custom format modules
|
||||||
- [ ] Add hooks for pre/post format operations
|
- [ ] Add hooks for pre/post format operations
|
||||||
- [ ] Support custom validation rules
|
- [ ] Support custom validation rules
|
||||||
- [ ] Integrate with git hooks for pre-commit formatting
|
- [ ] Integrate with git hooks for pre-commit formatting
|
||||||
|
|
||||||
### 8. Improved Template Integration ⏳
|
### 8. Improved Template Integration ⏳
|
||||||
|
|
||||||
- [ ] Better error handling when smartscaf operations fail
|
- [ ] Better error handling when smartscaf operations fail
|
||||||
- [ ] Add pre/post template hooks for custom processing
|
- [ ] Add pre/post template hooks for custom processing
|
||||||
- [ ] Validate template results before proceeding with format
|
- [ ] Validate template results before proceeding with format
|
||||||
- [ ] Support skipping template updates via configuration
|
- [ ] Support skipping template updates via configuration
|
||||||
|
|
||||||
### 9. Enhanced License Management ⏳
|
### 9. Enhanced License Management ⏳
|
||||||
|
|
||||||
- [ ] Make license checking configurable (partial)
|
- [ ] Make license checking configurable (partial)
|
||||||
- [ ] Add license compatibility matrix
|
- [ ] Add license compatibility matrix
|
||||||
- [x] Support license exceptions for specific packages
|
- [x] Support license exceptions for specific packages
|
||||||
- [ ] Generate license report for compliance
|
- [ ] Generate license report for compliance
|
||||||
|
|
||||||
### 10. Better Package.json Management ⏳
|
### 10. Better Package.json Management ⏳
|
||||||
|
|
||||||
- [ ] Smart dependency sorting and grouping
|
- [ ] Smart dependency sorting and grouping
|
||||||
- [ ] Automated script generation based on project type
|
- [ ] Automated script generation based on project type
|
||||||
- [ ] Support for pnpm workspace configurations
|
- [ ] Support for pnpm workspace configurations
|
||||||
- [ ] Validation of package.json schema
|
- [ ] Validation of package.json schema
|
||||||
|
|
||||||
### 11. Quality of Life Improvements ⏳
|
### 11. Quality of Life Improvements ⏳
|
||||||
|
|
||||||
- [ ] Interactive mode for format configuration
|
- [ ] Interactive mode for format configuration
|
||||||
- [ ] Undo/redo capability for format operations
|
- [ ] Undo/redo capability for format operations
|
||||||
- [ ] Format presets for common scenarios
|
- [ ] Format presets for common scenarios
|
||||||
@@ -85,28 +97,33 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
### ✅ Completed Features
|
### ✅ Completed Features
|
||||||
|
|
||||||
1. **Rollback Mechanism**
|
1. **Rollback Mechanism**
|
||||||
|
|
||||||
- Full backup/restore functionality
|
- Full backup/restore functionality
|
||||||
- Manifest tracking and integrity checks
|
- Manifest tracking and integrity checks
|
||||||
- CLI commands for rollback operations
|
- CLI commands for rollback operations
|
||||||
|
|
||||||
2. **Plan → Action Workflow**
|
2. **Plan → Action Workflow**
|
||||||
|
|
||||||
- Two-phase approach (analyze then execute)
|
- Two-phase approach (analyze then execute)
|
||||||
- Interactive confirmation
|
- Interactive confirmation
|
||||||
- Dry-run support
|
- Dry-run support
|
||||||
|
|
||||||
3. **Configuration System**
|
3. **Configuration System**
|
||||||
|
|
||||||
- Comprehensive npmextra.json support
|
- Comprehensive npmextra.json support
|
||||||
- Module control (skip/only/order)
|
- Module control (skip/only/order)
|
||||||
- Cache configuration
|
- Cache configuration
|
||||||
- Parallel execution settings
|
- Parallel execution settings
|
||||||
|
|
||||||
4. **Performance Improvements**
|
4. **Performance Improvements**
|
||||||
|
|
||||||
- Parallel execution by dependency analysis
|
- Parallel execution by dependency analysis
|
||||||
- File change caching
|
- File change caching
|
||||||
- Prettier batching
|
- Prettier batching
|
||||||
- Execution time tracking
|
- Execution time tracking
|
||||||
|
|
||||||
5. **Reporting & Statistics**
|
5. **Reporting & Statistics**
|
||||||
|
|
||||||
- Detailed diff views
|
- Detailed diff views
|
||||||
- Execution statistics
|
- Execution statistics
|
||||||
- Verbose logging mode
|
- Verbose logging mode
|
||||||
@@ -121,6 +138,7 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
### 🚧 Partially Completed
|
### 🚧 Partially Completed
|
||||||
|
|
||||||
1. **License Management**
|
1. **License Management**
|
||||||
|
|
||||||
- Basic configuration support
|
- Basic configuration support
|
||||||
- Exception handling for specific packages
|
- Exception handling for specific packages
|
||||||
- Need: compatibility matrix, compliance reports
|
- Need: compatibility matrix, compliance reports
|
||||||
@@ -132,11 +150,13 @@ This plan outlines improvements for the gitzone format module to enhance its fun
|
|||||||
### ⏳ Not Started
|
### ⏳ Not Started
|
||||||
|
|
||||||
1. **Plugin System**
|
1. **Plugin System**
|
||||||
|
|
||||||
- Need to design plugin API
|
- Need to design plugin API
|
||||||
- Hook system for pre/post operations
|
- Hook system for pre/post operations
|
||||||
- Custom validation rules
|
- Custom validation rules
|
||||||
|
|
||||||
2. **Git Integration**
|
2. **Git Integration**
|
||||||
|
|
||||||
- Pre-commit hooks
|
- Pre-commit hooks
|
||||||
- Automatic formatting on commit
|
- Automatic formatting on commit
|
||||||
|
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/cli',
|
name: '@git.zone/cli',
|
||||||
version: '1.16.5',
|
version: '1.16.9',
|
||||||
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,9 @@ export class GitzoneConfig {
|
|||||||
public async readConfigFromCwd() {
|
public async readConfigFromCwd() {
|
||||||
const npmextraInstance = new plugins.npmextra.Npmextra(paths.cwd);
|
const npmextraInstance = new plugins.npmextra.Npmextra(paths.cwd);
|
||||||
this.data = npmextraInstance.dataFor<IGitzoneConfigData>('gitzone', {});
|
this.data = npmextraInstance.dataFor<IGitzoneConfigData>('gitzone', {});
|
||||||
this.data.npmciOptions = npmextraInstance.dataFor<IGitzoneConfigData['npmciOptions']>('npmci', {
|
this.data.npmciOptions = npmextraInstance.dataFor<
|
||||||
|
IGitzoneConfigData['npmciOptions']
|
||||||
|
>('npmci', {
|
||||||
npmAccessLevel: 'public',
|
npmAccessLevel: 'public',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -89,7 +89,7 @@ export let run = async () => {
|
|||||||
detailed: argvArg.detailed,
|
detailed: argvArg.detailed,
|
||||||
interactive: argvArg.interactive !== false,
|
interactive: argvArg.interactive !== false,
|
||||||
parallel: argvArg.parallel !== false,
|
parallel: argvArg.parallel !== false,
|
||||||
verbose: argvArg.verbose
|
verbose: argvArg.verbose,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -5,7 +5,8 @@ import * as plugins from './plugins.js';
|
|||||||
export const logger = plugins.smartlog.Smartlog.createForCommitinfo(commitinfo);
|
export const logger = plugins.smartlog.Smartlog.createForCommitinfo(commitinfo);
|
||||||
|
|
||||||
// Add console destination
|
// Add console destination
|
||||||
const consoleDestination = new plugins.smartlogDestinationLocal.DestinationLocal();
|
const consoleDestination =
|
||||||
|
new plugins.smartlogDestinationLocal.DestinationLocal();
|
||||||
logger.addLogDestination(consoleDestination);
|
logger.addLogDestination(consoleDestination);
|
||||||
|
|
||||||
// Verbose logging helper
|
// Verbose logging helper
|
||||||
|
@@ -10,20 +10,22 @@ export const run = async (argvArg: any) => {
|
|||||||
await formatMod.run();
|
await formatMod.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
logger.log('info', `gathering facts...`);
|
logger.log('info', `gathering facts...`);
|
||||||
const aidoc = new plugins.tsdoc.AiDoc();
|
const aidoc = new plugins.tsdoc.AiDoc();
|
||||||
await aidoc.start();
|
await aidoc.start();
|
||||||
|
|
||||||
const nextCommitObject = await aidoc.buildNextCommitObject(paths.cwd);
|
const nextCommitObject = await aidoc.buildNextCommitObject(paths.cwd);
|
||||||
|
|
||||||
logger.log('info', `---------
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`---------
|
||||||
Next recommended commit would be:
|
Next recommended commit would be:
|
||||||
===========
|
===========
|
||||||
-> ${nextCommitObject.recommendedNextVersion}:
|
-> ${nextCommitObject.recommendedNextVersion}:
|
||||||
-> ${nextCommitObject.recommendedNextVersionLevel}(${nextCommitObject.recommendedNextVersionScope}): ${nextCommitObject.recommendedNextVersionMessage}
|
-> ${nextCommitObject.recommendedNextVersionLevel}(${nextCommitObject.recommendedNextVersionScope}): ${nextCommitObject.recommendedNextVersionMessage}
|
||||||
===========
|
===========
|
||||||
`);
|
`,
|
||||||
|
);
|
||||||
const commitInteract = new plugins.smartinteract.SmartInteract();
|
const commitInteract = new plugins.smartinteract.SmartInteract();
|
||||||
commitInteract.addQuestions([
|
commitInteract.addQuestions([
|
||||||
{
|
{
|
||||||
@@ -72,32 +74,55 @@ export const run = async (argvArg: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
logger.log('info', `Baking commitinfo into code ...`);
|
logger.log('info', `Baking commitinfo into code ...`);
|
||||||
const commitInfo = new plugins.commitinfo.CommitInfo(paths.cwd, commitVersionType);
|
const commitInfo = new plugins.commitinfo.CommitInfo(
|
||||||
|
paths.cwd,
|
||||||
|
commitVersionType,
|
||||||
|
);
|
||||||
await commitInfo.writeIntoPotentialDirs();
|
await commitInfo.writeIntoPotentialDirs();
|
||||||
|
|
||||||
logger.log('info', `Writing changelog.md ...`);
|
logger.log('info', `Writing changelog.md ...`);
|
||||||
let changelog = nextCommitObject.changelog;
|
let changelog = nextCommitObject.changelog;
|
||||||
changelog = changelog.replaceAll('{{nextVersion}}', (await commitInfo.getNextPlannedVersion()).versionString);
|
changelog = changelog.replaceAll(
|
||||||
changelog = changelog.replaceAll('{{nextVersionScope}}', `${await answerBucket.getAnswerFor('commitType')}(${await answerBucket.getAnswerFor('commitScope')})`);
|
'{{nextVersion}}',
|
||||||
changelog = changelog.replaceAll('{{nextVersionMessage}}', nextCommitObject.recommendedNextVersionMessage);
|
(await commitInfo.getNextPlannedVersion()).versionString,
|
||||||
|
);
|
||||||
|
changelog = changelog.replaceAll(
|
||||||
|
'{{nextVersionScope}}',
|
||||||
|
`${await answerBucket.getAnswerFor('commitType')}(${await answerBucket.getAnswerFor('commitScope')})`,
|
||||||
|
);
|
||||||
|
changelog = changelog.replaceAll(
|
||||||
|
'{{nextVersionMessage}}',
|
||||||
|
nextCommitObject.recommendedNextVersionMessage,
|
||||||
|
);
|
||||||
if (nextCommitObject.recommendedNextVersionDetails?.length > 0) {
|
if (nextCommitObject.recommendedNextVersionDetails?.length > 0) {
|
||||||
changelog = changelog.replaceAll('{{nextVersionDetails}}', '- ' + nextCommitObject.recommendedNextVersionDetails.join('\n- '));
|
changelog = changelog.replaceAll(
|
||||||
|
'{{nextVersionDetails}}',
|
||||||
|
'- ' + nextCommitObject.recommendedNextVersionDetails.join('\n- '),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
changelog = changelog.replaceAll('\n{{nextVersionDetails}}', '');
|
changelog = changelog.replaceAll('\n{{nextVersionDetails}}', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
await plugins.smartfile.memory.toFs(changelog, plugins.path.join(paths.cwd, `changelog.md`));
|
await plugins.smartfile.memory.toFs(
|
||||||
|
changelog,
|
||||||
|
plugins.path.join(paths.cwd, `changelog.md`),
|
||||||
|
);
|
||||||
|
|
||||||
logger.log('info', `Staging files for commit:`);
|
logger.log('info', `Staging files for commit:`);
|
||||||
await smartshellInstance.exec(`git add -A`);
|
await smartshellInstance.exec(`git add -A`);
|
||||||
await smartshellInstance.exec(`git commit -m "${commitString}"`);
|
await smartshellInstance.exec(`git commit -m "${commitString}"`);
|
||||||
await smartshellInstance.exec(`npm version ${commitVersionType}`);
|
await smartshellInstance.exec(`npm version ${commitVersionType}`);
|
||||||
if (answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true')) {
|
if (
|
||||||
|
answerBucket.getAnswerFor('pushToOrigin') &&
|
||||||
|
!(process.env.CI === 'true')
|
||||||
|
) {
|
||||||
await smartshellInstance.exec(`git push origin master --follow-tags`);
|
await smartshellInstance.exec(`git push origin master --follow-tags`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createCommitStringFromAnswerBucket = (answerBucket: plugins.smartinteract.AnswerBucket) => {
|
const createCommitStringFromAnswerBucket = (
|
||||||
|
answerBucket: plugins.smartinteract.AnswerBucket,
|
||||||
|
) => {
|
||||||
const commitType = answerBucket.getAnswerFor('commitType');
|
const commitType = answerBucket.getAnswerFor('commitType');
|
||||||
const commitScope = answerBucket.getAnswerFor('commitScope');
|
const commitScope = answerBucket.getAnswerFor('commitScope');
|
||||||
const commitDescription = answerBucket.getAnswerFor('commitDescription');
|
const commitDescription = answerBucket.getAnswerFor('commitDescription');
|
||||||
|
@@ -36,7 +36,10 @@ export const run = async () => {
|
|||||||
const registryUrls = answerBucket.getAnswerFor(`registryUrls`).split(',');
|
const registryUrls = answerBucket.getAnswerFor(`registryUrls`).split(',');
|
||||||
const oldPackageName = answerBucket.getAnswerFor(`oldPackageName`);
|
const oldPackageName = answerBucket.getAnswerFor(`oldPackageName`);
|
||||||
const newPackageName = answerBucket.getAnswerFor(`newPackageName`);
|
const newPackageName = answerBucket.getAnswerFor(`newPackageName`);
|
||||||
logger.log('info', `Deprecating package ${oldPackageName} in favour of ${newPackageName}`);
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`Deprecating package ${oldPackageName} in favour of ${newPackageName}`,
|
||||||
|
);
|
||||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||||
executor: 'bash',
|
executor: 'bash',
|
||||||
});
|
});
|
||||||
|
@@ -2,18 +2,15 @@ import * as plugins from './mod.plugins.js';
|
|||||||
import { FormatContext } from './classes.formatcontext.js';
|
import { FormatContext } from './classes.formatcontext.js';
|
||||||
import type { IPlannedChange } from './interfaces.format.js';
|
import type { IPlannedChange } from './interfaces.format.js';
|
||||||
import { Project } from '../classes.project.js';
|
import { Project } from '../classes.project.js';
|
||||||
import { ChangeCache } from './classes.changecache.js';
|
|
||||||
|
|
||||||
export abstract class BaseFormatter {
|
export abstract class BaseFormatter {
|
||||||
protected context: FormatContext;
|
protected context: FormatContext;
|
||||||
protected project: Project;
|
protected project: Project;
|
||||||
protected cache: ChangeCache;
|
|
||||||
protected stats: any; // Will be FormatStats from context
|
protected stats: any; // Will be FormatStats from context
|
||||||
|
|
||||||
constructor(context: FormatContext, project: Project) {
|
constructor(context: FormatContext, project: Project) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.project = project;
|
this.project = project;
|
||||||
this.cache = context.getChangeCache();
|
|
||||||
this.stats = context.getFormatStats();
|
this.stats = context.getFormatStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +37,7 @@ export abstract class BaseFormatter {
|
|||||||
|
|
||||||
await this.postExecute();
|
await this.postExecute();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.context.rollbackOperation();
|
// Don't rollback here - let the FormatPlanner handle it
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
this.stats.endModule(this.name, startTime);
|
this.stats.endModule(this.name, startTime);
|
||||||
@@ -56,38 +53,30 @@ export abstract class BaseFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async modifyFile(filepath: string, content: string): Promise<void> {
|
protected async modifyFile(filepath: string, content: string): Promise<void> {
|
||||||
await this.context.trackFileChange(filepath);
|
// Validate filepath before writing
|
||||||
await plugins.smartfile.memory.toFs(content, filepath);
|
if (!filepath || filepath.trim() === '') {
|
||||||
await this.cache.updateFileCache(filepath);
|
throw new Error(`Invalid empty filepath in modifyFile`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have a proper path with directory component
|
||||||
|
// If the path has no directory component (e.g., "package.json"), prepend "./"
|
||||||
|
let normalizedPath = filepath;
|
||||||
|
if (!plugins.path.parse(filepath).dir) {
|
||||||
|
normalizedPath = './' + filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
await plugins.smartfile.memory.toFs(content, normalizedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async createFile(filepath: string, content: string): Promise<void> {
|
protected async createFile(filepath: string, content: string): Promise<void> {
|
||||||
await plugins.smartfile.memory.toFs(content, filepath);
|
await plugins.smartfile.memory.toFs(content, filepath);
|
||||||
await this.cache.updateFileCache(filepath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async deleteFile(filepath: string): Promise<void> {
|
protected async deleteFile(filepath: string): Promise<void> {
|
||||||
await this.context.trackFileChange(filepath);
|
|
||||||
await plugins.smartfile.fs.remove(filepath);
|
await plugins.smartfile.fs.remove(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async shouldProcessFile(filepath: string): Promise<boolean> {
|
protected async shouldProcessFile(filepath: string): Promise<boolean> {
|
||||||
const config = new plugins.npmextra.Npmextra();
|
return true;
|
||||||
const useCache = config.dataFor('gitzone.format.cache.enabled', true);
|
|
||||||
|
|
||||||
if (!useCache) {
|
|
||||||
return true; // Process all files if cache is disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasChanged = await this.cache.hasFileChanged(filepath);
|
|
||||||
|
|
||||||
// Record cache statistics
|
|
||||||
if (hasChanged) {
|
|
||||||
this.stats.recordCacheMiss();
|
|
||||||
} else {
|
|
||||||
this.stats.recordCacheHit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasChanged;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -29,21 +29,54 @@ export class ChangeCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getManifest(): Promise<ICacheManifest> {
|
async getManifest(): Promise<ICacheManifest> {
|
||||||
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
const defaultManifest: ICacheManifest = {
|
||||||
if (!exists) {
|
|
||||||
return {
|
|
||||||
version: this.cacheVersion,
|
version: this.cacheVersion,
|
||||||
lastFormat: 0,
|
lastFormat: 0,
|
||||||
files: []
|
files: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
||||||
|
if (!exists) {
|
||||||
|
return defaultManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const content = plugins.smartfile.fs.toStringSync(this.manifestPath);
|
const content = plugins.smartfile.fs.toStringSync(this.manifestPath);
|
||||||
return JSON.parse(content);
|
const manifest = JSON.parse(content);
|
||||||
|
|
||||||
|
// Validate the manifest structure
|
||||||
|
if (this.isValidManifest(manifest)) {
|
||||||
|
return manifest;
|
||||||
|
} else {
|
||||||
|
console.warn('Invalid manifest structure, returning default manifest');
|
||||||
|
return defaultManifest;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(
|
||||||
|
`Failed to read cache manifest: ${error.message}, returning default manifest`,
|
||||||
|
);
|
||||||
|
// Try to delete the corrupted file
|
||||||
|
try {
|
||||||
|
await plugins.smartfile.fs.remove(this.manifestPath);
|
||||||
|
} catch (removeError) {
|
||||||
|
// Ignore removal errors
|
||||||
|
}
|
||||||
|
return defaultManifest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveManifest(manifest: ICacheManifest): Promise<void> {
|
async saveManifest(manifest: ICacheManifest): Promise<void> {
|
||||||
await plugins.smartfile.memory.toFs(JSON.stringify(manifest, null, 2), this.manifestPath);
|
// Validate before saving
|
||||||
|
if (!this.isValidManifest(manifest)) {
|
||||||
|
throw new Error('Invalid manifest structure, cannot save');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure directory exists
|
||||||
|
await plugins.smartfile.fs.ensureDir(this.cacheDir);
|
||||||
|
|
||||||
|
// Write directly with proper JSON stringification
|
||||||
|
const jsonContent = JSON.stringify(manifest, null, 2);
|
||||||
|
await plugins.smartfile.memory.toFs(jsonContent, this.manifestPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async hasFileChanged(filePath: string): Promise<boolean> {
|
async hasFileChanged(filePath: string): Promise<boolean> {
|
||||||
@@ -70,16 +103,18 @@ export class ChangeCache {
|
|||||||
|
|
||||||
// Get cached info
|
// Get cached info
|
||||||
const manifest = await this.getManifest();
|
const manifest = await this.getManifest();
|
||||||
const cachedFile = manifest.files.find(f => f.path === filePath);
|
const cachedFile = manifest.files.find((f) => f.path === filePath);
|
||||||
|
|
||||||
if (!cachedFile) {
|
if (!cachedFile) {
|
||||||
return true; // Not in cache, so it's changed
|
return true; // Not in cache, so it's changed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare checksums
|
// Compare checksums
|
||||||
return cachedFile.checksum !== currentChecksum ||
|
return (
|
||||||
|
cachedFile.checksum !== currentChecksum ||
|
||||||
cachedFile.size !== stats.size ||
|
cachedFile.size !== stats.size ||
|
||||||
cachedFile.modified !== stats.mtimeMs;
|
cachedFile.modified !== stats.mtimeMs
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateFileCache(filePath: string): Promise<void> {
|
async updateFileCache(filePath: string): Promise<void> {
|
||||||
@@ -95,18 +130,18 @@ export class ChangeCache {
|
|||||||
return; // Don't cache directories
|
return; // Don't cache directories
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await plugins.smartfile.fs.toStringSync(absolutePath);
|
const content = plugins.smartfile.fs.toStringSync(absolutePath);
|
||||||
const checksum = this.calculateChecksum(content);
|
const checksum = this.calculateChecksum(content);
|
||||||
|
|
||||||
// Update manifest
|
// Update manifest
|
||||||
const manifest = await this.getManifest();
|
const manifest = await this.getManifest();
|
||||||
const existingIndex = manifest.files.findIndex(f => f.path === filePath);
|
const existingIndex = manifest.files.findIndex((f) => f.path === filePath);
|
||||||
|
|
||||||
const cacheEntry: IFileCache = {
|
const cacheEntry: IFileCache = {
|
||||||
path: filePath,
|
path: filePath,
|
||||||
checksum,
|
checksum,
|
||||||
modified: stats.mtimeMs,
|
modified: stats.mtimeMs,
|
||||||
size: stats.size
|
size: stats.size,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (existingIndex !== -1) {
|
if (existingIndex !== -1) {
|
||||||
@@ -153,4 +188,36 @@ export class ChangeCache {
|
|||||||
private calculateChecksum(content: string | Buffer): string {
|
private calculateChecksum(content: string | Buffer): string {
|
||||||
return plugins.crypto.createHash('sha256').update(content).digest('hex');
|
return plugins.crypto.createHash('sha256').update(content).digest('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isValidManifest(manifest: any): manifest is ICacheManifest {
|
||||||
|
// Check if manifest has the required structure
|
||||||
|
if (!manifest || typeof manifest !== 'object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check required fields
|
||||||
|
if (
|
||||||
|
typeof manifest.version !== 'string' ||
|
||||||
|
typeof manifest.lastFormat !== 'number' ||
|
||||||
|
!Array.isArray(manifest.files)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each file entry
|
||||||
|
for (const file of manifest.files) {
|
||||||
|
if (
|
||||||
|
!file ||
|
||||||
|
typeof file !== 'object' ||
|
||||||
|
typeof file.path !== 'string' ||
|
||||||
|
typeof file.checksum !== 'string' ||
|
||||||
|
typeof file.modified !== 'number' ||
|
||||||
|
typeof file.size !== 'number'
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -17,16 +17,23 @@ export class DependencyAnalyzer {
|
|||||||
private initializeDependencies(): void {
|
private initializeDependencies(): void {
|
||||||
// Define dependencies between format modules
|
// Define dependencies between format modules
|
||||||
const dependencies = {
|
const dependencies = {
|
||||||
'cleanup': [], // No dependencies
|
cleanup: [], // No dependencies
|
||||||
'npmextra': [], // No dependencies
|
npmextra: [], // No dependencies
|
||||||
'license': ['npmextra'], // Depends on npmextra for config
|
license: ['npmextra'], // Depends on npmextra for config
|
||||||
'packagejson': ['npmextra'], // Depends on npmextra for config
|
packagejson: ['npmextra'], // Depends on npmextra for config
|
||||||
'templates': ['npmextra', 'packagejson'], // Depends on both
|
templates: ['npmextra', 'packagejson'], // Depends on both
|
||||||
'gitignore': ['templates'], // Depends on templates
|
gitignore: ['templates'], // Depends on templates
|
||||||
'tsconfig': ['packagejson'], // Depends on package.json
|
tsconfig: ['packagejson'], // Depends on package.json
|
||||||
'prettier': ['cleanup', 'npmextra', 'packagejson', 'templates', 'gitignore', 'tsconfig'], // Runs after most others
|
prettier: [
|
||||||
'readme': ['npmextra', 'packagejson'], // Depends on project metadata
|
'cleanup',
|
||||||
'copy': ['npmextra'], // Depends on config
|
'npmextra',
|
||||||
|
'packagejson',
|
||||||
|
'templates',
|
||||||
|
'gitignore',
|
||||||
|
'tsconfig',
|
||||||
|
], // Runs after most others
|
||||||
|
readme: ['npmextra', 'packagejson'], // Depends on project metadata
|
||||||
|
copy: ['npmextra'], // Depends on config
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize all modules
|
// Initialize all modules
|
||||||
@@ -34,7 +41,7 @@ export class DependencyAnalyzer {
|
|||||||
this.moduleDependencies.set(module, {
|
this.moduleDependencies.set(module, {
|
||||||
module,
|
module,
|
||||||
dependencies: new Set(deps),
|
dependencies: new Set(deps),
|
||||||
dependents: new Set()
|
dependents: new Set(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +57,7 @@ export class DependencyAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getExecutionGroups(modules: BaseFormatter[]): BaseFormatter[][] {
|
getExecutionGroups(modules: BaseFormatter[]): BaseFormatter[][] {
|
||||||
const modulesMap = new Map(modules.map(m => [m.name, m]));
|
const modulesMap = new Map(modules.map((m) => [m.name, m]));
|
||||||
const executed = new Set<string>();
|
const executed = new Set<string>();
|
||||||
const groups: BaseFormatter[][] = [];
|
const groups: BaseFormatter[][] = [];
|
||||||
|
|
||||||
@@ -68,8 +75,9 @@ export class DependencyAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if all dependencies have been executed
|
// Check if all dependencies have been executed
|
||||||
const allDepsExecuted = Array.from(dependency.dependencies)
|
const allDepsExecuted = Array.from(dependency.dependencies).every(
|
||||||
.every(dep => executed.has(dep) || !modulesMap.has(dep));
|
(dep) => executed.has(dep) || !modulesMap.has(dep),
|
||||||
|
);
|
||||||
|
|
||||||
if (allDepsExecuted) {
|
if (allDepsExecuted) {
|
||||||
currentGroup.push(module);
|
currentGroup.push(module);
|
||||||
@@ -85,7 +93,7 @@ export class DependencyAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentGroup.forEach(m => executed.add(m.name));
|
currentGroup.forEach((m) => executed.add(m.name));
|
||||||
groups.push(currentGroup);
|
groups.push(currentGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,9 +107,11 @@ export class DependencyAnalyzer {
|
|||||||
if (!dep1 || !dep2) return false;
|
if (!dep1 || !dep2) return false;
|
||||||
|
|
||||||
// Check if module1 depends on module2 or vice versa
|
// Check if module1 depends on module2 or vice versa
|
||||||
return !dep1.dependencies.has(module2) &&
|
return (
|
||||||
|
!dep1.dependencies.has(module2) &&
|
||||||
!dep2.dependencies.has(module1) &&
|
!dep2.dependencies.has(module1) &&
|
||||||
!dep1.dependents.has(module2) &&
|
!dep1.dependents.has(module2) &&
|
||||||
!dep2.dependents.has(module1);
|
!dep2.dependents.has(module1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -5,7 +5,11 @@ import { logger } from '../gitzone.logging.js';
|
|||||||
export class DiffReporter {
|
export class DiffReporter {
|
||||||
private diffs: Map<string, string> = new Map();
|
private diffs: Map<string, string> = new Map();
|
||||||
|
|
||||||
async generateDiff(filePath: string, oldContent: string, newContent: string): Promise<string> {
|
async generateDiff(
|
||||||
|
filePath: string,
|
||||||
|
oldContent: string,
|
||||||
|
newContent: string,
|
||||||
|
): Promise<string> {
|
||||||
const diff = plugins.smartdiff.createDiff(oldContent, newContent);
|
const diff = plugins.smartdiff.createDiff(oldContent, newContent);
|
||||||
this.diffs.set(filePath, diff);
|
this.diffs.set(filePath, diff);
|
||||||
return diff;
|
return diff;
|
||||||
@@ -22,16 +26,25 @@ export class DiffReporter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentContent = await plugins.smartfile.fs.toStringSync(change.path);
|
const currentContent = await plugins.smartfile.fs.toStringSync(
|
||||||
|
change.path,
|
||||||
|
);
|
||||||
|
|
||||||
// For planned changes, we need the new content
|
// For planned changes, we need the new content
|
||||||
if (!change.content) {
|
if (!change.content) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.generateDiff(change.path, currentContent, change.content);
|
return await this.generateDiff(
|
||||||
|
change.path,
|
||||||
|
currentContent,
|
||||||
|
change.content,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log('error', `Failed to generate diff for ${change.path}: ${error.message}`);
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Failed to generate diff for ${change.path}: ${error.message}`,
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,7 +82,7 @@ export class DiffReporter {
|
|||||||
|
|
||||||
private colorDiff(diff: string): string {
|
private colorDiff(diff: string): string {
|
||||||
const lines = diff.split('\n');
|
const lines = diff.split('\n');
|
||||||
const coloredLines = lines.map(line => {
|
const coloredLines = lines.map((line) => {
|
||||||
if (line.startsWith('+') && !line.startsWith('+++')) {
|
if (line.startsWith('+') && !line.startsWith('+++')) {
|
||||||
return `\x1b[32m${line}\x1b[0m`; // Green for additions
|
return `\x1b[32m${line}\x1b[0m`; // Green for additions
|
||||||
} else if (line.startsWith('-') && !line.startsWith('---')) {
|
} else if (line.startsWith('-') && !line.startsWith('---')) {
|
||||||
@@ -90,11 +103,14 @@ export class DiffReporter {
|
|||||||
totalFiles: this.diffs.size,
|
totalFiles: this.diffs.size,
|
||||||
diffs: Array.from(this.diffs.entries()).map(([path, diff]) => ({
|
diffs: Array.from(this.diffs.entries()).map(([path, diff]) => ({
|
||||||
path,
|
path,
|
||||||
diff
|
diff,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
await plugins.smartfile.memory.toFs(JSON.stringify(report, null, 2), outputPath);
|
await plugins.smartfile.memory.toFs(
|
||||||
|
JSON.stringify(report, null, 2),
|
||||||
|
outputPath,
|
||||||
|
);
|
||||||
logger.log('info', `Diff report saved to ${outputPath}`);
|
logger.log('info', `Diff report saved to ${outputPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,64 +1,13 @@
|
|||||||
import * as plugins from './mod.plugins.js';
|
import * as plugins from './mod.plugins.js';
|
||||||
import { RollbackManager } from './classes.rollbackmanager.js';
|
|
||||||
import { ChangeCache } from './classes.changecache.js';
|
|
||||||
import { FormatStats } from './classes.formatstats.js';
|
import { FormatStats } from './classes.formatstats.js';
|
||||||
import type { IFormatOperation, IFormatPlan } from './interfaces.format.js';
|
|
||||||
|
|
||||||
export class FormatContext {
|
export class FormatContext {
|
||||||
private rollbackManager: RollbackManager;
|
|
||||||
private currentOperation: IFormatOperation | null = null;
|
|
||||||
private changeCache: ChangeCache;
|
|
||||||
private formatStats: FormatStats;
|
private formatStats: FormatStats;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.rollbackManager = new RollbackManager();
|
|
||||||
this.changeCache = new ChangeCache();
|
|
||||||
this.formatStats = new FormatStats();
|
this.formatStats = new FormatStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
async beginOperation(): Promise<void> {
|
|
||||||
this.currentOperation = await this.rollbackManager.createOperation();
|
|
||||||
}
|
|
||||||
|
|
||||||
async trackFileChange(filepath: string): Promise<void> {
|
|
||||||
if (!this.currentOperation) {
|
|
||||||
throw new Error('No operation in progress. Call beginOperation() first.');
|
|
||||||
}
|
|
||||||
await this.rollbackManager.backupFile(filepath, this.currentOperation.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async commitOperation(): Promise<void> {
|
|
||||||
if (!this.currentOperation) {
|
|
||||||
throw new Error('No operation in progress. Call beginOperation() first.');
|
|
||||||
}
|
|
||||||
await this.rollbackManager.markComplete(this.currentOperation.id);
|
|
||||||
this.currentOperation = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async rollbackOperation(): Promise<void> {
|
|
||||||
if (!this.currentOperation) {
|
|
||||||
throw new Error('No operation in progress. Call beginOperation() first.');
|
|
||||||
}
|
|
||||||
await this.rollbackManager.rollback(this.currentOperation.id);
|
|
||||||
this.currentOperation = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async rollbackTo(operationId: string): Promise<void> {
|
|
||||||
await this.rollbackManager.rollback(operationId);
|
|
||||||
}
|
|
||||||
|
|
||||||
getRollbackManager(): RollbackManager {
|
|
||||||
return this.rollbackManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
getChangeCache(): ChangeCache {
|
|
||||||
return this.changeCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
async initializeCache(): Promise<void> {
|
|
||||||
await this.changeCache.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
getFormatStats(): FormatStats {
|
getFormatStats(): FormatStats {
|
||||||
return this.formatStats;
|
return this.formatStats;
|
||||||
}
|
}
|
||||||
|
@@ -18,10 +18,10 @@ export class FormatPlanner {
|
|||||||
filesAdded: 0,
|
filesAdded: 0,
|
||||||
filesModified: 0,
|
filesModified: 0,
|
||||||
filesRemoved: 0,
|
filesRemoved: 0,
|
||||||
estimatedTime: 0
|
estimatedTime: 0,
|
||||||
},
|
},
|
||||||
changes: [],
|
changes: [],
|
||||||
warnings: []
|
warnings: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const module of modules) {
|
for (const module of modules) {
|
||||||
@@ -49,45 +49,30 @@ export class FormatPlanner {
|
|||||||
plan.warnings.push({
|
plan.warnings.push({
|
||||||
level: 'error',
|
level: 'error',
|
||||||
message: `Failed to analyze module ${module.name}: ${error.message}`,
|
message: `Failed to analyze module ${module.name}: ${error.message}`,
|
||||||
module: module.name
|
module: module.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plan.summary.totalFiles = plan.summary.filesAdded + plan.summary.filesModified + plan.summary.filesRemoved;
|
plan.summary.totalFiles =
|
||||||
|
plan.summary.filesAdded +
|
||||||
|
plan.summary.filesModified +
|
||||||
|
plan.summary.filesRemoved;
|
||||||
plan.summary.estimatedTime = plan.summary.totalFiles * 100; // 100ms per file estimate
|
plan.summary.estimatedTime = plan.summary.totalFiles * 100; // 100ms per file estimate
|
||||||
|
|
||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
async executePlan(plan: IFormatPlan, modules: BaseFormatter[], context: FormatContext, parallel: boolean = true): Promise<void> {
|
async executePlan(
|
||||||
await context.beginOperation();
|
plan: IFormatPlan,
|
||||||
|
modules: BaseFormatter[],
|
||||||
|
context: FormatContext,
|
||||||
|
parallel: boolean = false,
|
||||||
|
): Promise<void> {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (parallel) {
|
// Always use sequential execution to avoid race conditions
|
||||||
// Get execution groups based on dependencies
|
|
||||||
const executionGroups = this.dependencyAnalyzer.getExecutionGroups(modules);
|
|
||||||
|
|
||||||
logger.log('info', `Executing formatters in ${executionGroups.length} groups...`);
|
|
||||||
|
|
||||||
for (let i = 0; i < executionGroups.length; i++) {
|
|
||||||
const group = executionGroups[i];
|
|
||||||
logger.log('info', `Executing group ${i + 1}: ${group.map(m => m.name).join(', ')}`);
|
|
||||||
|
|
||||||
// Execute modules in this group in parallel
|
|
||||||
const promises = group.map(async (module) => {
|
|
||||||
const changes = this.plannedChanges.get(module.name) || [];
|
|
||||||
if (changes.length > 0) {
|
|
||||||
logger.log('info', `Executing ${module.name} formatter...`);
|
|
||||||
await module.execute(changes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Sequential execution (original implementation)
|
|
||||||
for (const module of modules) {
|
for (const module of modules) {
|
||||||
const changes = this.plannedChanges.get(module.name) || [];
|
const changes = this.plannedChanges.get(module.name) || [];
|
||||||
|
|
||||||
@@ -96,20 +81,19 @@ export class FormatPlanner {
|
|||||||
await module.execute(changes);
|
await module.execute(changes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
const duration = endTime - startTime;
|
const duration = endTime - startTime;
|
||||||
logger.log('info', `Format operations completed in ${duration}ms`);
|
logger.log('info', `Format operations completed in ${duration}ms`);
|
||||||
|
|
||||||
await context.commitOperation();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await context.rollbackOperation();
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async displayPlan(plan: IFormatPlan, detailed: boolean = false): Promise<void> {
|
async displayPlan(
|
||||||
|
plan: IFormatPlan,
|
||||||
|
detailed: boolean = false,
|
||||||
|
): Promise<void> {
|
||||||
console.log('\nFormat Plan:');
|
console.log('\nFormat Plan:');
|
||||||
console.log('━'.repeat(50));
|
console.log('━'.repeat(50));
|
||||||
console.log(`Summary: ${plan.summary.totalFiles} files will be changed`);
|
console.log(`Summary: ${plan.summary.totalFiles} files will be changed`);
|
||||||
@@ -128,7 +112,9 @@ export class FormatPlanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [module, changes] of changesByModule) {
|
for (const [module, changes] of changesByModule) {
|
||||||
console.log(`\n${this.getModuleIcon(module)} ${module} (${changes.length} ${changes.length === 1 ? 'file' : 'files'})`);
|
console.log(
|
||||||
|
`\n${this.getModuleIcon(module)} ${module} (${changes.length} ${changes.length === 1 ? 'file' : 'files'})`,
|
||||||
|
);
|
||||||
|
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
const icon = this.getChangeIcon(change.type);
|
const icon = this.getChangeIcon(change.type);
|
||||||
@@ -157,16 +143,16 @@ export class FormatPlanner {
|
|||||||
|
|
||||||
private getModuleIcon(module: string): string {
|
private getModuleIcon(module: string): string {
|
||||||
const icons: Record<string, string> = {
|
const icons: Record<string, string> = {
|
||||||
'packagejson': '📦',
|
packagejson: '📦',
|
||||||
'license': '📝',
|
license: '📝',
|
||||||
'tsconfig': '🔧',
|
tsconfig: '🔧',
|
||||||
'cleanup': '🚮',
|
cleanup: '🚮',
|
||||||
'gitignore': '🔒',
|
gitignore: '🔒',
|
||||||
'prettier': '✨',
|
prettier: '✨',
|
||||||
'readme': '📖',
|
readme: '📖',
|
||||||
'templates': '📄',
|
templates: '📄',
|
||||||
'npmextra': '⚙️',
|
npmextra: '⚙️',
|
||||||
'copy': '📋'
|
copy: '📋',
|
||||||
};
|
};
|
||||||
return icons[module] || '📁';
|
return icons[module] || '📁';
|
||||||
}
|
}
|
||||||
|
@@ -44,8 +44,8 @@ export class FormatStats {
|
|||||||
totalDeleted: 0,
|
totalDeleted: 0,
|
||||||
totalErrors: 0,
|
totalErrors: 0,
|
||||||
cacheHits: 0,
|
cacheHits: 0,
|
||||||
cacheMisses: 0
|
cacheMisses: 0,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ export class FormatStats {
|
|||||||
successes: 0,
|
successes: 0,
|
||||||
filesCreated: 0,
|
filesCreated: 0,
|
||||||
filesModified: 0,
|
filesModified: 0,
|
||||||
filesDeleted: 0
|
filesDeleted: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,11 @@ export class FormatStats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recordFileOperation(moduleName: string, operation: 'create' | 'modify' | 'delete', success: boolean = true): void {
|
recordFileOperation(
|
||||||
|
moduleName: string,
|
||||||
|
operation: 'create' | 'modify' | 'delete',
|
||||||
|
success: boolean = true,
|
||||||
|
): void {
|
||||||
const moduleStats = this.stats.moduleStats.get(moduleName);
|
const moduleStats = this.stats.moduleStats.get(moduleName);
|
||||||
if (!moduleStats) return;
|
if (!moduleStats) return;
|
||||||
|
|
||||||
@@ -122,16 +126,24 @@ export class FormatStats {
|
|||||||
|
|
||||||
// Overall stats
|
// Overall stats
|
||||||
console.log('\nOverall Summary:');
|
console.log('\nOverall Summary:');
|
||||||
console.log(` Total Execution Time: ${this.formatDuration(this.stats.totalExecutionTime)}`);
|
console.log(
|
||||||
|
` Total Execution Time: ${this.formatDuration(this.stats.totalExecutionTime)}`,
|
||||||
|
);
|
||||||
console.log(` Files Processed: ${this.stats.overallStats.totalFiles}`);
|
console.log(` Files Processed: ${this.stats.overallStats.totalFiles}`);
|
||||||
console.log(` • Created: ${this.stats.overallStats.totalCreated}`);
|
console.log(` • Created: ${this.stats.overallStats.totalCreated}`);
|
||||||
console.log(` • Modified: ${this.stats.overallStats.totalModified}`);
|
console.log(` • Modified: ${this.stats.overallStats.totalModified}`);
|
||||||
console.log(` • Deleted: ${this.stats.overallStats.totalDeleted}`);
|
console.log(` • Deleted: ${this.stats.overallStats.totalDeleted}`);
|
||||||
console.log(` Errors: ${this.stats.overallStats.totalErrors}`);
|
console.log(` Errors: ${this.stats.overallStats.totalErrors}`);
|
||||||
|
|
||||||
if (this.stats.overallStats.cacheHits > 0 || this.stats.overallStats.cacheMisses > 0) {
|
if (
|
||||||
const cacheHitRate = this.stats.overallStats.cacheHits /
|
this.stats.overallStats.cacheHits > 0 ||
|
||||||
(this.stats.overallStats.cacheHits + this.stats.overallStats.cacheMisses) * 100;
|
this.stats.overallStats.cacheMisses > 0
|
||||||
|
) {
|
||||||
|
const cacheHitRate =
|
||||||
|
(this.stats.overallStats.cacheHits /
|
||||||
|
(this.stats.overallStats.cacheHits +
|
||||||
|
this.stats.overallStats.cacheMisses)) *
|
||||||
|
100;
|
||||||
console.log(` Cache Hit Rate: ${cacheHitRate.toFixed(1)}%`);
|
console.log(` Cache Hit Rate: ${cacheHitRate.toFixed(1)}%`);
|
||||||
console.log(` • Hits: ${this.stats.overallStats.cacheHits}`);
|
console.log(` • Hits: ${this.stats.overallStats.cacheHits}`);
|
||||||
console.log(` • Misses: ${this.stats.overallStats.cacheMisses}`);
|
console.log(` • Misses: ${this.stats.overallStats.cacheMisses}`);
|
||||||
@@ -141,12 +153,17 @@ export class FormatStats {
|
|||||||
console.log('\nModule Breakdown:');
|
console.log('\nModule Breakdown:');
|
||||||
console.log('─'.repeat(50));
|
console.log('─'.repeat(50));
|
||||||
|
|
||||||
const sortedModules = Array.from(this.stats.moduleStats.values())
|
const sortedModules = Array.from(this.stats.moduleStats.values()).sort(
|
||||||
.sort((a, b) => b.filesProcessed - a.filesProcessed);
|
(a, b) => b.filesProcessed - a.filesProcessed,
|
||||||
|
);
|
||||||
|
|
||||||
for (const moduleStats of sortedModules) {
|
for (const moduleStats of sortedModules) {
|
||||||
console.log(`\n${this.getModuleIcon(moduleStats.name)} ${moduleStats.name}:`);
|
console.log(
|
||||||
console.log(` Execution Time: ${this.formatDuration(moduleStats.executionTime)}`);
|
`\n${this.getModuleIcon(moduleStats.name)} ${moduleStats.name}:`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
` Execution Time: ${this.formatDuration(moduleStats.executionTime)}`,
|
||||||
|
);
|
||||||
console.log(` Files Processed: ${moduleStats.filesProcessed}`);
|
console.log(` Files Processed: ${moduleStats.filesProcessed}`);
|
||||||
|
|
||||||
if (moduleStats.filesCreated > 0) {
|
if (moduleStats.filesCreated > 0) {
|
||||||
@@ -172,10 +189,13 @@ export class FormatStats {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
executionTime: this.stats.totalExecutionTime,
|
executionTime: this.stats.totalExecutionTime,
|
||||||
overallStats: this.stats.overallStats,
|
overallStats: this.stats.overallStats,
|
||||||
moduleStats: Array.from(this.stats.moduleStats.values())
|
moduleStats: Array.from(this.stats.moduleStats.values()),
|
||||||
};
|
};
|
||||||
|
|
||||||
await plugins.smartfile.memory.toFs(JSON.stringify(report, null, 2), outputPath);
|
await plugins.smartfile.memory.toFs(
|
||||||
|
JSON.stringify(report, null, 2),
|
||||||
|
outputPath,
|
||||||
|
);
|
||||||
logger.log('info', `Statistics report saved to ${outputPath}`);
|
logger.log('info', `Statistics report saved to ${outputPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,16 +213,16 @@ export class FormatStats {
|
|||||||
|
|
||||||
private getModuleIcon(module: string): string {
|
private getModuleIcon(module: string): string {
|
||||||
const icons: Record<string, string> = {
|
const icons: Record<string, string> = {
|
||||||
'packagejson': '📦',
|
packagejson: '📦',
|
||||||
'license': '📝',
|
license: '📝',
|
||||||
'tsconfig': '🔧',
|
tsconfig: '🔧',
|
||||||
'cleanup': '🚮',
|
cleanup: '🚮',
|
||||||
'gitignore': '🔒',
|
gitignore: '🔒',
|
||||||
'prettier': '✨',
|
prettier: '✨',
|
||||||
'readme': '📖',
|
readme: '📖',
|
||||||
'templates': '📄',
|
templates: '📄',
|
||||||
'npmextra': '⚙️',
|
npmextra: '⚙️',
|
||||||
'copy': '📋'
|
copy: '📋',
|
||||||
};
|
};
|
||||||
return icons[module] || '📁';
|
return icons[module] || '📁';
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ export class RollbackManager {
|
|||||||
id: this.generateOperationId(),
|
id: this.generateOperationId(),
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
files: [],
|
files: [],
|
||||||
status: 'pending'
|
status: 'pending',
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.updateManifest(operation);
|
await this.updateManifest(operation);
|
||||||
@@ -43,7 +43,7 @@ export class RollbackManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read file content and metadata
|
// Read file content and metadata
|
||||||
const content = await plugins.smartfile.fs.toStringSync(absolutePath);
|
const content = plugins.smartfile.fs.toStringSync(absolutePath);
|
||||||
const stats = await plugins.smartfile.fs.stat(absolutePath);
|
const stats = await plugins.smartfile.fs.stat(absolutePath);
|
||||||
const checksum = this.calculateChecksum(content);
|
const checksum = this.calculateChecksum(content);
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ export class RollbackManager {
|
|||||||
path: filepath,
|
path: filepath,
|
||||||
originalContent: content,
|
originalContent: content,
|
||||||
checksum,
|
checksum,
|
||||||
permissions: stats.mode.toString(8)
|
permissions: stats.mode.toString(8),
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.updateManifest(operation);
|
await this.updateManifest(operation);
|
||||||
@@ -66,7 +66,9 @@ export class RollbackManager {
|
|||||||
async rollback(operationId: string): Promise<void> {
|
async rollback(operationId: string): Promise<void> {
|
||||||
const operation = await this.getOperation(operationId);
|
const operation = await this.getOperation(operationId);
|
||||||
if (!operation) {
|
if (!operation) {
|
||||||
throw new Error(`Operation ${operationId} not found`);
|
// Operation doesn't exist, might have already been rolled back or never created
|
||||||
|
console.warn(`Operation ${operationId} not found for rollback, skipping`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operation.status === 'rolled-back') {
|
if (operation.status === 'rolled-back') {
|
||||||
@@ -82,7 +84,7 @@ export class RollbackManager {
|
|||||||
|
|
||||||
// Verify backup integrity
|
// Verify backup integrity
|
||||||
const backupPath = this.getBackupPath(operationId, file.path);
|
const backupPath = this.getBackupPath(operationId, file.path);
|
||||||
const backupContent = await plugins.smartfile.fs.toStringSync(backupPath);
|
const backupContent = plugins.smartfile.fs.toStringSync(backupPath);
|
||||||
const backupChecksum = this.calculateChecksum(backupContent);
|
const backupChecksum = this.calculateChecksum(backupContent);
|
||||||
|
|
||||||
if (backupChecksum !== file.checksum) {
|
if (backupChecksum !== file.checksum) {
|
||||||
@@ -114,19 +116,25 @@ export class RollbackManager {
|
|||||||
|
|
||||||
async cleanOldBackups(retentionDays: number): Promise<void> {
|
async cleanOldBackups(retentionDays: number): Promise<void> {
|
||||||
const manifest = await this.getManifest();
|
const manifest = await this.getManifest();
|
||||||
const cutoffTime = Date.now() - (retentionDays * 24 * 60 * 60 * 1000);
|
const cutoffTime = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
const operationsToDelete = manifest.operations.filter(op =>
|
const operationsToDelete = manifest.operations.filter(
|
||||||
op.timestamp < cutoffTime && op.status === 'completed'
|
(op) => op.timestamp < cutoffTime && op.status === 'completed',
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const operation of operationsToDelete) {
|
for (const operation of operationsToDelete) {
|
||||||
// Remove backup files
|
// Remove backup files
|
||||||
const operationDir = plugins.path.join(this.backupDir, 'operations', operation.id);
|
const operationDir = plugins.path.join(
|
||||||
|
this.backupDir,
|
||||||
|
'operations',
|
||||||
|
operation.id,
|
||||||
|
);
|
||||||
await plugins.smartfile.fs.remove(operationDir);
|
await plugins.smartfile.fs.remove(operationDir);
|
||||||
|
|
||||||
// Remove from manifest
|
// Remove from manifest
|
||||||
manifest.operations = manifest.operations.filter(op => op.id !== operation.id);
|
manifest.operations = manifest.operations.filter(
|
||||||
|
(op) => op.id !== operation.id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.saveManifest(manifest);
|
await this.saveManifest(manifest);
|
||||||
@@ -146,7 +154,7 @@ export class RollbackManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await plugins.smartfile.fs.toStringSync(backupPath);
|
const content = plugins.smartfile.fs.toStringSync(backupPath);
|
||||||
const checksum = this.calculateChecksum(content);
|
const checksum = this.calculateChecksum(content);
|
||||||
|
|
||||||
if (checksum !== file.checksum) {
|
if (checksum !== file.checksum) {
|
||||||
@@ -164,7 +172,9 @@ export class RollbackManager {
|
|||||||
|
|
||||||
private async ensureBackupDir(): Promise<void> {
|
private async ensureBackupDir(): Promise<void> {
|
||||||
await plugins.smartfile.fs.ensureDir(this.backupDir);
|
await plugins.smartfile.fs.ensureDir(this.backupDir);
|
||||||
await plugins.smartfile.fs.ensureDir(plugins.path.join(this.backupDir, 'operations'));
|
await plugins.smartfile.fs.ensureDir(
|
||||||
|
plugins.path.join(this.backupDir, 'operations'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateOperationId(): string {
|
private generateOperationId(): string {
|
||||||
@@ -177,7 +187,14 @@ export class RollbackManager {
|
|||||||
const filename = plugins.path.basename(filepath);
|
const filename = plugins.path.basename(filepath);
|
||||||
const dir = plugins.path.dirname(filepath);
|
const dir = plugins.path.dirname(filepath);
|
||||||
const safeDir = dir.replace(/[/\\]/g, '__');
|
const safeDir = dir.replace(/[/\\]/g, '__');
|
||||||
return plugins.path.join(this.backupDir, 'operations', operationId, 'files', safeDir, `${filename}.backup`);
|
return plugins.path.join(
|
||||||
|
this.backupDir,
|
||||||
|
'operations',
|
||||||
|
operationId,
|
||||||
|
'files',
|
||||||
|
safeDir,
|
||||||
|
`${filename}.backup`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private calculateChecksum(content: string | Buffer): string {
|
private calculateChecksum(content: string | Buffer): string {
|
||||||
@@ -185,27 +202,68 @@ export class RollbackManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getManifest(): Promise<{ operations: IFormatOperation[] }> {
|
private async getManifest(): Promise<{ operations: IFormatOperation[] }> {
|
||||||
|
const defaultManifest = { operations: [] };
|
||||||
|
|
||||||
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return { operations: [] };
|
return defaultManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await plugins.smartfile.fs.toStringSync(this.manifestPath);
|
try {
|
||||||
return JSON.parse(content);
|
const content = plugins.smartfile.fs.toStringSync(this.manifestPath);
|
||||||
|
const manifest = JSON.parse(content);
|
||||||
|
|
||||||
|
// Validate the manifest structure
|
||||||
|
if (this.isValidManifest(manifest)) {
|
||||||
|
return manifest;
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
'Invalid rollback manifest structure, returning default manifest',
|
||||||
|
);
|
||||||
|
return defaultManifest;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(
|
||||||
|
`Failed to read rollback manifest: ${error.message}, returning default manifest`,
|
||||||
|
);
|
||||||
|
// Try to delete the corrupted file
|
||||||
|
try {
|
||||||
|
await plugins.smartfile.fs.remove(this.manifestPath);
|
||||||
|
} catch (removeError) {
|
||||||
|
// Ignore removal errors
|
||||||
|
}
|
||||||
|
return defaultManifest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async saveManifest(manifest: { operations: IFormatOperation[] }): Promise<void> {
|
private async saveManifest(manifest: {
|
||||||
await plugins.smartfile.memory.toFs(JSON.stringify(manifest, null, 2), this.manifestPath);
|
operations: IFormatOperation[];
|
||||||
|
}): Promise<void> {
|
||||||
|
// Validate before saving
|
||||||
|
if (!this.isValidManifest(manifest)) {
|
||||||
|
throw new Error('Invalid rollback manifest structure, cannot save');
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getOperation(operationId: string): Promise<IFormatOperation | null> {
|
// Ensure directory exists
|
||||||
|
await this.ensureBackupDir();
|
||||||
|
|
||||||
|
// Write directly with proper JSON stringification
|
||||||
|
const jsonContent = JSON.stringify(manifest, null, 2);
|
||||||
|
await plugins.smartfile.memory.toFs(jsonContent, this.manifestPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getOperation(
|
||||||
|
operationId: string,
|
||||||
|
): Promise<IFormatOperation | null> {
|
||||||
const manifest = await this.getManifest();
|
const manifest = await this.getManifest();
|
||||||
return manifest.operations.find(op => op.id === operationId) || null;
|
return manifest.operations.find((op) => op.id === operationId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateManifest(operation: IFormatOperation): Promise<void> {
|
private async updateManifest(operation: IFormatOperation): Promise<void> {
|
||||||
const manifest = await this.getManifest();
|
const manifest = await this.getManifest();
|
||||||
const existingIndex = manifest.operations.findIndex(op => op.id === operation.id);
|
const existingIndex = manifest.operations.findIndex(
|
||||||
|
(op) => op.id === operation.id,
|
||||||
|
);
|
||||||
|
|
||||||
if (existingIndex !== -1) {
|
if (existingIndex !== -1) {
|
||||||
manifest.operations[existingIndex] = operation;
|
manifest.operations[existingIndex] = operation;
|
||||||
@@ -215,4 +273,46 @@ export class RollbackManager {
|
|||||||
|
|
||||||
await this.saveManifest(manifest);
|
await this.saveManifest(manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isValidManifest(
|
||||||
|
manifest: any,
|
||||||
|
): manifest is { operations: IFormatOperation[] } {
|
||||||
|
// Check if manifest has the required structure
|
||||||
|
if (!manifest || typeof manifest !== 'object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check required fields
|
||||||
|
if (!Array.isArray(manifest.operations)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each operation entry
|
||||||
|
for (const operation of manifest.operations) {
|
||||||
|
if (
|
||||||
|
!operation ||
|
||||||
|
typeof operation !== 'object' ||
|
||||||
|
typeof operation.id !== 'string' ||
|
||||||
|
typeof operation.timestamp !== 'number' ||
|
||||||
|
typeof operation.status !== 'string' ||
|
||||||
|
!Array.isArray(operation.files)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each file in the operation
|
||||||
|
for (const file of operation.files) {
|
||||||
|
if (
|
||||||
|
!file ||
|
||||||
|
typeof file !== 'object' ||
|
||||||
|
typeof file.path !== 'string' ||
|
||||||
|
typeof file.checksum !== 'string'
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -4,14 +4,21 @@ import * as paths from '../paths.js';
|
|||||||
import { logger } from '../gitzone.logging.js';
|
import { logger } from '../gitzone.logging.js';
|
||||||
import { Project } from '../classes.project.js';
|
import { Project } from '../classes.project.js';
|
||||||
|
|
||||||
const filesToDelete = ['defaults.yml', 'yarn.lock', 'package-lock.json', 'tslint.json'];
|
const filesToDelete = [
|
||||||
|
'defaults.yml',
|
||||||
|
'yarn.lock',
|
||||||
|
'package-lock.json',
|
||||||
|
'tslint.json',
|
||||||
|
];
|
||||||
|
|
||||||
export const run = async (projectArg: Project) => {
|
export const run = async (projectArg: Project) => {
|
||||||
for (const relativeFilePath of filesToDelete) {
|
for (const relativeFilePath of filesToDelete) {
|
||||||
const fileExists = plugins.smartfile.fs.fileExistsSync(relativeFilePath);
|
const fileExists = plugins.smartfile.fs.fileExistsSync(relativeFilePath);
|
||||||
if (fileExists) {
|
if (fileExists) {
|
||||||
logger.log('info', `Found ${relativeFilePath}! Removing it!`);
|
logger.log('info', `Found ${relativeFilePath}! Removing it!`);
|
||||||
plugins.smartfile.fs.removeSync(plugins.path.join(paths.cwd, relativeFilePath));
|
plugins.smartfile.fs.removeSync(
|
||||||
|
plugins.path.join(paths.cwd, relativeFilePath),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.log('info', `Project is free of ${relativeFilePath}`);
|
logger.log('info', `Project is free of ${relativeFilePath}`);
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ export const run = async (projectArg: Project) => {
|
|||||||
// Get copy configuration from npmextra.json
|
// Get copy configuration from npmextra.json
|
||||||
const npmextraConfig = new plugins.npmextra.Npmextra();
|
const npmextraConfig = new plugins.npmextra.Npmextra();
|
||||||
const copyConfig = npmextraConfig.dataFor<any>('gitzone.format.copy', {
|
const copyConfig = npmextraConfig.dataFor<any>('gitzone.format.copy', {
|
||||||
patterns: []
|
patterns: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!copyConfig.patterns || copyConfig.patterns.length === 0) {
|
if (!copyConfig.patterns || copyConfig.patterns.length === 0) {
|
||||||
@@ -40,7 +40,7 @@ export const run = async (projectArg: Project) => {
|
|||||||
if (pattern.preservePath) {
|
if (pattern.preservePath) {
|
||||||
const relativePath = plugins.path.relative(
|
const relativePath = plugins.path.relative(
|
||||||
plugins.path.dirname(pattern.from.replace(/\*/g, '')),
|
plugins.path.dirname(pattern.from.replace(/\*/g, '')),
|
||||||
file
|
file,
|
||||||
);
|
);
|
||||||
destPath = plugins.path.join(pattern.to, relativePath);
|
destPath = plugins.path.join(pattern.to, relativePath);
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,10 @@ export const run = async (projectArg: Project) => {
|
|||||||
logger.log('info', `Copied ${sourcePath} to ${destPath}`);
|
logger.log('info', `Copied ${sourcePath} to ${destPath}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log('error', `Failed to copy pattern ${pattern.from}: ${error.message}`);
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Failed to copy pattern ${pattern.from}: ${error.message}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -8,14 +8,40 @@ const gitignorePath = plugins.path.join(paths.cwd, './.gitignore');
|
|||||||
|
|
||||||
export const run = async (projectArg: Project) => {
|
export const run = async (projectArg: Project) => {
|
||||||
const gitignoreExists = await plugins.smartfile.fs.fileExists(gitignorePath);
|
const gitignoreExists = await plugins.smartfile.fs.fileExists(gitignorePath);
|
||||||
const templateModule = await import('../mod_template/index.js');
|
let customContent = '';
|
||||||
const ciTemplate = await templateModule.getTemplate('gitignore');
|
|
||||||
if (gitignoreExists) {
|
if (gitignoreExists) {
|
||||||
// lets get the existing gitignore file
|
// lets get the existing gitignore file
|
||||||
const existingGitIgnoreString = plugins.smartfile.fs.toStringSync(gitignorePath);
|
const existingGitIgnoreString =
|
||||||
let customPart = existingGitIgnoreString.split('# custom\n')[1];
|
plugins.smartfile.fs.toStringSync(gitignorePath);
|
||||||
customPart ? null : (customPart = '');
|
|
||||||
|
// Check for different custom section markers
|
||||||
|
const customMarkers = ['#------# custom', '# custom'];
|
||||||
|
for (const marker of customMarkers) {
|
||||||
|
const splitResult = existingGitIgnoreString.split(marker);
|
||||||
|
if (splitResult.length > 1) {
|
||||||
|
// Get everything after the marker (excluding the marker itself)
|
||||||
|
customContent = splitResult[1].trim();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ciTemplate.writeToDisk(paths.cwd);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the template
|
||||||
|
const templateModule = await import('../mod_template/index.js');
|
||||||
|
const ciTemplate = await templateModule.getTemplate('gitignore');
|
||||||
|
await ciTemplate.writeToDisk(paths.cwd);
|
||||||
|
|
||||||
|
// Append the custom content if it exists
|
||||||
|
if (customContent) {
|
||||||
|
const newGitignoreContent =
|
||||||
|
plugins.smartfile.fs.toStringSync(gitignorePath);
|
||||||
|
// The template already ends with "#------# custom", so just append the content
|
||||||
|
const finalContent =
|
||||||
|
newGitignoreContent.trimEnd() + '\n' + customContent + '\n';
|
||||||
|
await plugins.smartfile.fs.toFs(finalContent, gitignorePath);
|
||||||
|
logger.log('info', 'Updated .gitignore while preserving custom section!');
|
||||||
|
} else {
|
||||||
logger.log('info', 'Added a .gitignore!');
|
logger.log('info', 'Added a .gitignore!');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@@ -24,7 +24,9 @@ export const run = async (projectArg: Project) => {
|
|||||||
} else {
|
} else {
|
||||||
logger.log('error', 'Error -> licenses failed. Here is why:');
|
logger.log('error', 'Error -> licenses failed. Here is why:');
|
||||||
for (const failedModule of licenseCheckResult.failingModules) {
|
for (const failedModule of licenseCheckResult.failingModules) {
|
||||||
console.log(`${failedModule.name} fails with license ${failedModule.license}`);
|
console.log(
|
||||||
|
`${failedModule.name} fails with license ${failedModule.license}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -29,7 +29,12 @@ export const run = async (projectArg: Project) => {
|
|||||||
|
|
||||||
const interactInstance = new plugins.smartinteract.SmartInteract();
|
const interactInstance = new plugins.smartinteract.SmartInteract();
|
||||||
for (const expectedRepoInformationItem of expectedRepoInformation) {
|
for (const expectedRepoInformationItem of expectedRepoInformation) {
|
||||||
if (!plugins.smartobject.smartGet(npmextraJson.gitzone, expectedRepoInformationItem)) {
|
if (
|
||||||
|
!plugins.smartobject.smartGet(
|
||||||
|
npmextraJson.gitzone,
|
||||||
|
expectedRepoInformationItem,
|
||||||
|
)
|
||||||
|
) {
|
||||||
interactInstance.addQuestions([
|
interactInstance.addQuestions([
|
||||||
{
|
{
|
||||||
message: `What is the value of ${expectedRepoInformationItem}`,
|
message: `What is the value of ${expectedRepoInformationItem}`,
|
||||||
@@ -43,7 +48,9 @@ export const run = async (projectArg: Project) => {
|
|||||||
|
|
||||||
const answerbucket = await interactInstance.runQueue();
|
const answerbucket = await interactInstance.runQueue();
|
||||||
for (const expectedRepoInformationItem of expectedRepoInformation) {
|
for (const expectedRepoInformationItem of expectedRepoInformation) {
|
||||||
const cliProvidedValue = answerbucket.getAnswerFor(expectedRepoInformationItem);
|
const cliProvidedValue = answerbucket.getAnswerFor(
|
||||||
|
expectedRepoInformationItem,
|
||||||
|
);
|
||||||
if (cliProvidedValue) {
|
if (cliProvidedValue) {
|
||||||
plugins.smartobject.smartAdd(
|
plugins.smartobject.smartAdd(
|
||||||
npmextraJson.gitzone,
|
npmextraJson.gitzone,
|
||||||
|
@@ -43,7 +43,8 @@ const ensureDependency = async (
|
|||||||
break;
|
break;
|
||||||
case 'include':
|
case 'include':
|
||||||
if (!packageJsonObjectArg[section][packageName]) {
|
if (!packageJsonObjectArg[section][packageName]) {
|
||||||
packageJsonObjectArg[section][packageName] = version === 'latest' ? '^1.0.0' : version;
|
packageJsonObjectArg[section][packageName] =
|
||||||
|
version === 'latest' ? '^1.0.0' : version;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'latest':
|
case 'latest':
|
||||||
@@ -54,9 +55,13 @@ const ensureDependency = async (
|
|||||||
const latestVersion = packageInfo['dist-tags'].latest;
|
const latestVersion = packageInfo['dist-tags'].latest;
|
||||||
packageJsonObjectArg[section][packageName] = `^${latestVersion}`;
|
packageJsonObjectArg[section][packageName] = `^${latestVersion}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log('warn', `Could not fetch latest version for ${packageName}, using existing or default`);
|
logger.log(
|
||||||
|
'warn',
|
||||||
|
`Could not fetch latest version for ${packageName}, using existing or default`,
|
||||||
|
);
|
||||||
if (!packageJsonObjectArg[section][packageName]) {
|
if (!packageJsonObjectArg[section][packageName]) {
|
||||||
packageJsonObjectArg[section][packageName] = version === 'latest' ? '^1.0.0' : version;
|
packageJsonObjectArg[section][packageName] =
|
||||||
|
version === 'latest' ? '^1.0.0' : version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -91,9 +96,15 @@ export const run = async (projectArg: Project) => {
|
|||||||
|
|
||||||
// Check for private or public
|
// Check for private or public
|
||||||
if (packageJson.private !== undefined) {
|
if (packageJson.private !== undefined) {
|
||||||
logger.log('info', 'Success -> found private/public info in package.json!');
|
logger.log(
|
||||||
|
'info',
|
||||||
|
'Success -> found private/public info in package.json!',
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.log('error', 'found no private boolean! Setting it to private for now!');
|
logger.log(
|
||||||
|
'error',
|
||||||
|
'found no private boolean! Setting it to private for now!',
|
||||||
|
);
|
||||||
packageJson.private = true;
|
packageJson.private = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +112,10 @@ export const run = async (projectArg: Project) => {
|
|||||||
if (packageJson.license) {
|
if (packageJson.license) {
|
||||||
logger.log('info', 'Success -> found license in package.json!');
|
logger.log('info', 'Success -> found license in package.json!');
|
||||||
} else {
|
} else {
|
||||||
logger.log('error', 'found no license! Setting it to UNLICENSED for now!');
|
logger.log(
|
||||||
|
'error',
|
||||||
|
'found no license! Setting it to UNLICENSED for now!',
|
||||||
|
);
|
||||||
packageJson.license = 'UNLICENSED';
|
packageJson.license = 'UNLICENSED';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,13 +123,19 @@ export const run = async (projectArg: Project) => {
|
|||||||
if (packageJson.scripts.build) {
|
if (packageJson.scripts.build) {
|
||||||
logger.log('info', 'Success -> found build script in package.json!');
|
logger.log('info', 'Success -> found build script in package.json!');
|
||||||
} else {
|
} else {
|
||||||
logger.log('error', 'found no build script! Putting a placeholder there for now!');
|
logger.log(
|
||||||
|
'error',
|
||||||
|
'found no build script! Putting a placeholder there for now!',
|
||||||
|
);
|
||||||
packageJson.scripts.build = `echo "Not needed for now"`;
|
packageJson.scripts.build = `echo "Not needed for now"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for buildDocs script
|
// Check for buildDocs script
|
||||||
if (!packageJson.scripts.buildDocs) {
|
if (!packageJson.scripts.buildDocs) {
|
||||||
logger.log('info', 'found no buildDocs script! Putting tsdoc script there now.');
|
logger.log(
|
||||||
|
'info',
|
||||||
|
'found no buildDocs script! Putting tsdoc script there now.',
|
||||||
|
);
|
||||||
packageJson.scripts.buildDocs = `tsdoc`;
|
packageJson.scripts.buildDocs = `tsdoc`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,9 +154,24 @@ export const run = async (projectArg: Project) => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// check for dependencies
|
// check for dependencies
|
||||||
await ensureDependency(packageJson, 'devDep', 'latest', '@push.rocks/tapbundle');
|
await ensureDependency(
|
||||||
await ensureDependency(packageJson, 'devDep', 'latest', '@git.zone/tstest');
|
packageJson,
|
||||||
await ensureDependency(packageJson, 'devDep', 'latest', '@git.zone/tsbuild');
|
'devDep',
|
||||||
|
'latest',
|
||||||
|
'@push.rocks/tapbundle',
|
||||||
|
);
|
||||||
|
await ensureDependency(
|
||||||
|
packageJson,
|
||||||
|
'devDep',
|
||||||
|
'latest',
|
||||||
|
'@git.zone/tstest',
|
||||||
|
);
|
||||||
|
await ensureDependency(
|
||||||
|
packageJson,
|
||||||
|
'devDep',
|
||||||
|
'latest',
|
||||||
|
'@git.zone/tsbuild',
|
||||||
|
);
|
||||||
|
|
||||||
// set overrides
|
// set overrides
|
||||||
const overrides = plugins.smartfile.fs.toObjectSync(
|
const overrides = plugins.smartfile.fs.toObjectSync(
|
||||||
|
@@ -16,7 +16,12 @@ const prettierDefaultMarkdownConfig: prettier.Options = {
|
|||||||
parser: 'markdown',
|
parser: 'markdown',
|
||||||
};
|
};
|
||||||
|
|
||||||
const filesToFormat = [`ts/**/*.ts`, `test/**/*.ts`, `readme.md`, `docs/**/*.md`];
|
const filesToFormat = [
|
||||||
|
`ts/**/*.ts`,
|
||||||
|
`test/**/*.ts`,
|
||||||
|
`readme.md`,
|
||||||
|
`docs/**/*.md`,
|
||||||
|
];
|
||||||
|
|
||||||
const choosePrettierConfig = (fileArg: plugins.smartfile.SmartFile) => {
|
const choosePrettierConfig = (fileArg: plugins.smartfile.SmartFile) => {
|
||||||
switch (fileArg.parsedPath.ext) {
|
switch (fileArg.parsedPath.ext) {
|
||||||
@@ -39,7 +44,10 @@ const prettierTypeScriptPipestop = plugins.through2.obj(
|
|||||||
cb(null);
|
cb(null);
|
||||||
} else {
|
} else {
|
||||||
logger.log('info', `${fileArg.path} is being reformated!`);
|
logger.log('info', `${fileArg.path} is being reformated!`);
|
||||||
const formatedFileString = await prettier.format(fileString, chosenConfig);
|
const formatedFileString = await prettier.format(
|
||||||
|
fileString,
|
||||||
|
chosenConfig,
|
||||||
|
);
|
||||||
fileArg.setContentsFromString(formatedFileString);
|
fileArg.setContentsFromString(formatedFileString);
|
||||||
cb(null, fileArg);
|
cb(null, fileArg);
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,8 @@ export const run = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check and initialize readme.hints.md if it doesn't exist
|
// Check and initialize readme.hints.md if it doesn't exist
|
||||||
const readmeHintsExists = await plugins.smartfile.fs.fileExists(readmeHintsPath);
|
const readmeHintsExists =
|
||||||
|
await plugins.smartfile.fs.fileExists(readmeHintsPath);
|
||||||
if (!readmeHintsExists) {
|
if (!readmeHintsExists) {
|
||||||
await plugins.smartfile.fs.toFs(
|
await plugins.smartfile.fs.toFs(
|
||||||
'# Project Readme Hints\n\nThis is the initial readme hints file.',
|
'# Project Readme Hints\n\nThis is the initial readme hints file.',
|
||||||
|
@@ -26,10 +26,12 @@ export const run = async (project: Project) => {
|
|||||||
case 'npm':
|
case 'npm':
|
||||||
case 'wcc':
|
case 'wcc':
|
||||||
if (project.gitzoneConfig.data.npmciOptions.npmAccessLevel === 'public') {
|
if (project.gitzoneConfig.data.npmciOptions.npmAccessLevel === 'public') {
|
||||||
const ciTemplateDefault = await templateModule.getTemplate('ci_default');
|
const ciTemplateDefault =
|
||||||
|
await templateModule.getTemplate('ci_default');
|
||||||
ciTemplateDefault.writeToDisk(paths.cwd);
|
ciTemplateDefault.writeToDisk(paths.cwd);
|
||||||
} else {
|
} else {
|
||||||
const ciTemplateDefault = await templateModule.getTemplate('ci_default_private');
|
const ciTemplateDefault =
|
||||||
|
await templateModule.getTemplate('ci_default_private');
|
||||||
ciTemplateDefault.writeToDisk(paths.cwd);
|
ciTemplateDefault.writeToDisk(paths.cwd);
|
||||||
}
|
}
|
||||||
logger.log('info', 'Updated .gitlabci.yml!');
|
logger.log('info', 'Updated .gitlabci.yml!');
|
||||||
@@ -41,7 +43,8 @@ export const run = async (project: Project) => {
|
|||||||
logger.log('info', 'Updated CI/CD config files!');
|
logger.log('info', 'Updated CI/CD config files!');
|
||||||
|
|
||||||
// lets care about docker
|
// lets care about docker
|
||||||
const dockerTemplate = await templateModule.getTemplate('dockerfile_service');
|
const dockerTemplate =
|
||||||
|
await templateModule.getTemplate('dockerfile_service');
|
||||||
dockerTemplate.writeToDisk(paths.cwd);
|
dockerTemplate.writeToDisk(paths.cwd);
|
||||||
logger.log('info', 'Updated Dockerfile!');
|
logger.log('info', 'Updated Dockerfile!');
|
||||||
|
|
||||||
@@ -56,17 +59,22 @@ export const run = async (project: Project) => {
|
|||||||
|
|
||||||
// update html
|
// update html
|
||||||
if (project.gitzoneConfig.data.projectType === 'website') {
|
if (project.gitzoneConfig.data.projectType === 'website') {
|
||||||
const websiteUpdateTemplate = await templateModule.getTemplate('website_update');
|
const websiteUpdateTemplate =
|
||||||
const variables ={
|
await templateModule.getTemplate('website_update');
|
||||||
|
const variables = {
|
||||||
assetbrokerUrl: project.gitzoneConfig.data.module.assetbrokerUrl,
|
assetbrokerUrl: project.gitzoneConfig.data.module.assetbrokerUrl,
|
||||||
legalUrl: project.gitzoneConfig.data.module.legalUrl,
|
legalUrl: project.gitzoneConfig.data.module.legalUrl,
|
||||||
};
|
};
|
||||||
console.log('updating website template with variables\n', JSON.stringify(variables, null, 2));
|
console.log(
|
||||||
|
'updating website template with variables\n',
|
||||||
|
JSON.stringify(variables, null, 2),
|
||||||
|
);
|
||||||
websiteUpdateTemplate.supplyVariables(variables);
|
websiteUpdateTemplate.supplyVariables(variables);
|
||||||
await websiteUpdateTemplate.writeToDisk(paths.cwd);
|
await websiteUpdateTemplate.writeToDisk(paths.cwd);
|
||||||
logger.log('info', `Updated html for website!`);
|
logger.log('info', `Updated html for website!`);
|
||||||
} else if (project.gitzoneConfig.data.projectType === 'service') {
|
} else if (project.gitzoneConfig.data.projectType === 'service') {
|
||||||
const websiteUpdateTemplate = await templateModule.getTemplate('service_update');
|
const websiteUpdateTemplate =
|
||||||
|
await templateModule.getTemplate('service_update');
|
||||||
await websiteUpdateTemplate.writeToDisk(paths.cwd);
|
await websiteUpdateTemplate.writeToDisk(paths.cwd);
|
||||||
logger.log('info', `Updated html for element template!`);
|
logger.log('info', `Updated html for element template!`);
|
||||||
} else if (project.gitzoneConfig.data.projectType === 'wcc') {
|
} else if (project.gitzoneConfig.data.projectType === 'wcc') {
|
||||||
|
@@ -19,8 +19,12 @@ export const run = async (projectArg: Project) => {
|
|||||||
const publishModules = await tsPublishInstance.getModuleSubDirs(paths.cwd);
|
const publishModules = await tsPublishInstance.getModuleSubDirs(paths.cwd);
|
||||||
for (const publishModule of Object.keys(publishModules)) {
|
for (const publishModule of Object.keys(publishModules)) {
|
||||||
const publishConfig = publishModules[publishModule];
|
const publishConfig = publishModules[publishModule];
|
||||||
tsconfigObject.compilerOptions.paths[`${publishConfig.name}`] = [`./${publishModule}/index.js`];
|
tsconfigObject.compilerOptions.paths[`${publishConfig.name}`] = [
|
||||||
|
`./${publishModule}/index.js`,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
tsconfigSmartfile.setContentsFromString(JSON.stringify(tsconfigObject, null, 2));
|
tsconfigSmartfile.setContentsFromString(
|
||||||
|
JSON.stringify(tsconfigObject, null, 2),
|
||||||
|
);
|
||||||
await tsconfigSmartfile.write();
|
await tsconfigSmartfile.write();
|
||||||
};
|
};
|
||||||
|
@@ -12,7 +12,12 @@ export class CleanupFormatter extends BaseFormatter {
|
|||||||
const changes: IPlannedChange[] = [];
|
const changes: IPlannedChange[] = [];
|
||||||
|
|
||||||
// List of files to remove
|
// List of files to remove
|
||||||
const filesToRemove = ['yarn.lock', 'package-lock.json', 'tslint.json', 'defaults.yml'];
|
const filesToRemove = [
|
||||||
|
'yarn.lock',
|
||||||
|
'package-lock.json',
|
||||||
|
'tslint.json',
|
||||||
|
'defaults.yml',
|
||||||
|
];
|
||||||
|
|
||||||
for (const file of filesToRemove) {
|
for (const file of filesToRemove) {
|
||||||
const exists = await plugins.smartfile.fs.fileExists(file);
|
const exists = await plugins.smartfile.fs.fileExists(file);
|
||||||
@@ -21,7 +26,7 @@ export class CleanupFormatter extends BaseFormatter {
|
|||||||
type: 'delete',
|
type: 'delete',
|
||||||
path: file,
|
path: file,
|
||||||
module: this.name,
|
module: this.name,
|
||||||
description: `Remove obsolete file`
|
description: `Remove obsolete file`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,12 @@ export class LegacyFormatter extends BaseFormatter {
|
|||||||
private moduleName: string;
|
private moduleName: string;
|
||||||
private formatModule: any;
|
private formatModule: any;
|
||||||
|
|
||||||
constructor(context: any, project: Project, moduleName: string, formatModule: any) {
|
constructor(
|
||||||
|
context: any,
|
||||||
|
project: Project,
|
||||||
|
moduleName: string,
|
||||||
|
formatModule: any,
|
||||||
|
) {
|
||||||
super(context, project);
|
super(context, project);
|
||||||
this.moduleName = moduleName;
|
this.moduleName = moduleName;
|
||||||
this.formatModule = formatModule;
|
this.formatModule = formatModule;
|
||||||
@@ -21,12 +26,14 @@ export class LegacyFormatter extends BaseFormatter {
|
|||||||
async analyze(): Promise<IPlannedChange[]> {
|
async analyze(): Promise<IPlannedChange[]> {
|
||||||
// For legacy modules, we can't easily predict changes
|
// For legacy modules, we can't easily predict changes
|
||||||
// So we'll return a generic change that indicates the module will run
|
// So we'll return a generic change that indicates the module will run
|
||||||
return [{
|
return [
|
||||||
|
{
|
||||||
type: 'modify',
|
type: 'modify',
|
||||||
path: '<various files>',
|
path: '<various files>',
|
||||||
module: this.name,
|
module: this.name,
|
||||||
description: `Run ${this.name} formatter`
|
description: `Run ${this.name} formatter`,
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyChange(change: IPlannedChange): Promise<void> {
|
async applyChange(change: IPlannedChange): Promise<void> {
|
||||||
|
@@ -12,12 +12,7 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
const changes: IPlannedChange[] = [];
|
const changes: IPlannedChange[] = [];
|
||||||
|
|
||||||
// Define directories to format (TypeScript directories by default)
|
// Define directories to format (TypeScript directories by default)
|
||||||
const includeDirs = [
|
const includeDirs = ['ts', 'ts_*', 'test', 'tests'];
|
||||||
'ts',
|
|
||||||
'ts_*',
|
|
||||||
'test',
|
|
||||||
'tests'
|
|
||||||
];
|
|
||||||
|
|
||||||
// File extensions to format
|
// File extensions to format
|
||||||
const extensions = '{ts,tsx,js,jsx,json,md,css,scss,html,xml,yaml,yml}';
|
const extensions = '{ts,tsx,js,jsx,json,md,css,scss,html,xml,yaml,yml}';
|
||||||
@@ -34,9 +29,10 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
'README.md',
|
'README.md',
|
||||||
'changelog.md',
|
'changelog.md',
|
||||||
'CHANGELOG.md',
|
'CHANGELOG.md',
|
||||||
'license',
|
// Skip files without extensions as prettier can't infer parser
|
||||||
'LICENSE',
|
// 'license',
|
||||||
'*.md'
|
// 'LICENSE',
|
||||||
|
'*.md',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Collect all files to format
|
// Collect all files to format
|
||||||
@@ -45,7 +41,10 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
// Add files from TypeScript directories
|
// Add files from TypeScript directories
|
||||||
for (const dir of includeDirs) {
|
for (const dir of includeDirs) {
|
||||||
const globPattern = `${dir}/**/*.${extensions}`;
|
const globPattern = `${dir}/**/*.${extensions}`;
|
||||||
const dirFiles = await plugins.smartfile.fs.listFileTree('.', globPattern);
|
const dirFiles = await plugins.smartfile.fs.listFileTree(
|
||||||
|
'.',
|
||||||
|
globPattern,
|
||||||
|
);
|
||||||
allFiles.push(...dirFiles);
|
allFiles.push(...dirFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
for (const pattern of rootConfigFiles) {
|
for (const pattern of rootConfigFiles) {
|
||||||
const rootFiles = await plugins.smartfile.fs.listFileTree('.', pattern);
|
const rootFiles = await plugins.smartfile.fs.listFileTree('.', pattern);
|
||||||
// Only include files at root level (no slashes in path)
|
// Only include files at root level (no slashes in path)
|
||||||
const rootLevelFiles = rootFiles.filter(f => !f.includes('/'));
|
const rootLevelFiles = rootFiles.filter((f) => !f.includes('/'));
|
||||||
allFiles.push(...rootLevelFiles);
|
allFiles.push(...rootLevelFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +79,7 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
// Check which files need formatting
|
// Check which files need formatting
|
||||||
for (const file of validFiles) {
|
for (const file of validFiles) {
|
||||||
// Skip files that haven't changed
|
// Skip files that haven't changed
|
||||||
if (!await this.shouldProcessFile(file)) {
|
if (!(await this.shouldProcessFile(file))) {
|
||||||
logVerbose(`Skipping ${file} - no changes detected`);
|
logVerbose(`Skipping ${file} - no changes detected`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -89,7 +88,7 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
type: 'modify',
|
type: 'modify',
|
||||||
path: file,
|
path: file,
|
||||||
module: this.name,
|
module: this.name,
|
||||||
description: 'Format with Prettier'
|
description: 'Format with Prettier',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,38 +103,31 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
try {
|
try {
|
||||||
await this.preExecute();
|
await this.preExecute();
|
||||||
|
|
||||||
// Batch process files
|
logVerbose(`Processing ${changes.length} files sequentially`);
|
||||||
const batchSize = 10; // Process 10 files at a time
|
|
||||||
const batches: IPlannedChange[][] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < changes.length; i += batchSize) {
|
// Process files sequentially to avoid prettier cache/state issues
|
||||||
batches.push(changes.slice(i, i + batchSize));
|
for (let i = 0; i < changes.length; i++) {
|
||||||
}
|
const change = changes[i];
|
||||||
|
logVerbose(
|
||||||
|
`Processing file ${i + 1}/${changes.length}: ${change.path}`,
|
||||||
|
);
|
||||||
|
|
||||||
logVerbose(`Processing ${changes.length} files in ${batches.length} batches`);
|
|
||||||
|
|
||||||
for (let i = 0; i < batches.length; i++) {
|
|
||||||
const batch = batches[i];
|
|
||||||
logVerbose(`Processing batch ${i + 1}/${batches.length} (${batch.length} files)`);
|
|
||||||
|
|
||||||
// Process batch in parallel
|
|
||||||
const promises = batch.map(async (change) => {
|
|
||||||
try {
|
try {
|
||||||
await this.applyChange(change);
|
await this.applyChange(change);
|
||||||
this.stats.recordFileOperation(this.name, change.type, true);
|
this.stats.recordFileOperation(this.name, change.type, true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.stats.recordFileOperation(this.name, change.type, false);
|
this.stats.recordFileOperation(this.name, change.type, false);
|
||||||
logger.log('error', `Failed to format ${change.path}: ${error.message}`);
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Failed to format ${change.path}: ${error.message}`,
|
||||||
|
);
|
||||||
// Don't throw - continue with other files
|
// Don't throw - continue with other files
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.postExecute();
|
await this.postExecute();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.context.rollbackOperation();
|
// Rollback removed - no longer tracking operations
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
this.stats.endModule(this.name, startTime);
|
this.stats.endModule(this.name, startTime);
|
||||||
@@ -146,27 +138,71 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
if (change.type !== 'modify') return;
|
if (change.type !== 'modify') return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Validate the path before processing
|
||||||
|
if (!change.path || change.path.trim() === '') {
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Invalid empty path in change: ${JSON.stringify(change)}`,
|
||||||
|
);
|
||||||
|
throw new Error('Invalid empty path');
|
||||||
|
}
|
||||||
|
|
||||||
// Read current content
|
// Read current content
|
||||||
const content = plugins.smartfile.fs.toStringSync(change.path);
|
const content = plugins.smartfile.fs.toStringSync(change.path);
|
||||||
|
|
||||||
// Format with prettier
|
// Format with prettier
|
||||||
const prettier = await import('prettier');
|
const prettier = await import('prettier');
|
||||||
|
|
||||||
|
// Skip files that prettier can't parse without explicit parser
|
||||||
|
const fileExt = plugins.path.extname(change.path).toLowerCase();
|
||||||
|
if (!fileExt || fileExt === '') {
|
||||||
|
// Files without extensions need explicit parser
|
||||||
|
logVerbose(
|
||||||
|
`Skipping ${change.path} - no file extension for parser inference`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const formatted = await prettier.format(content, {
|
const formatted = await prettier.format(content, {
|
||||||
filepath: change.path,
|
filepath: change.path,
|
||||||
...(await this.getPrettierConfig())
|
...(await this.getPrettierConfig()),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only write if content actually changed
|
// Only write if content actually changed
|
||||||
if (formatted !== content) {
|
if (formatted !== content) {
|
||||||
|
// Debug: log the path being written
|
||||||
|
logVerbose(`Writing formatted content to: ${change.path}`);
|
||||||
await this.modifyFile(change.path, formatted);
|
await this.modifyFile(change.path, formatted);
|
||||||
logVerbose(`Formatted ${change.path}`);
|
logVerbose(`Formatted ${change.path}`);
|
||||||
} else {
|
} else {
|
||||||
// Still update cache even if content didn't change
|
|
||||||
await this.cache.updateFileCache(change.path);
|
|
||||||
logVerbose(`No formatting changes for ${change.path}`);
|
logVerbose(`No formatting changes for ${change.path}`);
|
||||||
}
|
}
|
||||||
|
} catch (prettierError) {
|
||||||
|
// Check if it's a parser error
|
||||||
|
if (
|
||||||
|
prettierError.message &&
|
||||||
|
prettierError.message.includes('No parser could be inferred')
|
||||||
|
) {
|
||||||
|
logVerbose(`Skipping ${change.path} - ${prettierError.message}`);
|
||||||
|
return; // Skip this file silently
|
||||||
|
}
|
||||||
|
throw prettierError;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log('error', `Failed to format ${change.path}: ${error.message}`);
|
// Log the full error stack for debugging mkdir issues
|
||||||
|
if (error.message && error.message.includes('mkdir')) {
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Failed to format ${change.path}: ${error.message}`,
|
||||||
|
);
|
||||||
|
logger.log('error', `Error stack: ${error.stack}`);
|
||||||
|
} else {
|
||||||
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Failed to format ${change.path}: ${error.message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +217,7 @@ export class PrettierFormatter extends BaseFormatter {
|
|||||||
printWidth: 80,
|
printWidth: 80,
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
semi: true,
|
semi: true,
|
||||||
arrowParens: 'always'
|
arrowParens: 'always',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,12 +8,14 @@ export class ReadmeFormatter extends BaseFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async analyze(): Promise<IPlannedChange[]> {
|
async analyze(): Promise<IPlannedChange[]> {
|
||||||
return [{
|
return [
|
||||||
|
{
|
||||||
type: 'modify',
|
type: 'modify',
|
||||||
path: 'readme.md',
|
path: 'readme.md',
|
||||||
module: this.name,
|
module: this.name,
|
||||||
description: 'Ensure readme files exist'
|
description: 'Ensure readme files exist',
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyChange(change: IPlannedChange): Promise<void> {
|
async applyChange(change: IPlannedChange): Promise<void> {
|
||||||
|
@@ -16,7 +16,8 @@ import { PrettierFormatter } from './formatters/prettier.formatter.js';
|
|||||||
import { ReadmeFormatter } from './formatters/readme.formatter.js';
|
import { ReadmeFormatter } from './formatters/readme.formatter.js';
|
||||||
import { CopyFormatter } from './formatters/copy.formatter.js';
|
import { CopyFormatter } from './formatters/copy.formatter.js';
|
||||||
|
|
||||||
export let run = async (options: {
|
export let run = async (
|
||||||
|
options: {
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
yes?: boolean;
|
yes?: boolean;
|
||||||
planOnly?: boolean;
|
planOnly?: boolean;
|
||||||
@@ -26,7 +27,8 @@ export let run = async (options: {
|
|||||||
interactive?: boolean;
|
interactive?: boolean;
|
||||||
parallel?: boolean;
|
parallel?: boolean;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
} = {}): Promise<any> => {
|
} = {},
|
||||||
|
): Promise<any> => {
|
||||||
// Set verbose mode if requested
|
// Set verbose mode if requested
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
setVerboseMode(true);
|
setVerboseMode(true);
|
||||||
@@ -34,7 +36,7 @@ export let run = async (options: {
|
|||||||
|
|
||||||
const project = await Project.fromCwd();
|
const project = await Project.fromCwd();
|
||||||
const context = new FormatContext();
|
const context = new FormatContext();
|
||||||
await context.initializeCache(); // Initialize the cache system
|
// Cache system removed - no longer needed
|
||||||
const planner = new FormatPlanner();
|
const planner = new FormatPlanner();
|
||||||
|
|
||||||
// Get configuration from npmextra
|
// Get configuration from npmextra
|
||||||
@@ -49,24 +51,21 @@ export let run = async (options: {
|
|||||||
autoRollbackOnError: true,
|
autoRollbackOnError: true,
|
||||||
backupRetentionDays: 7,
|
backupRetentionDays: 7,
|
||||||
maxBackupSize: '100MB',
|
maxBackupSize: '100MB',
|
||||||
excludePatterns: ['node_modules/**', '.git/**']
|
excludePatterns: ['node_modules/**', '.git/**'],
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
skip: [],
|
skip: [],
|
||||||
only: [],
|
only: [],
|
||||||
order: []
|
order: [],
|
||||||
},
|
},
|
||||||
parallel: true,
|
parallel: true,
|
||||||
cache: {
|
cache: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
clean: true // Clean invalid entries from cache
|
clean: true, // Clean invalid entries from cache
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clean cache if configured
|
// Cache cleaning removed - no longer using cache system
|
||||||
if (formatConfig.cache.clean) {
|
|
||||||
await context.getChangeCache().clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override config with command options
|
// Override config with command options
|
||||||
const interactive = options.interactive ?? formatConfig.interactive;
|
const interactive = options.interactive ?? formatConfig.interactive;
|
||||||
@@ -89,7 +88,7 @@ export let run = async (options: {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Filter formatters based on configuration
|
// Filter formatters based on configuration
|
||||||
const activeFormatters = formatters.filter(formatter => {
|
const activeFormatters = formatters.filter((formatter) => {
|
||||||
if (formatConfig.modules.only.length > 0) {
|
if (formatConfig.modules.only.length > 0) {
|
||||||
return formatConfig.modules.only.includes(formatter.name);
|
return formatConfig.modules.only.includes(formatter.name);
|
||||||
}
|
}
|
||||||
@@ -110,7 +109,10 @@ export let run = async (options: {
|
|||||||
|
|
||||||
// Save plan if requested
|
// Save plan if requested
|
||||||
if (options.savePlan) {
|
if (options.savePlan) {
|
||||||
await plugins.smartfile.memory.toFs(JSON.stringify(plan, null, 2), options.savePlan);
|
await plugins.smartfile.memory.toFs(
|
||||||
|
JSON.stringify(plan, null, 2),
|
||||||
|
options.savePlan,
|
||||||
|
);
|
||||||
logger.log('info', `Plan saved to ${options.savePlan}`);
|
logger.log('info', `Plan saved to ${options.savePlan}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +134,7 @@ export let run = async (options: {
|
|||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'proceed',
|
name: 'proceed',
|
||||||
message: 'Proceed with formatting?',
|
message: 'Proceed with formatting?',
|
||||||
default: true
|
default: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(response as any).value) {
|
if (!(response as any).value) {
|
||||||
@@ -142,7 +144,10 @@ export let run = async (options: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute phase
|
// Execute phase
|
||||||
logger.log('info', `Executing format operations${parallel ? ' in parallel' : ' sequentially'}...`);
|
logger.log(
|
||||||
|
'info',
|
||||||
|
`Executing format operations${parallel ? ' in parallel' : ' sequentially'}...`,
|
||||||
|
);
|
||||||
await planner.executePlan(plan, activeFormatters, context, parallel);
|
await planner.executePlan(plan, activeFormatters, context, parallel);
|
||||||
|
|
||||||
// Finish statistics tracking
|
// Finish statistics tracking
|
||||||
@@ -161,20 +166,10 @@ export let run = async (options: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.log('success', 'Format operations completed successfully!');
|
logger.log('success', 'Format operations completed successfully!');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log('error', `Format operation failed: ${error.message}`);
|
logger.log('error', `Format operation failed: ${error.message}`);
|
||||||
|
|
||||||
// Automatic rollback if enabled
|
// Rollback system has been removed for stability
|
||||||
if (formatConfig.rollback.enabled && formatConfig.rollback.autoRollbackOnError) {
|
|
||||||
logger.log('info', 'Attempting automatic rollback...');
|
|
||||||
try {
|
|
||||||
await context.rollbackOperation();
|
|
||||||
logger.log('success', 'Rollback completed successfully');
|
|
||||||
} catch (rollbackError) {
|
|
||||||
logger.log('error', `Rollback failed: ${rollbackError.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -182,67 +177,16 @@ export let run = async (options: {
|
|||||||
|
|
||||||
// Export CLI command handlers
|
// Export CLI command handlers
|
||||||
export const handleRollback = async (operationId?: string): Promise<void> => {
|
export const handleRollback = async (operationId?: string): Promise<void> => {
|
||||||
const context = new FormatContext();
|
logger.log('info', 'Rollback system has been disabled for stability');
|
||||||
const rollbackManager = context.getRollbackManager();
|
|
||||||
|
|
||||||
if (!operationId) {
|
|
||||||
// Rollback to last operation
|
|
||||||
const backups = await rollbackManager.listBackups();
|
|
||||||
const lastOperation = backups
|
|
||||||
.filter(op => op.status !== 'rolled-back')
|
|
||||||
.sort((a, b) => b.timestamp - a.timestamp)[0];
|
|
||||||
|
|
||||||
if (!lastOperation) {
|
|
||||||
logger.log('warn', 'No operations available for rollback');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
operationId = lastOperation.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await rollbackManager.rollback(operationId);
|
|
||||||
logger.log('success', `Successfully rolled back operation ${operationId}`);
|
|
||||||
} catch (error) {
|
|
||||||
logger.log('error', `Rollback failed: ${error.message}`);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleListBackups = async (): Promise<void> => {
|
export const handleListBackups = async (): Promise<void> => {
|
||||||
const context = new FormatContext();
|
logger.log('info', 'Backup system has been disabled for stability');
|
||||||
const rollbackManager = context.getRollbackManager();
|
|
||||||
const backups = await rollbackManager.listBackups();
|
|
||||||
|
|
||||||
if (backups.length === 0) {
|
|
||||||
logger.log('info', 'No backup operations found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\nAvailable backups:');
|
|
||||||
console.log('━'.repeat(50));
|
|
||||||
|
|
||||||
for (const backup of backups) {
|
|
||||||
const date = new Date(backup.timestamp).toLocaleString();
|
|
||||||
const status = backup.status;
|
|
||||||
const filesCount = backup.files.length;
|
|
||||||
|
|
||||||
console.log(`ID: ${backup.id}`);
|
|
||||||
console.log(`Date: ${date}`);
|
|
||||||
console.log(`Status: ${status}`);
|
|
||||||
console.log(`Files: ${filesCount}`);
|
|
||||||
console.log('─'.repeat(50));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleCleanBackups = async (): Promise<void> => {
|
export const handleCleanBackups = async (): Promise<void> => {
|
||||||
const context = new FormatContext();
|
logger.log(
|
||||||
const rollbackManager = context.getRollbackManager();
|
'info',
|
||||||
|
'Backup cleaning has been disabled - backup system removed',
|
||||||
// Get retention days from config
|
);
|
||||||
const npmextraConfig = new plugins.npmextra.Npmextra();
|
|
||||||
const retentionDays = npmextraConfig.dataFor<any>('gitzone.format.rollback.backupRetentionDays', 7);
|
|
||||||
|
|
||||||
await rollbackManager.cleanOldBackups(retentionDays);
|
|
||||||
logger.log('success', `Cleaned backups older than ${retentionDays} days`);
|
|
||||||
};
|
};
|
@@ -9,7 +9,7 @@ export type IFormatOperation = {
|
|||||||
}>;
|
}>;
|
||||||
status: 'pending' | 'in-progress' | 'completed' | 'failed' | 'rolled-back';
|
status: 'pending' | 'in-progress' | 'completed' | 'failed' | 'rolled-back';
|
||||||
error?: Error;
|
error?: Error;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type IFormatPlan = {
|
export type IFormatPlan = {
|
||||||
summary: {
|
summary: {
|
||||||
@@ -32,7 +32,7 @@ export type IFormatPlan = {
|
|||||||
message: string;
|
message: string;
|
||||||
module: string;
|
module: string;
|
||||||
}>;
|
}>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type IPlannedChange = {
|
export type IPlannedChange = {
|
||||||
type: 'create' | 'modify' | 'delete';
|
type: 'create' | 'modify' | 'delete';
|
||||||
@@ -42,4 +42,4 @@ export type IPlannedChange = {
|
|||||||
content?: string; // For create/modify operations
|
content?: string; // For create/modify operations
|
||||||
diff?: string;
|
diff?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
}
|
};
|
||||||
|
@@ -35,7 +35,10 @@ export class Meta {
|
|||||||
* sorts the metaRepoData
|
* sorts the metaRepoData
|
||||||
*/
|
*/
|
||||||
public async sortMetaRepoData() {
|
public async sortMetaRepoData() {
|
||||||
const stringifiedMetadata = plugins.smartjson.stringify(this.metaRepoData, []);
|
const stringifiedMetadata = plugins.smartjson.stringify(
|
||||||
|
this.metaRepoData,
|
||||||
|
[],
|
||||||
|
);
|
||||||
this.metaRepoData = plugins.smartjson.parse(stringifiedMetadata);
|
this.metaRepoData = plugins.smartjson.parse(stringifiedMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,11 +48,15 @@ export class Meta {
|
|||||||
public async readDirectory() {
|
public async readDirectory() {
|
||||||
await this.syncToRemote(true);
|
await this.syncToRemote(true);
|
||||||
logger.log('info', `reading directory`);
|
logger.log('info', `reading directory`);
|
||||||
const metaFileExists = plugins.smartfile.fs.fileExistsSync(this.filePaths.metaJson);
|
const metaFileExists = plugins.smartfile.fs.fileExistsSync(
|
||||||
|
this.filePaths.metaJson,
|
||||||
|
);
|
||||||
if (!metaFileExists) {
|
if (!metaFileExists) {
|
||||||
throw new Error(`meta file does not exist at ${this.filePaths.metaJson}`);
|
throw new Error(`meta file does not exist at ${this.filePaths.metaJson}`);
|
||||||
}
|
}
|
||||||
this.metaRepoData = plugins.smartfile.fs.toObjectSync(this.filePaths.metaJson);
|
this.metaRepoData = plugins.smartfile.fs.toObjectSync(
|
||||||
|
this.filePaths.metaJson,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +83,10 @@ export class Meta {
|
|||||||
this.filePaths.metaJson,
|
this.filePaths.metaJson,
|
||||||
);
|
);
|
||||||
// write .gitignore to disk
|
// write .gitignore to disk
|
||||||
plugins.smartfile.memory.toFsSync(await this.generateGitignore(), this.filePaths.gitIgnore);
|
plugins.smartfile.memory.toFsSync(
|
||||||
|
await this.generateGitignore(),
|
||||||
|
this.filePaths.gitIgnore,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,13 +94,17 @@ export class Meta {
|
|||||||
*/
|
*/
|
||||||
public async syncToRemote(gitCleanArg = false) {
|
public async syncToRemote(gitCleanArg = false) {
|
||||||
logger.log('info', `syncing from origin master`);
|
logger.log('info', `syncing from origin master`);
|
||||||
await this.smartshellInstance.exec(`cd ${this.cwd} && git pull origin master`);
|
await this.smartshellInstance.exec(
|
||||||
|
`cd ${this.cwd} && git pull origin master`,
|
||||||
|
);
|
||||||
if (gitCleanArg) {
|
if (gitCleanArg) {
|
||||||
logger.log('info', `cleaning the repository from old directories`);
|
logger.log('info', `cleaning the repository from old directories`);
|
||||||
await this.smartshellInstance.exec(`cd ${this.cwd} && git clean -fd`);
|
await this.smartshellInstance.exec(`cd ${this.cwd} && git clean -fd`);
|
||||||
}
|
}
|
||||||
logger.log('info', `syncing to remote origin master`);
|
logger.log('info', `syncing to remote origin master`);
|
||||||
await this.smartshellInstance.exec(`cd ${this.cwd} && git push origin master`);
|
await this.smartshellInstance.exec(
|
||||||
|
`cd ${this.cwd} && git push origin master`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,7 +112,9 @@ export class Meta {
|
|||||||
*/
|
*/
|
||||||
public async updateLocalRepos() {
|
public async updateLocalRepos() {
|
||||||
await this.syncToRemote();
|
await this.syncToRemote();
|
||||||
const projects = plugins.smartfile.fs.toObjectSync(this.filePaths.metaJson).projects;
|
const projects = plugins.smartfile.fs.toObjectSync(
|
||||||
|
this.filePaths.metaJson,
|
||||||
|
).projects;
|
||||||
const preExistingFolders = plugins.smartfile.fs.listFoldersSync(this.cwd);
|
const preExistingFolders = plugins.smartfile.fs.listFoldersSync(this.cwd);
|
||||||
for (const preExistingFolderArg of preExistingFolders) {
|
for (const preExistingFolderArg of preExistingFolders) {
|
||||||
if (
|
if (
|
||||||
@@ -107,14 +123,18 @@ export class Meta {
|
|||||||
projectFolder.startsWith(preExistingFolderArg),
|
projectFolder.startsWith(preExistingFolderArg),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const response = await plugins.smartinteraction.SmartInteract.getCliConfirmation(
|
const response =
|
||||||
|
await plugins.smartinteraction.SmartInteract.getCliConfirmation(
|
||||||
`Do you want to delete superfluous directory >>${preExistingFolderArg}<< ?`,
|
`Do you want to delete superfluous directory >>${preExistingFolderArg}<< ?`,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (response) {
|
if (response) {
|
||||||
logger.log('warn', `Deleting >>${preExistingFolderArg}<<!`);
|
logger.log('warn', `Deleting >>${preExistingFolderArg}<<!`);
|
||||||
} else {
|
} else {
|
||||||
logger.log('warn', `Not deleting ${preExistingFolderArg} by request!`);
|
logger.log(
|
||||||
|
'warn',
|
||||||
|
`Not deleting ${preExistingFolderArg} by request!`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +180,9 @@ export class Meta {
|
|||||||
*/
|
*/
|
||||||
public async initProject() {
|
public async initProject() {
|
||||||
await this.syncToRemote(true);
|
await this.syncToRemote(true);
|
||||||
const fileExists = await plugins.smartfile.fs.fileExists(this.filePaths.metaJson);
|
const fileExists = await plugins.smartfile.fs.fileExists(
|
||||||
|
this.filePaths.metaJson,
|
||||||
|
);
|
||||||
if (!fileExists) {
|
if (!fileExists) {
|
||||||
await plugins.smartfile.memory.toFs(
|
await plugins.smartfile.memory.toFs(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -168,7 +190,10 @@ export class Meta {
|
|||||||
}),
|
}),
|
||||||
this.filePaths.metaJson,
|
this.filePaths.metaJson,
|
||||||
);
|
);
|
||||||
logger.log(`success`, `created a new .meta.json in directory ${this.cwd}`);
|
logger.log(
|
||||||
|
`success`,
|
||||||
|
`created a new .meta.json in directory ${this.cwd}`,
|
||||||
|
);
|
||||||
await plugins.smartfile.memory.toFs(
|
await plugins.smartfile.memory.toFs(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
name: this.dirName,
|
name: this.dirName,
|
||||||
@@ -176,9 +201,15 @@ export class Meta {
|
|||||||
}),
|
}),
|
||||||
this.filePaths.packageJson,
|
this.filePaths.packageJson,
|
||||||
);
|
);
|
||||||
logger.log(`success`, `created a new package.json in directory ${this.cwd}`);
|
logger.log(
|
||||||
|
`success`,
|
||||||
|
`created a new package.json in directory ${this.cwd}`,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.log(`error`, `directory ${this.cwd} already has a .metaJson file. Doing nothing.`);
|
logger.log(
|
||||||
|
`error`,
|
||||||
|
`directory ${this.cwd} already has a .metaJson file. Doing nothing.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
await this.smartshellInstance.exec(
|
await this.smartshellInstance.exec(
|
||||||
`cd ${this.cwd} && git add -A && git commit -m "feat(project): init meta project for ${this.dirName}"`,
|
`cd ${this.cwd} && git add -A && git commit -m "feat(project): init meta project for ${this.dirName}"`,
|
||||||
@@ -195,7 +226,9 @@ export class Meta {
|
|||||||
const existingProject = this.metaRepoData.projects[projectNameArg];
|
const existingProject = this.metaRepoData.projects[projectNameArg];
|
||||||
|
|
||||||
if (existingProject) {
|
if (existingProject) {
|
||||||
throw new Error('Project already exists! Please remove it first before adding it again.');
|
throw new Error(
|
||||||
|
'Project already exists! Please remove it first before adding it again.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.metaRepoData.projects[projectNameArg] = gitUrlArg;
|
this.metaRepoData.projects[projectNameArg] = gitUrlArg;
|
||||||
@@ -217,7 +250,10 @@ export class Meta {
|
|||||||
const existingProject = this.metaRepoData.projects[projectNameArg];
|
const existingProject = this.metaRepoData.projects[projectNameArg];
|
||||||
|
|
||||||
if (!existingProject) {
|
if (!existingProject) {
|
||||||
logger.log('error', `Project ${projectNameArg} does not exist! So it cannot be removed`);
|
logger.log(
|
||||||
|
'error',
|
||||||
|
`Project ${projectNameArg} does not exist! So it cannot be removed`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +264,9 @@ export class Meta {
|
|||||||
await this.writeToDisk();
|
await this.writeToDisk();
|
||||||
|
|
||||||
logger.log('info', 'removing directory from cwd');
|
logger.log('info', 'removing directory from cwd');
|
||||||
await plugins.smartfile.fs.remove(plugins.path.join(paths.cwd, projectNameArg));
|
await plugins.smartfile.fs.remove(
|
||||||
|
plugins.path.join(paths.cwd, projectNameArg),
|
||||||
|
);
|
||||||
await this.updateLocalRepos();
|
await this.updateLocalRepos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,9 @@ export let run = () => {
|
|||||||
* create a new project with 'gitzone template [template]'
|
* create a new project with 'gitzone template [template]'
|
||||||
the following templates exist: ${(() => {
|
the following templates exist: ${(() => {
|
||||||
let projects = `\n`;
|
let projects = `\n`;
|
||||||
for (const template of plugins.smartfile.fs.listFoldersSync(paths.templatesDir)) {
|
for (const template of plugins.smartfile.fs.listFoldersSync(
|
||||||
|
paths.templatesDir,
|
||||||
|
)) {
|
||||||
projects += ` - ${template}\n`;
|
projects += ` - ${template}\n`;
|
||||||
}
|
}
|
||||||
return projects;
|
return projects;
|
||||||
|
@@ -15,7 +15,9 @@ export const run = async (argvArg: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await smartshellInstance.execStrict(`cd ${paths.cwd} && git checkout master`);
|
await smartshellInstance.execStrict(`cd ${paths.cwd} && git checkout master`);
|
||||||
await smartshellInstance.execStrict(`cd ${paths.cwd} && git pull origin master`);
|
await smartshellInstance.execStrict(
|
||||||
|
`cd ${paths.cwd} && git pull origin master`,
|
||||||
|
);
|
||||||
await smartshellInstance.execStrict(`cd ${paths.cwd} && npm ci`);
|
await smartshellInstance.execStrict(`cd ${paths.cwd} && npm ci`);
|
||||||
|
|
||||||
await provideNoGitFiles();
|
await provideNoGitFiles();
|
||||||
|
@@ -16,7 +16,9 @@ export const isTemplate = async (templateNameArg: string) => {
|
|||||||
|
|
||||||
export const getTemplate = async (templateNameArg: string) => {
|
export const getTemplate = async (templateNameArg: string) => {
|
||||||
if (isTemplate(templateNameArg)) {
|
if (isTemplate(templateNameArg)) {
|
||||||
const localScafTemplate = new plugins.smartscaf.ScafTemplate(getTemplatePath(templateNameArg));
|
const localScafTemplate = new plugins.smartscaf.ScafTemplate(
|
||||||
|
getTemplatePath(templateNameArg),
|
||||||
|
);
|
||||||
await localScafTemplate.readTemplateFromDir();
|
await localScafTemplate.readTemplateFromDir();
|
||||||
return localScafTemplate;
|
return localScafTemplate;
|
||||||
} else {
|
} else {
|
||||||
@@ -32,7 +34,8 @@ export const run = async (argvArg: any) => {
|
|||||||
const answerBucket = await smartinteract.askQuestion({
|
const answerBucket = await smartinteract.askQuestion({
|
||||||
type: 'list',
|
type: 'list',
|
||||||
default: 'npm',
|
default: 'npm',
|
||||||
message: 'What template do you want to scaffold? (Only showing mpost common options)',
|
message:
|
||||||
|
'What template do you want to scaffold? (Only showing mpost common options)',
|
||||||
name: 'templateName',
|
name: 'templateName',
|
||||||
choices: ['npm', 'service', 'wcc', 'website'],
|
choices: ['npm', 'service', 'wcc', 'website'],
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,5 @@
|
|||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {}
|
"paths": {}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["dist_*/**/*.d.ts"]
|
||||||
"dist_*/**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user