feat: Add Continuous Delivery system with auto-commit and file watcher

Automatically commit and push changes to GitHub with zero manual intervention.

Features:
- File watcher mode: Auto-detects changes in real-time
- Timer mode: Commits at regular intervals (default 5 minutes)
- Smart exclusions: Ignores temp files, sessions, cache, db files
- Retry logic: Auto-retries failed pushes
- Change summaries: Detailed commit messages with file lists

Components:
- auto-deploy.ps1: Core CD engine with file watcher
- start-cd.ps1: Easy-to-use wrapper with commands
- .cd-config.json: Configuration file
- CONTINUOUS_DELIVERY_GUIDE.md: Complete documentation

Usage:
  .\start-cd.ps1 watch    # Start file watcher (recommended)
  .\start-cd.ps1 start    # Timer mode (every 5 min)
  .\start-cd.ps1 once     # One-time commit

Also removed db_data/ from git tracking (now in .gitignore).
Database runtime files should never be committed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SamiAhmed7777
2025-10-26 02:07:57 -07:00
parent d22b3e1c0d
commit 877b9347b6
207 changed files with 980 additions and 3658 deletions

18
.cd-config.json Normal file
View File

@@ -0,0 +1,18 @@
{
"intervalSeconds": 300,
"branch": "dev",
"commitPrefix": "auto:",
"excludePatterns": [
"f_data/data_sessions/*",
"f_data/data_cache/_c_tpl/*",
".setup_complete",
"*.log",
"db_data/*",
"node_modules/*",
"vendor/*",
".git/*",
".vscode/*"
],
"enableNotifications": true,
"autoStart": false
}

17
.gitignore vendored
View File

@@ -1,6 +1,23 @@
# Exclude temporary session files # Exclude temporary session files
f_data/data_sessions/sess_* f_data/data_sessions/sess_*
# Exclude cache files # Exclude cache files
f_data/data_cache/_c_tpl/* f_data/data_cache/_c_tpl/*
# Keep setup complete marker out of repo # Keep setup complete marker out of repo
.setup_complete .setup_complete
# Database runtime files (never commit these!)
db_data/
# Logs
*.log
*.log.*
# Dependencies
node_modules/
vendor/
# IDE
.vscode/
.idea/

View File

@@ -0,0 +1,428 @@
# EasyStream Continuous Delivery Guide
Automatically commit and push your changes to GitHub with zero manual intervention.
## Features
- **File Watcher Mode**: Detects file changes in real-time and auto-commits after 30 seconds of inactivity
- **Timer Mode**: Commits and pushes at regular intervals (default: 5 minutes)
- **Smart Exclusions**: Automatically excludes temporary files, sessions, cache, and database files
- **Retry Logic**: Automatically retries failed pushes with exponential backoff
- **Change Summaries**: Generates detailed commit messages with file change lists
- **Zero Configuration**: Works out of the box with sensible defaults
## Quick Start
### Option 1: File Watcher Mode (Recommended)
This mode monitors your files and automatically commits changes 30 seconds after you stop editing:
```powershell
.\start-cd.ps1 watch
```
You'll see:
```
========================================
EasyStream File Watcher Started
========================================
Watching: E:\repos\easystream-main
Branch: dev
Debounce: 30 seconds after last change
========================================
✓ File watcher active. Monitoring for changes...
```
When you save a file:
```
[14:23:45] Changed: setup.php
[14:23:47] Changed: f_core/config.href.php
[14:23:50] Changed: docker-compose.yml
Debounce period elapsed. Processing 3 changes...
Found 3 changed files
✓ Committed changes
✓ Successfully pushed to GitHub
```
### Option 2: Timer Mode
Commits and pushes at regular intervals (every 5 minutes by default):
```powershell
.\start-cd.ps1 start
```
Change the interval to 1 minute:
```powershell
.\start-cd.ps1 start -Interval 60
```
### Option 3: One-Time Commit
Manually trigger a single commit and push:
```powershell
.\start-cd.ps1 once
```
## Configuration
Edit [.cd-config.json](.cd-config.json) to customize behavior:
```json
{
"intervalSeconds": 300,
"branch": "dev",
"commitPrefix": "auto:",
"excludePatterns": [
"f_data/data_sessions/*",
"f_data/data_cache/_c_tpl/*",
".setup_complete",
"*.log",
"db_data/*",
"node_modules/*",
"vendor/*"
],
"enableNotifications": true,
"autoStart": false
}
```
### Configuration Options
| Option | Description | Default |
|--------|-------------|---------|
| `intervalSeconds` | Time between auto-commits (timer mode) | 300 (5 min) |
| `branch` | Git branch to push to | "dev" |
| `commitPrefix` | Prefix for auto-generated commit messages | "auto:" |
| `excludePatterns` | File patterns to ignore | See above |
| `enableNotifications` | Show Windows notifications (future) | true |
| `autoStart` | Start CD on system boot (future) | false |
## Commands Reference
### start-cd.ps1 Commands
```powershell
# Start file watcher mode
.\start-cd.ps1 watch
# Start timer mode (default interval: 5 minutes)
.\start-cd.ps1 start
# Start timer mode with custom interval (60 seconds)
.\start-cd.ps1 start -Interval 60
# Run one-time commit and push
.\start-cd.ps1 once
# Check git status
.\start-cd.ps1 status
# Stop all running CD processes
.\start-cd.ps1 stop
# Show help
.\start-cd.ps1 help
```
### auto-deploy.ps1 Advanced Usage
Direct script usage for advanced scenarios:
```powershell
# File watcher mode with verbose output
.\auto-deploy.ps1 -WatchMode -Verbose
# Timer mode with custom interval and branch
.\auto-deploy.ps1 -IntervalSeconds 120 -Branch main -Verbose
# Custom commit prefix
.\auto-deploy.ps1 -CommitPrefix "wip:" -IntervalSeconds 60
```
## How It Works
### File Watcher Mode
1. **Monitors**: Watches all files in the repository using .NET FileSystemWatcher
2. **Debounces**: Waits 30 seconds after the last file change to avoid committing partial edits
3. **Excludes**: Filters out temporary files based on `.gitignore` and config patterns
4. **Commits**: Stages all changes and creates a commit with file change summary
5. **Pushes**: Uploads to GitHub with retry logic
6. **Repeats**: Continues monitoring for the next change
### Timer Mode
1. **Checks**: Scans for changes at regular intervals
2. **Stages**: Adds all modified, new, and deleted files
3. **Commits**: Creates a timestamped commit with change summary
4. **Pushes**: Uploads to GitHub if there are new commits
5. **Waits**: Sleeps for the configured interval before next check
## Commit Message Format
Auto-generated commits include:
```
auto: Update at 2025-10-26 14:30:00
Changed files:
- setup.php
- docker-compose.yml
- f_core/config.href.php
- ... and 5 more files
🤖 Generated with Claude Code Continuous Delivery
Co-Authored-By: Claude <noreply@anthropic.com>
```
## Excluded Files
The following files are automatically excluded from commits:
- Session files: `f_data/data_sessions/sess_*`
- Cache files: `f_data/data_cache/_c_tpl/*`
- Setup marker: `.setup_complete`
- Database files: `db_data/*`
- Log files: `*.log`
- Dependencies: `node_modules/*`, `vendor/*`
- IDE files: `.vscode/*`, `.idea/*`
## Troubleshooting
### CD not detecting changes
**Problem**: Files changed but no commit triggered
**Solution**:
```powershell
# Check if files are excluded
git status
# Verify .gitignore doesn't over-exclude
cat .gitignore
# Check CD config
cat .cd-config.json
```
### Push failed: Authentication required
**Problem**: Git asks for credentials
**Solution**:
```powershell
# Set up Git credential helper (Windows)
git config --global credential.helper manager
# Or use SSH keys
git remote set-url origin git@github.com:SamiAhmed7777/easystream-main.git
```
### Multiple CD processes running
**Problem**: CD commits too frequently
**Solution**:
```powershell
# Stop all CD processes
.\start-cd.ps1 stop
# Restart with single instance
.\start-cd.ps1 watch
```
### Large files rejected by GitHub
**Problem**: `db_data/*` files are too large
**Solution**:
These files are already excluded in `.gitignore`. If they're already tracked:
```powershell
# Remove from git but keep locally
git rm --cached -r db_data/
git commit -m "Remove database files from tracking"
git push
```
## Running as Background Service
### Option 1: Windows Task Scheduler
1. Open Task Scheduler
2. Create Basic Task
3. Trigger: At system startup
4. Action: Start a program
- Program: `powershell.exe`
- Arguments: `-WindowStyle Hidden -File "E:\repos\easystream-main\start-cd.ps1" watch`
### Option 2: PowerShell Background Job
```powershell
# Start in background
Start-Job -ScriptBlock {
Set-Location "E:\repos\easystream-main"
.\start-cd.ps1 watch
}
# Check status
Get-Job
# View output
Receive-Job -Id 1 -Keep
# Stop
Stop-Job -Id 1
Remove-Job -Id 1
```
### Option 3: Screen/Tmux (Windows Terminal)
```powershell
# Open new Windows Terminal tab
wt -w 0 nt -d E:\repos\easystream-main powershell -NoExit -Command ".\start-cd.ps1 watch"
```
## Security Considerations
### What Gets Committed
- Application code (PHP, JavaScript, CSS)
- Configuration files (docker-compose.yml, .env templates)
- Documentation (Markdown files)
- SQL schema files
### What's Excluded
- Session data (user sessions)
- Cache (compiled templates)
- Database runtime files (actual data)
- Secrets (`.env` files are tracked but should only contain templates)
### Best Practices
1. **Review `.gitignore`**: Ensure sensitive files are excluded
2. **Use environment variables**: Never commit actual passwords or API keys
3. **Separate repos for secrets**: Use a private repo for production `.env` files
4. **Monitor commits**: Occasionally review auto-commits for unwanted files
## Performance Tips
### For Large Repositories
```json
{
"intervalSeconds": 600,
"excludePatterns": [
"f_data/*",
"uploads/*",
"*.mp4",
"*.mkv"
]
}
```
### For Active Development
```json
{
"intervalSeconds": 180,
"commitPrefix": "wip:"
}
```
## Integration with IDE
### VS Code
Add to `.vscode/tasks.json`:
```json
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Continuous Delivery",
"type": "shell",
"command": ".\\start-cd.ps1 watch",
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": []
}
]
}
```
Run with: `Ctrl+Shift+P``Tasks: Run Task``Start Continuous Delivery`
## FAQ
**Q: Will this commit every keystroke?**
A: No. File watcher mode waits 30 seconds after the last change before committing.
**Q: Can I customize commit messages?**
A: Yes, edit the commit message generation in [auto-deploy.ps1:176-188](auto-deploy.ps1#L176-L188)
**Q: Does this work with pull requests?**
A: Yes, but you may want to squash auto-commits before merging. Consider using a feature branch.
**Q: Can I run this on Linux/Mac?**
A: The scripts are PowerShell-specific. For Linux/Mac, use Git hooks or tools like `watchman` + bash scripts.
**Q: Will this conflict with manual commits?**
A: No. The CD system checks for changes and only commits if there are uncommitted files.
**Q: How do I temporarily pause CD?**
A: Press `Ctrl+C` in the CD terminal, or run `.\start-cd.ps1 stop`
## Examples
### Development Workflow
```powershell
# Morning: Start CD
.\start-cd.ps1 watch
# Work normally - changes auto-commit as you save
# End of day: Review commits
git log --oneline --since="8 hours ago"
# Squash if needed before PR
git rebase -i HEAD~20
```
### Emergency Hotfix
```powershell
# Stop CD
.\start-cd.ps1 stop
# Make critical fix
# ... edit files ...
# Manual commit with detailed message
git add .
git commit -m "fix: Critical security patch for XSS vulnerability"
git push
# Resume CD
.\start-cd.ps1 watch
```
## Support
For issues or questions:
- GitHub Issues: https://github.com/SamiAhmed7777/easystream-main/issues
- Check logs in terminal output
- Use `-Verbose` flag for detailed diagnostics
---
**Next Steps**: [Start using CD now!](#quick-start)

362
auto-deploy.ps1 Normal file
View File

@@ -0,0 +1,362 @@
# Continuous Delivery Script for EasyStream
# Automatically commits and pushes changes to GitHub
param(
[int]$IntervalSeconds = 300, # Default: 5 minutes
[string]$Branch = "dev",
[string]$CommitPrefix = "auto:",
[switch]$WatchMode,
[switch]$Verbose
)
$ErrorActionPreference = "Continue"
$RepoPath = $PSScriptRoot
# Color output functions
function Write-Success { param($msg) Write-Host "$msg" -ForegroundColor Green }
function Write-Info { param($msg) Write-Host " $msg" -ForegroundColor Cyan }
function Write-Warning { param($msg) Write-Host "$msg" -ForegroundColor Yellow }
function Write-Error { param($msg) Write-Host "$msg" -ForegroundColor Red }
# Load configuration
$configPath = Join-Path $RepoPath ".cd-config.json"
if (Test-Path $configPath) {
$config = Get-Content $configPath | ConvertFrom-Json
if ($config.intervalSeconds) { $IntervalSeconds = $config.intervalSeconds }
if ($config.branch) { $Branch = $config.branch }
if ($config.commitPrefix) { $CommitPrefix = $config.commitPrefix }
if ($config.excludePatterns) { $excludePatterns = $config.excludePatterns }
} else {
$excludePatterns = @(
"f_data/data_sessions/*",
"f_data/data_cache/_c_tpl/*",
".setup_complete",
"*.log",
"db_data/*",
"node_modules/*",
"vendor/*"
)
}
function Test-GitRepo {
Push-Location $RepoPath
try {
$null = git rev-parse --git-dir 2>&1
return $?
} finally {
Pop-Location
}
}
function Get-GitStatus {
Push-Location $RepoPath
try {
$status = git status --porcelain 2>&1
return $status
} finally {
Pop-Location
}
}
function Get-ChangeSummary {
Push-Location $RepoPath
try {
$modified = @(git diff --name-only).Count
$staged = @(git diff --cached --name-only).Count
$untracked = @(git ls-files --others --exclude-standard).Count
return @{
Modified = $modified
Staged = $staged
Untracked = $untracked
Total = $modified + $staged + $untracked
}
} finally {
Pop-Location
}
}
function Update-GitIgnore {
$gitignorePath = Join-Path $RepoPath ".gitignore"
$ignoreContent = @"
# Temporary session files
f_data/data_sessions/sess_*
# Cache files
f_data/data_cache/_c_tpl/*
# Setup marker
.setup_complete
# Database runtime files
db_data/*
# Logs
*.log
# Dependencies
node_modules/
vendor/
# IDE
.vscode/
.idea/
"@
if (-not (Test-Path $gitignorePath)) {
$ignoreContent | Out-File -FilePath $gitignorePath -Encoding UTF8
Write-Success "Created .gitignore"
} else {
# Append if patterns are missing
$existing = Get-Content $gitignorePath -Raw
if ($existing -notmatch "f_data/data_sessions/sess_\*") {
"`n# Auto-generated exclusions`n$ignoreContent" | Add-Content -Path $gitignorePath
Write-Success "Updated .gitignore"
}
}
}
function Invoke-AutoCommit {
param([string]$message)
Push-Location $RepoPath
try {
Write-Info "Checking for changes..."
$changes = Get-ChangeSummary
if ($changes.Total -eq 0) {
if ($Verbose) { Write-Info "No changes detected" }
return $false
}
Write-Info "Found $($changes.Total) changed files (Modified: $($changes.Modified), Staged: $($changes.Staged), Untracked: $($changes.Untracked))"
# Stage all changes
Write-Info "Staging changes..."
git add -A 2>&1 | Out-Null
# Generate commit message if not provided
if (-not $message) {
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$message = "${CommitPrefix} Update at $timestamp"
# Add file change summary
$fileList = @(git diff --cached --name-only | Select-Object -First 5)
if ($fileList.Count -gt 0) {
$message += "`n`nChanged files:"
foreach ($file in $fileList) {
$message += "`n- $file"
}
if ($changes.Total -gt 5) {
$message += "`n- ... and $($changes.Total - 5) more files"
}
}
$message += "`n`n🤖 Generated with Claude Code Continuous Delivery`n`nCo-Authored-By: Claude <noreply@anthropic.com>"
}
# Create commit
Write-Info "Creating commit..."
$commitResult = git commit -m $message 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Success "Committed changes"
return $true
} else {
Write-Warning "Commit failed or nothing to commit"
if ($Verbose) { Write-Host $commitResult }
return $false
}
} finally {
Pop-Location
}
}
function Invoke-AutoPush {
Push-Location $RepoPath
try {
Write-Info "Pushing to origin/$Branch..."
# Check if we're ahead of remote
$ahead = git rev-list --count "origin/$Branch..$Branch" 2>&1
if ($ahead -match "^\d+$" -and [int]$ahead -gt 0) {
Write-Info "Local is $ahead commit(s) ahead of remote"
# Push with retry logic
$maxRetries = 3
$retryCount = 0
while ($retryCount -lt $maxRetries) {
$pushResult = git push origin $Branch 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Success "Successfully pushed to GitHub"
return $true
} else {
$retryCount++
Write-Warning "Push attempt $retryCount failed"
if ($Verbose) { Write-Host $pushResult }
if ($retryCount -lt $maxRetries) {
Write-Info "Retrying in 5 seconds..."
Start-Sleep -Seconds 5
}
}
}
Write-Error "Failed to push after $maxRetries attempts"
return $false
} else {
if ($Verbose) { Write-Info "Already up to date with remote" }
return $false
}
} finally {
Pop-Location
}
}
function Start-ContinuousDelivery {
Write-Info "========================================="
Write-Info "EasyStream Continuous Delivery Started"
Write-Info "========================================="
Write-Info "Repository: $RepoPath"
Write-Info "Branch: $Branch"
Write-Info "Interval: $IntervalSeconds seconds"
Write-Info "========================================="
Write-Info ""
# Verify git repository
if (-not (Test-GitRepo)) {
Write-Error "Not a git repository: $RepoPath"
exit 1
}
# Update .gitignore
Update-GitIgnore
$iteration = 0
while ($true) {
$iteration++
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "`n[$timestamp] Check #$iteration" -ForegroundColor Magenta
try {
# Commit changes
$committed = Invoke-AutoCommit
# Push if there was a commit
if ($committed) {
Start-Sleep -Seconds 2
Invoke-AutoPush
}
# Wait for next interval
Write-Info "Next check in $IntervalSeconds seconds... (Press Ctrl+C to stop)"
Start-Sleep -Seconds $IntervalSeconds
} catch {
Write-Error "Error during CD cycle: $_"
Write-Info "Continuing in 30 seconds..."
Start-Sleep -Seconds 30
}
}
}
function Start-FileWatcher {
Write-Info "========================================="
Write-Info "EasyStream File Watcher Started"
Write-Info "========================================="
Write-Info "Watching: $RepoPath"
Write-Info "Branch: $Branch"
Write-Info "Debounce: 30 seconds after last change"
Write-Info "========================================="
Write-Info ""
# Verify git repository
if (-not (Test-GitRepo)) {
Write-Error "Not a git repository: $RepoPath"
exit 1
}
# Update .gitignore
Update-GitIgnore
# Create file system watcher
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $RepoPath
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
# Exclude patterns
$watcher.Filter = "*.*"
$watcher.NotifyFilter = [System.IO.NotifyFilters]::FileName -bor
[System.IO.NotifyFilters]::DirectoryName -bor
[System.IO.NotifyFilters]::LastWrite
$global:lastChangeTime = Get-Date
$global:changedFiles = @{}
$onChange = {
param($sender, $e)
# Skip excluded patterns
$relativePath = $e.FullPath.Replace($RepoPath, "").TrimStart('\', '/')
$exclude = $false
foreach ($pattern in $excludePatterns) {
if ($relativePath -like $pattern) {
$exclude = $true
break
}
}
if (-not $exclude) {
$global:lastChangeTime = Get-Date
$global:changedFiles[$e.FullPath] = $e.ChangeType
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] " -NoNewline -ForegroundColor Gray
Write-Host "$($e.ChangeType): " -NoNewline -ForegroundColor Yellow
Write-Host $relativePath -ForegroundColor White
}
}
# Register events
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $onChange | Out-Null
Register-ObjectEvent -InputObject $watcher -EventName Created -Action $onChange | Out-Null
Register-ObjectEvent -InputObject $watcher -EventName Deleted -Action $onChange | Out-Null
Register-ObjectEvent -InputObject $watcher -EventName Renamed -Action $onChange | Out-Null
Write-Success "File watcher active. Monitoring for changes..."
Write-Info "Changes will auto-commit 30 seconds after last modification"
Write-Info ""
try {
while ($true) {
Start-Sleep -Seconds 5
# Check if enough time has passed since last change
$timeSinceLastChange = (Get-Date) - $global:lastChangeTime
if ($global:changedFiles.Count -gt 0 -and $timeSinceLastChange.TotalSeconds -ge 30) {
Write-Info "`nDebounce period elapsed. Processing $($global:changedFiles.Count) changes..."
$committed = Invoke-AutoCommit
if ($committed) {
Start-Sleep -Seconds 2
Invoke-AutoPush
}
# Reset
$global:changedFiles = @{}
Write-Info "`nContinuing to watch for changes...`n"
}
}
} finally {
$watcher.Dispose()
Get-EventSubscriber | Unregister-Event
}
}
# Main execution
if ($WatchMode) {
Start-FileWatcher
} else {
Start-ContinuousDelivery
}

View File

@@ -1,6 +0,0 @@
[mariadb-client]
port=3306
socket=/run/mysqld/mysqld.sock
user=healthcheck
password=/dG+QV8:N6Kzmww>pXRbf(<8))b`L_wn

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,2 +0,0 @@
default-character-set=utf8mb4
default-collation=utf8mb4_general_ci

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,16 +0,0 @@
TYPE=VIEW
query=select `mysql`.`global_priv`.`Host` AS `Host`,`mysql`.`global_priv`.`User` AS `User`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\') in (\'mysql_native_password\',\'mysql_old_password\'),ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\'),\'\') AS `Password`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1,\'Y\',\'N\') AS `Select_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2,\'Y\',\'N\') AS `Insert_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4,\'Y\',\'N\') AS `Update_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8,\'Y\',\'N\') AS `Delete_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16,\'Y\',\'N\') AS `Create_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32,\'Y\',\'N\') AS `Drop_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 64,\'Y\',\'N\') AS `Reload_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 128,\'Y\',\'N\') AS `Shutdown_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 256,\'Y\',\'N\') AS `Process_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 512,\'Y\',\'N\') AS `File_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1024,\'Y\',\'N\') AS `Grant_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2048,\'Y\',\'N\') AS `References_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4096,\'Y\',\'N\') AS `Index_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8192,\'Y\',\'N\') AS `Alter_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16384,\'Y\',\'N\') AS `Show_db_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32768,\'Y\',\'N\') AS `Super_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 65536,\'Y\',\'N\') AS `Create_tmp_table_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 131072,\'Y\',\'N\') AS `Lock_tables_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 262144,\'Y\',\'N\') AS `Execute_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 524288,\'Y\',\'N\') AS `Repl_slave_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1048576,\'Y\',\'N\') AS `Repl_client_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2097152,\'Y\',\'N\') AS `Create_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4194304,\'Y\',\'N\') AS `Show_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8388608,\'Y\',\'N\') AS `Create_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16777216,\'Y\',\'N\') AS `Alter_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 33554432,\'Y\',\'N\') AS `Create_user_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 67108864,\'Y\',\'N\') AS `Event_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 134217728,\'Y\',\'N\') AS `Trigger_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 268435456,\'Y\',\'N\') AS `Create_tablespace_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 536870912,\'Y\',\'N\') AS `Delete_history_priv`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_type\'),0) + 1,\'\',\'ANY\',\'X509\',\'SPECIFIED\') AS `ssl_type`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_cipher\'),\'\') AS `ssl_cipher`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_issuer\'),\'\') AS `x509_issuer`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_subject\'),\'\') AS `x509_subject`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_questions\'),0) as unsigned) AS `max_questions`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_updates\'),0) as unsigned) AS `max_updates`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_connections\'),0) as unsigned) AS `max_connections`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_user_connections\'),0) as signed) AS `max_user_connections`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\'),\'\') AS `plugin`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\') AS `authentication_string`,if(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.password_last_changed\'),1) = 0,\'Y\',\'N\') AS `password_expired`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.is_role\'),0) + 1,\'N\',\'Y\') AS `is_role`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.default_role\'),\'\') AS `default_role`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_statement_time\'),0.0) as decimal(12,6)) AS `max_statement_time` from `mysql`.`global_priv`
md5=9e8063501afc8396f55d7c723632d5d8
updatable=1
algorithm=0
definer_user=mariadb.sys
definer_host=localhost
suid=1
with_check_option=0
timestamp=0001760433290176447
create-version=2
source=SELECT\n Host,\n User,\n IF(JSON_VALUE(Priv, \'$.plugin\') IN (\'mysql_native_password\', \'mysql_old_password\'), IFNULL(JSON_VALUE(Priv, \'$.authentication_string\'), \'\'), \'\') AS Password,\n IF(JSON_VALUE(Priv, \'$.access\') & 1, \'Y\', \'N\') AS Select_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 2, \'Y\', \'N\') AS Insert_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 4, \'Y\', \'N\') AS Update_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 8, \'Y\', \'N\') AS Delete_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 16, \'Y\', \'N\') AS Create_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 32, \'Y\', \'N\') AS Drop_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 64, \'Y\', \'N\') AS Reload_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 128, \'Y\', \'N\') AS Shutdown_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 256, \'Y\', \'N\') AS Process_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 512, \'Y\', \'N\') AS File_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 1024, \'Y\', \'N\') AS Grant_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 2048, \'Y\', \'N\') AS References_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 4096, \'Y\', \'N\') AS Index_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 8192, \'Y\', \'N\') AS Alter_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 16384, \'Y\', \'N\') AS Show_db_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 32768, \'Y\', \'N\') AS Super_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 65536, \'Y\', \'N\') AS Create_tmp_table_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 131072, \'Y\', \'N\') AS Lock_tables_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 262144, \'Y\', \'N\') AS Execute_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 524288, \'Y\', \'N\') AS Repl_slave_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 1048576, \'Y\', \'N\') AS Repl_client_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 2097152, \'Y\', \'N\') AS Create_view_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 4194304, \'Y\', \'N\') AS Show_view_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 8388608, \'Y\', \'N\') AS Create_routine_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 16777216, \'Y\', \'N\') AS Alter_routine_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 33554432, \'Y\', \'N\') AS Create_user_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 67108864, \'Y\', \'N\') AS Event_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 134217728, \'Y\', \'N\') AS Trigger_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 268435456, \'Y\', \'N\') AS Create_tablespace_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 536870912, \'Y\', \'N\') AS Delete_history_priv,\n ELT(IFNULL(JSON_VALUE(Priv, \'$.ssl_type\'), 0) + 1, \'\', \'ANY\',\'X509\', \'SPECIFIED\') AS ssl_type,\n IFNULL(JSON_VALUE(Priv, \'$.ssl_cipher\'), \'\') AS ssl_cipher,\n IFNULL(JSON_VALUE(Priv, \'$.x509_issuer\'), \'\') AS x509_issuer,\n IFNULL(JSON_VALUE(Priv, \'$.x509_subject\'), \'\') AS x509_subject,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_questions\'), 0) AS UNSIGNED) AS max_questions,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_updates\'), 0) AS UNSIGNED) AS max_updates,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_connections\'), 0) AS UNSIGNED) AS max_connections,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_user_connections\'), 0) AS SIGNED) AS max_user_connections,\n IFNULL(JSON_VALUE(Priv, \'$.plugin\'), \'\') AS plugin,\n IFNULL(JSON_VALUE(Priv, \'$.authentication_string\'), \'\') AS authentication_string,\n IF(IFNULL(JSON_VALUE(Priv, \'$.password_last_changed\'), 1) = 0, \'Y\', \'N\') AS password_expired,\n ELT(IFNULL(JSON_VALUE(Priv, \'$.is_role\'), 0) + 1, \'N\', \'Y\') AS is_role,\n IFNULL(JSON_VALUE(Priv, \'$.default_role\'), \'\') AS default_role,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_statement_time\'), 0.0) AS DECIMAL(12,6)) AS max_statement_time\n FROM global_priv;
client_cs_name=utf8mb4
connection_cl_name=utf8mb4_general_ci
view_body_utf8=select `mysql`.`global_priv`.`Host` AS `Host`,`mysql`.`global_priv`.`User` AS `User`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\') in (\'mysql_native_password\',\'mysql_old_password\'),ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\'),\'\') AS `Password`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1,\'Y\',\'N\') AS `Select_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2,\'Y\',\'N\') AS `Insert_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4,\'Y\',\'N\') AS `Update_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8,\'Y\',\'N\') AS `Delete_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16,\'Y\',\'N\') AS `Create_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32,\'Y\',\'N\') AS `Drop_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 64,\'Y\',\'N\') AS `Reload_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 128,\'Y\',\'N\') AS `Shutdown_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 256,\'Y\',\'N\') AS `Process_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 512,\'Y\',\'N\') AS `File_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1024,\'Y\',\'N\') AS `Grant_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2048,\'Y\',\'N\') AS `References_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4096,\'Y\',\'N\') AS `Index_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8192,\'Y\',\'N\') AS `Alter_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16384,\'Y\',\'N\') AS `Show_db_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32768,\'Y\',\'N\') AS `Super_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 65536,\'Y\',\'N\') AS `Create_tmp_table_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 131072,\'Y\',\'N\') AS `Lock_tables_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 262144,\'Y\',\'N\') AS `Execute_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 524288,\'Y\',\'N\') AS `Repl_slave_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1048576,\'Y\',\'N\') AS `Repl_client_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2097152,\'Y\',\'N\') AS `Create_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4194304,\'Y\',\'N\') AS `Show_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8388608,\'Y\',\'N\') AS `Create_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16777216,\'Y\',\'N\') AS `Alter_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 33554432,\'Y\',\'N\') AS `Create_user_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 67108864,\'Y\',\'N\') AS `Event_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 134217728,\'Y\',\'N\') AS `Trigger_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 268435456,\'Y\',\'N\') AS `Create_tablespace_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 536870912,\'Y\',\'N\') AS `Delete_history_priv`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_type\'),0) + 1,\'\',\'ANY\',\'X509\',\'SPECIFIED\') AS `ssl_type`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_cipher\'),\'\') AS `ssl_cipher`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_issuer\'),\'\') AS `x509_issuer`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_subject\'),\'\') AS `x509_subject`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_questions\'),0) as unsigned) AS `max_questions`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_updates\'),0) as unsigned) AS `max_updates`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_connections\'),0) as unsigned) AS `max_connections`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_user_connections\'),0) as signed) AS `max_user_connections`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\'),\'\') AS `plugin`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\') AS `authentication_string`,if(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.password_last_changed\'),1) = 0,\'Y\',\'N\') AS `password_expired`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.is_role\'),0) + 1,\'N\',\'Y\') AS `is_role`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.default_role\'),\'\') AS `default_role`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_statement_time\'),0.0) as decimal(12,6)) AS `max_statement_time` from `mysql`.`global_priv`
mariadb-version=100623

Some files were not shown because too many files have changed in this diff Show More