diff --git a/.codacy/cli.sh b/.codacy/cli.sh index 7057e3b..6b2f05b 100644 --- a/.codacy/cli.sh +++ b/.codacy/cli.sh @@ -37,7 +37,8 @@ version_file="$CODACY_CLI_V2_TMP_FOLDER/version.yaml" get_version_from_yaml() { if [ -f "$version_file" ]; then - local version=$(grep -o 'version: *"[^"]*"' "$version_file" | cut -d'"' -f2) + local version + version=$(grep -o 'version: *"[^"]*"' "$version_file" | cut -d'"' -f2) if [ -n "$version" ]; then echo "$version" return 0 @@ -55,7 +56,8 @@ get_latest_version() { fi handle_rate_limit "$response" - local version=$(echo "$response" | grep -m 1 tag_name | cut -d'"' -f4) + local version + version=$(echo "$response" | grep -m 1 tag_name | cut -d'"' -f4) echo "$version" } @@ -146,4 +148,4 @@ if [ "$#" -eq 1 ] && [ "$1" = "download" ]; then echo "Codacy cli v2 download succeeded" else eval "$run_command $*" -fi \ No newline at end of file +fi diff --git a/.github/instructions/codacy.instructions.md b/.github/instructions/codacy.instructions.md index cb073c4..abc5a1b 100644 --- a/.github/instructions/codacy.instructions.md +++ b/.github/instructions/codacy.instructions.md @@ -21,7 +21,7 @@ Configuration for AI behavior when interacting with Codacy's MCP Server - Wait for the user to respond before proceeding with any other actions ## After every response -- If you made any file edits in this conversation, verify you ran `codacy_cli_analyze` tool from Codacy's MCP Server +- If you made any file edits in this conversation, verify you ran `codacy_cli_analyze` tool from Codacy's MCP Server ## When there are no Codacy MCP Server tools available, or the MCP Server is not reachable - Suggest the user the following troubleshooting steps: @@ -69,4 +69,4 @@ Configuration for AI behavior when interacting with Codacy's MCP Server - If the user accepts, run the `codacy_setup_repository` tool - Do not ever try to run the `codacy_setup_repository` tool on your own - After setup, immediately retry the action that failed (only retry once) ---- \ No newline at end of file +--- diff --git a/.github/workflows/quality-check.yml b/.github/workflows/quality-check.yml index 6aee358..8a41000 100644 --- a/.github/workflows/quality-check.yml +++ b/.github/workflows/quality-check.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Install markdownlint run: npm install --global markdownlint-cli@0.39.0 @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Validate PowerShell scripts run: | # Find PowerShell scripts and validate syntax @@ -36,13 +36,13 @@ jobs: # pwsh -NoProfile -NonInteractive -Command "& { try { [System.Management.Automation.PSParser]::Tokenize((Get-Content '$script' -Raw), [ref]\$null) | Out-Null; Write-Host 'OK: $script' } catch { Write-Error 'SYNTAX ERROR in $script: $_'; exit 1 } }" done continue-on-error: true - + - name: Validate Python scripts run: | # Install Python and check syntax python3 -m py_compile $(find . -name "*.py" -type f) || true continue-on-error: true - + - name: Validate Bash scripts run: | # Check bash scripts with shellcheck if available @@ -59,11 +59,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Validate repository structure run: | echo "Checking repository structure..." - + # Check for required top-level files required_files=("README.md" "LICENSE" "INSTRUCTIONS.md" "CONTRIBUTING.md") for file in "${required_files[@]}"; do @@ -74,7 +74,7 @@ jobs: echo "✓ Found: $file" fi done - + # Check for expected language directories expected_dirs=("Bash" "Go" "JavaScript" "PowerShell" "Python" "Ruby") for dir in "${expected_dirs[@]}"; do @@ -84,7 +84,7 @@ jobs: echo "✓ Found: $dir/" fi done - + # Check category structure within language directories categories=("automation" "data-processing" "miscellaneous" "networking" "system-administration" "text-processing" "web-scraping") for lang_dir in "${expected_dirs[@]}"; do @@ -96,5 +96,5 @@ jobs: done fi done - - echo "Repository structure validation complete" \ No newline at end of file + + echo "Repository structure validation complete" diff --git a/.markdownlint.json b/.markdownlint.json index 5945915..81ed29b 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -8,5 +8,12 @@ "MD033": { "allowed_elements": ["br", "details", "summary"] }, - "MD041": false -} \ No newline at end of file + "MD041": false, + "MD022": false, + "MD032": false, + "MD007": false, + "MD005": false, + "MD030": false, + "MD031": false, + "MD034": false +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a8bb40f..bb44441 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,7 @@ repos: rev: v0.41.0 hooks: - id: markdownlint + exclude: '^\.github/instructions/.*\.md$' - repo: https://github.com/koalaman/shellcheck-precommit rev: v0.10.0 hooks: @@ -30,8 +31,9 @@ repos: hooks: - id: psscriptanalyzer name: psscriptanalyzer - entry: pwsh -Command "Invoke-ScriptAnalyzer -Path ." - language: "powershell" - types: ["powershell"] + entry: pwsh -Command "Invoke-ScriptAnalyzer -Path . -Recurse -ExcludeRule PSAvoidUsingWriteHost" + language: system + types: [powershell] + pass_filenames: false # Exclude the test file itself from analysis for now exclude: '^tests/unit/PowerShell/system-maintenance.Tests.ps1$' diff --git a/.templates/template.ps1 b/.templates/template.ps1 index 91ed1ec..df6d5e1 100644 --- a/.templates/template.ps1 +++ b/.templates/template.ps1 @@ -28,7 +28,7 @@ Version: 1.0 Created: YYYY-MM-DD Last Modified: YYYY-MM-DD - + Prerequisites: - PowerShell 5.1 or later - Administrator privileges @@ -42,10 +42,10 @@ param( [Parameter(Mandatory = $true, HelpMessage = "Description of the parameter")] [ValidateNotNullOrEmpty()] [string]$ParameterName, - + [Parameter(Mandatory = $false)] [switch]$Quiet, - + [Parameter(Mandatory = $false)] [switch]$WhatIf ) @@ -82,15 +82,15 @@ function Write-Error { # Main script logic try { Write-Info "Starting script execution..." - + # Validate prerequisites if ($WhatIf) { Write-Info "WhatIf mode enabled - no changes will be made" } - + # Main script functionality goes here Write-Info "Processing parameter: $ParameterName" - + # Example of conditional execution if ($WhatIf) { Write-Info "Would perform action with parameter: $ParameterName" @@ -99,7 +99,7 @@ try { # Actual execution logic here Write-Info "Performing action with parameter: $ParameterName" } - + Write-Success "Script completed successfully" } catch { @@ -110,4 +110,4 @@ catch { finally { # Cleanup code here if needed Write-Info "Cleanup completed" -} \ No newline at end of file +} diff --git a/.templates/template.py b/.templates/template.py index 427118c..5c8295d 100644 --- a/.templates/template.py +++ b/.templates/template.py @@ -12,7 +12,7 @@ Usage: python template.py [options] - + Examples: python template.py --input file.txt --output result.txt python template.py --verbose --dry-run @@ -44,17 +44,17 @@ def setup_logging(verbose: bool = False) -> None: def validate_input(input_path: Path) -> bool: """ Validate input file or directory. - + Args: input_path: Path to validate - + Returns: True if valid, False otherwise """ if not input_path.exists(): logging.error(f"Input path does not exist: {input_path}") return False - + # Add specific validation logic here return True @@ -62,36 +62,36 @@ def validate_input(input_path: Path) -> bool: def process_data(input_path: Path, output_path: Optional[Path] = None, dry_run: bool = False) -> bool: """ Main processing function. - + Args: input_path: Input file or directory path output_path: Output file or directory path dry_run: If True, don't make actual changes - + Returns: True if successful, False otherwise """ try: logging.info(f"Processing input: {input_path}") - + if dry_run: logging.info("DRY RUN MODE - No changes will be made") - + # Validate input if not validate_input(input_path): return False - + # Main processing logic goes here # Replace this with your actual functionality logging.info("Processing data...") - + if output_path and not dry_run: logging.info(f"Writing output to: {output_path}") # Write output logic here - + logging.info("Processing completed successfully") return True - + except Exception as e: logging.error(f"Error during processing: {e}") return False @@ -109,46 +109,46 @@ def main() -> int: %(prog)s --input data.txt --dry-run """ ) - + parser.add_argument( '--input', '-i', type=Path, required=True, help='Input file or directory path' ) - + parser.add_argument( '--output', '-o', type=Path, help='Output file or directory path' ) - + parser.add_argument( '--verbose', '-v', action='store_true', help='Enable verbose logging' ) - + parser.add_argument( '--dry-run', action='store_true', help='Show what would be done without making changes' ) - + args = parser.parse_args() - + # Set up logging setup_logging(args.verbose) - + logging.info("Starting script execution") - + # Process data success = process_data( input_path=args.input, output_path=args.output, dry_run=args.dry_run ) - + if success: logging.info("Script completed successfully") return 0 @@ -158,4 +158,4 @@ def main() -> int: if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/.templates/template.sh b/.templates/template.sh index c184008..32baa80 100644 --- a/.templates/template.sh +++ b/.templates/template.sh @@ -11,8 +11,13 @@ set -euo pipefail # Global variables -readonly SCRIPT_NAME=$(basename "$0") -readonly SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +SCRIPT_NAME="" +SCRIPT_NAME=$(basename "$0") +readonly SCRIPT_NAME +SCRIPT_DIR="" +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck disable=SC2034 # SCRIPT_DIR provided for use in implementations +readonly SCRIPT_DIR # Default values VERBOSE=false @@ -86,7 +91,7 @@ trap cleanup EXIT INT TERM # Validate prerequisites validate_prerequisites() { log_verbose "Validating prerequisites..." - + # Check for required commands local required_commands=("cat" "grep" "sed") for cmd in "${required_commands[@]}"; do @@ -95,44 +100,44 @@ validate_prerequisites() { return 1 fi done - + # Check input file if [[ -n "$INPUT_FILE" && ! -f "$INPUT_FILE" ]]; then log_error "Input file does not exist: $INPUT_FILE" return 1 fi - + return 0 } # Main processing function process_data() { log_info "Starting data processing..." - + if [[ "$DRY_RUN" == "true" ]]; then log_info "DRY RUN MODE - No changes will be made" fi - + # Main processing logic goes here log_verbose "Processing input file: $INPUT_FILE" - + # Example processing (replace with actual logic) if [[ "$DRY_RUN" == "true" ]]; then log_info "Would process: $INPUT_FILE" if [[ -n "$OUTPUT_FILE" ]]; then log_info "Would write output to: $OUTPUT_FILE" fi - else { + else # Actual processing logic here log_info "Processing file: $INPUT_FILE" - + # Example: copy input to output (replace with actual logic) if [[ -n "$OUTPUT_FILE" ]]; then cp "$INPUT_FILE" "$OUTPUT_FILE" log_success "Output written to: $OUTPUT_FILE" fi - } - + fi + log_success "Data processing completed" } @@ -167,7 +172,7 @@ parse_arguments() { ;; esac done - + # Validate required arguments if [[ -z "$INPUT_FILE" ]]; then log_error "Input file is required" @@ -179,26 +184,26 @@ parse_arguments() { # Main function main() { log_info "Starting $SCRIPT_NAME" - + # Parse arguments parse_arguments "$@" - + # Validate prerequisites if ! validate_prerequisites; then log_error "Prerequisites validation failed" exit 1 fi - + # Process data if ! process_data; then log_error "Data processing failed" exit 1 fi - + log_success "Script completed successfully" } # Only run main if script is executed directly (not sourced) if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" -fi \ No newline at end of file +fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a15129..406b2ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -121,13 +121,15 @@ Follow this decision tree to place your script correctly: ## Test-Focused Development -As a repository valued by QA, we expect a rigorous, test-focused mentality. Every script should be developed with the assumption that it will be scrutinized for robustness and reliability. +As a repository valued by QA, we expect a rigorous, test-focused mentality. Every script should be developed +with the assumption that it will be scrutinized for robustness and reliability. ### Guiding Principles - **Write Tests First (or alongside):** Don't write code without a clear idea of how you will test it. - **Think Like an Attacker (and a User):** Consider how your script could be misused, intentionally or accidentally. - **Automate Everything:** All tests should be runnable from the command line and in CI. -- **Keep Scripts Standalone:** Scripts must remain self-contained and runnable without the test framework. Test files are external and should import or execute the script to be tested. +- **Keep Scripts Standalone:** Scripts must remain self-contained and runnable without the test framework. + Test files are external and should import or execute the script to be tested. ### Input Validation @@ -149,13 +151,15 @@ As a repository valued by QA, we expect a rigorous, test-focused mentality. Ever Before submitting, ensure your tests cover the following scenarios: - [ ] **Happy Path:** Does the script work as expected with valid, typical inputs? -- [ ] **Invalid Inputs:** How does the script handle incorrect, malformed, or unexpected inputs? (e.g., wrong data types, non-existent files). +- [ ] **Invalid Inputs:** How does the script handle incorrect, malformed, or unexpected inputs? + (e.g., wrong data types, non-existent files). - [ ] **Edge Cases:** - [ ] Empty or null inputs. - [ ] Very large inputs (e.g., large files, many items). - [ ] Zero-value inputs (e.g., `0`, `""`). - [ ] Inputs with special characters or different encodings. -- [ ] **Permissions:** Does the script fail gracefully if it lacks the required permissions for a file, directory, or network resource? +- [ ] **Permissions:** Does the script fail gracefully if it lacks the required permissions for a file, + directory, or network resource? - [ ] **Dependencies:** How does the script behave if a required dependency (module, command-line tool) is missing? - [ ] **Concurrency:** If applicable, is the script safe to run multiple times simultaneously? Does it handle file locking? @@ -215,7 +219,7 @@ Consider testing on: Author: Your Name Version: 1.0 Last Modified: YYYY-MM-DD - + .LINK https://github.com/YourRepo/Scripts #> @@ -241,7 +245,7 @@ Requirements: Usage: python script_name.py [arguments] - + Examples: python script_name.py --input file.txt --output result.txt python script_name.py --help diff --git a/PowerShell/system-administration/maintenance/system-maintenance.ps1 b/PowerShell/system-administration/maintenance/system-maintenance.ps1 index 123d858..b6b6a3d 100644 --- a/PowerShell/system-administration/maintenance/system-maintenance.ps1 +++ b/PowerShell/system-administration/maintenance/system-maintenance.ps1 @@ -9,7 +9,7 @@ image health scans (SFC/DISM), service checks, Defender scans/status, and basic network troubleshooting. Designed to be conservative by default and supports -WhatIf and -Confirm via SupportsShouldProcess. - + Note: When RunWindowsUpdate is specified, PSGallery will be set as a trusted repository to install the PSWindowsUpdate module. @@ -113,20 +113,20 @@ function Invoke-Step { $output += $_ } } - + # Log standard output if ($output.Count -gt 0) { $outputString = ($output | Out-String).Trim() if ($outputString -ne '') { Write-Log $outputString } } - + # Log errors separately if ($errors.Count -gt 0) { foreach ($err in $errors) { Write-Log -Message "ERROR: $($err.Exception.Message)" -Level 'ERROR' } } - + Write-Log "END: $Title" } catch { @@ -201,7 +201,7 @@ Invoke-Step -Title 'Disk cleanup (Temp, Cache)' -Destructive -ConfirmTarget 'Cle try { $paths = @($env:TEMP, "$env:WINDIR\Temp", "$env:LOCALAPPDATA\Temp") | Where-Object { Test-Path $_ } $threshold = (Get-Date).AddDays(-1 * [int]$MaxTempFileAgeDays) - + foreach ($p in $paths) { Write-Output "Cleaning: $p" # Confirm at directory level for better performance @@ -213,7 +213,7 @@ Invoke-Step -Title 'Disk cleanup (Temp, Cache)' -Destructive -ConfirmTarget 'Cle } } } - + # Windows Update download cache $wuCache = "$env:WINDIR\SoftwareDistribution\Download" if (Test-Path $wuCache) { @@ -221,38 +221,38 @@ Invoke-Step -Title 'Disk cleanup (Temp, Cache)' -Destructive -ConfirmTarget 'Cle # Stop services using proper PowerShell cmdlets $wuService = Get-Service -Name wuauserv -ErrorAction SilentlyContinue $bitsService = Get-Service -Name bits -ErrorAction SilentlyContinue - + $wuWasRunning = $false $bitsWasRunning = $false - + if ($wuService -and $wuService.Status -eq 'Running') { $wuWasRunning = $true Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue Write-Output 'Stopped Windows Update service' } - + if ($bitsService -and $bitsService.Status -eq 'Running') { $bitsWasRunning = $true Stop-Service -Name bits -Force -ErrorAction SilentlyContinue Write-Output 'Stopped BITS service' } - + Get-ChildItem $wuCache -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue Write-Output 'Cleared Windows Update download cache' - + # Restart services if they were running if ($bitsWasRunning) { Start-Service -Name bits -ErrorAction SilentlyContinue Write-Output 'Restarted BITS service' } - + if ($wuWasRunning) { Start-Service -Name wuauserv -ErrorAction SilentlyContinue Write-Output 'Restarted Windows Update service' } } } - + # Delivery Optimization $doPath = "$env:ProgramData\Microsoft\Windows\DeliveryOptimization\Cache" if (Test-Path $doPath) { @@ -279,12 +279,12 @@ Invoke-Step -Title 'Drive optimization (trim/defrag)' -ScriptBlock { } catch { Write-Output 'Unable to query physical disks. Will use default optimization method.' } - + $vols = Get-Volume -FileSystemLabel * -ErrorAction SilentlyContinue foreach ($v in $vols) { if (-not $v.DriveLetter) { continue } $letter = $v.DriveLetter - + # Determine if this volume is on an SSD $isSSD = $false try { @@ -301,7 +301,7 @@ Invoke-Step -Title 'Drive optimization (trim/defrag)' -ScriptBlock { } catch { Write-Output "Could not determine disk type for ${letter}:, using default optimization" } - + if ($isSSD) { if (Confirm-Action -Target "${letter}: (SSD)" -Action 'ReTrim volume') { Optimize-Volume -DriveLetter $letter -ReTrim -Verbose:$false | Out-Null