@babajide234/git-merge-workflow 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,42 @@
1
- @{
2
- RootModule = 'GitMergeWorkflow.psm1'
3
- ModuleVersion = '1.0.1'
4
- GUID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
5
- Author = 'babajide Tomoshegbo'
6
- CompanyName = 'babajide234'
7
- Copyright = '(c) 2025 Expedier. All rights reserved.'
8
- Description = 'Automated Git workflow for merging feature branches through staging to develop'
9
- PowerShellVersion = '5.1'
10
- FunctionsToExport = @('Invoke-GitMergeWorkflow', 'New-GitWorkflowConfig', 'Get-GitWorkflowConfig')
11
- AliasesToExport = @('git-merge-workflow', 'gmw')
12
- PrivateData = @{
13
- PSData = @{
14
- Tags = @('Git', 'Workflow', 'Automation', 'Merge', 'DevOps')
15
- ProjectUri = 'https://github.com/babajide234/GitMergeWorkflow'
16
- }
17
- }
18
- }
1
+ @{
2
+ RootModule = 'GitMergeWorkflow.psm1'
3
+ ModuleVersion = '1.0.6'
4
+ GUID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
5
+ Author = 'babajide Tomoshegbo'
6
+ CompanyName = 'babajide234'
7
+ Copyright = '(c) 2025 Expedier. All rights reserved.'
8
+ Description = 'Automated Git workflow for merging feature branches through staging to develop'
9
+ PowerShellVersion = '5.1'
10
+ FunctionsToExport = @('Invoke-GitMergeWorkflow', 'New-GitWorkflowConfig', 'Get-GitWorkflowConfig')
11
+ AliasesToExport = @('git-merge-workflow', 'gmw')
12
+ PrivateData = @{
13
+ PSData = @{
14
+ Tags = @('Git', 'Workflow', 'Automation', 'Merge', 'DevOps')
15
+ ProjectUri = 'https://github.com/babajide234/GitMergeWorkflow'
16
+ ReleaseNotes = @"
17
+ ## 1.0.6
18
+ - Fix: Resolve false positive remote branch detection caused by git credential-manager stderr warnings polluting ls-remote output.
19
+ - Fix: Use full refs/heads/ refspec prefix in fetch command to prevent remote ref resolution failures.
20
+ - Improvement: Added fallback to create local branch if remote fetch fails unexpectedly.
21
+
22
+ ## 1.0.5
23
+ - Fix: Ensure correct remote branch referencing and fetching by using full refspecs in ls-remote and fetch commands.
24
+
25
+ ## 1.0.4
26
+ - Version bump for NPM publication.
27
+
28
+ ## 1.0.3
29
+ - Prepare for NPM publication.
30
+
31
+ ## 1.0.1
32
+ - chore: Bump module version, update branding and ownership details, and remove the developer guide.
33
+
34
+ ## 1.0.0
35
+ - Initial release with automated merge workflow (feature -> staging -> target).
36
+ - Safety checks, conflict handling, and automatic cleanup.
37
+ - Configurable via .git-merge-workflow.json.
38
+ - Dry run support with -WhatIf.
39
+ "@
40
+ }
41
+ }
42
+ }
@@ -1,343 +1,365 @@
1
-
2
- function Get-GitWorkflowConfig {
3
- <#
4
- .SYNOPSIS
5
- Retrieves the Git Merge Workflow configuration from the current repository
6
- .DESCRIPTION
7
- Looks for a .git-merge-workflow.json file in the root of the git repository.
8
- If found, parses and returns the configuration.
9
- If not found, returns null.
10
- #>
11
- [CmdletBinding()]
12
- param()
13
-
14
- try {
15
- # Get git root
16
- $gitRoot = git rev-parse --show-toplevel 2>$null
17
- if ($LASTEXITCODE -eq 0 -and $gitRoot) {
18
- $configPath = Join-Path $gitRoot ".git-merge-workflow.json"
19
- if (Test-Path $configPath) {
20
- return Get-Content $configPath -Raw | ConvertFrom-Json
21
- }
22
- }
23
- } catch {
24
- Write-Verbose "Error reading config: $_"
25
- }
26
- return $null
27
- }
28
-
29
- function New-GitWorkflowConfig {
30
- <#
31
- .SYNOPSIS
32
- Creates a new configuration file for the Git Merge Workflow
33
- .DESCRIPTION
34
- Creates a .git-merge-workflow.json file in the root of the current git repository.
35
- .PARAMETER TargetBranch
36
- The default target branch (default: develop)
37
- .PARAMETER StagingSuffix
38
- The suffix for staging branches (default: -staging)
39
- .PARAMETER Remote
40
- The default remote name (default: origin)
41
- .EXAMPLE
42
- New-GitWorkflowConfig -TargetBranch "main" -StagingSuffix "-test"
43
- #>
44
- [CmdletBinding(SupportsShouldProcess=$true)]
45
- param(
46
- [string]$TargetBranch = "develop",
47
- [string]$StagingSuffix = "-staging",
48
- [string]$Remote = "origin"
49
- )
50
-
51
- # Check if in git repo
52
- $gitRoot = git rev-parse --show-toplevel 2>$null
53
- if ($LASTEXITCODE -ne 0 -or -not $gitRoot) {
54
- Write-Error "Not in a git repository. Please run inside a git repository."
55
- return
56
- }
57
-
58
- $configPath = Join-Path $gitRoot ".git-merge-workflow.json"
59
-
60
- $config = @{
61
- TargetBranch = $TargetBranch
62
- StagingSuffix = $StagingSuffix
63
- Remote = $Remote
64
- }
65
-
66
- $json = $config | ConvertTo-Json -Depth 2
67
-
68
- if ($PSCmdlet.ShouldProcess($configPath, "Create configuration file")) {
69
- $json | Set-Content $configPath
70
- Write-Host "Configuration file created at: $configPath" -ForegroundColor Green
71
- Write-Host "Content:" -ForegroundColor Cyan
72
- Write-Host $json
73
- }
74
- }
75
-
76
- function Invoke-GitMergeWorkflow {
77
- <#
78
- .SYNOPSIS
79
- Automated Git workflow to merge current branch to staging and then to develop
80
- .DESCRIPTION
81
- This function automates the process of:
82
- 1. Getting the current branch name
83
- 2. Merging current branch to {branch}-staging
84
- 3. Merging {branch}-staging to develop
85
- 4. Pushing all changes
86
-
87
- Configuration can be stored in .git-merge-workflow.json in the repository root.
88
- .PARAMETER CommitMessage
89
- Optional commit message if there are uncommitted changes
90
- .PARAMETER StagingBranch
91
- Optional custom staging branch name.
92
- Defaults to {current-branch}{staging-suffix} (configured in JSON or defaults to -staging)
93
- .PARAMETER TargetBranch
94
- Optional target branch name.
95
- Defaults to 'develop' or value in configuration file.
96
- .PARAMETER Remote
97
- Optional remote name.
98
- Defaults to 'origin' or value in configuration file.
99
- .EXAMPLE
100
- Invoke-GitMergeWorkflow
101
- .EXAMPLE
102
- Invoke-GitMergeWorkflow -CommitMessage "Fix: Updated business contact form"
103
- .EXAMPLE
104
- git-merge-workflow -CommitMessage "Feature: Added new component" -WhatIf
105
- #>
106
-
107
- [CmdletBinding(SupportsShouldProcess=$true)]
108
- param(
109
- [Parameter(Mandatory=$false)]
110
- [string]$CommitMessage = "",
111
-
112
- [Parameter(Mandatory=$false)]
113
- [string]$StagingBranch = "",
114
-
115
- [Parameter(Mandatory=$false)]
116
- [string]$TargetBranch = "",
117
-
118
- [Parameter(Mandatory=$false)]
119
- [string]$Remote = ""
120
- )
121
-
122
- # Load configuration
123
- $config = Get-GitWorkflowConfig
124
-
125
- # Set defaults (Priority: Parameter > Config > Hardcoded Default)
126
- if (-not $TargetBranch) {
127
- $TargetBranch = if ($config.TargetBranch) { $config.TargetBranch } else { "develop" }
128
- }
129
-
130
- if (-not $Remote) {
131
- $Remote = if ($config.Remote) { $config.Remote } else { "origin" }
132
- }
133
-
134
- $stagingSuffix = if ($config.StagingSuffix) { $config.StagingSuffix } else { "-staging" }
135
-
136
- # Internal helper to execute git commands with error handling
137
- function Exec-Git {
138
- [CmdletBinding()]
139
- param(
140
- [Parameter(Mandatory=$true, Position=0)]
141
- [string]$Command,
142
-
143
- [Parameter(Mandatory=$false)]
144
- [string]$ErrorMessage,
145
-
146
- [Parameter(Mandatory=$false)]
147
- [switch]$IgnoreError,
148
-
149
- [Parameter(Mandatory=$false)]
150
- [switch]$ReturnOutput,
151
-
152
- [Parameter(ValueFromRemainingArguments=$true)]
153
- [string[]]$Arguments
154
- )
155
-
156
- $cmdDesc = "git $Command $Arguments"
157
-
158
- if ($PSCmdlet.ShouldProcess("Git Repository", "Execute: $cmdDesc")) {
159
- # Construct the command to run
160
- # Note: We use & operator to run git with arguments
161
- $output = & git $Command $Arguments 2>&1
162
- $exitCode = $LASTEXITCODE
163
-
164
- if ($ReturnOutput) {
165
- return $output
166
- } elseif ($output) {
167
- # If not capturing output, write it to the stream (except errors which we handle below)
168
- $output | ForEach-Object { Write-Verbose $_ }
169
- }
170
-
171
- if (-not $IgnoreError -and $exitCode -ne 0) {
172
- $msg = if ($ErrorMessage) { $ErrorMessage } else { "Git command failed: $cmdDesc" }
173
- throw "$msg`nDetails: $output"
174
- }
175
- }
176
- }
177
-
178
- Write-Host "`n=== Git Merge Workflow ===" -ForegroundColor Cyan
179
- Write-Host "Starting automated merge process...`n" -ForegroundColor Cyan
180
-
181
- # Check if we're in a git repository
182
- try {
183
- Exec-Git "rev-parse" "--is-inside-work-tree" -ErrorMessage "Not a git repository" -ReturnOutput | Out-Null
184
- } catch {
185
- Write-Error $_.Exception.Message
186
- return
187
- }
188
-
189
- # Get current branch
190
- $currentBranch = (git branch --show-current).Trim()
191
- Write-Host "Current branch: $currentBranch" -ForegroundColor Yellow
192
-
193
- if ([string]::IsNullOrWhiteSpace($currentBranch)) {
194
- Write-Error "Could not determine current branch."
195
- return
196
- }
197
-
198
- # Validate we are not on target or explicitly named staging
199
- if ($currentBranch -eq $TargetBranch) {
200
- Write-Error "You are currently on the target branch '$TargetBranch'. Please checkout your feature branch first."
201
- return
202
- }
203
-
204
- # Define staging branch
205
- if (-not $StagingBranch) {
206
- $StagingBranch = "$currentBranch$stagingSuffix"
207
- }
208
-
209
- if ($currentBranch -eq $StagingBranch) {
210
- Write-Error "You are currently on the staging branch '$StagingBranch'. Please checkout your feature branch first."
211
- return
212
- }
213
-
214
- Write-Host "`nStaging branch: $StagingBranch" -ForegroundColor Yellow
215
- Write-Host "Target branch: $TargetBranch" -ForegroundColor Yellow
216
- Write-Host "Remote: $Remote" -ForegroundColor Yellow
217
-
218
- # Store starting branch to return to it later
219
- $originalBranch = $currentBranch
220
-
221
- try {
222
- # Verify remote connection before proceeding
223
- Write-Host "`nVerifying connection to $Remote..." -ForegroundColor Yellow
224
- Exec-Git -Command "ls-remote" -Arguments $Remote, "HEAD" -ErrorMessage "Could not connect to remote '$Remote'. Please check your internet connection and git credentials." -ReturnOutput | Out-Null
225
- Write-Host "Connection successful!" -ForegroundColor Green
226
-
227
- # Check for uncommitted changes
228
- $status = git status --porcelain
229
- if ($status) {
230
- if ($CommitMessage) {
231
- Write-Host "`nCommitting changes..." -ForegroundColor Yellow
232
- if ($PSCmdlet.ShouldProcess("Current Branch", "Add all changes and commit with message '$CommitMessage'")) {
233
- Exec-Git "add" "." -ErrorMessage "Failed to add changes"
234
- Exec-Git "commit" "-m" "$CommitMessage" -ErrorMessage "Failed to commit changes"
235
- Write-Host "Changes committed!" -ForegroundColor Green
236
- }
237
- } else {
238
- Write-Error "You have uncommitted changes! Please commit them first or use -CommitMessage parameter"
239
- git status
240
- return
241
- }
242
- }
243
-
244
- # --- Handle Staging Branch ---
245
-
246
- # Check if staging branch exists locally
247
- $branchExists = git branch --list $StagingBranch
248
- if (-not $branchExists) {
249
- Write-Host "`nStaging branch doesn't exist locally. Checking remote..." -ForegroundColor Yellow
250
- # Check if exists on remote (explicit check to avoid silent failures)
251
- $remoteBranchExists = $false
252
- try {
253
- $lsRemote = Exec-Git -Command "ls-remote" -Arguments "--heads", $Remote, $StagingBranch -ReturnOutput
254
- if ($lsRemote) { $remoteBranchExists = $true }
255
- } catch {
256
- Write-Warning "Could not check remote branch: $_"
257
- }
258
-
259
- if ($remoteBranchExists) {
260
- Write-Host "Fetching remote staging branch..." -ForegroundColor Yellow
261
- Exec-Git -Command "fetch" -Arguments $Remote, $StagingBranch
262
- Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch, "$Remote/$StagingBranch"
263
- } else {
264
- Write-Host "Creating new staging branch..." -ForegroundColor Yellow
265
- Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch
266
- }
267
- } else {
268
- Write-Host "Checking out staging branch..." -ForegroundColor Yellow
269
- Exec-Git -Command "checkout" -Arguments $StagingBranch
270
- }
271
-
272
- # Pull latest from staging (if tracked)
273
- Write-Host "`nPulling latest changes from staging..." -ForegroundColor Yellow
274
- # We use IgnoreError because it might fail if there's no tracking info yet, which is acceptable here
275
- Exec-Git -Command "pull" -Arguments $Remote, $StagingBranch -IgnoreError
276
-
277
- # Merge current branch into staging
278
- Write-Host "`nMerging $currentBranch into $StagingBranch..." -ForegroundColor Yellow
279
- Exec-Git -Command "merge" -Arguments $currentBranch, "--no-ff", "-m", "Merge $currentBranch into $StagingBranch" -ErrorMessage "Merge conflict detected in staging! Please resolve conflicts manually."
280
-
281
- Write-Host "Successfully merged to staging!" -ForegroundColor Green
282
-
283
- # Push staging
284
- Write-Host "`nPushing $StagingBranch to remote..." -ForegroundColor Yellow
285
- try {
286
- Exec-Git -Command "push" -Arguments "-u", $Remote, $StagingBranch -ErrorMessage "Failed to push staging branch"
287
- Write-Host "Staging branch pushed!" -ForegroundColor Green
288
- } catch {
289
- Write-Warning "Failed to push staging branch to remote."
290
- Write-Warning "Error: $_"
291
- if ($PSCmdlet.ShouldContinue("Do you want to skip pushing the staging branch and continue to merge into $TargetBranch?", "Skip Staging Push")) {
292
- Write-Host "Skipping staging push..." -ForegroundColor Yellow
293
- } else {
294
- throw $_
295
- }
296
- }
297
-
298
- # --- Handle Target Branch ---
299
-
300
- # Checkout target branch
301
- Write-Host "`nChecking out $TargetBranch branch..." -ForegroundColor Yellow
302
- Exec-Git "checkout" $TargetBranch -ErrorMessage "Failed to checkout $TargetBranch"
303
-
304
- # Pull latest from target
305
- Write-Host "Pulling latest changes from $TargetBranch..." -ForegroundColor Yellow
306
- Exec-Git "pull" $Remote $TargetBranch -ErrorMessage "Failed to pull $TargetBranch"
307
-
308
- # Merge staging into target
309
- Write-Host "`nMerging $StagingBranch into $TargetBranch..." -ForegroundColor Yellow
310
- Exec-Git "merge" $StagingBranch "--no-ff" "-m" "Merge $StagingBranch into $TargetBranch" -ErrorMessage "Merge conflict detected in target! Please resolve conflicts manually."
311
-
312
- Write-Host "Successfully merged to target!" -ForegroundColor Green
313
-
314
- # Push target
315
- Write-Host "`nPushing $TargetBranch to remote..." -ForegroundColor Yellow
316
- Exec-Git "push" $Remote $TargetBranch -ErrorMessage "Failed to push $TargetBranch branch"
317
- Write-Host "$TargetBranch branch pushed!" -ForegroundColor Green
318
-
319
- Write-Host "`n=== Workflow Complete! ===" -ForegroundColor Green
320
- Write-Host "Summary:" -ForegroundColor Cyan
321
- Write-Host " Merged: $originalBranch → $StagingBranch → $TargetBranch" -ForegroundColor White
322
- Write-Host " All changes pushed to remote`n" -ForegroundColor White
323
-
324
- } catch {
325
- Write-Error $_.Exception.Message
326
- Write-Host "`nWorkflow failed. Attempting to return to original branch..." -ForegroundColor Red
327
- } finally {
328
- # Return to original branch
329
- $finalBranch = (git branch --show-current).Trim()
330
- if ($originalBranch -and $finalBranch -ne $originalBranch) {
331
- Write-Host "`nReturning to $originalBranch..." -ForegroundColor Yellow
332
- if ($PSCmdlet.ShouldProcess("Cleanup", "Checkout $originalBranch")) {
333
- git checkout $originalBranch 2>$null | Out-Null
334
- }
335
- }
336
- }
337
- }
338
-
339
- # Create aliases for easier usage
340
- New-Alias -Name git-merge-workflow -Value Invoke-GitMergeWorkflow -Force
341
- New-Alias -Name gmw -Value Invoke-GitMergeWorkflow -Force
342
-
343
- Export-ModuleMember -Function Invoke-GitMergeWorkflow, New-GitWorkflowConfig, Get-GitWorkflowConfig -Alias git-merge-workflow, gmw
1
+
2
+ function Get-GitWorkflowConfig {
3
+ <#
4
+ .SYNOPSIS
5
+ Retrieves the Git Merge Workflow configuration from the current repository
6
+ .DESCRIPTION
7
+ Looks for a .git-merge-workflow.json file in the root of the git repository.
8
+ If found, parses and returns the configuration.
9
+ If not found, returns null.
10
+ #>
11
+ [CmdletBinding()]
12
+ param()
13
+
14
+ try {
15
+ # Get git root
16
+ $gitRoot = git rev-parse --show-toplevel 2>$null
17
+ if ($LASTEXITCODE -eq 0 -and $gitRoot) {
18
+ $configPath = Join-Path $gitRoot ".git-merge-workflow.json"
19
+ if (Test-Path $configPath) {
20
+ return Get-Content $configPath -Raw | ConvertFrom-Json
21
+ }
22
+ }
23
+ }
24
+ catch {
25
+ Write-Verbose "Error reading config: $_"
26
+ }
27
+ return $null
28
+ }
29
+
30
+ function New-GitWorkflowConfig {
31
+ <#
32
+ .SYNOPSIS
33
+ Creates a new configuration file for the Git Merge Workflow
34
+ .DESCRIPTION
35
+ Creates a .git-merge-workflow.json file in the root of the current git repository.
36
+ .PARAMETER TargetBranch
37
+ The default target branch (default: develop)
38
+ .PARAMETER StagingSuffix
39
+ The suffix for staging branches (default: -staging)
40
+ .PARAMETER Remote
41
+ The default remote name (default: origin)
42
+ .EXAMPLE
43
+ New-GitWorkflowConfig -TargetBranch "main" -StagingSuffix "-test"
44
+ #>
45
+ [CmdletBinding(SupportsShouldProcess = $true)]
46
+ param(
47
+ [string]$TargetBranch = "develop",
48
+ [string]$StagingSuffix = "-staging",
49
+ [string]$Remote = "origin"
50
+ )
51
+
52
+ # Check if in git repo
53
+ $gitRoot = git rev-parse --show-toplevel 2>$null
54
+ if ($LASTEXITCODE -ne 0 -or -not $gitRoot) {
55
+ Write-Error "Not in a git repository. Please run inside a git repository."
56
+ return
57
+ }
58
+
59
+ $configPath = Join-Path $gitRoot ".git-merge-workflow.json"
60
+
61
+ $config = @{
62
+ TargetBranch = $TargetBranch
63
+ StagingSuffix = $StagingSuffix
64
+ Remote = $Remote
65
+ }
66
+
67
+ $json = $config | ConvertTo-Json -Depth 2
68
+
69
+ if ($PSCmdlet.ShouldProcess($configPath, "Create configuration file")) {
70
+ $json | Set-Content $configPath
71
+ Write-Host "Configuration file created at: $configPath" -ForegroundColor Green
72
+ Write-Host "Content:" -ForegroundColor Cyan
73
+ Write-Host $json
74
+ }
75
+ }
76
+
77
+ function Invoke-GitMergeWorkflow {
78
+ <#
79
+ .SYNOPSIS
80
+ Automated Git workflow to merge current branch to staging and then to develop
81
+ .DESCRIPTION
82
+ This function automates the process of:
83
+ 1. Getting the current branch name
84
+ 2. Merging current branch to {branch}-staging
85
+ 3. Merging {branch}-staging to develop
86
+ 4. Pushing all changes
87
+
88
+ Configuration can be stored in .git-merge-workflow.json in the repository root.
89
+ .PARAMETER CommitMessage
90
+ Optional commit message if there are uncommitted changes
91
+ .PARAMETER StagingBranch
92
+ Optional custom staging branch name.
93
+ Defaults to {current-branch}{staging-suffix} (configured in JSON or defaults to -staging)
94
+ .PARAMETER TargetBranch
95
+ Optional target branch name.
96
+ Defaults to 'develop' or value in configuration file.
97
+ .PARAMETER Remote
98
+ Optional remote name.
99
+ Defaults to 'origin' or value in configuration file.
100
+ .EXAMPLE
101
+ Invoke-GitMergeWorkflow
102
+ .EXAMPLE
103
+ Invoke-GitMergeWorkflow -CommitMessage "Fix: Updated business contact form"
104
+ .EXAMPLE
105
+ git-merge-workflow -CommitMessage "Feature: Added new component" -WhatIf
106
+ #>
107
+
108
+ [CmdletBinding(SupportsShouldProcess = $true)]
109
+ param(
110
+ [Parameter(Mandatory = $false)]
111
+ [string]$CommitMessage = "",
112
+
113
+ [Parameter(Mandatory = $false)]
114
+ [string]$StagingBranch = "",
115
+
116
+ [Parameter(Mandatory = $false)]
117
+ [string]$TargetBranch = "",
118
+
119
+ [Parameter(Mandatory = $false)]
120
+ [string]$Remote = ""
121
+ )
122
+
123
+ # Load configuration
124
+ $config = Get-GitWorkflowConfig
125
+
126
+ # Set defaults (Priority: Parameter > Config > Hardcoded Default)
127
+ if (-not $TargetBranch) {
128
+ $TargetBranch = if ($config.TargetBranch) { $config.TargetBranch } else { "develop" }
129
+ }
130
+
131
+ if (-not $Remote) {
132
+ $Remote = if ($config.Remote) { $config.Remote } else { "origin" }
133
+ }
134
+
135
+ $stagingSuffix = if ($config.StagingSuffix) { $config.StagingSuffix } else { "-staging" }
136
+
137
+ # Internal helper to execute git commands with error handling
138
+ function Exec-Git {
139
+ [CmdletBinding()]
140
+ param(
141
+ [Parameter(Mandatory = $true, Position = 0)]
142
+ [string]$Command,
143
+
144
+ [Parameter(Mandatory = $false)]
145
+ [string]$ErrorMessage,
146
+
147
+ [Parameter(Mandatory = $false)]
148
+ [switch]$IgnoreError,
149
+
150
+ [Parameter(Mandatory = $false)]
151
+ [switch]$ReturnOutput,
152
+
153
+ [Parameter(ValueFromRemainingArguments = $true)]
154
+ [string[]]$Arguments
155
+ )
156
+
157
+ $cmdDesc = "git $Command $Arguments"
158
+
159
+ if ($PSCmdlet.ShouldProcess("Git Repository", "Execute: $cmdDesc")) {
160
+ # Construct the command to run
161
+ # Note: We use & operator to run git with arguments
162
+ $output = & git $Command $Arguments 2>&1
163
+ $exitCode = $LASTEXITCODE
164
+
165
+ if ($ReturnOutput) {
166
+ return $output
167
+ }
168
+ elseif ($output) {
169
+ # If not capturing output, write it to the stream (except errors which we handle below)
170
+ $output | ForEach-Object { Write-Verbose $_ }
171
+ }
172
+
173
+ if (-not $IgnoreError -and $exitCode -ne 0) {
174
+ $msg = if ($ErrorMessage) { $ErrorMessage } else { "Git command failed: $cmdDesc" }
175
+ throw "$msg`nDetails: $output"
176
+ }
177
+ }
178
+ }
179
+
180
+ Write-Host "`n=== Git Merge Workflow ===" -ForegroundColor Cyan
181
+ Write-Host "Starting automated merge process...`n" -ForegroundColor Cyan
182
+
183
+ # Check if we're in a git repository
184
+ try {
185
+ Exec-Git "rev-parse" "--is-inside-work-tree" -ErrorMessage "Not a git repository" -ReturnOutput | Out-Null
186
+ }
187
+ catch {
188
+ Write-Error $_.Exception.Message
189
+ return
190
+ }
191
+
192
+ # Get current branch
193
+ $currentBranch = (git branch --show-current).Trim()
194
+ Write-Host "Current branch: $currentBranch" -ForegroundColor Yellow
195
+
196
+ if ([string]::IsNullOrWhiteSpace($currentBranch)) {
197
+ Write-Error "Could not determine current branch."
198
+ return
199
+ }
200
+
201
+ # Validate we are not on target or explicitly named staging
202
+ if ($currentBranch -eq $TargetBranch) {
203
+ Write-Error "You are currently on the target branch '$TargetBranch'. Please checkout your feature branch first."
204
+ return
205
+ }
206
+
207
+ # Define staging branch
208
+ if (-not $StagingBranch) {
209
+ $StagingBranch = "$currentBranch$stagingSuffix"
210
+ }
211
+
212
+ if ($currentBranch -eq $StagingBranch) {
213
+ Write-Error "You are currently on the staging branch '$StagingBranch'. Please checkout your feature branch first."
214
+ return
215
+ }
216
+
217
+ Write-Host "`nStaging branch: $StagingBranch" -ForegroundColor Yellow
218
+ Write-Host "Target branch: $TargetBranch" -ForegroundColor Yellow
219
+ Write-Host "Remote: $Remote" -ForegroundColor Yellow
220
+
221
+ # Store starting branch to return to it later
222
+ $originalBranch = $currentBranch
223
+
224
+ try {
225
+ # Verify remote connection before proceeding
226
+ Write-Host "`nVerifying connection to $Remote..." -ForegroundColor Yellow
227
+ Exec-Git -Command "ls-remote" -Arguments $Remote, "HEAD" -ErrorMessage "Could not connect to remote '$Remote'. Please check your internet connection and git credentials." -ReturnOutput | Out-Null
228
+ Write-Host "Connection successful!" -ForegroundColor Green
229
+
230
+ # Check for uncommitted changes
231
+ $status = git status --porcelain
232
+ if ($status) {
233
+ if ($CommitMessage) {
234
+ Write-Host "`nCommitting changes..." -ForegroundColor Yellow
235
+ if ($PSCmdlet.ShouldProcess("Current Branch", "Add all changes and commit with message '$CommitMessage'")) {
236
+ Exec-Git "add" "." -ErrorMessage "Failed to add changes"
237
+ Exec-Git "commit" "-m" "$CommitMessage" -ErrorMessage "Failed to commit changes"
238
+ Write-Host "Changes committed!" -ForegroundColor Green
239
+ }
240
+ }
241
+ else {
242
+ Write-Error "You have uncommitted changes! Please commit them first or use -CommitMessage parameter"
243
+ git status
244
+ return
245
+ }
246
+ }
247
+
248
+ # --- Handle Staging Branch ---
249
+
250
+ # Check if staging branch exists locally
251
+ $branchExists = git branch --list $StagingBranch
252
+ if (-not $branchExists) {
253
+ Write-Host "`nStaging branch doesn't exist locally. Checking remote..." -ForegroundColor Yellow
254
+ # Check if exists on remote using a direct git command to avoid
255
+ # false positives from stderr warnings (e.g. credential-manager)
256
+ $remoteBranchExists = $false
257
+ try {
258
+ # Use & git directly so stderr warnings don't pollute the result.
259
+ # ls-remote --heads returns lines like "<hash>\trefs/heads/<branch>" for matches.
260
+ $lsOutput = & git ls-remote --heads $Remote "refs/heads/$StagingBranch" 2>$null
261
+ if ($lsOutput -and $lsOutput -match "refs/heads/$([regex]::Escape($StagingBranch))") {
262
+ $remoteBranchExists = $true
263
+ }
264
+ }
265
+ catch {
266
+ Write-Warning "Could not check remote branch: $_"
267
+ }
268
+
269
+ if ($remoteBranchExists) {
270
+ Write-Host "Fetching remote staging branch..." -ForegroundColor Yellow
271
+ try {
272
+ Exec-Git -Command "fetch" -Arguments $Remote, "refs/heads/${StagingBranch}:refs/remotes/$Remote/$StagingBranch"
273
+ Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch, "$Remote/$StagingBranch"
274
+ }
275
+ catch {
276
+ Write-Warning "Failed to fetch remote staging branch. Creating new local branch instead."
277
+ Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch
278
+ }
279
+ }
280
+ else {
281
+ Write-Host "Creating new staging branch..." -ForegroundColor Yellow
282
+ Exec-Git -Command "checkout" -Arguments "-b", $StagingBranch
283
+ }
284
+ }
285
+ else {
286
+ Write-Host "Checking out staging branch..." -ForegroundColor Yellow
287
+ Exec-Git -Command "checkout" -Arguments $StagingBranch
288
+ }
289
+
290
+ # Pull latest from staging (if tracked)
291
+ Write-Host "`nPulling latest changes from staging..." -ForegroundColor Yellow
292
+ # We use IgnoreError because it might fail if there's no tracking info yet, which is acceptable here
293
+ Exec-Git -Command "pull" -Arguments $Remote, $StagingBranch -IgnoreError
294
+
295
+ # Merge current branch into staging
296
+ Write-Host "`nMerging $currentBranch into $StagingBranch..." -ForegroundColor Yellow
297
+ Exec-Git -Command "merge" -Arguments $currentBranch, "--no-ff", "-m", "Merge $currentBranch into $StagingBranch" -ErrorMessage "Merge conflict detected in staging! Please resolve conflicts manually."
298
+
299
+ Write-Host "Successfully merged to staging!" -ForegroundColor Green
300
+
301
+ # Push staging
302
+ Write-Host "`nPushing $StagingBranch to remote..." -ForegroundColor Yellow
303
+ try {
304
+ Exec-Git -Command "push" -Arguments "-u", $Remote, $StagingBranch -ErrorMessage "Failed to push staging branch"
305
+ Write-Host "Staging branch pushed!" -ForegroundColor Green
306
+ }
307
+ catch {
308
+ Write-Warning "Failed to push staging branch to remote."
309
+ Write-Warning "Error: $_"
310
+ if ($PSCmdlet.ShouldContinue("Do you want to skip pushing the staging branch and continue to merge into $TargetBranch?", "Skip Staging Push")) {
311
+ Write-Host "Skipping staging push..." -ForegroundColor Yellow
312
+ }
313
+ else {
314
+ throw $_
315
+ }
316
+ }
317
+
318
+ # --- Handle Target Branch ---
319
+
320
+ # Checkout target branch
321
+ Write-Host "`nChecking out $TargetBranch branch..." -ForegroundColor Yellow
322
+ Exec-Git "checkout" $TargetBranch -ErrorMessage "Failed to checkout $TargetBranch"
323
+
324
+ # Pull latest from target
325
+ Write-Host "Pulling latest changes from $TargetBranch..." -ForegroundColor Yellow
326
+ Exec-Git "pull" $Remote $TargetBranch -ErrorMessage "Failed to pull $TargetBranch"
327
+
328
+ # Merge staging into target
329
+ Write-Host "`nMerging $StagingBranch into $TargetBranch..." -ForegroundColor Yellow
330
+ Exec-Git "merge" $StagingBranch "--no-ff" "-m" "Merge $StagingBranch into $TargetBranch" -ErrorMessage "Merge conflict detected in target! Please resolve conflicts manually."
331
+
332
+ Write-Host "Successfully merged to target!" -ForegroundColor Green
333
+
334
+ # Push target
335
+ Write-Host "`nPushing $TargetBranch to remote..." -ForegroundColor Yellow
336
+ Exec-Git "push" $Remote $TargetBranch -ErrorMessage "Failed to push $TargetBranch branch"
337
+ Write-Host "$TargetBranch branch pushed!" -ForegroundColor Green
338
+
339
+ Write-Host "`n=== Workflow Complete! ===" -ForegroundColor Green
340
+ Write-Host "Summary:" -ForegroundColor Cyan
341
+ Write-Host " ✓ Merged: $originalBranch → $StagingBranch → $TargetBranch" -ForegroundColor White
342
+ Write-Host " ✓ All changes pushed to remote`n" -ForegroundColor White
343
+
344
+ }
345
+ catch {
346
+ Write-Error $_.Exception.Message
347
+ Write-Host "`nWorkflow failed. Attempting to return to original branch..." -ForegroundColor Red
348
+ }
349
+ finally {
350
+ # Return to original branch
351
+ $finalBranch = (git branch --show-current).Trim()
352
+ if ($originalBranch -and $finalBranch -ne $originalBranch) {
353
+ Write-Host "`nReturning to $originalBranch..." -ForegroundColor Yellow
354
+ if ($PSCmdlet.ShouldProcess("Cleanup", "Checkout $originalBranch")) {
355
+ git checkout $originalBranch 2>$null | Out-Null
356
+ }
357
+ }
358
+ }
359
+ }
360
+
361
+ # Create aliases for easier usage
362
+ New-Alias -Name git-merge-workflow -Value Invoke-GitMergeWorkflow -Force
363
+ New-Alias -Name gmw -Value Invoke-GitMergeWorkflow -Force
364
+
365
+ Export-ModuleMember -Function Invoke-GitMergeWorkflow, New-GitWorkflowConfig, Get-GitWorkflowConfig -Alias git-merge-workflow, gmw
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 babajide Tomoshegbo
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 babajide Tomoshegbo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -17,7 +17,7 @@ Automate your git merge workflow with safety and ease. This module helps you mer
17
17
  You can install this tool globally using npm:
18
18
 
19
19
  ```bash
20
- npm install -g @expedier/git-merge-workflow
20
+ npm install -g @babajide234/git-merge-workflow
21
21
  ```
22
22
  This will make the `gmw` and `git-merge-workflow` commands available in your terminal.
23
23
 
package/package.json CHANGED
@@ -1,39 +1,39 @@
1
- {
2
- "name": "@babajide234/git-merge-workflow",
3
- "version": "1.0.4",
4
- "private": false,
5
- "publishConfig": {
6
- "access": "public"
7
- },
8
- "description": "Automated Git workflow for merging feature branches through staging to develop",
9
- "bin": {
10
- "git-merge-workflow": "./bin/cli.js",
11
- "gmw": "./bin/cli.js"
12
- },
13
- "files": [
14
- "bin/",
15
- "GitMergeWorkflow.psd1",
16
- "GitMergeWorkflow.psm1",
17
- "Install.ps1",
18
- "README.md"
19
- ],
20
- "scripts": {
21
- "test": "echo \"Error: no test specified\" && exit 1"
22
- },
23
- "keywords": [
24
- "git",
25
- "workflow",
26
- "powershell",
27
- "automation",
28
- "devops"
29
- ],
30
- "author": "babajide Tomoshegbo",
31
- "license": "MIT",
32
- "repository": {
33
- "type": "git",
34
- "url": "https://github.com/babajide234/GitMergeWorkflow.git"
35
- },
36
- "engines": {
37
- "node": ">=14"
38
- }
39
- }
1
+ {
2
+ "name": "@babajide234/git-merge-workflow",
3
+ "version": "1.0.6",
4
+ "private": false,
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "description": "Automated Git workflow for merging feature branches through staging to develop",
9
+ "bin": {
10
+ "git-merge-workflow": "./bin/cli.js",
11
+ "gmw": "./bin/cli.js"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "GitMergeWorkflow.psd1",
16
+ "GitMergeWorkflow.psm1",
17
+ "Install.ps1",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "test": "echo \"Error: no test specified\" && exit 1"
22
+ },
23
+ "keywords": [
24
+ "git",
25
+ "workflow",
26
+ "powershell",
27
+ "automation",
28
+ "devops"
29
+ ],
30
+ "author": "babajide Tomoshegbo",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/babajide234/GitMergeWorkflow.git"
35
+ },
36
+ "engines": {
37
+ "node": ">=14"
38
+ }
39
+ }