import dayjs from 'dayjs' import { getOrElse } from 'fp-ts/lib/Either' import { pipe } from 'fp-ts/lib/function' import { orderBy } from 'lodash-es' import { useQuery } from 'react-query' import { DeployFragment, DeploymentState, RepoFragment, } from '../generated/graphql' import { useAppState, useEffects } from '../overmind' import { DeploymentModel, GitHubEnvironment, GitHubEnvironmentsCodec, ReleaseModel, RepoModel, } from '../overmind/state' import graphQLApi from '../utils/graphQLApi' export const useFetchReleases = () => { const { selectedApplication, appSettings } = useAppState() const repo = selectedApplication?.repo const prefix = selectedApplication?.releaseFilter ?? '' const { data, isLoading, error } = useQuery( `${repo?.owner}/${repo?.name}/releases/${prefix}`, async () => { if (!repo) return [] const result = await graphQLApi.fetchReleases({ repoName: repo.name, repoOwner: repo.owner, prefix, }) const fragments = result.repository?.refs?.nodes?.map((n) => n!) ?? [] const releases = fragments .map(({ id, name, target }): ReleaseModel | null => target?.__typename === 'Commit' ? { id, name, tagName: name, createdAt: dayjs(target.pushedDate ?? target.committedDate), commit: target.oid, deployments: target.deployments?.nodes ?.filter((node) => !!node) .map((n) => n! as DeployFragment) .map( ({ id, createdAt, environment, state, latestStatus, }): DeploymentModel => ({ id, createdAt: dayjs(createdAt), environment: environment || '', state: state || DeploymentState.Inactive, modifiedAt: dayjs(latestStatus?.createdAt), }) ) .orderBy((n) => n.createdAt, 'desc') || [], } : null ) .filter((n): n is ReleaseModel => !!n) return releases }, { refetchInterval: 1000 * appSettings.refreshIntervalSecs, } ) return { data, isLoading, error } } export const useFetchWorkflows = () => { const { token, selectedApplication } = useAppState() const { restApi } = useEffects() const repo = selectedApplication?.repo const { data, isLoading, error } = useQuery( `${repo?.owner}/${repo?.name}/workflows`, async () => { if (!token || !repo) return [] const { owner, name } = repo const response = await restApi.octokit.actions.listRepoWorkflows({ owner, repo: name, per_page: 100, }) // TODO: Only return workflows with `workflow_dispatch` trigger return orderBy(response.data?.workflows ?? [], (w) => w.name) } ) return { data, isLoading, error } } export const useFetchEnvironments = () => { const { token, selectedApplication } = useAppState() const { restApi } = useEffects() const repo = selectedApplication?.repo const { data, isLoading, error } = useQuery( `${repo?.owner}/${repo?.name}/environments`, async () => { if (!token || !repo) return [] const { owner, name } = repo const data = await restApi.octokit.paginate( restApi.octokit.repos.getAllEnvironments, { owner, repo: name, per_page: 100, }, (response) => response.data as any ) console.log(data) return pipe( GitHubEnvironmentsCodec.decode(data), getOrElse((e) => { console.log(e) return [] as GitHubEnvironment[] }) ) } ) return { data, isLoading, error } } export const useFetchRepos = () => { const { data, isLoading, error } = useQuery('repos', async () => { let after: string | null = null let keepFetching = true const repos: RepoFragment[] = [] while (keepFetching) { const result = await graphQLApi.fetchReposWithWriteAccess({ after, }) const { hasNextPage, endCursor } = result.viewer.repositories.pageInfo const nodes = result.viewer.repositories.nodes?.map((e) => e as RepoFragment) ?? [] repos.push(...nodes) keepFetching = hasNextPage after = endCursor as string | null } return repos.map( (r): RepoModel => ({ id: r.id, name: r.name, owner: r.owner.login, defaultBranch: r.defaultBranchRef?.name ?? '', }) ) }) return { data, isLoading, error } }