Skip to content

Commit 01439db

Browse files
authored
Add support for bdd-runner (#2166)
* begin adding bdd-runner * bdd-runner cli and entry point * cleanup * basic api support * basic given support * basic undo support * rename directory * add back assertions and object serialization * fix up additional tests and path resolution * fix api name resolution * run in ci * remove examples dep and bump min version * lint * [AAWF-316] Add back licenses check (#2176) * add back licenses check * run it in tests
1 parent 934804d commit 01439db

File tree

20 files changed

+3624
-31
lines changed

20 files changed

+3624
-31
lines changed

.github/workflows/test.yml

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ on:
1515
- cron: "0 5 * * *"
1616

1717
concurrency:
18-
group: unit-${{ github.head_ref }}
18+
group: unit-split-package-${{ github.head_ref }}
1919
cancel-in-progress: true
2020

2121
jobs:
@@ -56,7 +56,7 @@ jobs:
5656
- uses: actions/cache@v3
5757
with:
5858
path: ~/.cache/pre-commit
59-
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
59+
key: pre-commit|split-package|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
6060
- id: pre_commit
6161
name: Run generate to fix lint and format
6262
if: github.event.action != 'closed' && github.event.pull_request.merged != true
@@ -77,3 +77,59 @@ jobs:
7777
if: github.event_name == 'schedule'
7878
run: |
7979
pre-commit run --all-files --show-diff-on-failure --color=always
80+
81+
test:
82+
strategy:
83+
matrix:
84+
node-version: ["18", "20"]
85+
platform: [ubuntu-latest]
86+
runs-on: ${{ matrix.platform }}
87+
if: (github.event.pull_request.draft == false && !contains(github.event.pull_request.labels.*.name, 'ci/skip') && !contains(github.event.pull_request.head.ref, 'datadog-api-spec/test/')) || github.event_name == 'schedule'
88+
steps:
89+
- uses: actions/checkout@v3
90+
- name: Set up Node ${{ matrix.node-version }}
91+
uses: actions/setup-node@v3
92+
with:
93+
node-version: ${{ matrix.node-version }}
94+
cache: 'yarn'
95+
- name: Test
96+
run: ./run-tests.sh
97+
shell: bash
98+
99+
# examples:
100+
# runs-on: ubuntu-latest
101+
# if: (github.event.pull_request.draft == false && !contains(github.event.pull_request.labels.*.name, 'ci/skip') && !contains(github.event.pull_request.head.ref, 'datadog-api-spec/test/')) || github.event_name == 'schedule'
102+
# steps:
103+
# - uses: actions/checkout@v3
104+
# - name: Set up Node 16
105+
# uses: actions/setup-node@v3
106+
# with:
107+
# node-version: 16
108+
# cache: 'yarn'
109+
# - name: Check examples
110+
# run: ./check-examples.sh
111+
# shell: bash
112+
113+
report:
114+
runs-on: ubuntu-latest
115+
if: always() && github.event_name == 'pull_request' && contains(github.event.pull_request.head.ref, 'datadog-api-spec/generated/')
116+
needs:
117+
- test
118+
# - examples
119+
steps:
120+
- name: Get GitHub App token
121+
if: github.event_name == 'pull_request'
122+
id: get_token
123+
uses: actions/create-github-app-token@v1
124+
with:
125+
app-id: ${{ secrets.PIPELINE_GITHUB_APP_ID }}
126+
private-key: ${{ secrets.PIPELINE_GITHUB_APP_PRIVATE_KEY }}
127+
repositories: datadog-api-spec
128+
- name: Post status check
129+
uses: DataDog/github-actions/post-status-check@v2
130+
with:
131+
github-token: ${{ steps.get_token.outputs.token }}
132+
repo: datadog-api-spec
133+
# status: ${{ (needs.test.result == 'cancelled' || needs.examples.result == 'cancelled') && 'pending' || needs.test.result == 'success' && needs.examples.result == 'success' && 'success' || 'failure' }}
134+
status: ${{ needs.test.result == 'cancelled' && 'pending' || needs.test.result == 'success' && 'success' || 'failure' }}
135+
context: unit

LICENSE-3rdparty.csv

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,19 @@ Component,Licence,Copyright
99
@types/jest,MIT,Copyright Microsoft Corporation
1010
@types/node,MIT,Copyright Microsoft Corporation
1111
@types/pako,MIT,Copyright Caleb Eggensperger Muhammet Öztürk
12-
@typescript-eslint/eslint-plugin,MIT,Copyright (c) 2019 TypeScript ESLint and other contributors
13-
@typescript-eslint/parser,BSD-2-Clause,
1412
buffer-from,MIT,Copyright (c) 2016, 2018 Linus Unnebäck
1513
chai,MIT,Copyright (c) 2017 Chai.js Assertion Library
1614
chai-quantifiers,MIT,
1715
cross-fetch,MIT,Copyright (c) 2017 Leonardo Quixadá
18-
jest,MIT,Copyright (c) Facebook, Inc. and its affiliates.
19-
ts-jest,MIT,Copyright (c) 2016-2018
2016
dd-trace,BSD-3-Clause,Copyright 2016-Present Datadog Inc.
2117
es6-promise,MIT,Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
22-
eslint-plugin-import,MIT,Copyright (c) 2015 Ben Mosher
23-
eslint-plugin-node,MIT,Copyright (c) 2015 Toru Nagashima
24-
eslint-plugin-unused-imports,MIT,Copyright (c) 2021 Mikkel Holmer
2518
eslint,MIT,Copyright JS Foundation and other contributors, https://js.foundation
2619
form-data,MIT,Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
2720
pako,MIT,Copyright (C) 2014-2017 Vitaly Puzrin and Andrei Tuputcyn
28-
nock,MIT,Copyright (c) 2011-2019 Pedro Teixeira and other contributors
2921
prettier,MIT,Copyright © James Long and contributors
3022
ts-node,MIT,Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)
31-
typedoc,Apache-2.0,Copyright (c) 2015 Sebastian Lenz Copyright (c) 2016-2021 TypeDoc Contributors.
3223
typescript,Apache-2.0,Copyright (c) Microsoft Corporation.
3324
loglevel,MIT,Copyright (c) 2013 Tim Perry
3425
zstd.ts,BSD-2-Clause,Copyright (c) [2021] [Beeno Tung (Tung Cheung Leong)]
26+
commander,MIT,(c) 2011 TJ Holowaychuk
27+
typescript-eslint,MIT,2019 typescript-eslint and other contributors

bin/check-licenses.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"use strict";
2+
3+
const fs = require("fs");
4+
const path = require("path");
5+
const readline = require("readline");
6+
const util = require("util");
7+
const exec = util.promisify(require("child_process").exec);
8+
9+
const LICENSE_FILE = "LICENSE-3rdparty.csv";
10+
11+
async function main() {
12+
const packageJsonPaths = await findPackageJsonPaths();
13+
14+
console.log(`Look for dependencies in:\n`, packageJsonPaths);
15+
const declaredDependencies = withoutDuplicates(
16+
packageJsonPaths.flatMap(retrievePackageJsonDependencies),
17+
).sort();
18+
19+
const declaredLicenses = withoutDuplicates(await retrieveLicenses()).sort();
20+
21+
if (
22+
JSON.stringify(declaredDependencies) !== JSON.stringify(declaredLicenses)
23+
) {
24+
console.error(JSON.stringify(declaredDependencies, null, 2));
25+
console.error(JSON.stringify(declaredLicenses, null, 2));
26+
console.error(
27+
`\n❌ package.json dependencies and ${LICENSE_FILE} mismatch`,
28+
);
29+
console.error(
30+
`\nIn package.json but not in ${LICENSE_FILE}:\n`,
31+
declaredDependencies.filter((d) => !declaredLicenses.includes(d)),
32+
);
33+
console.error(
34+
`\nIn ${LICENSE_FILE} but not in package.json:\n`,
35+
declaredLicenses.filter((d) => !declaredDependencies.includes(d)),
36+
);
37+
throw new Error("dependencies mismatch");
38+
}
39+
console.log(`\n✅ All dependencies listed in ${LICENSE_FILE}`);
40+
}
41+
42+
async function findPackageJsonPaths() {
43+
const { stdout } = await exec(
44+
'find . -path "*/node_modules/*" -prune -o -name "package.json" -print',
45+
);
46+
return stdout.trim().split("\n");
47+
}
48+
49+
function retrievePackageJsonDependencies(packageJsonPath) {
50+
const packageJson = require(path.join(__dirname, "..", packageJsonPath));
51+
52+
return Object.keys(packageJson.dependencies || {})
53+
.concat(Object.keys(packageJson.devDependencies || {}))
54+
.filter((dependency) => !dependency.includes("@datadog"));
55+
}
56+
57+
function withoutDuplicates(a) {
58+
return [...new Set(a)];
59+
}
60+
61+
async function retrieveLicenses() {
62+
const fileStream = fs.createReadStream(
63+
path.join(__dirname, "..", LICENSE_FILE),
64+
);
65+
const rl = readline.createInterface({ input: fileStream });
66+
const licenses = [];
67+
let header = true;
68+
for await (const line of rl) {
69+
const csvColumns = line.split(",");
70+
if (!header && csvColumns[0] !== "file") {
71+
licenses.push(csvColumns[0]);
72+
}
73+
header = false;
74+
}
75+
return licenses;
76+
}
77+
78+
main().catch((e) => {
79+
console.error("\nStacktrace:\n", e);
80+
process.exit(1);
81+
});

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@
2121
"private": true,
2222
"workspaces": [
2323
"packages/*",
24-
"services/*"
24+
"services/*",
25+
"private/*"
2526
],
2627
"scripts": {
28+
"check-licenses": "node bin/check-licenses.js",
2729
"build": "yarn workspaces run build",
2830
"lint": "yarn install --ignore-scripts; eslint --ext .ts packages/* services/*",
2931
"lint:fix": "yarn install --ignore-scripts; yarn lint --fix",
30-
"format": "yarn install --ignore-scripts; prettier --write --ignore-unknown '**.{js,ts}'"
32+
"format": "yarn install --ignore-scripts; prettier --write --ignore-unknown '**.{js,ts}'",
33+
"bdd-test": "yarn workspace bdd-runner run start --working-dir \"$(pwd)\" \"features/v*/*.feature\""
3134
},
3235
"devDependencies": {
33-
"@eslint/js": "^9.23.0",
3436
"eslint": "^9.23.0",
3537
"prettier": "^3.5.3",
3638
"typescript": "^5.8.2",

private/bdd_runner/package.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "bdd-runner",
3+
"repository": {
4+
"type": "git",
5+
"directory": "private/bdd_runner",
6+
"url": "https://github.com/DataDog/datadog-api-client-typescript.git"
7+
},
8+
"files": [
9+
"dist/**/*"
10+
],
11+
"main": "./dist/index.js",
12+
"typings": "./dist/index.d.ts",
13+
"bin": {
14+
"bdd-runner": "./dist/index.js"
15+
},
16+
"scripts": {
17+
"build": "tsc",
18+
"start": "ts-node src/index.ts"
19+
},
20+
"dependencies": {
21+
"@cucumber/cucumber": "^9.2.0",
22+
"@cucumber/messages": "^22.0.0",
23+
"@datadog/datadog-api-client": "^2.0.0-beta.0",
24+
"@pollyjs/adapter-node-http": "^6.0.5",
25+
"@pollyjs/core": "^6.0.5",
26+
"@pollyjs/persister-fs": "^6.0.5",
27+
"@types/chai": "^4.3.4",
28+
"@types/jest": "^29.5.2",
29+
"chai": "^4.3.7",
30+
"chai-quantifiers": "^1.0.17",
31+
"commander": "^13.1.0",
32+
"dd-trace": "^4.3.0",
33+
"@types/node": "*",
34+
"ts-node": "^10.9.1",
35+
"zstd.ts": "^1.1.3"
36+
},
37+
"devDependencies": {
38+
"typescript": "4.8.4"
39+
},
40+
"engines": {
41+
"node": ">=18.0.0"
42+
},
43+
"version": "0.0.1",
44+
"private": true,
45+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
46+
}

private/bdd_runner/src/index.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env node
2+
3+
import { Command } from "commander";
4+
import Cli from "@cucumber/cucumber/lib/cli/index";
5+
6+
import path from "path";
7+
8+
let cwd = process.cwd();
9+
const program = new Command();
10+
program
11+
.name("bdd-runner")
12+
.description("A BDD test runner with Datadog integration")
13+
.option(
14+
"--working-dir <path>",
15+
"Fully qualified path to working directory",
16+
cwd,
17+
)
18+
.option(
19+
"--cassettes-dir <path>",
20+
"Fully qualified path to cassettes directory",
21+
)
22+
.option("--services-dir <path>", "Fully qualified path to services directory")
23+
.option(
24+
"--package-prefix <prefix>",
25+
"Prefix to add to the package name",
26+
"@datadog/datadog-api-client",
27+
)
28+
.option(
29+
"--additional-givens <additionalGivens>",
30+
"Additional given files to be added to cucumber. The value is mapping of version to the given file.",
31+
)
32+
.argument("<feature>", "Fully qualified path to feature files")
33+
.parse(process.argv);
34+
35+
const options = program.opts();
36+
37+
// Initialize Datadog tracing if enabled and host is set
38+
if (process.env.DD_AGENT_HOST != undefined) {
39+
require("dd-trace/ci/init");
40+
}
41+
42+
if (options.workingDir) {
43+
cwd = options.workingDir;
44+
}
45+
let worldParameters = {};
46+
worldParameters["workingDir"] = cwd;
47+
worldParameters["cassettesDir"] =
48+
options.cassettesDir || path.resolve(cwd, "cassettes");
49+
worldParameters["packagePrefix"] = options.packagePrefix;
50+
worldParameters["servicesDir"] =
51+
options.servicesDir || path.resolve(cwd, "services");
52+
53+
let args = program.args;
54+
args.unshift("--world-parameters", JSON.stringify(worldParameters));
55+
args.unshift("--require", process.cwd() + "/src/**/*.ts");
56+
args.unshift(
57+
"--format",
58+
process.env.CI || !process.stdout.isTTY ? "progress" : "progress-bar",
59+
);
60+
args.unshift("--format", "rerun:@rerun.txt");
61+
62+
// Handle additional givens and undo actions
63+
// These are special and need to be loaded in seperately outside of the
64+
// World constructor so we cannot rely on passing them in the worldParameters.
65+
const additionalGivens =
66+
options.additionalGivens ||
67+
JSON.stringify({
68+
v1: path.resolve(cwd, "features/v1/given.json"),
69+
v2: path.resolve(cwd, "features/v2/given.json"),
70+
});
71+
72+
const undoActions = JSON.stringify({
73+
v1: path.resolve(cwd, "features/v1/undo.json"),
74+
v2: path.resolve(cwd, "features/v2/undo.json"),
75+
});
76+
77+
if (additionalGivens.length > 0) {
78+
process.env.BDD_RUNNER_ADDITIONAL_GIVENS = additionalGivens;
79+
}
80+
81+
if (undoActions.length > 0) {
82+
process.env.BDD_RUNNER_UNDO_ACTIONS = undoActions;
83+
}
84+
85+
// Run Cucumber
86+
const cli = new Cli({
87+
argv: args,
88+
cwd: cwd,
89+
stdout: process.stdout,
90+
stderr: process.stderr,
91+
env: process.env,
92+
});
93+
94+
cli.run();

0 commit comments

Comments
 (0)