Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
name: CI
run-name: >-
${{ github.event_name == 'pull_request' && format('PR-CI #{0}', github.event.pull_request.number)
|| github.event_name == 'merge_group' && 'MergeQueue-CI'
|| github.event_name == 'push' && 'Main-CI'
|| 'CI' }}

on:
push:
Expand Down Expand Up @@ -141,9 +146,16 @@ jobs:

# ---------------------------------------------------------------------------
# REQUIRED CHECKS GATE
#
# Fan-in aggregator that must turn RED when any required job fails or is
# cancelled. `if: always()` is critical: without it, this job is skipped
# when any `needs` dependency fails, and GitHub treats a skipped required
# status check as "not failed" — which let PR #151 merge through the
# merge queue despite failing e2e + orchestrator integration tests.
# ---------------------------------------------------------------------------
required-checks:
name: Required Checks
if: always()
runs-on: ubuntu-latest
needs:
- lint
Expand All @@ -157,6 +169,12 @@ jobs:
- storage-integration-test
- consumer-integration-test
steps:
- name: All required checks passed
- name: Fail if any required check did not succeed
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}
run: |
echo "All required checks passed!" >&2
echo "One or more required checks did not succeed:" >&2
echo '${{ toJSON(needs) }}' >&2
exit 1

- name: All required checks passed
run: echo "All required checks passed!"
25 changes: 21 additions & 4 deletions example/server/orchestrator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,13 +606,18 @@ func newChangeProvider(logger *zap.Logger, scope tally.Scope) (changeprovider.Ch
}

// newPusher creates a git-backed Pusher bound to the configured checkout
// path, remote, and target branch. Configured via PUSHER_CHECKOUT_PATH
// (required), PUSHER_REMOTE (default "origin"), and PUSHER_TARGET (default
// "main").
// path, remote, and target branch. Configured via PUSHER_CHECKOUT_PATH,
// PUSHER_REMOTE (default "origin"), and PUSHER_TARGET (default "main").
//
// If PUSHER_CHECKOUT_PATH is not set the orchestrator falls back to a
// no-op pusher that errors when invoked. This keeps the example server
// runnable in environments that don't exercise the merge controller
// (e.g. ping-only integration tests, local dev without a git checkout).
func newPusher(logger *zap.Logger, scope tally.Scope) (pusher.Pusher, error) {
checkout := os.Getenv("PUSHER_CHECKOUT_PATH")
if checkout == "" {
return nil, fmt.Errorf("PUSHER_CHECKOUT_PATH environment variable is required")
logger.Warn("PUSHER_CHECKOUT_PATH not set; using no-op pusher (merge controller will fail if invoked)")
return noopPusher{}, nil
}
return gitpusher.NewPusher(gitpusher.Params{
CheckoutPath: checkout,
Expand All @@ -622,3 +627,15 @@ func newPusher(logger *zap.Logger, scope tally.Scope) (pusher.Pusher, error) {
MetricsScope: scope.SubScope("pusher"),
}), nil
}

// noopPusher is a fallback Pusher used when PUSHER_CHECKOUT_PATH is not
// configured. It returns an error on every Push so the merge controller
// (which treats non-ErrConflict errors as transient and nacks the message)
// will not silently report success. It exists so the orchestrator can
// still start up — and serve Ping / accept enqueues — in environments
// that don't run the merge step.
type noopPusher struct{}

func (noopPusher) Push(_ context.Context, _ []entity.Change) (pusher.Result, error) {
return pusher.Result{}, fmt.Errorf("pusher not configured: set PUSHER_CHECKOUT_PATH to enable pushing")
}
Loading