Commit e30a310b authored by Jiaan Louw's avatar Jiaan Louw 2️⃣
Browse files

feat!: remove TypeScript experiment, use WASM-only implementation

Remove the TypeScript GLQL implementation that was added as an
experiment in !257. New backend requirements for Duo integration
require the Rust implementation, as running TypeScript server-side
would need a JS runtime and add substantial complexity.

The Ruby gem (gitlab_query_language) requires no changes as it
compiles Rust directly to native code.

BREAKING CHANGE: Bump minor version. The glqlTypescript feature flag
is no longer supported. All queries now use the Rust/WASM version.

See: !257
parent 8cb0a5c2
Loading
Loading
Loading
Loading
+2 −64
Original line number Diff line number Diff line
@@ -147,26 +147,6 @@ graphql-validate:
      - tmp/gitlab_schema.graphql
    expire_in: 1 hour

graphql-validate-ts:
  extends: .node-job-template
  tags: [saas-linux-large-amd64]
  stage: post-test
  needs:
    - test-ts
    - fetch-graphql-schema
  dependencies:
    - test-ts
    - fetch-graphql-schema
  script:
    - npm i --global @graphql-inspector/cli graphql
    - graphql-inspector validate './tmp/ts/graphql/*.graphql' './tmp/gitlab_schema.graphql' --onlyErrors --relativePaths
  artifacts:
    when: always
    paths:
      - tmp/ts/graphql
      - tmp/gitlab_schema.graphql
    expire_in: 1 hour

fmt:
  extends: .rust-job-template
  stage: lint
@@ -249,25 +229,9 @@ test-wasm:
  script:
    - npm install
    - npm run build
    - npm run test:ci:wasm
  artifacts:
    when: always
    reports:
      junit:
        - junit.xml

test-ts:
  extends: .node-job-template
  stage: test
  script:
    - npm install
    - npm run build
    - DUMP_GRAPHQL=1 npm run test:ci
    - npm run test:ci
  artifacts:
    when: always
    paths:
      - tmp/ts/graphql
    expire_in: 1 hour
    reports:
      junit:
        - junit.xml
@@ -297,28 +261,6 @@ coverage:
        coverage_format: cobertura
        path: coverage.xml

coverage-ts:
  extends: .node-job-template
  stage: post-test
  before_script:
    - apk add --no-cache lcov
  script:
    - npm install
    - npm run build
    - npm run test:coverage
    - lcov --summary coverage-ts/lcov.info --ignore-errors inconsistent
  coverage: '/lines\.+: (\d+.\d+)%/'
  artifacts:
    when: always
    paths:
      - coverage-ts/
      - coverage-ts/lcov.info
      - coverage-ts/cobertura-coverage.xml
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage-ts/cobertura-coverage.xml

pages-artifacts-examples:
  extends: .node-job-template
  stage: build
@@ -350,17 +292,15 @@ pages-artifacts-docs:
pages:
  stage: deploy
  script:
    - mkdir -p public/coverage public/coverage-ts
    - mkdir -p public/coverage
    - cp -r docs public/
    - cp -r examples public/
    - cp -r target/llvm-cov/html/* public/coverage
    - cp -r coverage-ts/* public/coverage-ts
    - cd public
    - echo "<h2>GLQL - Quick links:</h2><ul>" > ./index.html
    - echo "<li><a href='./examples'>Examples</a>" >> ./index.html
    - echo "<li><a href='./docs/glql'>Crate docs</a>" >> ./index.html
    - echo "<li><a href='./coverage'>Rust Coverage report</a>" >> ./index.html
    - echo "<li><a href='./coverage-ts'>TypeScript Coverage report</a>" >> ./index.html
    - echo "<li><a href='https://gitlab.com/gitlab-org/glql/-/blob/main/README.md'>Project readme</a>" >> ./index.html
    - echo "<li><a href='https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/glql/'>Architecture design document</a>" >> ./index.html
    - echo "<li><a href='https://docs.gitlab.com/ee/user/glql/'>Usage docs</a>" >> ./index.html
@@ -368,12 +308,10 @@ pages:
    - pages-artifacts-examples
    - pages-artifacts-docs
    - coverage
    - coverage-ts
  dependencies:
    - pages-artifacts-examples
    - pages-artifacts-docs
    - coverage
    - coverage-ts
  only:
    - main
  artifacts:
+1 −34
Original line number Diff line number Diff line
@@ -11,42 +11,9 @@ module.exports = {
      },
    ],
  },
  testMatch: [
    '**/src/**/*.test.ts',
    '**/src/**/*.test.js',
    '**/tests/**/*.test.ts',
    '**/tests/**/*.test.js',
  ],
  testMatch: ['**/tests/**/*.test.ts', '**/tests/**/*.test.js'],
  moduleFileExtensions: ['ts', 'js', 'json'],
  moduleNameMapper: {
    '\\.wasm$': '<rootDir>/npm/tests/__mocks__/wasmBuffer.ts',
  },
  // Coverage configuration
  collectCoverage: false, // Will be enabled via CLI flag
  coverageDirectory: 'coverage-ts',
  coverageReporters: ['html', 'lcov', 'cobertura', 'text-summary'],
  collectCoverageFrom: [
    'npm/src/**/*.ts',
    '!npm/src/**/*.test.ts',
    '!npm/src/**/*.d.ts',
    '!npm/src/**/__mocks__/**',
    '!npm/src/**/__tests__/**',
  ],
  coveragePathIgnorePatterns: [
    '/node_modules/',
    '/pkg/',
    '/target/',
    '/coverage/',
    '/coverage-ts/',
    '\\.test\\.',
    '\\.d\\.ts$',
  ],
  coverageThreshold: {
    global: {
      branches: 0,
      functions: 0,
      lines: 0,
      statements: 0,
    },
  },
};
+0 −2
Original line number Diff line number Diff line
@@ -72,7 +72,6 @@
          username: 'johnhope',
          featureFlags: {
            glqlWorkItems: true,
            glqlTypescript: true,
          },
        });

@@ -96,7 +95,6 @@
          username: 'johnhope',
          featureFlags: {
            glqlWorkItems: true,
            glqlTypescript: true,
          },
        });
        document.getElementById('outputPre').innerHTML = compiled.output;

npm/src/analyzer/expression.ts

deleted100644 → 0
+0 −20
Original line number Diff line number Diff line
import { Expression } from '../types/expression';
import { Source } from '../types/source';
import { FieldAnalyzer } from './field';
import { ValueAnalyzer } from './value';

export class ExpressionAnalyzer {
  constructor(
    public readonly expression: Expression,
    public readonly source: Source,
  ) {}

  analyze() {
    new FieldAnalyzer(this.expression.field, this.source).analyze(
      this.expression.operator,
      this.expression.value,
    );

    new ValueAnalyzer(this.expression.value, this.source).analyze(this.expression.field);
  }
}

npm/src/analyzer/field.ts

deleted100644 → 0
+0 −71
Original line number Diff line number Diff line
import { GlqlAnalyzeError } from '../errors';
import { Field } from '../types/field';
import { Operator } from '../types/operator';
import { Source } from '../types/source';
import { Value } from '../types/value';
import { ValueAnalyzer } from './value';

export class FieldAnalyzer {
  constructor(
    public readonly field: Field,
    public readonly source: Source,
  ) {}

  get operators(): Set<Operator> {
    return new Set(
      this.source.analyzer.allFieldTypes(this.field).flatMap((f) => [...f.analyzer.operators]),
    );
  }

  operatorsForValue(value: Value): Set<Operator> {
    return (
      new ValueAnalyzer(value, this.source).fieldType(this.field)?.analyzer.operators || new Set()
    );
  }

  analyzeField() {
    if (this.field instanceof Field.Unknown)
      throw new GlqlAnalyzeError.UnrecognizedField(this.field);
  }

  analyzeFieldForSource() {
    return this.source.analyzer.analyzeField(this.field);
  }

  analyzePairedFields(fields: Field[]) {
    const field = this.field.dealias();
    const { pairableFields } = this.source.analyzer.fieldType(field).analyzer;

    if (pairableFields.length > 0 && !fields.some((f) => pairableFields.some((p) => p.eq(f))))
      throw new GlqlAnalyzeError.IncorrectFieldPairing(this.field, pairableFields);
  }

  analyzeOperator(op: Operator) {
    const ops = [...this.operators];
    const supportedOperators = [...ops];
    if (!ops.some((o) => o.eq(op)))
      throw new GlqlAnalyzeError.UnsupportedOperatorForField(this.field, op, supportedOperators);
  }

  analyzeOperatorForValue(op: Operator, value: Value) {
    const ops = [...this.operatorsForValue(value)];

    if (!ops.some((o) => o.eq(op)))
      throw new GlqlAnalyzeError.UnsupportedOperatorValueForField(this.field, op, value, ops);
  }

  analyzeValue(value: Value) {
    const types = this.source.analyzer.allFieldTypes(this.field);

    if (!types.some((t) => t.analyzer.analyze(value)))
      throw new GlqlAnalyzeError.UnsupportedValueForField(this.field, value, types);
  }

  analyze(op: Operator, value: Value) {
    this.analyzeField();
    this.analyzeFieldForSource();
    this.analyzeOperator(op);
    this.analyzeValue(value);
    this.analyzeOperatorForValue(op, value);
  }
}
Loading