squash-only 2.0.0 → 3.0.0
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.
- package/README.md +70 -6
- package/package.json +1 -1
- package/scripts/squash-only.sh +216 -25
package/README.md
CHANGED
|
@@ -15,7 +15,11 @@ This script updates all repositories you own on GitHub to:
|
|
|
15
15
|
- ❌ Disable merge commits
|
|
16
16
|
- ❌ Disable rebase merges
|
|
17
17
|
|
|
18
|
-
It automatically
|
|
18
|
+
It automatically:
|
|
19
|
+
- Skips repositories you don't own
|
|
20
|
+
- Skips repositories that are already configured for squash-only (efficient reruns; no unnecessary network requests)
|
|
21
|
+
- Only processes repositories that need updating
|
|
22
|
+
- Provides a summary of the results
|
|
19
23
|
|
|
20
24
|
## Requirements
|
|
21
25
|
|
|
@@ -68,6 +72,11 @@ With custom sleep interval:
|
|
|
68
72
|
npx github:pRizz/squash-only --sleep 0.5
|
|
69
73
|
```
|
|
70
74
|
|
|
75
|
+
With force flag (process all repos, including already squash-only):
|
|
76
|
+
```bash
|
|
77
|
+
npx github:pRizz/squash-only --force
|
|
78
|
+
```
|
|
79
|
+
|
|
71
80
|
**Note:** If the package is published to npm, you can also use:
|
|
72
81
|
```bash
|
|
73
82
|
npx squash-only
|
|
@@ -87,6 +96,13 @@ With custom sleep interval:
|
|
|
87
96
|
./scripts/squash-only.sh -s 1.0
|
|
88
97
|
```
|
|
89
98
|
|
|
99
|
+
With force flag (process all repos, including already squash-only):
|
|
100
|
+
```bash
|
|
101
|
+
./scripts/squash-only.sh --force
|
|
102
|
+
# or
|
|
103
|
+
./scripts/squash-only.sh -f
|
|
104
|
+
```
|
|
105
|
+
|
|
90
106
|
### Option 3: Run Locally with npm (Development)
|
|
91
107
|
|
|
92
108
|
If you've cloned the repository, you can run it locally using npm scripts:
|
|
@@ -101,6 +117,11 @@ With custom sleep interval:
|
|
|
101
117
|
npm start -- --sleep 0.5
|
|
102
118
|
```
|
|
103
119
|
|
|
120
|
+
With force flag:
|
|
121
|
+
```bash
|
|
122
|
+
npm start -- --force
|
|
123
|
+
```
|
|
124
|
+
|
|
104
125
|
You can also use `npx` to run the local version:
|
|
105
126
|
```bash
|
|
106
127
|
npx .
|
|
@@ -149,19 +170,51 @@ npm start -- --sleep 0.5
|
|
|
149
170
|
./scripts/squash-only.sh -s 1.0
|
|
150
171
|
```
|
|
151
172
|
|
|
173
|
+
### Force mode
|
|
174
|
+
Process all repositories, including those already configured for squash-only:
|
|
175
|
+
```bash
|
|
176
|
+
# Using npx
|
|
177
|
+
npx github:pRizz/squash-only --force
|
|
178
|
+
|
|
179
|
+
# Or run locally with npm
|
|
180
|
+
npm start -- --force
|
|
181
|
+
|
|
182
|
+
# Or using the bash script
|
|
183
|
+
./scripts/squash-only.sh --force
|
|
184
|
+
# or
|
|
185
|
+
./scripts/squash-only.sh -f
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Combine options:
|
|
189
|
+
```bash
|
|
190
|
+
npx github:pRizz/squash-only --force --sleep 0.5
|
|
191
|
+
```
|
|
192
|
+
|
|
152
193
|
## Options
|
|
153
194
|
|
|
154
|
-
- `-s, --sleep SECONDS` - Set the sleep interval between API requests (
|
|
195
|
+
- `-s, --sleep SECONDS` - Set the sleep interval between API requests (default: 0.1 seconds). This delay helps prevent triggering GitHub's rate limits. Authenticated requests (OAuth or PAT) are limited to ~5,000 requests per hour per user or app. See [GitHub's API rate limits documentation](https://github.com/orgs/community/discussions/163553) for more details.
|
|
196
|
+
- `-f, --force` - Process all repositories, including those already configured for squash-only (default: skip already configured repos)
|
|
155
197
|
|
|
156
198
|
## Features
|
|
157
199
|
|
|
158
200
|
- 🔐 **Automatic authentication** - Tries multiple authentication methods
|
|
159
201
|
- 📄 **Pagination support** - Handles users with 100+ repositories
|
|
160
202
|
- 🔍 **Ownership filtering** - Only updates repositories you own
|
|
161
|
-
-
|
|
203
|
+
- ⚡ **Smart skipping** - Automatically skips repositories already configured for squash-only (efficient reruns and new repo handling)
|
|
204
|
+
- 📊 **Progress tracking** - Shows success, skipped, already configured, and failed counts
|
|
162
205
|
- ⏱️ **Performance metrics** - Displays elapsed time
|
|
163
206
|
- 🛡️ **Error handling** - Validates inputs and provides clear error messages
|
|
164
207
|
|
|
208
|
+
## Technical Details
|
|
209
|
+
|
|
210
|
+
This script uses a hybrid approach for GitHub API access:
|
|
211
|
+
|
|
212
|
+
- **GraphQL API** - Used to fetch repositories and their merge strategies in a single, efficient query with cursor-based pagination. This allows us to retrieve all repository information and merge strategy settings in fewer API calls.
|
|
213
|
+
|
|
214
|
+
- **REST API** - Used to update repository merge strategies. As of January 11, 2026, the GitHub GraphQL API does not support mutations for repository merge strategy settings, so the REST API is required for this operation. Therefore, we must call the REST endpoint for each repository individually to update its merge strategy settings.
|
|
215
|
+
|
|
216
|
+
- **Rate Limiting** - To avoid hitting GitHub's API rate limits, the script includes a configurable sleep interval between REST API requests (default: 0.1 seconds). Authenticated requests (OAuth or PAT) are limited to ~5,000 requests per hour per user or app. The sleep delay helps ensure we stay well below this limit when processing large numbers of repositories. See [GitHub's API rate limits documentation](https://github.com/orgs/community/discussions/163553) for more details.
|
|
217
|
+
|
|
165
218
|
## Output
|
|
166
219
|
|
|
167
220
|
The script provides:
|
|
@@ -169,6 +222,7 @@ The script provides:
|
|
|
169
222
|
- Success/failure status for each update
|
|
170
223
|
- A summary at the end showing:
|
|
171
224
|
- Number of successfully updated repositories
|
|
225
|
+
- Number of repositories already configured for squash-only (skipped)
|
|
172
226
|
- Number of skipped repositories (not owned by you)
|
|
173
227
|
- Number of failed updates (if any)
|
|
174
228
|
- Total elapsed time
|
|
@@ -177,9 +231,10 @@ Example output:
|
|
|
177
231
|
```
|
|
178
232
|
────────────────────────────────────
|
|
179
233
|
Summary:
|
|
180
|
-
✅ Successfully updated:
|
|
181
|
-
⏭️
|
|
182
|
-
|
|
234
|
+
✅ Successfully updated: 5
|
|
235
|
+
⏭️ Already squash-only (skipped): 10
|
|
236
|
+
⏭️ Skipped (not owned by you): 3
|
|
237
|
+
⏱️ Elapsed time: 1m 15s
|
|
183
238
|
```
|
|
184
239
|
|
|
185
240
|
## Examples
|
|
@@ -205,6 +260,15 @@ npx github:pRizz/squash-only --sleep 1.0
|
|
|
205
260
|
./scripts/squash-only.sh --sleep 1.0
|
|
206
261
|
```
|
|
207
262
|
|
|
263
|
+
Force update all repositories (including already configured):
|
|
264
|
+
```bash
|
|
265
|
+
# Using npx
|
|
266
|
+
npx github:pRizz/squash-only --force
|
|
267
|
+
|
|
268
|
+
# Or using the bash script
|
|
269
|
+
./scripts/squash-only.sh --force
|
|
270
|
+
```
|
|
271
|
+
|
|
208
272
|
Use with environment variable:
|
|
209
273
|
```bash
|
|
210
274
|
# Using npx
|
package/package.json
CHANGED
package/scripts/squash-only.sh
CHANGED
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
set -uo pipefail
|
|
4
4
|
|
|
5
|
-
SLEEP_SECS=0.
|
|
5
|
+
SLEEP_SECS=0.1
|
|
6
6
|
SHOULD_EXIT=0
|
|
7
7
|
|
|
8
8
|
# Temporary files for tracking counts across subshells
|
|
9
9
|
SUCCESS_COUNT_FILE=$(mktemp)
|
|
10
10
|
SKIP_COUNT_FILE=$(mktemp)
|
|
11
11
|
FAILED_COUNT_FILE=$(mktemp)
|
|
12
|
+
ALREADY_SQUASH_ONLY_COUNT_FILE=$(mktemp)
|
|
13
|
+
|
|
14
|
+
# Flag to force processing all repos even if they already have squash-only enabled
|
|
15
|
+
FORCE_FLAG=0
|
|
12
16
|
|
|
13
17
|
cleanup() {
|
|
14
|
-
rm -f "$SUCCESS_COUNT_FILE" "$SKIP_COUNT_FILE" "$FAILED_COUNT_FILE"
|
|
18
|
+
rm -f "$SUCCESS_COUNT_FILE" "$SKIP_COUNT_FILE" "$FAILED_COUNT_FILE" "$ALREADY_SQUASH_ONLY_COUNT_FILE"
|
|
15
19
|
}
|
|
16
20
|
trap cleanup EXIT
|
|
17
21
|
|
|
@@ -99,9 +103,36 @@ increment_counter() {
|
|
|
99
103
|
echo $((current + 1)) > "$counter_file"
|
|
100
104
|
}
|
|
101
105
|
|
|
106
|
+
is_squash_only() {
|
|
107
|
+
local allow_squash_merge=$1
|
|
108
|
+
local allow_merge_commit=$2
|
|
109
|
+
local allow_rebase_merge=$3
|
|
110
|
+
|
|
111
|
+
# Treat empty, "null", or missing values as false
|
|
112
|
+
[ -z "$allow_squash_merge" ] && allow_squash_merge="false"
|
|
113
|
+
[ "$allow_squash_merge" = "null" ] && allow_squash_merge="false"
|
|
114
|
+
[ -z "$allow_merge_commit" ] && allow_merge_commit="false"
|
|
115
|
+
[ "$allow_merge_commit" = "null" ] && allow_merge_commit="false"
|
|
116
|
+
[ -z "$allow_rebase_merge" ] && allow_rebase_merge="false"
|
|
117
|
+
[ "$allow_rebase_merge" = "null" ] && allow_rebase_merge="false"
|
|
118
|
+
|
|
119
|
+
# Normalize case (in case of unexpected casing)
|
|
120
|
+
allow_squash_merge=$(echo "$allow_squash_merge" | tr '[:upper:]' '[:lower:]')
|
|
121
|
+
allow_merge_commit=$(echo "$allow_merge_commit" | tr '[:upper:]' '[:lower:]')
|
|
122
|
+
allow_rebase_merge=$(echo "$allow_rebase_merge" | tr '[:upper:]' '[:lower:]')
|
|
123
|
+
|
|
124
|
+
if [ "$allow_squash_merge" = "true" ] && [ "$allow_merge_commit" = "false" ] && [ "$allow_rebase_merge" = "false" ]; then
|
|
125
|
+
return 0
|
|
126
|
+
fi
|
|
127
|
+
return 1
|
|
128
|
+
}
|
|
129
|
+
|
|
102
130
|
process_repo() {
|
|
103
131
|
local repo=$1
|
|
104
132
|
local owner=$2
|
|
133
|
+
local allow_squash_merge=$3
|
|
134
|
+
local allow_merge_commit=$4
|
|
135
|
+
local allow_rebase_merge=$5
|
|
105
136
|
|
|
106
137
|
# Check if we should exit
|
|
107
138
|
[ "$SHOULD_EXIT" -eq 1 ] && return 1
|
|
@@ -117,8 +148,20 @@ process_repo() {
|
|
|
117
148
|
return 0
|
|
118
149
|
fi
|
|
119
150
|
|
|
151
|
+
# Check if repo already has squash-only enabled
|
|
152
|
+
if [ "$FORCE_FLAG" -eq 0 ] && is_squash_only "$allow_squash_merge" "$allow_merge_commit" "$allow_rebase_merge"; then
|
|
153
|
+
echo "────────────────────────────────────"
|
|
154
|
+
echo "⏭️ Skipping repo: $repo (already squash-only)"
|
|
155
|
+
increment_counter "$ALREADY_SQUASH_ONLY_COUNT_FILE"
|
|
156
|
+
return 0
|
|
157
|
+
fi
|
|
158
|
+
|
|
120
159
|
echo "────────────────────────────────────"
|
|
121
|
-
|
|
160
|
+
if [ "$FORCE_FLAG" -eq 1 ] && is_squash_only "$allow_squash_merge" "$allow_merge_commit" "$allow_rebase_merge"; then
|
|
161
|
+
echo "Updating repo: $repo (forced, already squash-only)"
|
|
162
|
+
else
|
|
163
|
+
echo "Updating repo: $repo"
|
|
164
|
+
fi
|
|
122
165
|
|
|
123
166
|
local http_code
|
|
124
167
|
http_code=$(curl -s --max-time 30 -o /dev/null -w "%{http_code}" \
|
|
@@ -151,42 +194,174 @@ process_repo() {
|
|
|
151
194
|
sleep "$SLEEP_SECS"
|
|
152
195
|
}
|
|
153
196
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
local
|
|
197
|
+
# Executes a GraphQL query and returns the response
|
|
198
|
+
execute_graphql_query() {
|
|
199
|
+
local query=$1
|
|
200
|
+
local variables_json=$2
|
|
201
|
+
|
|
202
|
+
local payload
|
|
203
|
+
if [ -n "$variables_json" ]; then
|
|
204
|
+
payload=$(jq -n \
|
|
205
|
+
--arg query "$query" \
|
|
206
|
+
--argjson variables "$variables_json" \
|
|
207
|
+
'{query: $query, variables: $variables}')
|
|
208
|
+
else
|
|
209
|
+
payload=$(jq -n \
|
|
210
|
+
--arg query "$query" \
|
|
211
|
+
'{query: $query}')
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
local response
|
|
215
|
+
response=$(curl -sS --max-time 30 \
|
|
216
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
217
|
+
-H "Content-Type: application/json" \
|
|
218
|
+
-H "Accept: application/vnd.github+json" \
|
|
219
|
+
https://api.github.com/graphql \
|
|
220
|
+
-d "$payload")
|
|
221
|
+
|
|
222
|
+
# Check for GraphQL errors
|
|
223
|
+
local errors
|
|
224
|
+
errors=$(echo "$response" | jq -r '.errors // empty')
|
|
225
|
+
if [ -n "$errors" ]; then
|
|
226
|
+
echo "GraphQL error: $errors" >&2
|
|
227
|
+
return 1
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
echo "$response"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Fetches all repos with merge strategies for a given owner using GraphQL
|
|
234
|
+
# Uses repositoryOwner query with pagination
|
|
235
|
+
# Returns JSON array with repos and their merge strategy info
|
|
236
|
+
fetch_repos_with_strategies() {
|
|
237
|
+
local owner=$1
|
|
238
|
+
|
|
239
|
+
read -r -d '' QUERY <<'GRAPHQL'
|
|
240
|
+
query($login: String!, $first: Int!, $after: String) {
|
|
241
|
+
repositoryOwner(login: $login) {
|
|
242
|
+
repositories(first: $first, after: $after) {
|
|
243
|
+
pageInfo {
|
|
244
|
+
hasNextPage
|
|
245
|
+
endCursor
|
|
246
|
+
}
|
|
247
|
+
nodes {
|
|
248
|
+
name
|
|
249
|
+
owner {
|
|
250
|
+
login
|
|
251
|
+
}
|
|
252
|
+
mergeCommitAllowed
|
|
253
|
+
squashMergeAllowed
|
|
254
|
+
rebaseMergeAllowed
|
|
255
|
+
autoMergeAllowed
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
GRAPHQL
|
|
261
|
+
|
|
262
|
+
local all_repos="[]"
|
|
263
|
+
local after_cursor=""
|
|
264
|
+
local first=100
|
|
157
265
|
|
|
158
266
|
while true; do
|
|
159
|
-
# Check if we should exit
|
|
160
267
|
[ "$SHOULD_EXIT" -eq 1 ] && break
|
|
161
268
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
269
|
+
# Build variables JSON
|
|
270
|
+
local variables_json
|
|
271
|
+
if [ -n "$after_cursor" ]; then
|
|
272
|
+
variables_json=$(jq -n \
|
|
273
|
+
--arg login "$owner" \
|
|
274
|
+
--argjson first "$first" \
|
|
275
|
+
--arg after "$after_cursor" \
|
|
276
|
+
'{login: $login, first: $first, after: $after}')
|
|
277
|
+
else
|
|
278
|
+
variables_json=$(jq -n \
|
|
279
|
+
--arg login "$owner" \
|
|
280
|
+
--argjson first "$first" \
|
|
281
|
+
'{login: $login, first: $first}')
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
# Execute GraphQL query
|
|
285
|
+
local response
|
|
286
|
+
response=$(execute_graphql_query "$QUERY" "$variables_json")
|
|
287
|
+
if [ $? -ne 0 ]; then
|
|
288
|
+
return 1
|
|
289
|
+
fi
|
|
165
290
|
|
|
166
|
-
# Check if we should exit after curl
|
|
167
291
|
[ "$SHOULD_EXIT" -eq 1 ] && break
|
|
168
292
|
|
|
293
|
+
# Extract repos from response
|
|
294
|
+
local repos
|
|
295
|
+
repos=$(echo "$response" | jq '.data.repositoryOwner.repositories.nodes // []')
|
|
296
|
+
|
|
297
|
+
# Check if we got any repos
|
|
169
298
|
local repo_count
|
|
170
|
-
repo_count=$(echo "$
|
|
171
|
-
if [
|
|
299
|
+
repo_count=$(echo "$repos" | jq '. | length')
|
|
300
|
+
if [ "$repo_count" -eq 0 ]; then
|
|
172
301
|
break
|
|
173
302
|
fi
|
|
174
303
|
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
while IFS='|' read -r repo owner; do
|
|
178
|
-
[ "$SHOULD_EXIT" -eq 1 ] && break
|
|
179
|
-
process_repo "$repo" "$owner" || break
|
|
180
|
-
done < <(echo "$body" | jq -r '.[] | "\(.full_name)|\(.owner.login)"')
|
|
304
|
+
# Merge repos into all_repos
|
|
305
|
+
all_repos=$(echo "$all_repos" "$repos" | jq -s 'add')
|
|
181
306
|
|
|
182
|
-
|
|
307
|
+
# Check pagination info
|
|
308
|
+
local has_next_page
|
|
309
|
+
has_next_page=$(echo "$response" | jq -r '.data.repositoryOwner.repositories.pageInfo.hasNextPage')
|
|
310
|
+
after_cursor=$(echo "$response" | jq -r '.data.repositoryOwner.repositories.pageInfo.endCursor // ""')
|
|
183
311
|
|
|
184
|
-
if [ "$
|
|
312
|
+
if [ "$has_next_page" != "true" ] || [ -z "$after_cursor" ]; then
|
|
185
313
|
break
|
|
186
314
|
fi
|
|
187
|
-
|
|
188
|
-
page=$((page + 1))
|
|
189
315
|
done
|
|
316
|
+
|
|
317
|
+
echo "$all_repos"
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# Processes repos with their merge strategies
|
|
321
|
+
# Takes JSON array of repos with name, owner.login, and merge strategy flags
|
|
322
|
+
process_repos_with_strategies() {
|
|
323
|
+
local repos_json=$1
|
|
324
|
+
|
|
325
|
+
while IFS= read -r line; do
|
|
326
|
+
[ "$SHOULD_EXIT" -eq 1 ] && break
|
|
327
|
+
|
|
328
|
+
# Parse the line: full_name|owner|squash|merge|rebase
|
|
329
|
+
IFS='|' read -r repo owner allow_squash_merge allow_merge_commit allow_rebase_merge <<< "$line"
|
|
330
|
+
|
|
331
|
+
# Trim leading/trailing whitespace
|
|
332
|
+
repo=$(echo "$repo" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
333
|
+
owner=$(echo "$owner" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
334
|
+
allow_squash_merge=$(echo "$allow_squash_merge" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
335
|
+
allow_merge_commit=$(echo "$allow_merge_commit" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
336
|
+
allow_rebase_merge=$(echo "$allow_rebase_merge" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
337
|
+
|
|
338
|
+
process_repo "$repo" "$owner" "$allow_squash_merge" "$allow_merge_commit" "$allow_rebase_merge" || break
|
|
339
|
+
done < <(echo "$repos_json" | jq -r '.[] |
|
|
340
|
+
"\(.owner.login)/\(.name)|\(.owner.login)|\(
|
|
341
|
+
if .squashMergeAllowed == null then false else .squashMergeAllowed end
|
|
342
|
+
)|\(
|
|
343
|
+
if .mergeCommitAllowed == null then false else .mergeCommitAllowed end
|
|
344
|
+
)|\(
|
|
345
|
+
if .rebaseMergeAllowed == null then false else .rebaseMergeAllowed end
|
|
346
|
+
)"')
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
fetch_all_repos() {
|
|
350
|
+
# Fetch all repos with merge strategies using GraphQL
|
|
351
|
+
local repos_json
|
|
352
|
+
repos_json=$(fetch_repos_with_strategies "$GITHUB_USER")
|
|
353
|
+
if [ $? -ne 0 ]; then
|
|
354
|
+
echo "❌ Failed to fetch repos" >&2
|
|
355
|
+
return 1
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
if [ -z "$repos_json" ] || [ "$repos_json" = "[]" ]; then
|
|
359
|
+
echo "❌ No repos found" >&2
|
|
360
|
+
return 0
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
# Process repos with their merge strategies
|
|
364
|
+
process_repos_with_strategies "$repos_json"
|
|
190
365
|
}
|
|
191
366
|
|
|
192
367
|
is_number() {
|
|
@@ -212,9 +387,13 @@ parse_args() {
|
|
|
212
387
|
SLEEP_SECS="$2"
|
|
213
388
|
shift 2
|
|
214
389
|
;;
|
|
390
|
+
-f|--force)
|
|
391
|
+
FORCE_FLAG=1
|
|
392
|
+
shift
|
|
393
|
+
;;
|
|
215
394
|
*)
|
|
216
395
|
echo "❌ Error: Unknown option: $1"
|
|
217
|
-
echo "Usage: $0 [--sleep SECONDS]"
|
|
396
|
+
echo "Usage: $0 [--sleep SECONDS] [--force]"
|
|
218
397
|
exit 1
|
|
219
398
|
;;
|
|
220
399
|
esac
|
|
@@ -232,11 +411,17 @@ main() {
|
|
|
232
411
|
echo "0" > "$SUCCESS_COUNT_FILE"
|
|
233
412
|
echo "0" > "$SKIP_COUNT_FILE"
|
|
234
413
|
echo "0" > "$FAILED_COUNT_FILE"
|
|
414
|
+
echo "0" > "$ALREADY_SQUASH_ONLY_COUNT_FILE"
|
|
235
415
|
|
|
236
416
|
echo "Updating all your repos to Squash Only!"
|
|
237
417
|
echo "→ Disables merge commits"
|
|
238
418
|
echo "→ Disables rebase merges"
|
|
239
419
|
echo "→ Enables squash merges"
|
|
420
|
+
if [ "$FORCE_FLAG" -eq 1 ]; then
|
|
421
|
+
echo "→ Force mode: processing all repos (including already squash-only)"
|
|
422
|
+
else
|
|
423
|
+
echo "→ Skipping repos that are already squash-only (use --force to process all)"
|
|
424
|
+
fi
|
|
240
425
|
|
|
241
426
|
echo "→ Logging in to GitHub…"
|
|
242
427
|
GITHUB_TOKEN=$(get_github_token)
|
|
@@ -271,8 +456,14 @@ main() {
|
|
|
271
456
|
SUCCESS_COUNT=$(cat "$SUCCESS_COUNT_FILE")
|
|
272
457
|
SKIP_COUNT=$(cat "$SKIP_COUNT_FILE")
|
|
273
458
|
FAILED_COUNT=$(cat "$FAILED_COUNT_FILE")
|
|
459
|
+
ALREADY_SQUASH_ONLY_COUNT=$(cat "$ALREADY_SQUASH_ONLY_COUNT_FILE")
|
|
274
460
|
echo " ✅ Successfully updated: $SUCCESS_COUNT"
|
|
275
|
-
|
|
461
|
+
if [ "$ALREADY_SQUASH_ONLY_COUNT" -gt 0 ]; then
|
|
462
|
+
echo " ⏭️ Already squash-only (skipped): $ALREADY_SQUASH_ONLY_COUNT"
|
|
463
|
+
fi
|
|
464
|
+
if [ "$SKIP_COUNT" -gt 0 ]; then
|
|
465
|
+
echo " ⏭️ Skipped (not owned by you): $SKIP_COUNT"
|
|
466
|
+
fi
|
|
276
467
|
if [ "$FAILED_COUNT" -gt 0 ]; then
|
|
277
468
|
echo " ❌ Failed: $FAILED_COUNT"
|
|
278
469
|
fi
|