Compare commits
7 Commits
c7871397d3
...
v2.2.2
| Author | SHA1 | Date | |
|---|---|---|---|
| ac0b9b4ea3 | |||
| 427cc4c3f1 | |||
| 8776ccf2d2 | |||
| b82311829c | |||
| 9071e17d31 | |||
|
|
5f942bced4 | ||
|
|
4df4044f20 |
@@ -1,8 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Unreleased - REACHED the standalone repo
|
## 2.2.2
|
||||||
|
|
||||||
- Bidirectional sync smoke-test marker — forward leg (monorepo → subrepo), 2026-05-28.
|
### Fixes
|
||||||
|
|
||||||
|
- Forward sync no longer skips the entire action when the checked-out HEAD commit has the configured sync trailer. This allows valid multi-hop setups where one repo receives sync commits from an upstream repository and forwards its filtered subtree to another repository. Reverse sync still filters bot commits by trailer for loop prevention.
|
||||||
|
|
||||||
## 2.2.1
|
## 2.2.1
|
||||||
|
|
||||||
|
|||||||
14
action.yml
14
action.yml
@@ -38,21 +38,7 @@ runs:
|
|||||||
command -v "$cmd" &>/dev/null || { echo "::error::Missing required tool: $cmd"; exit 1; }
|
command -v "$cmd" &>/dev/null || { echo "::error::Missing required tool: $cmd"; exit 1; }
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Loop guard (forward)
|
|
||||||
id: guard
|
|
||||||
if: inputs.direction == 'forward' || inputs.direction == 'both'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
TRAILER=$(yq '.bot.trailer' "${{ inputs.config }}" 2>/dev/null || echo "Josh-Sync-Origin")
|
|
||||||
if git log -1 --format=%B | grep -q "^${TRAILER}:"; then
|
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "::notice::Skipping sync — HEAD commit has sync trailer (loop prevention)"
|
|
||||||
else
|
|
||||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Sync
|
- name: Sync
|
||||||
if: steps.guard.outputs.skip != 'true'
|
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
JOSH_SYNC_DEBUG: ${{ inputs.debug == 'true' && '1' || '0' }}
|
JOSH_SYNC_DEBUG: ${{ inputs.debug == 'true' && '1' || '0' }}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Bidirectional sync creates an infinite loop risk: forward sync pushes commit A t
|
|||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
All bot commits include a git trailer with a configurable key (default: `Josh-Sync-Origin`). Both sync directions filter out commits containing this trailer.
|
All bot commits include a git trailer with a configurable key (default: `Josh-Sync-Origin`). Reverse sync filters out commits containing this trailer so bot-generated forward-sync commits are not proposed back to the monorepo.
|
||||||
|
|
||||||
### Format
|
### Format
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ The trailer value encodes: direction, branch, and timestamp. This aids debugging
|
|||||||
### Filtering
|
### Filtering
|
||||||
|
|
||||||
- **Reverse sync**: `git log --invert-grep --grep="^${BOT_TRAILER}:"` excludes all commits with the trailer
|
- **Reverse sync**: `git log --invert-grep --grep="^${BOT_TRAILER}:"` excludes all commits with the trailer
|
||||||
- **CI loop guard**: The composite action checks if HEAD commit has the trailer before running sync at all
|
- **Forward sync**: the composite action still runs even when HEAD has the trailer; forward sync uses tree comparison, sync state, and merge checks to decide whether to push
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ The trailer key is set in `.josh-sync.yml` under `bot.trailer`. This allows mult
|
|||||||
- Reliable loop prevention — trailer is part of the immutable commit object
|
- Reliable loop prevention — trailer is part of the immutable commit object
|
||||||
- Configurable key avoids conflicts between multiple sync bots
|
- Configurable key avoids conflicts between multiple sync bots
|
||||||
- Human-readable — `git log` shows the trailer in commit messages
|
- Human-readable — `git log` shows the trailer in commit messages
|
||||||
- CI loop guard prevents unnecessary sync runs entirely
|
- Repositories can act as middle hops, receiving a sync commit from one relationship and forwarding relevant changes to another
|
||||||
|
|
||||||
**Negative:**
|
**Negative:**
|
||||||
- Commits with manually-added trailers matching the key would be incorrectly filtered
|
- Commits with manually-added trailers matching the key would be incorrectly filtered
|
||||||
|
|||||||
@@ -554,7 +554,9 @@ Runs on a cron schedule (never triggered by subrepo pushes):
|
|||||||
|
|
||||||
### Loop prevention
|
### Loop prevention
|
||||||
|
|
||||||
Bot commits include a git trailer like `Josh-Sync-Origin: forward/main/2024-02-12T10:30:00Z`. Each sync direction filters out commits with this trailer, preventing changes from bouncing back and forth. The CI action also has a loop guard that skips entirely if the HEAD commit has the trailer.
|
Bot commits include a git trailer like `Josh-Sync-Origin: forward/main/2024-02-12T10:30:00Z`. Reverse sync filters out commits with this trailer, preventing changes from bouncing back from the target repo into the source repo.
|
||||||
|
|
||||||
|
The CI action does not skip forward sync solely because the checked-out HEAD commit has a sync trailer. A repo can be a valid middle hop: it may receive a sync commit from one repository and still need to forward its filtered subtree to another repository. Forward sync relies on tree comparison, sync state, and merge checks to decide whether anything should be pushed.
|
||||||
|
|
||||||
### State tracking
|
### State tracking
|
||||||
|
|
||||||
|
|||||||
17
tests/unit/action.bats
Normal file
17
tests/unit/action.bats
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
# tests/unit/action.bats — Composite action regression tests
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
JOSH_SYNC_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)"
|
||||||
|
ACTION_FILE="${JOSH_SYNC_ROOT}/action.yml"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "forward sync is not globally skipped when HEAD has the sync trailer" {
|
||||||
|
! grep -q "Loop guard (forward)" "$ACTION_FILE"
|
||||||
|
! grep -q "HEAD commit has sync trailer" "$ACTION_FILE"
|
||||||
|
! grep -q "steps.guard.outputs.skip" "$ACTION_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "composite action still invokes the josh-sync CLI" {
|
||||||
|
grep -q "josh-sync sync" "$ACTION_FILE"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user