mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 11:45:20 +02:00
feat: multi-platform BASE_BRANCH_DETECT (GitHub + GitLab + GHE + git-native)
Update the shared BASE_BRANCH_DETECT resolver to support GitHub, GitLab, GitHub Enterprise, self-hosted GitLab, and a git-native fallback chain. Platform detection uses remote URL matching plus CLI auth status for custom domains. Add glab issue create alternative in test failure triage. Add 7 new test assertions covering GitLab CLI presence, git symbolic-ref fallback, and platform-specific output in retro and ship generated files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -222,14 +222,22 @@ Use AskUserQuestion:
|
||||
git log --format="%an (%ae)" -1 -- <source-file-under-test>
|
||||
\`\`\`
|
||||
If these are different people, prefer the production code author — they likely introduced the regression.
|
||||
- Create a GitHub issue assigned to that person:
|
||||
\`\`\`bash
|
||||
gh issue create \\
|
||||
--title "Pre-existing test failure: <test-name>" \\
|
||||
--body "Found failing on branch <current-branch>. Failure is pre-existing.\\n\\n**Error:**\\n\`\`\`\\n<first 10 lines>\\n\`\`\`\\n\\n**Last modified by:** <author>\\n**Noticed by:** gstack /ship on <date>" \\
|
||||
--assignee "<github-username>"
|
||||
\`\`\`
|
||||
- If \`gh\` is not available or \`--assignee\` fails (user not in org, etc.), create the issue without assignee and note who should look at it in the body.
|
||||
- Create an issue assigned to that person (use the platform detected in Step 0):
|
||||
- **If GitHub:**
|
||||
\`\`\`bash
|
||||
gh issue create \\
|
||||
--title "Pre-existing test failure: <test-name>" \\
|
||||
--body "Found failing on branch <current-branch>. Failure is pre-existing.\\n\\n**Error:**\\n\`\`\`\\n<first 10 lines>\\n\`\`\`\\n\\n**Last modified by:** <author>\\n**Noticed by:** gstack /ship on <date>" \\
|
||||
--assignee "<github-username>"
|
||||
\`\`\`
|
||||
- **If GitLab:**
|
||||
\`\`\`bash
|
||||
glab issue create \\
|
||||
-t "Pre-existing test failure: <test-name>" \\
|
||||
-d "Found failing on branch <current-branch>. Failure is pre-existing.\\n\\n**Error:**\\n\`\`\`\\n<first 10 lines>\\n\`\`\`\\n\\n**Last modified by:** <author>\\n**Noticed by:** gstack /ship on <date>" \\
|
||||
-a "<gitlab-username>"
|
||||
\`\`\`
|
||||
- If neither CLI is available or \`--assignee\`/\`-a\` fails (user not in org, etc.), create the issue without assignee and note who should look at it in the body.
|
||||
- Continue with the workflow.
|
||||
|
||||
**If "Skip":**
|
||||
|
||||
@@ -9,22 +9,42 @@ export function generateSlugSetup(ctx: TemplateContext): string {
|
||||
}
|
||||
|
||||
export function generateBaseBranchDetect(_ctx: TemplateContext): string {
|
||||
return `## Step 0: Detect base branch
|
||||
return `## Step 0: Detect platform and base branch
|
||||
|
||||
Determine which branch this PR targets. Use the result as "the base branch" in all subsequent steps.
|
||||
First, detect the git hosting platform from the remote URL:
|
||||
|
||||
1. Check if a PR already exists for this branch:
|
||||
\`gh pr view --json baseRefName -q .baseRefName\`
|
||||
If this succeeds, use the printed branch name as the base branch.
|
||||
\`\`\`bash
|
||||
git remote get-url origin 2>/dev/null
|
||||
\`\`\`
|
||||
|
||||
2. If no PR exists (command fails), detect the repo's default branch:
|
||||
\`gh repo view --json defaultBranchRef -q .defaultBranchRef.name\`
|
||||
- If the URL contains "github.com" → platform is **GitHub**
|
||||
- If the URL contains "gitlab" → platform is **GitLab**
|
||||
- Otherwise, check CLI availability:
|
||||
- \`gh auth status 2>/dev/null\` succeeds → platform is **GitHub** (covers GitHub Enterprise)
|
||||
- \`glab auth status 2>/dev/null\` succeeds → platform is **GitLab** (covers self-hosted)
|
||||
- Neither → **unknown** (use git-native commands only)
|
||||
|
||||
3. If both commands fail, fall back to \`main\`.
|
||||
Determine which branch this PR/MR targets, or the repo's default branch if no
|
||||
PR/MR exists. Use the result as "the base branch" in all subsequent steps.
|
||||
|
||||
**If GitHub:**
|
||||
1. \`gh pr view --json baseRefName -q .baseRefName\` — if succeeds, use it
|
||||
2. \`gh repo view --json defaultBranchRef -q .defaultBranchRef.name\` — if succeeds, use it
|
||||
|
||||
**If GitLab:**
|
||||
1. \`glab mr view -F json 2>/dev/null\` and extract the \`target_branch\` field — if succeeds, use it
|
||||
2. \`glab repo view -F json 2>/dev/null\` and extract the \`default_branch\` field — if succeeds, use it
|
||||
|
||||
**Git-native fallback (if unknown platform, or CLI commands fail):**
|
||||
1. \`git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'\`
|
||||
2. If that fails: \`git rev-parse --verify origin/main 2>/dev/null\` → use \`main\`
|
||||
3. If that fails: \`git rev-parse --verify origin/master 2>/dev/null\` → use \`master\`
|
||||
|
||||
If all fail, fall back to \`main\`.
|
||||
|
||||
Print the detected base branch name. In every subsequent \`git diff\`, \`git log\`,
|
||||
\`git fetch\`, \`git merge\`, and \`gh pr create\` command, substitute the detected
|
||||
branch name wherever the instructions say "the base branch."
|
||||
\`git fetch\`, \`git merge\`, and PR/MR creation command, substitute the detected
|
||||
branch name wherever the instructions say "the base branch" or \`<default>\`.
|
||||
|
||||
---`;
|
||||
}
|
||||
|
||||
@@ -333,6 +333,39 @@ describe('BASE_BRANCH_DETECT resolver', () => {
|
||||
test('resolver output uses "the base branch" phrasing', () => {
|
||||
expect(shipContent).toContain('the base branch');
|
||||
});
|
||||
|
||||
test('resolver output contains GitLab CLI commands', () => {
|
||||
expect(shipContent).toContain('glab');
|
||||
});
|
||||
|
||||
test('resolver output contains git-native fallback', () => {
|
||||
expect(shipContent).toContain('git symbolic-ref');
|
||||
});
|
||||
|
||||
test('resolver output mentions GitLab platform', () => {
|
||||
expect(shipContent).toMatch(/gitlab/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GitLab support in generated skills', () => {
|
||||
const retroContent = fs.readFileSync(path.join(ROOT, 'retro', 'SKILL.md'), 'utf-8');
|
||||
const shipSkillContent = fs.readFileSync(path.join(ROOT, 'ship', 'SKILL.md'), 'utf-8');
|
||||
|
||||
test('retro contains GitLab MR number extraction', () => {
|
||||
expect(retroContent).toContain('[#!]');
|
||||
});
|
||||
|
||||
test('retro uses BASE_BRANCH_DETECT (contains glab)', () => {
|
||||
expect(retroContent).toContain('glab');
|
||||
});
|
||||
|
||||
test('ship contains glab mr create', () => {
|
||||
expect(shipSkillContent).toContain('glab mr create');
|
||||
});
|
||||
|
||||
test('ship checks .gitlab-ci.yml', () => {
|
||||
expect(shipSkillContent).toContain('.gitlab-ci.yml');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user