Add github checks status to branch header

- more work needed on when to request and how often to update
This commit is contained in:
Mattias Granlund 2024-02-04 19:09:08 +01:00
parent a34f766dac
commit 0c63a1b7cf
5 changed files with 75 additions and 13 deletions

View File

@ -83,6 +83,10 @@ export class BranchService {
createPrSpan.finish();
}
}
async reloadVirtualBranches() {
await this.vbranchService.reload();
}
}
function mergeBranchesAndPrs(

View File

@ -141,6 +141,7 @@
{branch}
{base}
{githubService}
{branchService}
projectId={project.id}
on:action={(e) => {
if (e.detail == 'generate-branch-name') {

View File

@ -4,37 +4,63 @@
import Tag from './Tag.svelte';
import { clickOutside } from '$lib/clickOutside';
import Button from '$lib/components/Button.svelte';
import Icon from '$lib/components/Icon.svelte';
import Icon, { type IconColor } from '$lib/components/Icon.svelte';
import { normalizeBranchName } from '$lib/utils/branch';
import * as toasts from '$lib/utils/toasts';
import { tooltip } from '$lib/utils/tooltip';
import { open } from '@tauri-apps/api/shell';
import toast from 'svelte-french-toast';
import type { BranchService } from '$lib/branches/service';
import type { GitHubService } from '$lib/github/service';
import type { PrStatus } from '$lib/github/types';
import type { BranchController } from '$lib/vbranches/branchController';
import type { BaseBranch, Branch } from '$lib/vbranches/types';
import type iconsJson from '../icons/icons.json';
import { goto } from '$app/navigation';
export let isUnapplied = false;
export let branch: Branch;
export let base: BaseBranch | undefined | null;
export let branchController: BranchController;
export let branchService: BranchService;
export let projectId: string;
export let githubService: GitHubService;
$: pr$ = githubService.get(branch.upstreamName);
// $: prStatus$ = githubService.getStatus($pr$?.targetBranch);
$: prStatus$ = githubService.getStatus($pr$?.targetBranch);
let meatballButton: HTMLDivElement;
let visible = false;
let container: HTMLDivElement;
let isApplying = false;
let isDeleting = false;
let isMerging = false;
function handleBranchNameChange() {
branchController.updateBranchName(branch.id, branch.name);
}
$: prColor = statusToColor($prStatus$);
$: prIcon = statusToIcon($prStatus$);
function statusToColor(status: PrStatus | undefined): IconColor {
if (!status) return 'neutral';
if (status && !status.hasChecks) return 'neutral';
if (status.completed) {
return status.success ? 'success' : 'error';
}
return 'warn';
}
function statusToIcon(status: PrStatus | undefined): keyof typeof iconsJson | undefined {
if (!status) return;
if (status && !status.hasChecks) return;
if (status.completed) {
return status.success ? 'success' : 'error';
}
return 'warning';
}
$: hasIntegratedCommits = branch.commits?.some((b) => b.isIntegrated);
</script>
@ -122,6 +148,9 @@
View PR
</Tag>
{/if}
{#if prIcon}
<Icon name={prIcon} color={prColor} />
{/if}
{/if}
{#await branch.isMergeable then isMergeable}
{#if !isMergeable}
@ -162,6 +191,26 @@
Set as default
</Button>
{/if}
{#if $prStatus$?.success}
<Button
help="Merge pull request and refresh"
disabled={isUnapplied}
loading={isMerging}
on:click={async () => {
isMerging = true;
try {
if ($pr$) await githubService.merge($pr$.number);
branchService.reloadVirtualBranches();
} catch {
toasts.error('Failed to merge pull request');
} finally {
isMerging = false;
}
}}
>
Merge
</Button>
{/if}
</div>
<div class="relative" bind:this={meatballButton}>
{#if isUnapplied}

View File

@ -10,17 +10,6 @@
let element: HTMLButtonElement | undefined = undefined;
// $: prColor = statusToColor($prStatus$);
// function statusToColor(status: PrStatus | undefined): TagColor {
// if (!status) return 'neutral-light';
// if (status && !status.hasChecks) return 'neutral-light';
// if (status.completed) {
// return status.success ? 'success' : 'error';
// }
// return 'warning';
// }
onMount(() => (height = element?.offsetHeight));
</script>

View File

@ -47,6 +47,10 @@ export class GitHubService {
private ctx$: Observable<GitHubIntegrationContext | undefined>;
private octokit$: Observable<Octokit | undefined>;
// For use with user initiated actions like merging
private ctx: GitHubIntegrationContext | undefined;
private octokit: Octokit | undefined;
private enabled = false;
constructor(userService: UserService, baseBranchService: BaseBranchService) {
@ -68,12 +72,14 @@ export class GitHubService {
return of({ authToken, owner, repo, username });
}),
distinct((val) => JSON.stringify(val)),
tap((ctx) => (this.ctx = ctx)),
shareReplay(1)
);
// Create a github client
this.octokit$ = this.ctx$.pipe(
map((ctx) => (ctx ? newClient(ctx.authToken) : undefined)),
tap((octokit) => (this.octokit = octokit)),
shareReplay(1)
);
@ -243,6 +249,19 @@ export class GitHubService {
})
);
}
async merge(pullNumber: number) {
if (!this.octokit || !this.ctx) return;
try {
await this.octokit.pulls.merge({
owner: this.ctx.owner,
repo: this.ctx.repo,
pull_number: pullNumber
});
} finally {
this.reload();
}
}
}
function loadPrs(