mirror of
https://github.com/pezkuwichain/pezkuwi-api.git
synced 2026-10-20 18:56:29 +00:00
Make the PR workflow a real gate
- every matrix step (lint, test, build) must pass; nothing is allowed to fail silently - after build, scripts/check-built-manifests.py checks the package.json each build/ directory holds, which is what npm receives: entry points must exist, no ./build/ or ./cjs/cjs/ paths, no string spread into exports, no workspace:/link: ranges - the tree must be unchanged after the step: `yarn lint` runs eslint --fix and `yarn build` regenerates the augment interfaces, so both used to pass on a tree they had rewritten - the dot-notation exclusion had been renamed from kusama to zagros (no such directory) instead of dicle; with the dicle augmentation in the lint program, eslint --fix rewrote api.query['registrar'] style accesses that the build cannot compile - the four compiled-only packages (bizinikiwi-bindings, merkleize-metadata, metadata-builders, papi-utils) have no sources here and are not linted - the auto-approve and auto-merge bots are removed - .prettierrc.cjs uses @pezkuwi/dev
This commit is contained in:
1 parent
6468c53ec8
commit
c228f3b56c
7 files changed
+123
-43
No files matched your search
@@ -1,16 +0,0 @@
|
||||
name: bot
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
if: "! startsWith(github.event.head_commit.message, '[CI Skip]') && (!github.event.pull_request || github.event.pull_request.head.repo.full_name == github.repository)"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: jacogr/action-approve@795afd1dd096a2071d7ec98740661af4e853b7da
|
||||
with:
|
||||
authors: jacogr, TarikGul
|
||||
labels: -auto
|
||||
token: ${{ secrets.GH_PAT_BOT }}
|
||||
@@ -1,16 +0,0 @@
|
||||
name: bot
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: jacogr/action-merge@d2d64b4545acd93b0a9575177d3d215ae3f92029
|
||||
with:
|
||||
checks: pr (build),pr (lint),pr (test)
|
||||
labels: -auto
|
||||
strategy: squash
|
||||
token: ${{ secrets.GH_PAT_BOT }}
|
||||
@@ -3,10 +3,10 @@ on: [pull_request]
|
||||
|
||||
jobs:
|
||||
pr:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
step: ['lint', 'test', 'build', 'deno']
|
||||
step: ['lint', 'test', 'build']
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
YARN_ENABLE_SCRIPTS: false
|
||||
@@ -15,11 +15,19 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: denoland/setup-deno@v1
|
||||
with:
|
||||
deno-version: v1.46.3
|
||||
- name: ${{ matrix.step }}
|
||||
if: always()
|
||||
run: |
|
||||
yarn install --immutable
|
||||
yarn ${{ matrix.step }}
|
||||
# `yarn lint` runs eslint --fix and `yarn build` regenerates the augment
|
||||
# interfaces, so both pass on a tree they rewrote. The committed tree must
|
||||
# already be what they produce.
|
||||
- name: tree unchanged
|
||||
run: git diff --exit-code --stat
|
||||
# The package.json each build/ directory holds is what npm receives: every
|
||||
# entry point must name a file that is there, with no ./build/ or ./cjs/cjs/
|
||||
# path and no string spread into exports (the January 2026 fault).
|
||||
- name: check built manifests
|
||||
if: matrix.step == 'build'
|
||||
run: python3 scripts/check-built-manifests.py .
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2025 @polkadot/api authors & contributors
|
||||
// Copyright 2017-2026 @pezkuwi/api authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module.exports = require('@polkadot/dev/config/prettier.cjs');
|
||||
module.exports = require('@pezkuwi/dev/config/prettier.cjs');
|
||||
+8
-3
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2025 @pezkuwi/api authors & contributors
|
||||
// Copyright 2017-2026 @pezkuwi/api authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import baseConfig from '@pezkuwi/dev/config/eslint';
|
||||
@@ -7,8 +7,13 @@ export default [
|
||||
{
|
||||
ignores: [
|
||||
// see the tsconfig.eslint.json for explanation
|
||||
'packages/api-augment/src/zagros/*.ts',
|
||||
'packages/api-augment/src/pezkuwi/*.ts'
|
||||
'packages/api-augment/src/dicle/*.ts',
|
||||
'packages/api-augment/src/pezkuwi/*.ts',
|
||||
// compiled packages without sources here; there is nothing to lint
|
||||
'packages/bizinikiwi-bindings/**',
|
||||
'packages/merkleize-metadata/**',
|
||||
'packages/metadata-builders/**',
|
||||
'packages/papi-utils/**'
|
||||
]
|
||||
},
|
||||
...baseConfig,
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Check the package.json the build wrote into each packages/*/build directory.
|
||||
|
||||
This is the manifest npm receives. It fails on what broke the January 2026
|
||||
releases and wasm 7.5.19: an entry point (main, module, types, browser,
|
||||
react-native, every exports target) naming a file that is not in the build
|
||||
directory, a path with ./build/ or a doubled ./cjs/cjs/ in it, numeric keys
|
||||
inside exports (a string spread into an object), and workspace:/portal:/link:
|
||||
dependency ranges.
|
||||
|
||||
check-built-manifests.py <repo-dir> [package ...]
|
||||
|
||||
Prints one line per package and exits 1 if any package fails.
|
||||
"""
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
ENTRY_FIELDS = ('main', 'module', 'types', 'typings', 'browser', 'react-native')
|
||||
DEP_FIELDS = ('dependencies', 'peerDependencies', 'optionalDependencies')
|
||||
|
||||
|
||||
def targets(node, path):
|
||||
"""Yield (json-path, target string) for every string leaf under exports."""
|
||||
if isinstance(node, str):
|
||||
yield path, node
|
||||
elif isinstance(node, dict):
|
||||
for key, value in node.items():
|
||||
yield from targets(value, f'{path}/{key}')
|
||||
elif isinstance(node, list):
|
||||
for i, value in enumerate(node):
|
||||
yield from targets(value, f'{path}[{i}]')
|
||||
|
||||
|
||||
def numeric_keys(node, path):
|
||||
if isinstance(node, dict):
|
||||
for key, value in node.items():
|
||||
if key.isdigit():
|
||||
yield f'{path}/{key}'
|
||||
yield from numeric_keys(value, f'{path}/{key}')
|
||||
|
||||
|
||||
def check(build):
|
||||
problems = []
|
||||
manifest = build / 'package.json'
|
||||
if not manifest.is_file():
|
||||
return ['no build/package.json']
|
||||
pkg = json.loads(manifest.read_text())
|
||||
|
||||
def check_path(where, target):
|
||||
if not isinstance(target, str) or not target.startswith('.'):
|
||||
return
|
||||
if '/build/' in target or target.startswith('./build') or '/cjs/cjs/' in target:
|
||||
problems.append(f'{where}: suspicious path {target}')
|
||||
if '*' in target:
|
||||
base = build / target.split('*', 1)[0]
|
||||
if not base.parent.exists():
|
||||
problems.append(f'{where}: {target} has no directory')
|
||||
return
|
||||
if not (build / target).is_file():
|
||||
problems.append(f'{where}: {target} does not exist')
|
||||
|
||||
for field in ENTRY_FIELDS:
|
||||
value = pkg.get(field)
|
||||
if isinstance(value, str):
|
||||
check_path(field, value)
|
||||
for where, target in targets(pkg.get('exports'), 'exports'):
|
||||
check_path(where, target)
|
||||
for where in numeric_keys(pkg.get('exports'), 'exports'):
|
||||
problems.append(f'{where}: numeric key (a string spread into an object)')
|
||||
for field in DEP_FIELDS:
|
||||
for dep, rng in (pkg.get(field) or {}).items():
|
||||
if str(rng).startswith(('workspace:', 'portal:', 'link:', 'file:')):
|
||||
problems.append(f'{field}.{dep}: {rng}')
|
||||
return problems
|
||||
|
||||
|
||||
def main():
|
||||
repo = pathlib.Path(sys.argv[1])
|
||||
names = sys.argv[2:]
|
||||
builds = [repo / 'packages' / n / 'build' for n in names] if names else sorted(repo.glob('packages/*/build'))
|
||||
failed = 0
|
||||
for build in builds:
|
||||
problems = check(build)
|
||||
name = build.parent.name
|
||||
if problems:
|
||||
failed += 1
|
||||
print(f'FAIL {name}')
|
||||
for p in problems[:12]:
|
||||
print(f' {p}')
|
||||
if len(problems) > 12:
|
||||
print(f' ... {len(problems) - 12} more')
|
||||
else:
|
||||
print(f'ok {name}')
|
||||
sys.exit(1 if failed else 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -17,7 +17,7 @@
|
||||
"**/node_modules/**/*",
|
||||
// We exclude these since it creates some issues with the
|
||||
// @typescript-eslint/dot-notation rules
|
||||
"packages/api-augment/src/zagros/*.ts",
|
||||
"packages/api-augment/src/dicle/*.ts",
|
||||
"packages/api-augment/src/pezkuwi/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user