Passed
Push — master ( 0ddaf0...97ef82 )
by Darko
07:24
created

UpdateNNTmuxGit::hasUncommittedChanges()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace App\Console\Commands;
4
5
use Blacklight\Tmux;
6
use Illuminate\Console\Command;
7
use Illuminate\Support\Facades\File;
8
use Illuminate\Support\Facades\Process;
9
10
class UpdateNNTmuxGit extends Command
11
{
12
    /**
13
     * The name and signature of the console command.
14
     *
15
     * @var string
16
     */
17
    protected $signature = 'nntmux:git
18
                            {--branch= : Specific branch to checkout}
19
                            {--no-stash : Skip stashing local changes}
20
                            {--force : Force pull even if there are conflicts}';
21
22
    /**
23
     * The console command description.
24
     *
25
     * @var string
26
     */
27
    protected $description = 'Update NNTmux from git repository with improved error handling';
28
29
    /**
30
     * Create a new command instance.
31
     */
32
    public function __construct()
33
    {
34
        parent::__construct();
35
    }
36
37
    /**
38
     * Execute the console command.
39
     */
40
    public function handle(): int
41
    {
42
        try {
43
            $this->info('🔄 Starting git update process...');
44
45
            // Check if we're in a git repository
46
            if (!$this->isGitRepository()) {
47
                $this->error('Not in a git repository');
48
                return Command::FAILURE;
49
            }
50
51
            // Check for uncommitted changes
52
            if ($this->hasUncommittedChanges() && !$this->option('no-stash')) {
53
                $this->info('📦 Stashing local changes...');
54
                $this->stashChanges();
55
            }
56
57
            // Get current branch
58
            $currentBranch = $this->getCurrentBranch();
59
            $targetBranch = $this->option('branch') ?? $currentBranch;
60
61
            // Fetch latest changes
62
            $this->info('📡 Fetching latest changes...');
63
            $this->fetchChanges();
64
65
            // Check if update is needed
66
            if (!$this->option('force') && !$this->isUpdateNeeded($targetBranch)) {
67
                $this->info('✅ Already up-to-date');
68
                return Command::SUCCESS;
69
            }
70
71
            // Perform the update
72
            $this->info("🔄 Updating to latest $targetBranch...");
73
            $this->pullChanges($targetBranch);
74
75
            $this->info('✅ Git update completed successfully');
76
            return Command::SUCCESS;
77
78
        } catch (\Exception $e) {
79
            $this->error('❌ Git update failed: ' . $e->getMessage());
80
            return Command::FAILURE;
81
        }
82
    }
83
84
    /**
85
     * Check if current directory is a git repository
86
     */
87
    private function isGitRepository(): bool
88
    {
89
        return File::exists(base_path('.git'));
90
    }
91
92
    /**
93
     * Check if there are uncommitted changes
94
     */
95
    private function hasUncommittedChanges(): bool
96
    {
97
        $process = Process::run('git status --porcelain');
98
        return !empty(trim($process->output()));
99
    }
100
101
    /**
102
     * Stash uncommitted changes
103
     */
104
    private function stashChanges(): void
105
    {
106
        $process = Process::run('git stash push -m "Auto-stash before update on ' . now()->toDateTimeString() . '"');
107
108
        if (!$process->successful()) {
109
            throw new \Exception('Failed to stash changes: ' . $process->errorOutput());
110
        }
111
112
        $this->line('  ✓ Changes stashed successfully');
113
    }
114
115
    /**
116
     * Get current git branch
117
     */
118
    private function getCurrentBranch(): string
119
    {
120
        $process = Process::run('git branch --show-current');
121
122
        if (!$process->successful()) {
123
            throw new \Exception('Failed to get current branch: ' . $process->errorOutput());
124
        }
125
126
        return trim($process->output());
127
    }
128
129
    /**
130
     * Fetch latest changes from remote
131
     */
132
    private function fetchChanges(): void
133
    {
134
        $process = Process::timeout(300)->run('git fetch --prune');
135
136
        if (!$process->successful()) {
137
            throw new \Exception('Failed to fetch changes: ' . $process->errorOutput());
138
        }
139
    }
140
141
    /**
142
     * Check if update is needed
143
     */
144
    private function isUpdateNeeded(string $branch): bool
145
    {
146
        $process = Process::run("git rev-list HEAD...origin/$branch --count");
147
148
        if (!$process->successful()) {
149
            // If we can't check, assume update is needed
150
            return true;
151
        }
152
153
        return (int) trim($process->output()) > 0;
154
    }
155
156
    /**
157
     * Pull changes from remote
158
     */
159
    private function pullChanges(string $branch): void
160
    {
161
        $pullCommand = $this->option('force')
162
            ? "git reset --hard origin/$branch"
163
            : "git pull origin $branch";
164
165
        $process = Process::timeout(300)->run($pullCommand);
166
167
        if (!$process->successful()) {
168
            throw new \Exception('Failed to pull changes: ' . $process->errorOutput());
169
        }
170
171
        $this->line('  ✓ Changes pulled successfully');
172
    }
173
}
174