@@ -38,43 +38,89 @@ jobs:
38
38
fetch-depth : 0
39
39
token : ${{ secrets.WORKFLOW_AUTOMATION }}
40
40
41
- - name : Set up Git identity
41
+ - name : Set up Git identity, authentication, and temp directories
42
42
run : |
43
43
# Configure git with identity
44
44
git config --global user.name "GitHub Actions"
45
45
git config --global user.email "[email protected] "
46
46
47
47
# Disable signing by default - we'll use GitHub's verified commits instead
48
48
git config --global commit.gpgsign false
49
+
50
+ # Configure git remote URL with authentication token for push operations
51
+ git remote set-url origin https://x-access-token:${{ secrets.WORKFLOW_AUTOMATION }}@github.com/${{ github.repository }}
52
+
53
+ # Verify remote URL configuration
54
+ echo "Git remote URL configured:"
55
+ git remote get-url origin | sed 's/x-access-token:[^@]*@/x-access-token:***@/'
56
+
57
+ # Create temp directory structure in GitHub's recommended location
58
+ export TEMP_DIR="${RUNNER_TEMP}/workflow_deployment"
59
+ mkdir -p "$TEMP_DIR"
60
+ echo "TEMP_DIR=$TEMP_DIR" >> $GITHUB_ENV
61
+
62
+ # Create temp subdirectories for organized cleanup
63
+ mkdir -p "$TEMP_DIR/worktrees"
64
+ mkdir -p "$TEMP_DIR/artifacts"
65
+
66
+ echo "Temporary directory created at: $TEMP_DIR"
49
67
50
- - name : Decode workflow content
68
+ - name : Decode workflow content and prepare artifacts
51
69
run : |
52
- echo "${{ github.event.inputs.workflow_content }}" | base64 -d > workflow_content.yml
53
- mkdir -p .github/workflows
70
+ # Decode workflow content to temp directory (outside git working tree)
71
+ echo "${{ github.event.inputs.workflow_content }}" | base64 -d > "$TEMP_DIR/artifacts/workflow_content.yml"
72
+
73
+ # Validate decoded content
74
+ if [ ! -s "$TEMP_DIR/artifacts/workflow_content.yml" ]; then
75
+ echo "ERROR: Workflow content is empty after decoding"
76
+ exit 1
77
+ fi
54
78
55
- - name : Get all branches and save to file
79
+ echo "Workflow content decoded successfully"
80
+ echo "Content size: $(wc -c < "$TEMP_DIR/artifacts/workflow_content.yml") bytes"
81
+
82
+ - name : Get all remote branches and prepare processing list
56
83
run : |
57
- # Save branches to a file instead of environment variable
58
- git branch -r | grep -v HEAD | sed 's/origin\///' > all_branches.txt
59
- echo "All branches found:"
60
- cat all_branches.txt
84
+ # Save branches to temp file outside git working tree
85
+ BRANCHES_FILE="$TEMP_DIR/artifacts/all_branches.txt"
86
+
87
+ # Get all remote branches, excluding HEAD reference
88
+ git branch -r | grep -v HEAD | sed 's/origin\///' | sed 's/^[[:space:]]*//' > "$BRANCHES_FILE"
89
+
90
+ # Validate we found branches
91
+ BRANCH_COUNT=$(wc -l < "$BRANCHES_FILE")
92
+ if [ "$BRANCH_COUNT" -eq 0 ]; then
93
+ echo "ERROR: No remote branches found"
94
+ exit 1
95
+ fi
96
+
97
+ echo "Found $BRANCH_COUNT remote branches:"
98
+ cat "$BRANCHES_FILE"
99
+
100
+ # Save branches file path to environment
101
+ echo "BRANCHES_FILE=$BRANCHES_FILE" >> $GITHUB_ENV
61
102
62
- - name : Deploy workflow to all branches
103
+ - name : Deploy workflow using git worktree strategy
63
104
run : |
64
105
WORKFLOW_PATH=".github/workflows/${{ github.event.inputs.workflow_path }}"
65
106
SKIP_BRANCHES="${{ github.event.inputs.skip_branches }}"
66
107
FORCE_DEPLOY="${{ github.event.inputs.force_deploy }}"
67
- USE_GITHUB_APP="${{ github.event.inputs.use_github_app }}"
68
108
IFS=',' read -ra SKIP_ARRAY <<< "$SKIP_BRANCHES"
69
109
70
110
CURRENT_BRANCH=$(git branch --show-current)
71
111
echo "Current branch: $CURRENT_BRANCH"
112
+ echo "Target workflow path: $WORKFLOW_PATH"
72
113
73
- # Initialize tracking for successful deployments
74
- echo "" > successful_deployments.txt
114
+ # Initialize tracking for successful deployments in temp directory
115
+ DEPLOYMENTS_LOG="$TEMP_DIR/artifacts/successful_deployments.txt"
116
+ echo "" > "$DEPLOYMENTS_LOG"
75
117
76
- # Process each branch from the file
77
- while read branch; do
118
+ # Initialize error tracking
119
+ ERRORS_LOG="$TEMP_DIR/artifacts/deployment_errors.txt"
120
+ echo "" > "$ERRORS_LOG"
121
+
122
+ # Process each branch using worktree strategy
123
+ while IFS= read -r branch; do
78
124
# Trim whitespace from branch name
79
125
branch=$(echo "$branch" | xargs)
80
126
@@ -97,12 +143,70 @@ jobs:
97
143
continue
98
144
fi
99
145
146
+ echo "================================================================"
100
147
echo "Processing branch: $branch"
148
+ echo "================================================================"
149
+
150
+ # Define worktree path in temp directory
151
+ WORKTREE_PATH="$TEMP_DIR/worktrees/$branch"
152
+
153
+ # Cleanup any existing worktree for this branch (defensive)
154
+ if [ -d "$WORKTREE_PATH" ]; then
155
+ echo "Cleaning up existing worktree for $branch"
156
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
157
+ rm -rf "$WORKTREE_PATH" 2>/dev/null || true
158
+ fi
159
+
160
+ # Check if local branch exists, create tracking branch if it doesn't
161
+ echo "Checking if local branch '$branch' exists..."
162
+ if ! git show-ref --verify --quiet refs/heads/"$branch"; then
163
+ echo "Local branch '$branch' does not exist. Creating tracking branch..."
164
+
165
+ # Verify remote branch exists
166
+ if ! git show-ref --verify --quiet refs/remotes/origin/"$branch"; then
167
+ echo "ERROR: Remote branch 'origin/$branch' does not exist" | tee -a "$ERRORS_LOG"
168
+ echo "Skipping branch: $branch"
169
+ continue
170
+ fi
171
+
172
+ # Create local tracking branch
173
+ if ! git branch --track "$branch" "origin/$branch"; then
174
+ echo "ERROR: Failed to create tracking branch for $branch" | tee -a "$ERRORS_LOG"
175
+ echo "Skipping branch: $branch"
176
+ continue
177
+ fi
178
+ echo "Created tracking branch '$branch' -> 'origin/$branch'"
179
+ else
180
+ echo "Local branch '$branch' already exists"
181
+ fi
182
+
183
+ # Create worktree for the branch (using local branch name only)
184
+ echo "Creating worktree for branch: $branch"
185
+ if ! git worktree add "$WORKTREE_PATH" "$branch" 2>&1; then
186
+ echo "ERROR: Failed to create worktree for branch $branch" | tee -a "$ERRORS_LOG"
187
+ echo "Skipping branch: $branch"
188
+ continue
189
+ fi
190
+
191
+ # Verify worktree was created successfully
192
+ if [ ! -d "$WORKTREE_PATH" ]; then
193
+ echo "ERROR: Worktree directory not found after creation: $WORKTREE_PATH" | tee -a "$ERRORS_LOG"
194
+ echo "Skipping branch: $branch"
195
+ continue
196
+ fi
197
+
198
+ echo "Worktree created successfully at: $WORKTREE_PATH"
101
199
102
- # Checkout branch
103
- git checkout "$branch" || { echo "Failed to checkout $branch, skipping"; continue; }
200
+ # Change to worktree directory for all subsequent operations
201
+ cd "$WORKTREE_PATH"
104
202
105
- # Enhanced file existence check - check both tracked and untracked files
203
+ # Verify we're in the correct branch
204
+ ACTUAL_BRANCH=$(git branch --show-current)
205
+ if [ "$ACTUAL_BRANCH" != "$branch" ]; then
206
+ echo "WARNING: Expected branch '$branch', but worktree is on '$ACTUAL_BRANCH'"
207
+ fi
208
+
209
+ # Enhanced file existence check in worktree
106
210
FILE_EXISTS=false
107
211
108
212
# Check if the file exists on disk
@@ -111,23 +215,17 @@ jobs:
111
215
FILE_EXISTS=true
112
216
fi
113
217
114
- # Check if the file is untracked by git
115
- UNTRACKED=$(git ls-files --others --exclude-standard "$WORKFLOW_PATH" 2>/dev/null)
116
- if [ -n "$UNTRACKED" ]; then
117
- echo "Workflow file exists but is untracked in branch $branch"
118
- FILE_EXISTS=true
119
- fi
120
-
121
- # Check if file is in git's index (tracked)
122
- TRACKED=$(git ls-files "$WORKFLOW_PATH" 2>/dev/null)
123
- if [ -n "$TRACKED" ]; then
218
+ # Check if the file is tracked by git
219
+ if git ls-files --error-unmatch "$WORKFLOW_PATH" >/dev/null 2>&1; then
124
220
echo "Workflow file is tracked by git in branch $branch"
125
221
FILE_EXISTS=true
126
222
fi
127
223
128
224
# Act based on file existence and force_deploy flag
129
225
if [ "$FILE_EXISTS" = true ] && [ "$FORCE_DEPLOY" != "true" ]; then
130
226
echo "Workflow file exists in $branch and force_deploy is not enabled. Skipping."
227
+ cd - > /dev/null # Return to main repo
228
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
131
229
continue
132
230
elif [ "$FILE_EXISTS" = true ] && [ "$FORCE_DEPLOY" = "true" ]; then
133
231
echo "Workflow file exists in $branch, but force_deploy is enabled. Overwriting."
@@ -138,57 +236,131 @@ jobs:
138
236
# Create directory structure if it doesn't exist
139
237
mkdir -p "$(dirname "$WORKFLOW_PATH")"
140
238
141
- # Copy workflow file
142
- cp workflow_content.yml "$WORKFLOW_PATH"
239
+ # Copy workflow file from temp artifacts
240
+ cp "$TEMP_DIR/artifacts/workflow_content.yml" "$WORKFLOW_PATH"
241
+
242
+ # Verify file was created successfully
243
+ if [ ! -f "$WORKFLOW_PATH" ]; then
244
+ echo "ERROR: Failed to create workflow file in worktree" | tee -a "$ERRORS_LOG"
245
+ cd - > /dev/null # Return to main repo
246
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
247
+ continue
248
+ fi
143
249
144
- # Add diagnostic output to verify file was created
145
- echo "Verifying workflow file was created:"
146
- ls -la "$WORKFLOW_PATH" || echo "Error: File not found after creation"
250
+ echo "Workflow file created successfully:"
251
+ ls -la "$WORKFLOW_PATH"
147
252
148
253
# Check if file is in .gitignore
149
- if grep -q "$WORKFLOW_PATH" .gitignore 2>/dev/null; then
254
+ if [ -f ".gitignore" ] && grep -q "$WORKFLOW_PATH" .gitignore 2>/dev/null; then
150
255
echo "WARNING: The workflow path '$WORKFLOW_PATH' appears to be in .gitignore"
151
256
echo "This could prevent git from tracking the file"
152
257
fi
153
258
154
- # Add the file and check if it was added successfully
259
+ # Add the file to git index
155
260
git add "$WORKFLOW_PATH"
156
- if ! git ls-files --stage | grep -q "$WORKFLOW_PATH"; then
157
- echo "WARNING: Failed to add file to git index. File may be ignored by gitignore rules."
158
- echo "Attempting to force-add the file..."
261
+
262
+ # Verify the file was added to index
263
+ if ! git diff --cached --name-only | grep -q "$WORKFLOW_PATH"; then
264
+ echo "WARNING: File was not added to git index. Attempting force add..."
159
265
git add -f "$WORKFLOW_PATH"
266
+
267
+ # Final verification
268
+ if ! git diff --cached --name-only | grep -q "$WORKFLOW_PATH"; then
269
+ echo "ERROR: Unable to add file to git index despite force-add attempt" | tee -a "$ERRORS_LOG"
270
+ echo "File may be blocked by gitignore rules or git configuration"
271
+ cd - > /dev/null # Return to main repo
272
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
273
+ continue
274
+ fi
160
275
fi
161
276
162
- # Verify the file is now in the index
163
- if git ls-files --stage | grep -q "$WORKFLOW_PATH"; then
164
- echo "File successfully added to git index"
165
- else
166
- echo "ERROR: Still unable to add file to git index despite force-add attempt"
167
- echo "This suggests a strong gitignore rule or other git configuration issue"
277
+ echo "File successfully added to git index"
278
+
279
+ # Commit changes in worktree
280
+ echo "Committing changes in worktree"
281
+ if ! git commit -m "Deploy workflow file: ${{ github.event.inputs.workflow_path }} to branch $branch"; then
282
+ echo "WARNING: No changes to commit for $branch or commit failed"
283
+ cd - > /dev/null # Return to main repo
284
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
168
285
continue
169
286
fi
170
287
171
- # Commit changes
172
- echo "Committing changes"
173
- if ! git commit -m "Add workflow file to branch $branch"; then
174
- echo "No changes to commit for $branch or commit failed"
288
+ # Push changes from worktree to existing remote
289
+ echo "Pushing changes to origin/$branch"
290
+
291
+ # Verify remote branch exists before pushing
292
+ if ! git ls-remote --heads origin "$branch" | grep -q "$branch"; then
293
+ echo "ERROR: Remote branch 'origin/$branch' does not exist" | tee -a "$ERRORS_LOG"
294
+ echo "Cannot push to non-existent remote branch. Skipping."
295
+ cd - > /dev/null # Return to main repo
296
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
175
297
continue
176
298
fi
177
299
178
300
if ! git push origin "$branch"; then
179
- echo "Failed to push changes to $branch"
180
- echo "This branch may be protected and require verified commits."
301
+ echo "ERROR: Failed to push changes to $branch" | tee -a "$ERRORS_LOG"
302
+ echo "Branch may be protected, require different authentication, or have push restrictions"
303
+ cd - > /dev/null # Return to main repo
304
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
181
305
continue
182
306
fi
183
307
184
308
echo "Successfully deployed workflow to $branch"
309
+
185
310
# Track successful deployment
186
- echo "$branch" >> successful_deployments.txt
311
+ echo "$branch" >> "$DEPLOYMENTS_LOG"
187
312
188
- done < all_branches.txt
313
+ # Return to main repository directory
314
+ cd - > /dev/null
315
+
316
+ # Cleanup worktree for this branch
317
+ echo "Cleaning up worktree for $branch"
318
+ git worktree remove "$WORKTREE_PATH" 2>/dev/null || {
319
+ echo "WARNING: Standard worktree removal failed, attempting force removal"
320
+ git worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
321
+ rm -rf "$WORKTREE_PATH" 2>/dev/null || true
322
+ }
323
+
324
+ echo "Branch $branch processing completed"
325
+ echo ""
326
+
327
+ done < "$BRANCHES_FILE"
328
+
329
+ # Copy results back to working directory for the next step
330
+ cp "$DEPLOYMENTS_LOG" "./successful_deployments.txt"
331
+ cp "$ERRORS_LOG" "./deployment_errors.txt" 2>/dev/null || touch "./deployment_errors.txt"
332
+
333
+ echo "================================================================"
334
+ echo "Deployment Summary"
335
+ echo "================================================================"
336
+ SUCCESSFUL_COUNT=$(grep -c . "./successful_deployments.txt" 2>/dev/null || echo "0")
337
+ echo "Successfully deployed to $SUCCESSFUL_COUNT branches"
338
+
339
+ if [ -s "./deployment_errors.txt" ]; then
340
+ echo "Errors encountered during deployment:"
341
+ cat "./deployment_errors.txt"
342
+ fi
343
+
344
+ - name : Cleanup temp directories
345
+ if : always()
346
+ run : |
347
+ echo "Performing cleanup of temporary directories"
348
+
349
+ # Force cleanup any remaining worktrees
350
+ if [ -d "$TEMP_DIR/worktrees" ]; then
351
+ for worktree_dir in "$TEMP_DIR/worktrees"/*; do
352
+ if [ -d "$worktree_dir" ]; then
353
+ worktree_name=$(basename "$worktree_dir")
354
+ echo "Force cleaning remaining worktree: $worktree_name"
355
+ git worktree remove --force "$worktree_dir" 2>/dev/null || true
356
+ fi
357
+ done
358
+ fi
359
+
360
+ # Remove temp directory
361
+ rm -rf "$TEMP_DIR" 2>/dev/null || true
189
362
190
- # Return to original branch
191
- git checkout "$CURRENT_BRANCH"
363
+ echo "Cleanup completed"
192
364
193
365
- name : Trigger sync workflow if changes were made
194
366
uses : actions/github-script@v6
0 commit comments