feat(environment): github releases (#3426)
This commit is contained in:
parent
d4f5643799
commit
2f4bc9484b
@ -1,3 +1,5 @@
|
|||||||
export * from './use-environment';
|
export * from './use-environment';
|
||||||
export * from './use-links';
|
export * from './use-links';
|
||||||
export * from './use-node-health';
|
export * from './use-node-health';
|
||||||
|
export * from './use-vega-releases';
|
||||||
|
export * from './use-vega-release';
|
||||||
|
40137
libs/environment/src/hooks/mocks/github-releases.ts
Normal file
40137
libs/environment/src/hooks/mocks/github-releases.ts
Normal file
File diff suppressed because one or more lines are too long
41
libs/environment/src/hooks/use-vega-release.spec.ts
Normal file
41
libs/environment/src/hooks/use-vega-release.spec.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { renderHook, waitFor } from '@testing-library/react';
|
||||||
|
import fetchMock from 'fetch-mock';
|
||||||
|
import {
|
||||||
|
GITHUB_VEGA_DEV_RELEASES,
|
||||||
|
GITHUB_VEGA_RELEASES,
|
||||||
|
} from './use-vega-releases';
|
||||||
|
import {
|
||||||
|
GITHUB_VEGA_RELEASES_DATA,
|
||||||
|
GITHUB_VEGA_DEV_RELEASES_DATA,
|
||||||
|
} from './mocks/github-releases';
|
||||||
|
import { useVegaRelease } from './use-vega-release';
|
||||||
|
|
||||||
|
describe('useVegaRelease', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||||
|
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
fetchMock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return release information by given tag', async () => {
|
||||||
|
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current).toBeTruthy();
|
||||||
|
expect(result.current?.tagName).toEqual('v0.70.1');
|
||||||
|
expect(result.current?.htmlUrl).toEqual(
|
||||||
|
'https://github.com/vegaprotocol/vega/releases/tag/v0.70.1'
|
||||||
|
);
|
||||||
|
expect(result.current?.name).toEqual('v0.70.1');
|
||||||
|
expect(result.current?.isDraft).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when a release cannot be found', async () => {
|
||||||
|
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current).toEqual(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
9
libs/environment/src/hooks/use-vega-release.ts
Normal file
9
libs/environment/src/hooks/use-vega-release.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useVegaReleases } from './use-vega-releases';
|
||||||
|
|
||||||
|
export const useVegaRelease = (tag: string, includeDevReleases = false) => {
|
||||||
|
const { data } = useVegaReleases();
|
||||||
|
return useMemo(() => {
|
||||||
|
return data?.find((r) => r.tagName === tag);
|
||||||
|
}, [data, tag]);
|
||||||
|
};
|
58
libs/environment/src/hooks/use-vega-releases.spec.ts
Normal file
58
libs/environment/src/hooks/use-vega-releases.spec.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { renderHook, waitFor } from '@testing-library/react';
|
||||||
|
import fetchMock from 'fetch-mock';
|
||||||
|
import {
|
||||||
|
GITHUB_VEGA_DEV_RELEASES,
|
||||||
|
GITHUB_VEGA_RELEASES,
|
||||||
|
useVegaReleases,
|
||||||
|
} from './use-vega-releases';
|
||||||
|
import {
|
||||||
|
GITHUB_VEGA_RELEASES_DATA,
|
||||||
|
GITHUB_VEGA_DEV_RELEASES_DATA,
|
||||||
|
} from './mocks/github-releases';
|
||||||
|
|
||||||
|
describe('useVegaReleases', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
fetchMock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty list when request is unsuccessful', async () => {
|
||||||
|
fetchMock.get(GITHUB_VEGA_RELEASES, 404);
|
||||||
|
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, 404);
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useVegaReleases());
|
||||||
|
expect(result.current.loading).toBeTruthy();
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.loading).toBeFalsy();
|
||||||
|
expect(result.current.data).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a list of releases', async () => {
|
||||||
|
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||||
|
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useVegaReleases());
|
||||||
|
expect(result.current.loading).toBeTruthy();
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.loading).toBeFalsy();
|
||||||
|
expect(result.current).not.toEqual([]);
|
||||||
|
const data = result.current.data;
|
||||||
|
expect(data?.[0].tagName).toEqual('v0.70.3');
|
||||||
|
expect(data?.[0].htmlUrl).toEqual(
|
||||||
|
'https://github.com/vegaprotocol/vega/releases/tag/v0.70.3'
|
||||||
|
);
|
||||||
|
expect(data?.[1].tagName).toEqual('v0.70.2');
|
||||||
|
expect(data?.[2].tagName).toEqual('v0.70.1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a list of releases including dev releases', async () => {
|
||||||
|
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||||
|
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||||
|
const { result } = renderHook(() => useVegaReleases(true));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(result.current.data?.length).toBeGreaterThan(30);
|
||||||
|
expect(fetchMock.calls().length).toEqual(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
124
libs/environment/src/hooks/use-vega-releases.ts
Normal file
124
libs/environment/src/hooks/use-vega-releases.ts
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
export const GITHUB_VEGA_RELEASES =
|
||||||
|
'https://api.github.com/repos/vegaprotocol/vega/releases';
|
||||||
|
export const GITHUB_VEGA_DEV_RELEASES =
|
||||||
|
'https://api.github.com/repos/vegaprotocol/vega-dev-releases/releases';
|
||||||
|
|
||||||
|
const GithubReleaseSchema = z.object({
|
||||||
|
url: z.string(),
|
||||||
|
html_url: z.string(),
|
||||||
|
id: z.number(),
|
||||||
|
tag_name: z.string(),
|
||||||
|
name: z.string().nullable(),
|
||||||
|
draft: z.boolean(),
|
||||||
|
created_at: z.string().datetime(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const GithubReleasesSchema = z.array(GithubReleaseSchema);
|
||||||
|
|
||||||
|
type ReleaseInfo = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
tagName: string;
|
||||||
|
htmlUrl: string;
|
||||||
|
url: string;
|
||||||
|
isDraft: boolean;
|
||||||
|
createdAt: Date;
|
||||||
|
isDevRelease: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toReleaseInfo = (
|
||||||
|
releaseData: z.infer<typeof GithubReleaseSchema>,
|
||||||
|
isDevRelease: boolean
|
||||||
|
): ReleaseInfo => ({
|
||||||
|
id: releaseData.id,
|
||||||
|
name: releaseData.name || '',
|
||||||
|
tagName: releaseData.tag_name,
|
||||||
|
htmlUrl: releaseData.html_url,
|
||||||
|
url: releaseData.url,
|
||||||
|
isDraft: releaseData.draft,
|
||||||
|
createdAt: new Date(releaseData.created_at),
|
||||||
|
isDevRelease,
|
||||||
|
});
|
||||||
|
|
||||||
|
enum ReleaseFeed {
|
||||||
|
// @ts-ignore TS18033 - allowed in 5.0
|
||||||
|
Vega = GITHUB_VEGA_RELEASES,
|
||||||
|
// @ts-ignore TS18033
|
||||||
|
VegaDev = GITHUB_VEGA_DEV_RELEASES,
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchReleases = async (feed: ReleaseFeed) => {
|
||||||
|
const response = await fetch(String(feed), {
|
||||||
|
cache: 'force-cache',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const json = await response.json();
|
||||||
|
const data = GithubReleasesSchema.parse(json);
|
||||||
|
return data.map((d) => toReleaseInfo(d, feed === ReleaseFeed.VegaDev));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
loading: boolean;
|
||||||
|
data: ReleaseInfo[] | null;
|
||||||
|
error: Error | null | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of vega releases from github.
|
||||||
|
* First element is the newest.
|
||||||
|
*/
|
||||||
|
export const useVegaReleases = (includeDevReleases = false) => {
|
||||||
|
const [state, setState] = useState<State>({
|
||||||
|
loading: true,
|
||||||
|
data: null,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchData = useCallback(() => {
|
||||||
|
let mounted = true;
|
||||||
|
|
||||||
|
Promise.all(
|
||||||
|
includeDevReleases
|
||||||
|
? [fetchReleases(ReleaseFeed.Vega), fetchReleases(ReleaseFeed.VegaDev)]
|
||||||
|
: [fetchReleases(ReleaseFeed.Vega)]
|
||||||
|
)
|
||||||
|
.then(([vega, vegaDev]) => {
|
||||||
|
if (mounted) {
|
||||||
|
setState({
|
||||||
|
loading: false,
|
||||||
|
data: (vegaDev ? vega.concat(vegaDev) : vega).sort(
|
||||||
|
(a, b) => b.createdAt.valueOf() - a.createdAt.valueOf()
|
||||||
|
),
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (mounted) {
|
||||||
|
setState({
|
||||||
|
loading: false,
|
||||||
|
data: null,
|
||||||
|
error: err,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mounted = false;
|
||||||
|
};
|
||||||
|
}, [includeDevReleases, setState]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchData();
|
||||||
|
}, [fetchData]);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user