mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-29 22:02:02 +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
|
yarn.lock
|
||||||
|
|
||||||
# Fork-specific workflow files (should never be committed)
|
# Fork-specific workflow files (should never be committed)
|
||||||
DEVELOPMENT_WORKFLOW.md
|
|
||||||
check-sync.sh
|
|
||||||
# API key files
|
# API key files
|
||||||
data/.api-key
|
data/.api-key
|
||||||
data/credentials.json
|
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