mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-18 18:46:02 +00:00
ci: stabilise package boundary validation
This commit is contained in:
@@ -91,16 +91,34 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Detect LiveSync-owned integration tests
|
||||
id: integration_tests
|
||||
shell: bash
|
||||
run: |
|
||||
git ls-files -- ':(glob)**/*.integration.spec.ts' ':(glob)**/*.integration.test.ts' > "$RUNNER_TEMP/livesync-integration-tests.txt"
|
||||
if [[ -s "$RUNNER_TEMP/livesync-integration-tests.txt" ]]; then
|
||||
echo 'present=true' >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo 'present=false' >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Record delegated integration coverage
|
||||
if: ${{ steps.integration_tests.outputs.present != 'true' }}
|
||||
run: echo 'No LiveSync-owned integration tests are present. Commonlib integration tests run in the Commonlib package CI.' >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Setup Node.js
|
||||
if: ${{ steps.integration_tests.outputs.present == 'true' }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '24.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
if: ${{ steps.integration_tests.outputs.present == 'true' }}
|
||||
run: npm ci
|
||||
|
||||
- name: Create environment configuration files
|
||||
if: ${{ steps.integration_tests.outputs.present == 'true' }}
|
||||
run: |
|
||||
cat <<EOF > .env
|
||||
BUILD_MODE=dev
|
||||
@@ -118,16 +136,19 @@ jobs:
|
||||
EOF
|
||||
|
||||
- name: Start CouchDB container
|
||||
if: ${{ steps.integration_tests.outputs.present == 'true' }}
|
||||
run: npm run test:docker-couchdb:start
|
||||
|
||||
- name: Start MinIO container
|
||||
if: ${{ steps.integration_tests.outputs.present == 'true' }}
|
||||
run: npm run test:docker-s3:start
|
||||
|
||||
- name: Run integration tests
|
||||
if: ${{ steps.integration_tests.outputs.present == 'true' }}
|
||||
run: npm run test:integration
|
||||
|
||||
- name: Stop containers
|
||||
if: always()
|
||||
if: ${{ always() && steps.integration_tests.outputs.present == 'true' }}
|
||||
run: |
|
||||
npm run test:docker-couchdb:stop || true
|
||||
npm run test:docker-s3:stop || true
|
||||
|
||||
Generated
+8
-4
@@ -15154,12 +15154,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz",
|
||||
"integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"pretty": "npm run prettyNoWrite -- --write --log-level error",
|
||||
"prettyCheck": "npm run prettyNoWrite -- --check",
|
||||
"prettyNoWrite": "prettier --config ./.prettierrc.mjs \"**/*.js\" \"**/*.ts\" \"**/*.json\" ",
|
||||
"precheck:compatibility": "npm run build",
|
||||
"check:compatibility": "node utils/check-compatibility.js --file main.js --ios 15",
|
||||
"check": "npm run tsc-check && npm run tsc-check:apps && npm run lint && npm run lint:community -- --quiet && npm run svelte-check && npm run check:compatibility",
|
||||
"unittest": "deno test -A --no-check --coverage=cov_profile --v8-flags=--expose-gc --trace-leaks ./src/",
|
||||
@@ -169,6 +170,14 @@
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
||||
},
|
||||
"overrides": {
|
||||
"pouchdb-core": {
|
||||
"uuid": "11.1.1"
|
||||
},
|
||||
"pouchdb-utils": {
|
||||
"uuid": "11.1.1"
|
||||
}
|
||||
},
|
||||
"workspaces": [
|
||||
"src/apps/cli",
|
||||
"src/apps/webpeer",
|
||||
|
||||
@@ -6,21 +6,33 @@ const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url))
|
||||
const dependencyFacadePath = path.resolve(repositoryRoot, "src/deps.ts");
|
||||
const obsidianMockPath = path.resolve(repositoryRoot, "test/harness/obsidian-mock.ts");
|
||||
|
||||
function parseSourceFile(filePath: string): ts.SourceFile {
|
||||
const source = ts.sys.readFile(filePath);
|
||||
if (source === undefined) throw new Error(`Could not read ${filePath}`);
|
||||
return ts.createSourceFile(filePath, source, ts.ScriptTarget.ESNext, true, ts.ScriptKind.TS);
|
||||
}
|
||||
|
||||
function hasExportModifier(statement: ts.Statement): boolean {
|
||||
return ts.getModifiers(statement)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
||||
}
|
||||
|
||||
function addBindingNames(name: ts.BindingName, names: Set<string>): void {
|
||||
if (ts.isIdentifier(name)) {
|
||||
names.add(name.text);
|
||||
return;
|
||||
}
|
||||
for (const element of name.elements) {
|
||||
if (!ts.isOmittedExpression(element)) addBindingNames(element.name, names);
|
||||
}
|
||||
}
|
||||
|
||||
describe("Webapp Obsidian mock exports", () => {
|
||||
it("provides every value re-exported from Obsidian", () => {
|
||||
const program = ts.createProgram([dependencyFacadePath, obsidianMockPath], {
|
||||
module: ts.ModuleKind.ESNext,
|
||||
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
||||
skipLibCheck: true,
|
||||
target: ts.ScriptTarget.ESNext,
|
||||
});
|
||||
const dependencyFacade = program.getSourceFile(dependencyFacadePath);
|
||||
const obsidianMock = program.getSourceFile(obsidianMockPath);
|
||||
expect(dependencyFacade).toBeDefined();
|
||||
expect(obsidianMock).toBeDefined();
|
||||
const dependencyFacade = parseSourceFile(dependencyFacadePath);
|
||||
const obsidianMock = parseSourceFile(obsidianMockPath);
|
||||
|
||||
const requiredExports = new Set<string>();
|
||||
for (const statement of dependencyFacade!.statements) {
|
||||
for (const statement of dependencyFacade.statements) {
|
||||
if (
|
||||
ts.isExportDeclaration(statement) &&
|
||||
statement.moduleSpecifier &&
|
||||
@@ -38,10 +50,33 @@ describe("Webapp Obsidian mock exports", () => {
|
||||
}
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const mockSymbol = checker.getSymbolAtLocation(obsidianMock!);
|
||||
expect(mockSymbol).toBeDefined();
|
||||
const availableExports = new Set(checker.getExportsOfModule(mockSymbol!).map((symbol) => symbol.name));
|
||||
const availableExports = new Set<string>();
|
||||
for (const statement of obsidianMock.statements) {
|
||||
if (
|
||||
ts.isExportDeclaration(statement) &&
|
||||
!statement.isTypeOnly &&
|
||||
statement.exportClause &&
|
||||
ts.isNamedExports(statement.exportClause)
|
||||
) {
|
||||
for (const element of statement.exportClause.elements) {
|
||||
if (!element.isTypeOnly) availableExports.add(element.name.text);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!hasExportModifier(statement)) continue;
|
||||
if (
|
||||
(ts.isClassDeclaration(statement) ||
|
||||
ts.isFunctionDeclaration(statement) ||
|
||||
ts.isEnumDeclaration(statement)) &&
|
||||
statement.name
|
||||
) {
|
||||
availableExports.add(statement.name.text);
|
||||
} else if (ts.isVariableStatement(statement)) {
|
||||
for (const declaration of statement.declarationList.declarations) {
|
||||
addBindingNames(declaration.name, availableExports);
|
||||
}
|
||||
}
|
||||
}
|
||||
const missingExports = [...requiredExports].filter((name) => !availableExports.has(name)).sort();
|
||||
|
||||
expect(missingExports).toEqual([]);
|
||||
|
||||
Reference in New Issue
Block a user