Chain types CI check (#5460)

* Chain types CI check

* SLOW for test
This commit is contained in:
Jaco 2021-06-05 14:58:33 +03:00 committed by GitHub
parent 21481572f3
commit 3d6b6734dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 139 additions and 27 deletions

10
.github/chain-types.md vendored Normal file
View File

@ -0,0 +1,10 @@
---
title: Outdated chain types
labels: ['ci', '@apps-config']
---
cc @polkadot-js/notifications
Some configured chains have outdated types and is determined to problematic as an available chain.
Check the nightly cron output (or via `yarn ci:chainTypes` locally) and disable the chains until the issue is resolved. The output as found from the test includes:

25
.github/workflows/chain-types.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Chain type check
on:
schedule:
- cron: '30 0 * * *'
jobs:
ss58:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: check
env:
CI_LOG: 123
run: |
yarn install --immutable | grep -v 'YN0013'
yarn ci:chainTypes
- name: issue
if: ${{ failure() }}
uses: JasonEtco/create-an-issue@v2
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT_BOT }}
with:
filename: .github/chain-types.md
update_existing: true

View File

@ -12,6 +12,6 @@ jobs:
repo-token: ${{ secrets.GH_PAT_BOT }}
stale-issue-message: 'This issue has been open for 21 days with no activity and is not labelled as an enhancement. It will be closed in 7 days.'
stale-issue-label: 'stale'
exempt-issue-labels: '-size-l,-size-m,-size-s,-size-xl,-size-xs,[bug]'
exempt-issue-labels: '-size-l,-size-m,-size-s,-size-xl,-size-xs,[bug],ci'
days-before-stale: 21
days-before-close: 7

View File

@ -24,6 +24,6 @@ module.exports = {
},
setupFilesAfterEnv: ['<rootDir>/jest/jest-setup.ts'],
testEnvironment: 'jsdom',
testTimeout: 25000,
testTimeout: 60000,
transformIgnorePatterns: ['/node_modules/(?!@polkadot|@babel/runtime/helpers/esm/)']
};

View File

@ -50,6 +50,7 @@
"packElectron:linux": "yarn build:release:electron && electron-builder build --linux",
"packElectron": "yarn build:release:electron && yarn clean:electronRelease && electron-builder build -mwl",
"docs": "echo \"skipping docs\"",
"ci:chainTypes": "polkadot-dev-run-test --silent packages/apps-config/src/ciChainTypes",
"clean": "polkadot-dev-clean-build",
"clean:electronBuild": "cd packages/apps-electron && polkadot-dev-clean-build",
"clean:electronRelease": "cd packages/apps-electron && rm -rf release",

View File

@ -0,0 +1,73 @@
// Copyright 2017-2021 @polkadot/apps-config authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ApiPromise, WsProvider } from '@polkadot/api';
import { assert, isError, isString } from '@polkadot/util';
import { fetch } from '@polkadot/x-fetch';
import { typesBundle, typesChain } from './api';
import { createWsEndpoints } from './endpoints';
interface Endpoint {
name: string;
ws: string;
}
interface DnsResponse {
Answer?: { name: string }[];
Question: { name: string }[];
}
const endpoints = createWsEndpoints((k: string, v?: string) => v || k, true)
.filter(({ isDisabled, value }) => !isDisabled && value && isString(value) && !value.startsWith('ws://'))
.map(({ text, value }): Partial<Endpoint> => ({ name: text as string, ws: value as string }))
.filter((v): v is Endpoint => !!v.ws);
describe('--SLOW--: check configured chain connections', (): void => {
endpoints.forEach(({ name, ws }) =>
it(`${name} @ ${ws}`, async (): Promise<void> => {
const [,, hostWithPort] = ws.split('/');
const [host] = hostWithPort.split(':');
const response = await fetch(`https://dns.google/resolve?name=${host}`);
const json = await response.json() as DnsResponse;
assert(json.Answer, `No DNS entry for ${host}`);
let provider: WsProvider | null = null;
let api: ApiPromise | null = null;
try {
provider = new WsProvider(ws, false);
api = new ApiPromise({
provider,
throwOnConnect: true,
typesBundle,
typesChain
});
setTimeout((): void => {
provider && provider.connect().catch(() => undefined);
}, 1000);
await api.isReadyOrError;
} catch (error) {
if (isError(error) && error.message.includes('Cannot construct unknown type')) {
throw error;
}
} finally {
if (provider) {
try {
if (api) {
await api.disconnect();
} else {
await provider.disconnect();
}
} catch {
// ignore
}
}
}
})
);
});

View File

@ -12,7 +12,7 @@ import { createTestingRelays } from './testingRelays';
export { CUSTOM_ENDPOINT_KEY } from './development';
export function createWsEndpoints (t: TFunction): LinkOption[] {
export function createWsEndpoints (t: TFunction, firstOnly?: boolean): LinkOption[] {
return [
...createCustom(t),
{
@ -23,7 +23,7 @@ export function createWsEndpoints (t: TFunction): LinkOption[] {
textBy: '',
value: ''
},
...createProductionRelays(t),
...createProductionRelays(t, firstOnly),
{
isDisabled: false,
isHeader: true,
@ -31,7 +31,7 @@ export function createWsEndpoints (t: TFunction): LinkOption[] {
textBy: '',
value: ''
},
...createTestingRelays(t),
...createTestingRelays(t, firstOnly),
{
isDisabled: false,
isHeader: true,
@ -40,7 +40,7 @@ export function createWsEndpoints (t: TFunction): LinkOption[] {
textBy: '',
value: ''
},
...createProduction(t),
...createProduction(t, firstOnly),
{
isDisabled: false,
isHeader: true,
@ -48,7 +48,7 @@ export function createWsEndpoints (t: TFunction): LinkOption[] {
textBy: '',
value: ''
},
...createTesting(t),
...createTesting(t, firstOnly),
{
isDevelopment: true,
isDisabled: false,

View File

@ -15,7 +15,7 @@ import { expandEndpoints } from './util';
// value: The actual hosted secure websocket endpoint
// alphabetical based on chain name
export function createProduction (t: TFunction): LinkOption[] {
export function createProduction (t: TFunction, firstOnly?: boolean): LinkOption[] {
return expandEndpoints(t, [
{
dnslink: 'centrifuge',
@ -166,5 +166,5 @@ export function createProduction (t: TFunction): LinkOption[] {
DataHighway: 'wss://westlake.datahighway.com'
}
}
]);
], firstOnly);
}

View File

@ -8,9 +8,9 @@ import { createKusama } from './productionRelayKusama';
import { createPolkadot } from './productionRelayPolkadot';
import { expandEndpoints } from './util';
export function createProductionRelays (t: TFunction): LinkOption[] {
export function createProductionRelays (t: TFunction, firstOnly?: boolean): LinkOption[] {
return expandEndpoints(t, [
createPolkadot(t),
createKusama(t)
]);
], firstOnly);
}

View File

@ -14,7 +14,7 @@ import { expandEndpoints } from './util';
// text: The text to display on the dropdown
// value: The actual hosted secure websocket endpoint
export function createTesting (t: TFunction): LinkOption[] {
export function createTesting (t: TFunction, firstOnly?: boolean): LinkOption[] {
return expandEndpoints(t, [
// alphabetical based on chain name, e.g. Amber, Arcadia, Beresheet, ...
{
@ -399,5 +399,5 @@ export function createTesting (t: TFunction): LinkOption[] {
ZERO: 'wss://alphaville.zero.io'
}
}
]);
], firstOnly);
}

View File

@ -8,9 +8,9 @@ import { createRococo } from './testingRelayRococo';
import { createWestend } from './testingRelayWestend';
import { expandEndpoints } from './util';
export function createTestingRelays (t: TFunction): LinkOption[] {
export function createTestingRelays (t: TFunction, firstOnly?: boolean): LinkOption[] {
return expandEndpoints(t, [
createRococo(t),
createWestend(t)
]);
], firstOnly);
}

View File

@ -21,7 +21,7 @@ export function expandLinked (input: LinkOption[]): LinkOption[] {
}, []);
}
export function expandEndpoint (t: TFunction, { dnslink, genesisHash, info, isChild, isDisabled, linked, paraId, providers, teleport, text }: EndpointOption): LinkOption[] {
export function expandEndpoint (t: TFunction, { dnslink, genesisHash, info, isChild, isDisabled, linked, paraId, providers, teleport, text }: EndpointOption, firstOnly?: boolean): LinkOption[] {
const base = {
genesisHash,
info,
@ -32,19 +32,22 @@ export function expandEndpoint (t: TFunction, { dnslink, genesisHash, info, isCh
text
};
const result = Object.entries(providers).map(([host, value], index): LinkOption => ({
...base,
dnslink: index === 0 ? dnslink : undefined,
isRelay: false,
textBy: t('rpc.hosted.by', 'hosted by {{host}}', { ns: 'apps-config', replace: { host } }),
value
}));
const result = Object
.entries(providers)
.filter((_, index) => !firstOnly || index === 0)
.map(([host, value], index): LinkOption => ({
...base,
dnslink: index === 0 ? dnslink : undefined,
isRelay: false,
textBy: t('rpc.hosted.by', 'hosted by {{host}}', { ns: 'apps-config', replace: { host } }),
value
}));
if (linked) {
const last = result[result.length - 1];
const options: LinkOption[] = [];
linked.forEach((o) => options.push(...expandEndpoint(t, o)));
linked.forEach((o) => options.push(...expandEndpoint(t, o, firstOnly)));
last.isRelay = true;
last.linked = options;
}
@ -52,6 +55,6 @@ export function expandEndpoint (t: TFunction, { dnslink, genesisHash, info, isCh
return expandLinked(result);
}
export function expandEndpoints (t: TFunction, input: EndpointOption[]): LinkOption[] {
return input.reduce((result: LinkOption[], input) => result.concat(expandEndpoint(t, input)), []);
export function expandEndpoints (t: TFunction, input: EndpointOption[], firstOnly?: boolean): LinkOption[] {
return input.reduce((result: LinkOption[], input) => result.concat(expandEndpoint(t, input, firstOnly)), []);
}

View File

@ -30,7 +30,7 @@ const DEFAULT_STATE: Teleport = {
oneWay: []
};
const endpoints = createWsEndpoints((k: string, v: string | undefined) => v || k).filter((v): v is ExtLinkOption => !!v.teleport);
const endpoints = createWsEndpoints((k: string, v?: string) => v || k).filter((v): v is ExtLinkOption => !!v.teleport);
function extractRelayDestinations (relayGenesis: string, filter: (l: ExtLinkOption) => boolean): ExtLinkOption[] {
return endpoints