mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
chore: add workflow files to git tracking
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -90,8 +90,6 @@ pnpm-lock.yaml
|
||||
yarn.lock
|
||||
|
||||
# Fork-specific workflow files (should never be committed)
|
||||
DEVELOPMENT_WORKFLOW.md
|
||||
check-sync.sh
|
||||
# API key files
|
||||
data/.api-key
|
||||
data/credentials.json
|
||||
|
||||
253
DEVELOPMENT_WORKFLOW.md
Normal file
253
DEVELOPMENT_WORKFLOW.md
Normal file
@@ -0,0 +1,253 @@
|
||||
# Development Workflow
|
||||
|
||||
This document defines the standard workflow for keeping a branch in sync with the upstream
|
||||
release candidate (RC) and for shipping feature work. It is paired with `check-sync.sh`.
|
||||
|
||||
## Quick Decision Rule
|
||||
|
||||
1. Ask the user to select a workflow:
|
||||
- **Sync Workflow** → you are maintaining the current RC branch with fixes/improvements
|
||||
and will push the same fixes to both origin and upstream RC when you have local
|
||||
commits to publish.
|
||||
- **PR Workflow** → you are starting new feature work on a new branch; upstream updates
|
||||
happen via PR only.
|
||||
2. After the user selects, run:
|
||||
```bash
|
||||
./check-sync.sh
|
||||
```
|
||||
3. Use the status output to confirm alignment. If it reports **diverged**, default to
|
||||
merging `upstream/<TARGET_RC>` into the current branch and preserving local commits.
|
||||
For Sync Workflow, when the working tree is clean and you are behind upstream RC,
|
||||
proceed with the fetch + merge without asking for additional confirmation.
|
||||
|
||||
## Target RC Resolution
|
||||
|
||||
The target RC is resolved dynamically so the workflow stays current as the RC changes.
|
||||
|
||||
Resolution order:
|
||||
|
||||
1. Latest `upstream/v*rc` branch (auto-detected)
|
||||
2. `upstream/HEAD` (fallback)
|
||||
3. If neither is available, you must pass `--rc <branch>`
|
||||
|
||||
Override for a single run:
|
||||
|
||||
```bash
|
||||
./check-sync.sh --rc <rc-branch>
|
||||
```
|
||||
|
||||
## Pre-Flight Checklist
|
||||
|
||||
1. Confirm a clean working tree:
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
2. Confirm the current branch:
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
3. Ensure remotes exist (origin + upstream):
|
||||
```bash
|
||||
git remote -v
|
||||
```
|
||||
|
||||
## Sync Workflow (Upstream Sync)
|
||||
|
||||
Use this flow when you are updating the current branch with fixes or improvements and
|
||||
intend to keep origin and upstream RC in lockstep.
|
||||
|
||||
1. **Check sync status**
|
||||
```bash
|
||||
./check-sync.sh
|
||||
```
|
||||
2. **Update from upstream RC before editing (no pulls)**
|
||||
- **Behind upstream RC** → fetch and merge RC into your branch:
|
||||
```bash
|
||||
git fetch upstream
|
||||
git merge upstream/<TARGET_RC> --no-edit
|
||||
```
|
||||
When the working tree is clean and the user selected Sync Workflow, proceed without
|
||||
an extra confirmation prompt.
|
||||
- **Diverged** → stop and resolve manually.
|
||||
3. **Resolve conflicts if needed**
|
||||
- Handle conflicts intelligently: preserve upstream behavior and your local intent.
|
||||
4. **Make changes and commit (if you are delivering fixes)**
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "type: description"
|
||||
```
|
||||
5. **Build to verify**
|
||||
```bash
|
||||
npm run build:packages
|
||||
npm run build
|
||||
```
|
||||
6. **Push after a successful merge to keep remotes aligned**
|
||||
- If you only merged upstream RC changes, push **origin only** to sync your fork:
|
||||
```bash
|
||||
git push origin <branch>
|
||||
```
|
||||
- If you have local fixes to publish, push **origin + upstream**:
|
||||
```bash
|
||||
git push origin <branch>
|
||||
git push upstream <branch>:<TARGET_RC>
|
||||
```
|
||||
- Always ask the user which push to perform.
|
||||
- Origin (origin-only sync):
|
||||
```bash
|
||||
git push origin <branch>
|
||||
```
|
||||
- Upstream RC (publish the same fixes when you have local commits):
|
||||
```bash
|
||||
git push upstream <branch>:<TARGET_RC>
|
||||
```
|
||||
7. **Re-check sync**
|
||||
```bash
|
||||
./check-sync.sh
|
||||
```
|
||||
|
||||
## PR Workflow (Feature Work)
|
||||
|
||||
Use this flow only for new feature work on a new branch. Do not push to upstream RC.
|
||||
|
||||
1. **Create or switch to a feature branch**
|
||||
```bash
|
||||
git checkout -b <branch>
|
||||
```
|
||||
2. **Make changes and commit**
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "type: description"
|
||||
```
|
||||
3. **Merge upstream RC before shipping**
|
||||
```bash
|
||||
git merge upstream/<TARGET_RC> --no-edit
|
||||
```
|
||||
4. **Build and/or test**
|
||||
```bash
|
||||
npm run build:packages
|
||||
npm run build
|
||||
```
|
||||
5. **Push to origin**
|
||||
```bash
|
||||
git push -u origin <branch>
|
||||
```
|
||||
6. **Create or update the PR**
|
||||
- Use `gh pr create` or the GitHub UI.
|
||||
7. **Review and follow-up**
|
||||
|
||||
- Apply feedback, commit changes, and push again.
|
||||
- Re-run `./check-sync.sh` if additional upstream sync is needed.
|
||||
|
||||
## Conflict Resolution Checklist
|
||||
|
||||
1. Identify which changes are from upstream vs. local.
|
||||
2. Preserve both behaviors where possible; avoid dropping either side.
|
||||
3. Prefer minimal, safe integrations over refactors.
|
||||
4. Re-run build commands after resolving conflicts.
|
||||
5. Re-run `./check-sync.sh` to confirm status.
|
||||
|
||||
## Build/Test Matrix
|
||||
|
||||
- **Sync Workflow**: `npm run build:packages` and `npm run build`.
|
||||
- **PR Workflow**: `npm run build:packages` and `npm run build` (plus relevant tests).
|
||||
|
||||
## Post-Sync Verification
|
||||
|
||||
1. `git status` should be clean.
|
||||
2. `./check-sync.sh` should show expected alignment.
|
||||
3. Verify recent commits with:
|
||||
```bash
|
||||
git log --oneline -5
|
||||
```
|
||||
|
||||
## check-sync.sh Usage
|
||||
|
||||
- Uses dynamic Target RC resolution (see above).
|
||||
- Override target RC:
|
||||
```bash
|
||||
./check-sync.sh --rc <rc-branch>
|
||||
```
|
||||
- Optional preview limit:
|
||||
```bash
|
||||
./check-sync.sh --preview 10
|
||||
```
|
||||
- The script prints sync status for both origin and upstream and previews recent commits
|
||||
when you are behind.
|
||||
|
||||
## Stop Conditions
|
||||
|
||||
Stop and ask for guidance if any of the following are true:
|
||||
|
||||
- The working tree is dirty and you are about to merge or push.
|
||||
- `./check-sync.sh` reports **diverged** during PR Workflow, or a merge cannot be completed.
|
||||
- The script cannot resolve a target RC and requests `--rc`.
|
||||
- A build fails after sync or conflict resolution.
|
||||
|
||||
## AI Agent Guardrails
|
||||
|
||||
- Always run `./check-sync.sh` before merges or pushes.
|
||||
- Always ask for explicit user approval before any push command.
|
||||
- Do not ask for additional confirmation before a Sync Workflow fetch + merge when the
|
||||
working tree is clean and the user has already selected the Sync Workflow.
|
||||
- Choose Sync vs PR workflow based on intent (RC maintenance vs new feature work), not
|
||||
on the script's workflow hint.
|
||||
- Only use force push when the user explicitly requests a history rewrite.
|
||||
- Ask for explicit approval before dependency installs, branch deletion, or destructive operations.
|
||||
- When resolving merge conflicts, preserve both upstream changes and local intent where possible.
|
||||
- Do not create or switch to new branches unless the user explicitly requests it.
|
||||
|
||||
## AI Agent Decision Guidance
|
||||
|
||||
Agents should provide concrete, task-specific suggestions instead of repeatedly asking
|
||||
open-ended questions. Use the user's stated goal and the `./check-sync.sh` status to
|
||||
propose a default path plus one or two alternatives, and only ask for confirmation when
|
||||
an action requires explicit approval.
|
||||
|
||||
Default behavior:
|
||||
|
||||
- If the intent is RC maintenance, recommend the Sync Workflow and proceed with
|
||||
safe preparation steps (status checks, previews). If the branch is behind upstream RC,
|
||||
fetch and merge without additional confirmation when the working tree is clean, then
|
||||
push to origin to keep the fork aligned. Push upstream only when there are local fixes
|
||||
to publish.
|
||||
- If the intent is new feature work, recommend the PR Workflow and proceed with safe
|
||||
preparation steps (status checks, identifying scope). Ask for approval before merges,
|
||||
pushes, or dependency installs.
|
||||
- If `./check-sync.sh` reports **diverged** during Sync Workflow, merge
|
||||
`upstream/<TARGET_RC>` into the current branch and preserve local commits.
|
||||
- If `./check-sync.sh` reports **diverged** during PR Workflow, stop and ask for guidance
|
||||
with a short explanation of the divergence and the minimal options to resolve it.
|
||||
If the user's intent is RC maintenance, prefer the Sync Workflow regardless of the
|
||||
script hint. When the intent is new feature work, use the PR Workflow and avoid upstream
|
||||
RC pushes.
|
||||
|
||||
Suggestion format (keep it short):
|
||||
|
||||
- **Recommended**: one sentence with the default path and why it fits the task.
|
||||
- **Alternatives**: one or two options with the tradeoff or prerequisite.
|
||||
- **Approval points**: mention any upcoming actions that need explicit approval (exclude sync
|
||||
workflow pushes and merges).
|
||||
|
||||
## Failure Modes and How to Avoid Them
|
||||
|
||||
Sync Workflow:
|
||||
|
||||
- Wrong RC target: verify the auto-detected RC in `./check-sync.sh` output before merging.
|
||||
- Diverged from upstream RC: stop and resolve manually before any merge or push.
|
||||
- Dirty working tree: commit or stash before syncing to avoid accidental merges.
|
||||
- Missing remotes: ensure both `origin` and `upstream` are configured before syncing.
|
||||
- Build breaks after sync: run `npm run build:packages` and `npm run build` before pushing.
|
||||
|
||||
PR Workflow:
|
||||
|
||||
- Branch not synced to current RC: re-run `./check-sync.sh` and merge RC before shipping.
|
||||
- Pushing the wrong branch: confirm `git branch --show-current` before pushing.
|
||||
- Unreviewed changes: always commit and push to origin before opening or updating a PR.
|
||||
- Skipped tests/builds: run the build commands before declaring the PR ready.
|
||||
|
||||
## Notes
|
||||
|
||||
- Avoid merging with uncommitted changes; commit or stash first.
|
||||
- Prefer merge over rebase for PR branches; rebases rewrite history and often require a force push,
|
||||
which should only be done with an explicit user request.
|
||||
- Use clear, conventional commit messages and split unrelated changes into separate commits.
|
||||
215
check-sync.sh
Executable file
215
check-sync.sh
Executable file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
DEFAULT_RC_PATTERN="v*rc"
|
||||
DEFAULT_PREVIEW_COUNT=5
|
||||
|
||||
PREVIEW_COUNT="${PREVIEW_COUNT:-$DEFAULT_PREVIEW_COUNT}"
|
||||
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||
|
||||
ORIGIN_REF="origin/${CURRENT_BRANCH}"
|
||||
TARGET_RC_SOURCE="auto"
|
||||
|
||||
print_header() {
|
||||
echo "=== Sync Status Check ==="
|
||||
echo
|
||||
printf "Target RC: %s (%s)\n" "$TARGET_RC" "$TARGET_RC_SOURCE"
|
||||
echo
|
||||
}
|
||||
|
||||
ensure_git_repo() {
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "Not inside a git repository."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_remote() {
|
||||
local remote="$1"
|
||||
if ! git remote get-url "$remote" >/dev/null 2>&1; then
|
||||
echo "Remote '$remote' is not configured."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fetch_remote() {
|
||||
local remote="$1"
|
||||
git fetch --quiet "$remote"
|
||||
}
|
||||
|
||||
warn_if_dirty() {
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
echo "Warning: working tree has uncommitted changes."
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_target_rc() {
|
||||
if [[ -n "${TARGET_RC:-}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local rc_candidates
|
||||
rc_candidates="$(git for-each-ref --format='%(refname:short)' "refs/remotes/upstream/${DEFAULT_RC_PATTERN}" || true)"
|
||||
if [[ -n "$rc_candidates" ]]; then
|
||||
TARGET_RC="$(printf "%s\n" "$rc_candidates" | sed 's|^upstream/||' | sort -V | tail -n 1)"
|
||||
TARGET_RC_SOURCE="auto:latest"
|
||||
return
|
||||
fi
|
||||
|
||||
local upstream_head
|
||||
upstream_head="$(git symbolic-ref --quiet --short refs/remotes/upstream/HEAD 2>/dev/null || true)"
|
||||
if [[ -n "$upstream_head" ]]; then
|
||||
TARGET_RC="${upstream_head#upstream/}"
|
||||
TARGET_RC_SOURCE="auto:upstream-head"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Unable to resolve target RC automatically. Use --rc <branch>."
|
||||
exit 1
|
||||
}
|
||||
|
||||
ref_exists() {
|
||||
local ref="$1"
|
||||
git show-ref --verify --quiet "refs/remotes/${ref}"
|
||||
}
|
||||
|
||||
print_status_line() {
|
||||
local label="$1"
|
||||
local behind="$2"
|
||||
local ahead="$3"
|
||||
|
||||
if [[ "$behind" -eq 0 && "$ahead" -eq 0 ]]; then
|
||||
printf "✅ %s: in sync (behind %s, ahead %s)\n" "$label" "$behind" "$ahead"
|
||||
elif [[ "$behind" -eq 0 ]]; then
|
||||
printf "⬆️ %s: ahead %s (behind %s)\n" "$label" "$ahead" "$behind"
|
||||
elif [[ "$ahead" -eq 0 ]]; then
|
||||
printf "⬇️ %s: behind %s (ahead %s)\n" "$label" "$behind" "$ahead"
|
||||
else
|
||||
printf "⚠️ %s: %s behind, %s ahead (diverged)\n" "$label" "$behind" "$ahead"
|
||||
fi
|
||||
}
|
||||
|
||||
print_preview() {
|
||||
local title="$1"
|
||||
local range="$2"
|
||||
|
||||
echo
|
||||
echo "$title"
|
||||
git log --oneline -n "$PREVIEW_COUNT" "$range"
|
||||
}
|
||||
|
||||
print_branch_context() {
|
||||
echo "Branch: $CURRENT_BRANCH"
|
||||
echo "Upstream RC: $UPSTREAM_REF"
|
||||
echo "Upstream push: enabled for sync workflow"
|
||||
echo
|
||||
}
|
||||
|
||||
print_upstream_summary() {
|
||||
local behind="$1"
|
||||
local ahead="$2"
|
||||
|
||||
if [[ "$behind" -eq 0 && "$ahead" -eq 0 ]]; then
|
||||
echo "Branch vs upstream RC: in sync (behind $behind, ahead $ahead)"
|
||||
else
|
||||
echo "Branch vs upstream RC: behind $behind, ahead $ahead"
|
||||
fi
|
||||
}
|
||||
|
||||
print_workflow_hint() {
|
||||
local behind="$1"
|
||||
local ahead="$2"
|
||||
|
||||
if [[ "$behind" -eq 0 && "$ahead" -eq 0 ]]; then
|
||||
echo "Workflow: sync"
|
||||
elif [[ "$behind" -gt 0 && "$ahead" -eq 0 ]]; then
|
||||
echo "Workflow: sync (merge upstream RC)"
|
||||
elif [[ "$ahead" -gt 0 && "$behind" -eq 0 ]]; then
|
||||
echo "Workflow: pr (local work not in upstream)"
|
||||
else
|
||||
echo "Workflow: diverged (resolve manually)"
|
||||
fi
|
||||
}
|
||||
|
||||
print_usage() {
|
||||
echo "Usage: ./check-sync.sh [--rc <branch>] [--preview <count>]"
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--rc)
|
||||
shift
|
||||
if [[ -z "${1-}" ]]; then
|
||||
echo "Missing value for --rc"
|
||||
exit 1
|
||||
fi
|
||||
TARGET_RC="$1"
|
||||
TARGET_RC_SOURCE="flag"
|
||||
;;
|
||||
--preview)
|
||||
shift
|
||||
if [[ -z "${1-}" ]]; then
|
||||
echo "Missing value for --preview"
|
||||
exit 1
|
||||
fi
|
||||
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid preview count: $1"
|
||||
exit 1
|
||||
fi
|
||||
PREVIEW_COUNT="$1"
|
||||
;;
|
||||
-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
ensure_git_repo
|
||||
ensure_remote origin
|
||||
ensure_remote upstream
|
||||
parse_args "$@"
|
||||
|
||||
fetch_remote origin
|
||||
fetch_remote upstream
|
||||
resolve_target_rc
|
||||
|
||||
UPSTREAM_REF="upstream/${TARGET_RC}"
|
||||
|
||||
print_header
|
||||
warn_if_dirty
|
||||
print_branch_context
|
||||
|
||||
if ! ref_exists "$ORIGIN_REF"; then
|
||||
echo "Origin branch '$ORIGIN_REF' does not exist."
|
||||
else
|
||||
read -r origin_behind origin_ahead < <(git rev-list --left-right --count "$ORIGIN_REF...HEAD")
|
||||
print_status_line "Origin" "$origin_behind" "$origin_ahead"
|
||||
fi
|
||||
|
||||
if ! ref_exists "$UPSTREAM_REF"; then
|
||||
echo "Upstream ref '$UPSTREAM_REF' does not exist."
|
||||
else
|
||||
read -r upstream_behind upstream_ahead < <(git rev-list --left-right --count "$UPSTREAM_REF...HEAD")
|
||||
print_status_line "Upstream" "$upstream_behind" "$upstream_ahead"
|
||||
echo
|
||||
print_upstream_summary "$upstream_behind" "$upstream_ahead"
|
||||
print_workflow_hint "$upstream_behind" "$upstream_ahead"
|
||||
|
||||
if [[ "$upstream_behind" -gt 0 ]]; then
|
||||
print_preview "Recent upstream commits:" "HEAD..$UPSTREAM_REF"
|
||||
fi
|
||||
|
||||
if [[ "$upstream_ahead" -gt 0 ]]; then
|
||||
print_preview "Commits on this branch not in upstream:" "$UPSTREAM_REF..HEAD"
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user