From 23b0bea887ab79ae2883fe8906e4ec756cb7fe77 Mon Sep 17 00:00:00 2001 From: Sophie Stadler Date: Tue, 2 Apr 2024 11:55:09 -0400 Subject: [PATCH 01/31] DEVPROD-5138: Merge Jest config (#24) --- .evergreen/attach.yml | 2 +- .evergreen/shared.yml | 4 +- .gitignore | 3 ++ README.md | 34 ++++++++++++++ apps/parsley/{ => config/jest}/jest.setup.ts | 0 .../{jest.config.js => jest.config.ts} | 34 +++++--------- apps/parsley/package.json | 5 +- .../parsley/scripts/deploy/utils/git/index.ts | 11 +++-- apps/parsley/src/gql/generated/types.ts | 44 +++++++++++++++-- apps/spruce/{ => config/jest}/global-setup.js | 0 .../spruce/{jest.config.js => jest.config.ts} | 27 ++++------- apps/spruce/package.json | 3 +- .../scripts/deploy/utils/git/git.test.ts | 3 +- apps/spruce/scripts/deploy/utils/git/index.ts | 11 +++-- apps/spruce/scripts/test.js | 47 ------------------- apps/spruce/src/gql/generated/types.ts | 44 +++++++++++++++-- jest.config.ts | 24 ++++++++++ package.json | 11 ++++- yarn.lock | 8 ---- 19 files changed, 187 insertions(+), 128 deletions(-) rename apps/parsley/{ => config/jest}/jest.setup.ts (100%) rename apps/parsley/{jest.config.js => jest.config.ts} (63%) rename apps/spruce/{ => config/jest}/global-setup.js (100%) rename apps/spruce/{jest.config.js => jest.config.ts} (73%) delete mode 100644 apps/spruce/scripts/test.js create mode 100644 jest.config.ts diff --git a/.evergreen/attach.yml b/.evergreen/attach.yml index 1799ec5d9..7f74528e1 100644 --- a/.evergreen/attach.yml +++ b/.evergreen/attach.yml @@ -167,4 +167,4 @@ functions: command: attach.xunit_results params: files: - - "./ui/${app_dir}/bin/jest/*.xml" + - "./ui/bin/jest/*.xml" diff --git a/.evergreen/shared.yml b/.evergreen/shared.yml index ba3e62eaf..98d515913 100644 --- a/.evergreen/shared.yml +++ b/.evergreen/shared.yml @@ -310,10 +310,10 @@ functions: yarn-test: command: shell.exec params: - working_dir: ui/${app_dir} + working_dir: ui script: | ${PREPARE_SHELL} - yarn test --ci --testPathIgnorePatterns=snapshot.test.ts + yarn test --ci --testPathIgnorePatterns=snapshot.test.ts --selectProjects ${build_variant} yarn-tsc: command: shell.exec diff --git a/.gitignore b/.gitignore index 3c3629e64..6e9e9ab13 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ node_modules + +# artifacts +bin diff --git a/README.md b/README.md index 8147c26c4..27837d521 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,37 @@ # Evergreen UI The new home of [Spruce](/apps/spruce) and [Parsley](/apps/parsley). + +## Monorepo Tips & Tricks + +Check out the [Yarn Workspaces documentation](https://classic.yarnpkg.com/lang/en/docs/workspaces/) for more. + +### Upgrades + +To upgrade a dependency across workspaces: + +```bash +yarn upgrade-interactive [--latest] [package-name] +``` + +### Scripts + +To run a script in a workspace from root: + +```bash +yarn workspace [workspace-name] run [script-name] +``` + +For example, `yarn workspace spruce run storybook`. + +### Testing + +To run all unit tests across the repository, from root: +```bash +yarn test +``` + +To run a particular workspace's unit tests from root: +```bash +yarn test --selectProjects [workspace-name] +``` diff --git a/apps/parsley/jest.setup.ts b/apps/parsley/config/jest/jest.setup.ts similarity index 100% rename from apps/parsley/jest.setup.ts rename to apps/parsley/config/jest/jest.setup.ts diff --git a/apps/parsley/jest.config.js b/apps/parsley/jest.config.ts similarity index 63% rename from apps/parsley/jest.config.js rename to apps/parsley/jest.config.ts index a5978e117..5a8f4b8b8 100644 --- a/apps/parsley/jest.config.js +++ b/apps/parsley/jest.config.ts @@ -1,25 +1,27 @@ -module.exports = { +import type { Config } from "jest"; + +const config: Config = { + displayName: "parsley", collectCoverageFrom: [ "src/**/*.{js,jsx,ts,tsx}", "!/node_modules/", "!/src/{main.tsx,vite-env.d.ts}", ], - coverageReporters: ["text"], - moduleFileExtensions: ["json", "js", "jsx", "ts", "tsx"], + moduleFileExtensions: ["tsx", "ts", "json", "js", "jsx"], moduleNameMapper: { "^uuid$": "/node_modules/uuid/dist/index.js", }, modulePaths: ["/src"], - setupFiles: ["./jest.setup.ts"], - preset: "ts-jest", + setupFiles: ["./config/jest/jest.setup.ts"], + preset: "ts-jest/presets/js-with-ts", resetMocks: true, setupFilesAfterEnv: ["/config/jest/setupTests.ts"], snapshotSerializers: ["@emotion/jest/serializer"], testEnvironment: "jsdom", - testMatch: ["/{src,scripts}/**/*.{spec,test}.{js,jsx,ts,tsx}"], + testMatch: ["/{src,scripts}/**/*.{spec,test}.{ts,tsx}"], transform: { + "^.+\\.[tj]sx?$": ["ts-jest", { isolatedModules: true }], "^.+\\.graphql$": "@graphql-tools/jest-transform", - "^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "ts-jest", "^.+\\.css$": "/config/jest/cssTransform.js", "^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "/config/jest/svgTransform.js", @@ -35,20 +37,6 @@ module.exports = { "filter-obj", ].join("|")})`, ], - watchPlugins: [ - "jest-watch-typeahead/filename", - "jest-watch-typeahead/testname", - ], - - // Set the output directory for generating test results. - reporters: [ - "default", - [ - "jest-junit", - { - outputDirectory: "bin/jest", - outputName: "junit.xml", - }, - ], - ], }; + +export default config; diff --git a/apps/parsley/package.json b/apps/parsley/package.json index 2bc858edb..339968773 100644 --- a/apps/parsley/package.json +++ b/apps/parsley/package.json @@ -32,8 +32,7 @@ "verify-backend": "./scripts/verify-backend.sh", "storybook": "storybook dev -p 6006", "storybook:build": "env-cmd -e local -r .env-cmdrc.local.json storybook build", - "test": "jest --watchAll=false", - "test:watch": "jest --watch --verbose", + "test": "yarn --cwd='../..' test --selectProjects parsley", "postversion": "scripts/push-version.sh" }, "dependencies": { @@ -102,7 +101,7 @@ "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "14.1.2", "@testing-library/user-event": "14.5.1", - "@types/jest": "29.5.5", + "@types/jest": "29.5.12", "@types/jest-specific-snapshot": "0.5.9", "@types/js-cookie": "3.0.4", "@types/lodash.debounce": "4.0.7", diff --git a/apps/parsley/scripts/deploy/utils/git/index.ts b/apps/parsley/scripts/deploy/utils/git/index.ts index a5cd5394b..ef57a7a7e 100644 --- a/apps/parsley/scripts/deploy/utils/git/index.ts +++ b/apps/parsley/scripts/deploy/utils/git/index.ts @@ -1,4 +1,5 @@ import { execSync } from "child_process"; +import { resolve } from "path"; /** * `getCommitMessages` returns a string of all commit messages between the currently deployed commit and HEAD. @@ -8,7 +9,7 @@ import { execSync } from "child_process"; const getCommitMessages = (currentlyDeployedCommit: string) => { const commitMessages = execSync( `git log ${currentlyDeployedCommit}..HEAD --oneline -- .`, - { encoding: "utf-8" } + { encoding: "utf-8" }, ).toString(); return commitMessages; }; @@ -19,10 +20,10 @@ const getCommitMessages = (currentlyDeployedCommit: string) => { * @returns - the currently deployed commit */ const getCurrentlyDeployedCommit = () => { - const currentlyDeployedCommit = execSync( - "bash scripts/deploy/get-current-deployed-commit.sh", - { encoding: "utf-8" } - ) + const filePath = resolve(__dirname, "../../get-current-deployed-commit.sh"); + const currentlyDeployedCommit = execSync(`bash ${filePath}`, { + encoding: "utf-8", + }) .toString() .trim(); return currentlyDeployedCommit; diff --git a/apps/parsley/src/gql/generated/types.ts b/apps/parsley/src/gql/generated/types.ts index 9aed845d3..24e9b8eb8 100644 --- a/apps/parsley/src/gql/generated/types.ts +++ b/apps/parsley/src/gql/generated/types.ts @@ -507,6 +507,7 @@ export type EditSpawnHostInput = { publicKey?: InputMaybe; savePublicKey?: InputMaybe; servicePassword?: InputMaybe; + sleepSchedule?: InputMaybe; volume?: InputMaybe; }; @@ -707,6 +708,7 @@ export type Host = { persistentDnsName: Scalars["String"]["output"]; provider: Scalars["String"]["output"]; runningTask?: Maybe; + sleepSchedule?: Maybe; startedBy: Scalars["String"]["output"]; status: Scalars["String"]["output"]; tag: Scalars["String"]["output"]; @@ -1268,6 +1270,7 @@ export type MutationSchedulePatchTasksArgs = { export type MutationScheduleTasksArgs = { taskIds: Array; + versionId?: InputMaybe; }; export type MutationScheduleUndispatchedBaseTasksArgs = { @@ -1420,10 +1423,12 @@ export type ParsleyFilterInput = { /** ParsleySettings contains information about a user's settings for Parsley. */ export type ParsleySettings = { __typename?: "ParsleySettings"; + jumpToFailingLineEnabled: Scalars["Boolean"]["output"]; sectionsEnabled: Scalars["Boolean"]["output"]; }; export type ParsleySettingsInput = { + jumpToFailingLineEnabled?: InputMaybe; sectionsEnabled?: InputMaybe; }; @@ -1892,6 +1897,7 @@ export enum ProjectSettingsAccess { export type ProjectSettingsInput = { aliases?: InputMaybe>; githubWebhooksEnabled?: InputMaybe; + projectId?: InputMaybe; projectRef?: InputMaybe; subscriptions?: InputMaybe>; vars?: InputMaybe; @@ -2029,7 +2035,8 @@ export type QueryGithubProjectConflictsArgs = { }; export type QueryHasVersionArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + patchId?: InputMaybe; }; export type QueryHostArgs = { @@ -2065,7 +2072,8 @@ export type QueryMainlineCommitsArgs = { }; export type QueryPatchArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + patchId?: InputMaybe; }; export type QueryPodArgs = { @@ -2088,12 +2096,14 @@ export type QueryProjectSettingsArgs = { export type QueryRepoEventsArgs = { before?: InputMaybe; - id: Scalars["String"]["input"]; + id?: InputMaybe; limit?: InputMaybe; + repoId?: InputMaybe; }; export type QueryRepoSettingsArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + repoId?: InputMaybe; }; export type QueryTaskArgs = { @@ -2120,7 +2130,8 @@ export type QueryUserArgs = { }; export type QueryVersionArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + versionId?: InputMaybe; }; export type RepoCommitQueueParams = { @@ -2242,6 +2253,7 @@ export type RepoSettingsInput = { aliases?: InputMaybe>; githubWebhooksEnabled?: InputMaybe; projectRef?: InputMaybe; + repoId?: InputMaybe; subscriptions?: InputMaybe>; vars?: InputMaybe; }; @@ -2351,6 +2363,27 @@ export type SlackConfig = { name?: Maybe; }; +export type SleepSchedule = { + __typename?: "SleepSchedule"; + dailyStartTime: Scalars["String"]["output"]; + dailyStopTime: Scalars["String"]["output"]; + permanentlyExempt: Scalars["Boolean"]["output"]; + shouldKeepOff: Scalars["Boolean"]["output"]; + temporarilyExemptUntil?: Maybe; + timeZone: Scalars["String"]["output"]; + wholeWeekdaysOff: Array; +}; + +export type SleepScheduleInput = { + dailyStartTime: Scalars["String"]["input"]; + dailyStopTime: Scalars["String"]["input"]; + permanentlyExempt: Scalars["Boolean"]["input"]; + shouldKeepOff: Scalars["Boolean"]["input"]; + temporarilyExemptUntil?: InputMaybe; + timeZone: Scalars["String"]["input"]; + wholeWeekdaysOff: Array; +}; + export enum SortDirection { Asc = "ASC", Desc = "DESC", @@ -2390,6 +2423,7 @@ export type SpawnHostInput = { region: Scalars["String"]["input"]; savePublicKey: Scalars["Boolean"]["input"]; setUpScript?: InputMaybe; + sleepSchedule?: InputMaybe; spawnHostsStartedByTask?: InputMaybe; taskId?: InputMaybe; taskSync?: InputMaybe; diff --git a/apps/spruce/global-setup.js b/apps/spruce/config/jest/global-setup.js similarity index 100% rename from apps/spruce/global-setup.js rename to apps/spruce/config/jest/global-setup.js diff --git a/apps/spruce/jest.config.js b/apps/spruce/jest.config.ts similarity index 73% rename from apps/spruce/jest.config.js rename to apps/spruce/jest.config.ts index d8a941837..926f129e4 100644 --- a/apps/spruce/jest.config.js +++ b/apps/spruce/jest.config.ts @@ -1,10 +1,12 @@ -module.exports = { +import type { Config } from "jest"; + +const config: Config = { + displayName: "spruce", collectCoverageFrom: [ "src/**/*.{js,jsx,ts,tsx}", "!/node_modules/", "!/src/{index.tsx,react-app-env.d.ts}", ], - coverageReporters: ["text"], moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"], moduleNameMapper: { "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy", @@ -16,7 +18,7 @@ module.exports = { setupFilesAfterEnv: ["/config/jest/setupTests.ts"], snapshotSerializers: ["@emotion/jest/serializer"], testEnvironment: "jsdom", - testMatch: ["/{src,scripts}/**/*.{spec,test}.{js,jsx,ts,tsx}"], + testMatch: ["/{src,scripts}/**/*.{spec,test}.{ts,tsx}"], transform: { "^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "babel-jest", "^.+\\.css$": "/config/jest/cssTransform.js", @@ -35,20 +37,7 @@ module.exports = { "filter-obj", ].join("|")})`, ], - watchPlugins: [ - "jest-watch-typeahead/filename", - "jest-watch-typeahead/testname", - ], - globalSetup: "/global-setup.js", - testTimeout: 30000, - reporters: [ - "default", - [ - "jest-junit", - { - outputDirectory: "bin/jest", - outputName: "junit.xml", - }, - ], - ], + globalSetup: "/config/jest/global-setup.js", }; + +export default config; diff --git a/apps/spruce/package.json b/apps/spruce/package.json index 2ec46c9bb..14ff36f18 100644 --- a/apps/spruce/package.json +++ b/apps/spruce/package.json @@ -34,8 +34,7 @@ "staging": "env-cmd -e devStaging -r .env-cmdrc.local.json yarn start", "start": "vite", "storybook": "storybook dev -p 6006", - "test:watch": "node scripts/test.js --verbose", - "test": "node scripts/test.js --watchAll=false", + "test": "yarn --cwd='../..' test --selectProjects spruce", "postversion": "scripts/push-version.sh" }, "browserslist": { diff --git a/apps/spruce/scripts/deploy/utils/git/git.test.ts b/apps/spruce/scripts/deploy/utils/git/git.test.ts index 03c8857de..0847dea52 100644 --- a/apps/spruce/scripts/deploy/utils/git/git.test.ts +++ b/apps/spruce/scripts/deploy/utils/git/git.test.ts @@ -1,3 +1,4 @@ +import { execSync } from "child_process"; import { getCurrentlyDeployedCommit } from "."; const currentlyDeployedCommitRegex = /^[0-9a-f]{40}$/; @@ -6,7 +7,7 @@ describe("getCurrentlyDeployedCommit", () => { it("should return the currently deployed commit", () => { const currentlyDeployedCommit = getCurrentlyDeployedCommit(); const currentlyDeployedCommitIsHash = currentlyDeployedCommitRegex.test( - currentlyDeployedCommit + currentlyDeployedCommit, ); expect(currentlyDeployedCommitIsHash).toBeTruthy(); }); diff --git a/apps/spruce/scripts/deploy/utils/git/index.ts b/apps/spruce/scripts/deploy/utils/git/index.ts index d73178f8c..5af814401 100644 --- a/apps/spruce/scripts/deploy/utils/git/index.ts +++ b/apps/spruce/scripts/deploy/utils/git/index.ts @@ -1,4 +1,5 @@ import { execSync } from "child_process"; +import { resolve } from "path"; /** * `getCommitMessages` returns a string of all commit messages between the currently deployed commit and HEAD. @@ -8,7 +9,7 @@ import { execSync } from "child_process"; const getCommitMessages = (currentlyDeployedCommit: string) => { const commitMessages = execSync( `git log ${currentlyDeployedCommit}..HEAD --oneline -- .`, - { encoding: "utf-8" } + { encoding: "utf-8" }, ).toString(); return commitMessages; }; @@ -19,10 +20,10 @@ const getCommitMessages = (currentlyDeployedCommit: string) => { * @returns - the currently deployed commit */ const getCurrentlyDeployedCommit = () => { - const currentlyDeployedCommit = execSync( - "bash scripts/deploy/get-current-deployed-commit.sh", - { encoding: "utf-8" } - ) + const filePath = resolve(__dirname, "../../get-current-deployed-commit.sh"); + const currentlyDeployedCommit = execSync(`bash ${filePath}`, { + encoding: "utf-8", + }) .toString() .trim(); return currentlyDeployedCommit; diff --git a/apps/spruce/scripts/test.js b/apps/spruce/scripts/test.js deleted file mode 100644 index 77cc33405..000000000 --- a/apps/spruce/scripts/test.js +++ /dev/null @@ -1,47 +0,0 @@ -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = "test"; -process.env.NODE_ENV = "test"; -process.env.PUBLIC_URL = ""; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on("unhandledRejection", (err) => { - throw err; -}); - -const jest = require("jest"); -const { execSync } = require("child_process"); -const path = require("path"); - -const argv = process.argv.slice(2); - -/** - * isInGitRepository identifies whether the current working directory uses git. - * @returns - A boolean indicating whether the current directory uses git. - */ -function isInGitRepository() { - try { - execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" }); - return true; - } catch (e) { - return false; - } -} - -// Watch unless on CI or explicitly running all tests -if ( - !process.env.CI && - argv.indexOf("--watchAll") === -1 && - argv.indexOf("--watchAll=false") === -1 -) { - // https://github.com/facebook/create-react-app/issues/5210 - const hasSourceControl = isInGitRepository(); - argv.push(hasSourceControl ? "--watch" : "--watchAll"); -} - -if (argv.indexOf("--reporters=jest-junit") !== -1) { - process.env.JEST_JUNIT_OUTPUT_DIR = path.join(process.cwd(), "/bin/jest"); -} - -jest.run(argv); diff --git a/apps/spruce/src/gql/generated/types.ts b/apps/spruce/src/gql/generated/types.ts index 40574d2fb..35afa95f6 100644 --- a/apps/spruce/src/gql/generated/types.ts +++ b/apps/spruce/src/gql/generated/types.ts @@ -507,6 +507,7 @@ export type EditSpawnHostInput = { publicKey?: InputMaybe; savePublicKey?: InputMaybe; servicePassword?: InputMaybe; + sleepSchedule?: InputMaybe; volume?: InputMaybe; }; @@ -707,6 +708,7 @@ export type Host = { persistentDnsName: Scalars["String"]["output"]; provider: Scalars["String"]["output"]; runningTask?: Maybe; + sleepSchedule?: Maybe; startedBy: Scalars["String"]["output"]; status: Scalars["String"]["output"]; tag: Scalars["String"]["output"]; @@ -1268,6 +1270,7 @@ export type MutationSchedulePatchTasksArgs = { export type MutationScheduleTasksArgs = { taskIds: Array; + versionId?: InputMaybe; }; export type MutationScheduleUndispatchedBaseTasksArgs = { @@ -1420,10 +1423,12 @@ export type ParsleyFilterInput = { /** ParsleySettings contains information about a user's settings for Parsley. */ export type ParsleySettings = { __typename?: "ParsleySettings"; + jumpToFailingLineEnabled: Scalars["Boolean"]["output"]; sectionsEnabled: Scalars["Boolean"]["output"]; }; export type ParsleySettingsInput = { + jumpToFailingLineEnabled?: InputMaybe; sectionsEnabled?: InputMaybe; }; @@ -1892,6 +1897,7 @@ export enum ProjectSettingsAccess { export type ProjectSettingsInput = { aliases?: InputMaybe>; githubWebhooksEnabled?: InputMaybe; + projectId?: InputMaybe; projectRef?: InputMaybe; subscriptions?: InputMaybe>; vars?: InputMaybe; @@ -2029,7 +2035,8 @@ export type QueryGithubProjectConflictsArgs = { }; export type QueryHasVersionArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + patchId?: InputMaybe; }; export type QueryHostArgs = { @@ -2065,7 +2072,8 @@ export type QueryMainlineCommitsArgs = { }; export type QueryPatchArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + patchId?: InputMaybe; }; export type QueryPodArgs = { @@ -2088,12 +2096,14 @@ export type QueryProjectSettingsArgs = { export type QueryRepoEventsArgs = { before?: InputMaybe; - id: Scalars["String"]["input"]; + id?: InputMaybe; limit?: InputMaybe; + repoId?: InputMaybe; }; export type QueryRepoSettingsArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + repoId?: InputMaybe; }; export type QueryTaskArgs = { @@ -2120,7 +2130,8 @@ export type QueryUserArgs = { }; export type QueryVersionArgs = { - id: Scalars["String"]["input"]; + id?: InputMaybe; + versionId?: InputMaybe; }; export type RepoCommitQueueParams = { @@ -2242,6 +2253,7 @@ export type RepoSettingsInput = { aliases?: InputMaybe>; githubWebhooksEnabled?: InputMaybe; projectRef?: InputMaybe; + repoId?: InputMaybe; subscriptions?: InputMaybe>; vars?: InputMaybe; }; @@ -2351,6 +2363,27 @@ export type SlackConfig = { name?: Maybe; }; +export type SleepSchedule = { + __typename?: "SleepSchedule"; + dailyStartTime: Scalars["String"]["output"]; + dailyStopTime: Scalars["String"]["output"]; + permanentlyExempt: Scalars["Boolean"]["output"]; + shouldKeepOff: Scalars["Boolean"]["output"]; + temporarilyExemptUntil?: Maybe; + timeZone: Scalars["String"]["output"]; + wholeWeekdaysOff: Array; +}; + +export type SleepScheduleInput = { + dailyStartTime: Scalars["String"]["input"]; + dailyStopTime: Scalars["String"]["input"]; + permanentlyExempt: Scalars["Boolean"]["input"]; + shouldKeepOff: Scalars["Boolean"]["input"]; + temporarilyExemptUntil?: InputMaybe; + timeZone: Scalars["String"]["input"]; + wholeWeekdaysOff: Array; +}; + export enum SortDirection { Asc = "ASC", Desc = "DESC", @@ -2390,6 +2423,7 @@ export type SpawnHostInput = { region: Scalars["String"]["input"]; savePublicKey: Scalars["Boolean"]["input"]; setUpScript?: InputMaybe; + sleepSchedule?: InputMaybe; spawnHostsStartedByTask?: InputMaybe; taskId?: InputMaybe; taskSync?: InputMaybe; diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 000000000..ba775f5d8 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,24 @@ +import type { Config } from "jest"; + +const config: Config = { + coverageReporters: ["text"], + projects: ["/apps/*"], + reporters: [ + "default", + [ + "jest-junit", + { + outputDirectory: "bin/jest", + outputName: "junit.xml", + }, + ], + ], + testEnvironment: "jsdom", + testTimeout: 30000, + watchPlugins: [ + "jest-watch-typeahead/filename", + "jest-watch-typeahead/testname", + ], +}; + +export default config; diff --git a/package.json b/package.json index 366c04120..d8127efd3 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,15 @@ "repository": "https://github.com/evergreen-ci/ui", "private": true, "workspaces": { - "packages": ["apps/*"], - "nohoist": ["**/storybook-addon-apollo-client"] + "packages": [ + "apps/*" + ], + "nohoist": [ + "**/storybook-addon-apollo-client" + ] + }, + "scripts": { + "test": "jest" }, "resolutions": { "@tanstack/react-table": "8.9.3", diff --git a/yarn.lock b/yarn.lock index f565a8f0d..74870c846 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6378,14 +6378,6 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/jest@29.5.5": - version "29.5.5" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.5.tgz#727204e06228fe24373df9bae76b90f3e8236a2a" - integrity sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - "@types/js-cookie@3.0.4": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.4.tgz#23475b6d3b03acc84192e7c24da88eb38c1039ef" From 7534d90af2423930fff60f205173d1c118a31be0 Mon Sep 17 00:00:00 2001 From: minnakt <47064971+minnakt@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:37:56 -0400 Subject: [PATCH 02/31] DEVPROD-5460: Update GraphQL queries to use specific arguments (#23) --- .../components/ScheduleTasksModal/index.tsx | 4 +- apps/spruce/src/gql/generated/types.ts | 1 + .../src/gql/mutations/schedule-tasks.graphql | 4 +- .../gql/queries/build-variant-stats.graphql | 2 +- .../build-variants-with-children.graphql | 2 +- .../src/gql/queries/code-changes.graphql | 2 +- .../src/gql/queries/has-version.graphql | 2 +- .../gql/queries/is-patch-configured.graphql | 2 +- .../src/gql/queries/patch-configure.graphql | 2 +- .../gql/queries/patch-task-statuses.graphql | 2 +- apps/spruce/src/gql/queries/patch.graphql | 2 +- .../src/gql/queries/repo-event-logs.graphql | 2 +- .../src/gql/queries/repo-settings.graphql | 2 +- .../src/gql/queries/task-statuses.graphql | 2 +- .../gql/queries/undispatched-tasks.graphql | 2 +- .../queries/version-task-durations.graphql | 2 +- .../src/gql/queries/version-tasks.graphql | 2 +- apps/spruce/src/gql/queries/version.graphql | 2 +- .../pages/projectSettings/HeaderButtons.tsx | 2 +- .../tabs/AccessTab/transformers.test.ts | 12 ++- .../tabs/AccessTab/transformers.ts | 4 +- .../tabs/ContainersTab/transformers.test.ts | 3 +- .../tabs/ContainersTab/transformers.ts | 3 +- .../tabs/GeneralTab/transformers.test.ts | 12 ++- .../tabs/GeneralTab/transformers.ts | 3 +- .../GithubCommitQueueTab/transformers.test.ts | 74 +++++++++------- .../tabs/GithubCommitQueueTab/transformers.ts | 2 + .../NotificationsTab/transformers.test.ts | 19 ++-- .../tabs/NotificationsTab/transformers.ts | 7 +- .../tabs/PatchAliasesTab/transformers.test.ts | 88 ++++++++++--------- .../tabs/PatchAliasesTab/transformers.ts | 2 + .../PeriodicBuildsTab/transformers.test.ts | 12 ++- .../tabs/PeriodicBuildsTab/transformers.ts | 17 +++- .../tabs/PluginsTab/transformers.test.ts | 12 ++- .../tabs/PluginsTab/transformers.ts | 3 +- .../ProjectTriggersTab/transformers.test.ts | 12 ++- .../tabs/ProjectTriggersTab/transformers.ts | 5 +- .../tabs/VariablesTab/transformers.test.ts | 23 ++--- .../tabs/VariablesTab/transformers.ts | 3 +- .../ViewsAndFiltersTab/transformers.test.ts | 12 ++- .../tabs/ViewsAndFiltersTab/transformers.ts | 3 +- .../transformers.test.ts | 12 ++- .../VirtualWorkstationTab/transformers.ts | 2 + .../src/pages/projectSettings/tabs/types.ts | 4 +- apps/spruce/src/pages/task/ActionButtons.tsx | 4 +- 45 files changed, 239 insertions(+), 155 deletions(-) diff --git a/apps/spruce/src/components/ScheduleTasksModal/index.tsx b/apps/spruce/src/components/ScheduleTasksModal/index.tsx index 75f15ada0..ea26a665e 100644 --- a/apps/spruce/src/components/ScheduleTasksModal/index.tsx +++ b/apps/spruce/src/components/ScheduleTasksModal/index.tsx @@ -81,7 +81,9 @@ export const ScheduleTasksModal: React.FC = ({ loadingTaskData || loadingScheduleTasksMutation || !selectedTasks.size } onConfirm={() => { - scheduleTasks({ variables: { taskIds: Array.from(selectedTasks) } }); + scheduleTasks({ + variables: { taskIds: Array.from(selectedTasks), versionId }, + }); }} > diff --git a/apps/spruce/src/gql/generated/types.ts b/apps/spruce/src/gql/generated/types.ts index 35afa95f6..1d4f15717 100644 --- a/apps/spruce/src/gql/generated/types.ts +++ b/apps/spruce/src/gql/generated/types.ts @@ -5155,6 +5155,7 @@ export type SchedulePatchMutation = { export type ScheduleTasksMutationVariables = Exact<{ taskIds: Array; + versionId: Scalars["String"]["input"]; }>; export type ScheduleTasksMutation = { diff --git a/apps/spruce/src/gql/mutations/schedule-tasks.graphql b/apps/spruce/src/gql/mutations/schedule-tasks.graphql index 7d40446da..0ed65a8d1 100644 --- a/apps/spruce/src/gql/mutations/schedule-tasks.graphql +++ b/apps/spruce/src/gql/mutations/schedule-tasks.graphql @@ -1,7 +1,7 @@ #import "../fragments/baseTask.graphql" -mutation ScheduleTasks($taskIds: [String!]!) { - scheduleTasks(taskIds: $taskIds) { +mutation ScheduleTasks($taskIds: [String!]!, $versionId: String!) { + scheduleTasks(taskIds: $taskIds, versionId: $versionId) { ...BaseTask } } diff --git a/apps/spruce/src/gql/queries/build-variant-stats.graphql b/apps/spruce/src/gql/queries/build-variant-stats.graphql index 7a1fc058a..37a943aa6 100644 --- a/apps/spruce/src/gql/queries/build-variant-stats.graphql +++ b/apps/spruce/src/gql/queries/build-variant-stats.graphql @@ -1,5 +1,5 @@ query BuildVariantStats($id: String!) { - version(id: $id) { + version(versionId: $id) { buildVariantStats(options: {}) { displayName statusCounts { diff --git a/apps/spruce/src/gql/queries/build-variants-with-children.graphql b/apps/spruce/src/gql/queries/build-variants-with-children.graphql index 47e38e0c4..d282409f6 100644 --- a/apps/spruce/src/gql/queries/build-variants-with-children.graphql +++ b/apps/spruce/src/gql/queries/build-variants-with-children.graphql @@ -1,5 +1,5 @@ query BuildVariantsWithChildren($id: String!) { - version(id: $id) { + version(versionId: $id) { buildVariants(options: {}) { displayName tasks { diff --git a/apps/spruce/src/gql/queries/code-changes.graphql b/apps/spruce/src/gql/queries/code-changes.graphql index 95634dcf8..fbed2ba14 100644 --- a/apps/spruce/src/gql/queries/code-changes.graphql +++ b/apps/spruce/src/gql/queries/code-changes.graphql @@ -1,7 +1,7 @@ #import "../fragments/moduleCodeChanges.graphql" query CodeChanges($id: String!) { - patch(id: $id) { + patch(patchId: $id) { id moduleCodeChanges { ...ModuleCodeChange diff --git a/apps/spruce/src/gql/queries/has-version.graphql b/apps/spruce/src/gql/queries/has-version.graphql index 4c2194754..9255c4172 100644 --- a/apps/spruce/src/gql/queries/has-version.graphql +++ b/apps/spruce/src/gql/queries/has-version.graphql @@ -1,3 +1,3 @@ query HasVersion($id: String!) { - hasVersion(id: $id) + hasVersion(patchId: $id) } diff --git a/apps/spruce/src/gql/queries/is-patch-configured.graphql b/apps/spruce/src/gql/queries/is-patch-configured.graphql index cfa48ef15..3ff217a81 100644 --- a/apps/spruce/src/gql/queries/is-patch-configured.graphql +++ b/apps/spruce/src/gql/queries/is-patch-configured.graphql @@ -1,5 +1,5 @@ query IsPatchConfigured($id: String!) { - patch(id: $id) { + patch(patchId: $id) { activated alias id diff --git a/apps/spruce/src/gql/queries/patch-configure.graphql b/apps/spruce/src/gql/queries/patch-configure.graphql index 0a3eb503b..dbed78cf1 100644 --- a/apps/spruce/src/gql/queries/patch-configure.graphql +++ b/apps/spruce/src/gql/queries/patch-configure.graphql @@ -1,7 +1,7 @@ #import "../fragments/basePatch.graphql" query ConfigurePatch($id: String!) { - patch(id: $id) { + patch(patchId: $id) { ...BasePatch childPatchAliases { alias diff --git a/apps/spruce/src/gql/queries/patch-task-statuses.graphql b/apps/spruce/src/gql/queries/patch-task-statuses.graphql index 44ee40ab7..6da995fce 100644 --- a/apps/spruce/src/gql/queries/patch-task-statuses.graphql +++ b/apps/spruce/src/gql/queries/patch-task-statuses.graphql @@ -1,5 +1,5 @@ query PatchTaskStatuses($id: String!) { - patch(id: $id) { + patch(patchId: $id) { baseTaskStatuses id taskStatuses diff --git a/apps/spruce/src/gql/queries/patch.graphql b/apps/spruce/src/gql/queries/patch.graphql index 48eeb5bd8..4eeb247f3 100644 --- a/apps/spruce/src/gql/queries/patch.graphql +++ b/apps/spruce/src/gql/queries/patch.graphql @@ -1,7 +1,7 @@ #import "../fragments/basePatch.graphql" query Patch($id: String!) { - patch(id: $id) { + patch(patchId: $id) { ...BasePatch githash patchNumber diff --git a/apps/spruce/src/gql/queries/repo-event-logs.graphql b/apps/spruce/src/gql/queries/repo-event-logs.graphql index 8fc5d8e3f..57b703dee 100644 --- a/apps/spruce/src/gql/queries/repo-event-logs.graphql +++ b/apps/spruce/src/gql/queries/repo-event-logs.graphql @@ -1,7 +1,7 @@ #import "../fragments/projectSettings/projectEventSettings.graphql" query RepoEventLogs($id: String!, $limit: Int, $before: Time) { - repoEvents(id: $id, limit: $limit, before: $before) { + repoEvents(id: $id, repoId: $id, limit: $limit, before: $before) { count eventLogEntries { after { diff --git a/apps/spruce/src/gql/queries/repo-settings.graphql b/apps/spruce/src/gql/queries/repo-settings.graphql index 465c72d0d..138acaf45 100644 --- a/apps/spruce/src/gql/queries/repo-settings.graphql +++ b/apps/spruce/src/gql/queries/repo-settings.graphql @@ -1,7 +1,7 @@ #import "../fragments/projectSettings/index.graphql" query RepoSettings($repoId: String!) { - repoSettings(id: $repoId) { + repoSettings(id: $repoId, repoId: $repoId) { ...RepoSettingsFields } } diff --git a/apps/spruce/src/gql/queries/task-statuses.graphql b/apps/spruce/src/gql/queries/task-statuses.graphql index 66310aa1c..45b21f9c0 100644 --- a/apps/spruce/src/gql/queries/task-statuses.graphql +++ b/apps/spruce/src/gql/queries/task-statuses.graphql @@ -1,5 +1,5 @@ query TaskStatuses($id: String!) { - version(id: $id) { + version(versionId: $id) { baseTaskStatuses id taskStatuses diff --git a/apps/spruce/src/gql/queries/undispatched-tasks.graphql b/apps/spruce/src/gql/queries/undispatched-tasks.graphql index 9e08e0f8e..ea4402e99 100644 --- a/apps/spruce/src/gql/queries/undispatched-tasks.graphql +++ b/apps/spruce/src/gql/queries/undispatched-tasks.graphql @@ -1,5 +1,5 @@ query UndispatchedTasks($versionId: String!) { - version(id: $versionId) { + version(versionId: $versionId) { id tasks( options: { statuses: ["unscheduled"], includeEmptyActivation: true } diff --git a/apps/spruce/src/gql/queries/version-task-durations.graphql b/apps/spruce/src/gql/queries/version-task-durations.graphql index ea697ca71..db390688e 100644 --- a/apps/spruce/src/gql/queries/version-task-durations.graphql +++ b/apps/spruce/src/gql/queries/version-task-durations.graphql @@ -2,7 +2,7 @@ query VersionTaskDurations( $versionId: String! $taskFilterOptions: TaskFilterOptions! ) { - version(id: $versionId) { + version(versionId: $versionId) { id tasks(options: $taskFilterOptions) { count diff --git a/apps/spruce/src/gql/queries/version-tasks.graphql b/apps/spruce/src/gql/queries/version-tasks.graphql index 6d6f21b59..c583fa9ec 100644 --- a/apps/spruce/src/gql/queries/version-tasks.graphql +++ b/apps/spruce/src/gql/queries/version-tasks.graphql @@ -2,7 +2,7 @@ query VersionTasks( $versionId: String! $taskFilterOptions: TaskFilterOptions! ) { - version(id: $versionId) { + version(versionId: $versionId) { id isPatch tasks(options: $taskFilterOptions) { diff --git a/apps/spruce/src/gql/queries/version.graphql b/apps/spruce/src/gql/queries/version.graphql index 56ab21c20..397dadc0f 100644 --- a/apps/spruce/src/gql/queries/version.graphql +++ b/apps/spruce/src/gql/queries/version.graphql @@ -1,7 +1,7 @@ #import "../fragments/upstreamProject.graphql" query Version($id: String!) { - version(id: $id) { + version(versionId: $id) { activated author authorEmail diff --git a/apps/spruce/src/pages/projectSettings/HeaderButtons.tsx b/apps/spruce/src/pages/projectSettings/HeaderButtons.tsx index 314ef8593..c39c9e607 100644 --- a/apps/spruce/src/pages/projectSettings/HeaderButtons.tsx +++ b/apps/spruce/src/pages/projectSettings/HeaderButtons.tsx @@ -105,7 +105,7 @@ export const HeaderButtons: React.FC = ({ id, projectType, tab }) => { const onClick = () => { const formToGql: FormToGqlFunction = formToGqlMap[tab]; - const newData = formToGql(formData, id); + const newData = formToGql(formData, isRepo, id); const save = (update, section) => isRepo ? saveRepoSection({ diff --git a/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.test.ts index acf509fca..1cb23f0cd 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.test.ts @@ -11,7 +11,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -21,7 +21,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -34,7 +36,8 @@ const projectForm: AccessFormState = { }, }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", restricted: true, @@ -51,7 +54,8 @@ const repoForm: AccessFormState = { }, }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", restricted: true, diff --git a/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.ts index d9b86cd8a..63841e0a6 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/AccessTab/transformers.ts @@ -18,12 +18,12 @@ export const gqlToForm = ((data) => { }; }) satisfies GqlToFormFunction; -export const formToGql = (({ accessSettings, admin }, id) => { +export const formToGql = (({ accessSettings, admin }, isRepo, id) => { const projectRef: ProjectInput = { id, restricted: accessSettings.restricted, admins: admin.admins, }; - return { projectRef }; + return { ...(isRepo ? { repoId: id } : { projectId: id }), projectRef }; }) satisfies FormToGqlFunction; diff --git a/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.test.ts index 7050c462d..fc13b2b0e 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.test.ts @@ -10,7 +10,7 @@ describe("containers", () => { expect(gqlToForm(projectBase)).toStrictEqual(projectFormBase); }); it("correctly converts from a form to GQL", () => { - expect(formToGql(projectFormBase, "spruce")).toStrictEqual( + expect(formToGql(projectFormBase, false, "spruce")).toStrictEqual( projectResultBase, ); }); @@ -29,6 +29,7 @@ const projectFormBase: ContainersFormState = { }; const projectResultBase: ProjectSettingsInput = { + projectId: "spruce", projectRef: { id: "spruce", containerSizeDefinitions: [ diff --git a/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.ts index 2f983a4f9..a9e8216c6 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/ContainersTab/transformers.ts @@ -15,9 +15,10 @@ export const gqlToForm = ((data) => { }; }) satisfies GqlToFormFunction; -export const formToGql = ((formState, id) => { +export const formToGql = ((formState, isRepo, id) => { const { containerSizeDefinitions } = formState; return { + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { id, containerSizeDefinitions: containerSizeDefinitions.variables, diff --git a/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts index bd8b21c10..6b0e01e8b 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts @@ -14,7 +14,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -24,7 +24,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -67,7 +69,8 @@ const repoForm: GeneralFormState = { }, }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", owner: "evergreen-ci", @@ -133,7 +136,8 @@ const projectForm: GeneralFormState = { }, }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", enabled: false, diff --git a/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.ts index 328ab6dc2..59be18c6d 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GeneralTab/transformers.ts @@ -68,6 +68,7 @@ export const formToGql = (( historicalTaskDataCaching: { disabledStatsCache }, projectFlags, }, + isRepo, id, ) => { const projectRef: ProjectInput = { @@ -101,5 +102,5 @@ export const formToGql = (( disabledStatsCache, }; - return { projectRef }; + return { ...(isRepo ? { repoId: id } : { projectId: id }), projectRef }; }) satisfies FormToGqlFunction; diff --git a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts index 8c19342fb..7f2378cd2 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts @@ -19,7 +19,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -31,7 +31,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL and omits empty strings", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); it("correctly merges project and repo form states", () => { @@ -139,7 +141,11 @@ const projectForm: GCQFormState = { }, }; -const projectResult: Pick = { +const projectResult: Pick< + ProjectSettingsInput, + "projectId" | "projectRef" | "aliases" +> = { + projectId: "project", projectRef: { id: "project", prTestingEnabled: null, @@ -275,37 +281,39 @@ const repoForm: GCQFormState = { }, }; -const repoResult: Pick = { - projectRef: { - id: "repo", - prTestingEnabled: false, - manualPrTestingEnabled: false, - githubChecksEnabled: true, - gitTagVersionsEnabled: false, - gitTagAuthorizedUsers: ["admin"], - gitTagAuthorizedTeams: [], - commitQueue: { - enabled: true, - message: "Commit Queue Message", - mergeMethod: "squash", - mergeQueue: MergeQueue.Github, - }, - }, - aliases: [ - { - id: "2", - alias: "__github_checks", - description: "", - gitTag: "", - remotePath: "", - task: "", - taskTags: ["tTag"], - variant: "", - variantTags: ["vTag"], - parameters: [], +const repoResult: Pick = + { + repoId: "repo", + projectRef: { + id: "repo", + prTestingEnabled: false, + manualPrTestingEnabled: false, + githubChecksEnabled: true, + gitTagVersionsEnabled: false, + gitTagAuthorizedUsers: ["admin"], + gitTagAuthorizedTeams: [], + commitQueue: { + enabled: true, + message: "Commit Queue Message", + mergeMethod: "squash", + mergeQueue: MergeQueue.Github, + }, }, - ], -}; + aliases: [ + { + id: "2", + alias: "__github_checks", + description: "", + gitTag: "", + remotePath: "", + task: "", + taskTags: ["tTag"], + variant: "", + variantTags: ["vTag"], + parameters: [], + }, + ], + }; const mergedForm: GCQFormState = { github: { diff --git a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts index 0243fd7bd..2d23f813c 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts @@ -127,6 +127,7 @@ export const formToGql = (( users: { gitTagAuthorizedUsers, gitTagAuthorizedUsersOverride }, }, }, + isRepo, id, ) => { const projectRef: ProjectInput = { @@ -181,6 +182,7 @@ export const formToGql = (( ]; return { + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef, aliases, }; diff --git a/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.test.ts index ab4e39003..e3990347e 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.test.ts @@ -20,7 +20,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL when a banner value exists in the form", () => { - expect(formToGql({ ...projectFormBase, banner }, "spruce")).toStrictEqual({ + expect( + formToGql({ ...projectFormBase, banner }, false, "spruce"), + ).toStrictEqual({ ...projectResultBase, projectRef: { ...projectResultBase.projectRef, @@ -30,7 +32,7 @@ describe("project data", () => { }); it("correctly converts from a form to GQL when the subscriptions field is empty", () => { - expect(formToGql(projectFormBase, "spruce")).toStrictEqual( + expect(formToGql(projectFormBase, false, "spruce")).toStrictEqual( projectResultBase, ); }); @@ -88,7 +90,9 @@ describe("project data", () => { ], }; - expect(formToGql(projectForm, "spruce")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "spruce")).toStrictEqual( + projectResult, + ); }); it("handles jira issue subscriptions", () => { @@ -150,7 +154,9 @@ describe("project data", () => { }, ], }; - expect(formToGql(projectForm, "spruce")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "spruce")).toStrictEqual( + projectResult, + ); }); it("handles webhook subscriptions", () => { const projectForm = { @@ -230,7 +236,9 @@ describe("project data", () => { ], }; - expect(formToGql(projectForm, "spruce")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "spruce")).toStrictEqual( + projectResult, + ); }); }); @@ -242,6 +250,7 @@ const projectFormBase: NotificationsFormState = { }; const projectResultBase: ProjectSettingsInput = { + projectId: "spruce", projectRef: { id: "spruce", notifyOnBuildFailure: null, diff --git a/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.ts index 6e235bb82..ba2ec5eab 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/NotificationsTab/transformers.ts @@ -138,17 +138,18 @@ export const gqlToForm = ((data, { projectType }) => { }; }) satisfies GqlToFormFunction; -export const formToGql = ((formState, projectId) => { +export const formToGql = ((formState, isRepo, id) => { const { banner, buildBreakSettings, subscriptions } = formState; const projectRef: ProjectInput = { - id: projectId, + id, notifyOnBuildFailure: buildBreakSettings.notifyOnBuildFailure, ...(banner && { banner: banner.bannerData }), }; const transformedSubscriptions: SubscriptionInput[] = subscriptions.map( - getGqlPayload(projectId), + getGqlPayload(id), ); return { + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef, subscriptions: transformedSubscriptions, }; diff --git a/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.test.ts index d9ea5025a..8091d7ef8 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.test.ts @@ -15,7 +15,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -27,7 +27,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL and omits empty strings", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -42,7 +44,11 @@ const projectForm: PatchAliasesFormState = { }, }; -const projectResult: Pick = { +const projectResult: Pick< + ProjectSettingsInput, + "projectId" | "projectRef" | "aliases" +> = { + projectId: "project", projectRef: { id: "project", patchTriggerAliases: null, @@ -105,43 +111,45 @@ const repoForm: PatchAliasesFormState = { }, }; -const repoResult: Pick = { - projectRef: { - id: "repo", - patchTriggerAliases: [ +const repoResult: Pick = + { + repoId: "repo", + projectRef: { + id: "repo", + patchTriggerAliases: [ + { + alias: "alias1", + childProjectIdentifier: "spruce", + taskSpecifiers: [ + { + patchAlias: "alias2", + taskRegex: "", + variantRegex: "", + }, + { + patchAlias: "", + taskRegex: ".*", + variantRegex: ".*", + }, + ], + status: "success", + parentAsModule: "", + }, + ], + githubTriggerAliases: ["alias1"], + }, + aliases: [ { - alias: "alias1", - childProjectIdentifier: "spruce", - taskSpecifiers: [ - { - patchAlias: "alias2", - taskRegex: "", - variantRegex: "", - }, - { - patchAlias: "", - taskRegex: ".*", - variantRegex: ".*", - }, - ], - status: "success", - parentAsModule: "", + id: "4", + alias: "my alias name", + description: "my description", + gitTag: "", + variant: "", + task: "", + remotePath: "", + parameters: [], + variantTags: ["okay"], + taskTags: ["hi"], }, ], - githubTriggerAliases: ["alias1"], - }, - aliases: [ - { - id: "4", - alias: "my alias name", - description: "my description", - gitTag: "", - variant: "", - task: "", - remotePath: "", - parameters: [], - variantTags: ["okay"], - taskTags: ["hi"], - }, - ], -}; + }; diff --git a/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.ts index 54ee14b6f..ed901f86b 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/PatchAliasesTab/transformers.ts @@ -60,6 +60,7 @@ export const gqlToForm: GqlToFormFunction = ((data, options) => { export const formToGql = (( { patchAliases, patchTriggerAliases: ptaData }, + isRepo, id, ) => { const aliases = transformAliases( @@ -98,6 +99,7 @@ export const formToGql = (( : null; return { + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { id, patchTriggerAliases, githubTriggerAliases }, aliases, }; diff --git a/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.test.ts index cdf9595e2..e854bf70f 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.test.ts @@ -14,7 +14,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL and omits empty strings", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -26,7 +28,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -35,7 +37,8 @@ const projectForm: PeriodicBuildsFormState = { periodicBuilds: [], }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", periodicBuilds: [], @@ -76,7 +79,8 @@ const repoForm: PeriodicBuildsFormState = { ], }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", periodicBuilds: [ diff --git a/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.ts index 27f6f2d51..7c35e1fda 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/PeriodicBuildsTab/transformers.ts @@ -65,16 +65,25 @@ export const gqlToForm = ((data, { projectType }) => { export const formToGql = (( { periodicBuilds, periodicBuildsOverride }, - projectId, + isRepo, + id, ) => ({ + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { - id: projectId, + id, periodicBuilds: periodicBuildsOverride ? periodicBuilds.map( - ({ alias, configFile, id, interval, message, nextRunTime }) => ({ + ({ alias, configFile, - id: id || "", + id: periodicBuildId, + interval, + message, + nextRunTime, + }) => ({ + alias, + configFile, + id: periodicBuildId || "", message, nextRunTime: new Date(nextRunTime), ...(interval.specifier === IntervalSpecifier.Cron diff --git a/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.test.ts index 5b6b35dfa..fcb3cbc77 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.test.ts @@ -12,7 +12,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -22,7 +22,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -63,7 +65,8 @@ const projectForm: PluginsFormState = { ], }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", perfEnabled: true, @@ -135,7 +138,8 @@ const repoForm: PluginsFormState = { ], }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", perfEnabled: true, diff --git a/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.ts index b1aa4214e..7a0969e0d 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/PluginsTab/transformers.ts @@ -54,6 +54,7 @@ export const gqlToForm = ((data) => { export const formToGql = (( { buildBaronSettings, externalLinks, performanceSettings }, + isRepo, id, ) => { const projectRef: ProjectInput = { @@ -79,7 +80,7 @@ export const formToGql = (( })) : null, }; - return { projectRef }; + return { ...(isRepo ? { repoId: id } : { projectId: id }), projectRef }; }) satisfies FormToGqlFunction; // conditionally include the buildBaronSettings field based on the useBuildBaron boolean diff --git a/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.test.ts index 4d58bf659..c245e520e 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.test.ts @@ -14,7 +14,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -26,7 +28,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -35,7 +37,8 @@ const projectForm: ProjectTriggersFormState = { triggers: [], }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", triggers: [], @@ -60,7 +63,8 @@ const repoForm: ProjectTriggersFormState = { ], }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", triggers: [ diff --git a/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.ts index c8c77334f..7f6ff7a8e 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/ProjectTriggersTab/transformers.ts @@ -37,9 +37,10 @@ export const gqlToForm = ((data, { projectType }) => { }; }) satisfies GqlToFormFunction; -export const formToGql = (({ triggers, triggersOverride }, projectId) => ({ +export const formToGql = (({ triggers, triggersOverride }, isRepo, id) => ({ + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { - id: projectId, + id, triggers: triggersOverride ? triggers.map((trigger) => ({ project: trigger.project, diff --git a/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.test.ts index 4ecf0bcfd..f568e5936 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.test.ts @@ -17,6 +17,7 @@ describe("project data", () => { { vars: [...form.vars, {} as Unpacked], }, + false, "project", ), ).toStrictEqual(result); @@ -42,13 +43,15 @@ const form: VariablesFormState = { ], }; -const result: Pick = { - projectRef: { - id: "project", - }, - vars: { - vars: { test_name: "", test_two: "val" }, - privateVarsList: ["test_name"], - adminOnlyVarsList: ["test_name"], - }, -}; +const result: Pick = + { + projectId: "project", + projectRef: { + id: "project", + }, + vars: { + vars: { test_name: "", test_two: "val" }, + privateVarsList: ["test_name"], + adminOnlyVarsList: ["test_name"], + }, + }; diff --git a/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.ts index 0292c951c..65e83656d 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/VariablesTab/transformers.ts @@ -21,7 +21,7 @@ export const gqlToForm = ((data) => { }; }) satisfies GqlToFormFunction; -export const formToGql = (({ vars: varsData }, id) => { +export const formToGql = (({ vars: varsData }, isRepo, id) => { const vars = varsData.reduce( (acc, { isAdminOnly, isDisabled, isPrivate, varName, varValue }) => { if (!varName || !varValue) return acc; @@ -45,6 +45,7 @@ export const formToGql = (({ vars: varsData }, id) => { }, ); return { + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { id }, vars, }; diff --git a/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.test.ts index e078500ba..1659ba86c 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.test.ts @@ -18,7 +18,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -30,7 +30,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -45,7 +47,8 @@ const repoForm: ViewsFormState = { ], }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", parsleyFilters: [ @@ -78,7 +81,8 @@ const projectForm: ViewsFormState = { }, }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", parsleyFilters: [ diff --git a/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.ts index ca0ab34a3..af92888c8 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/ViewsAndFiltersTab/transformers.ts @@ -28,7 +28,8 @@ export const gqlToForm = ((data, { projectType }) => { }; }) satisfies GqlToFormFunction; -export const formToGql = (({ parsleyFilters, view }, id) => ({ +export const formToGql = (({ parsleyFilters, view }, isRepo, id) => ({ + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { id, parsleyFilters: parsleyFilters.map( diff --git a/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.test.ts index bab83ab5e..3106ef116 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.test.ts @@ -14,7 +14,9 @@ describe("project data", () => { }); it("correctly converts from a form to GQL and omits empty strings", () => { - expect(formToGql(projectForm, "project")).toStrictEqual(projectResult); + expect(formToGql(projectForm, false, "project")).toStrictEqual( + projectResult, + ); }); }); @@ -26,7 +28,7 @@ describe("repo data", () => { }); it("correctly converts from a form to GQL", () => { - expect(formToGql(repoForm, "repo")).toStrictEqual(repoResult); + expect(formToGql(repoForm, true, "repo")).toStrictEqual(repoResult); }); }); @@ -43,7 +45,8 @@ const projectForm: VWFormState = { }, }; -const projectResult: Pick = { +const projectResult: Pick = { + projectId: "project", projectRef: { id: "project", workstationConfig: { @@ -66,7 +69,8 @@ const repoForm: VWFormState = { }, }; -const repoResult: Pick = { +const repoResult: Pick = { + repoId: "repo", projectRef: { id: "repo", workstationConfig: { diff --git a/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.ts index 9976b7877..202389bdf 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/VirtualWorkstationTab/transformers.ts @@ -29,8 +29,10 @@ export const gqlToForm = ((data, options) => { export const formToGql = (( { commands: { setupCommands, setupCommandsOverride }, gitClone }, + isRepo, id, ) => ({ + ...(isRepo ? { repoId: id } : { projectId: id }), projectRef: { id, workstationConfig: { diff --git a/apps/spruce/src/pages/projectSettings/tabs/types.ts b/apps/spruce/src/pages/projectSettings/tabs/types.ts index e5d439c1b..9523ab1d5 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/types.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/types.ts @@ -2,6 +2,7 @@ import { ProjectSettingsTabRoutes } from "constants/routes"; import { ProjectSettingsInput, ProjectSettingsQuery, + RepoSettingsInput, RepoSettingsQuery, } from "gql/generated/types"; import { AccessFormState } from "./AccessTab/types"; @@ -51,8 +52,9 @@ export type GqlToFormFunction = ( export type FormToGqlFunction = ( form: FormStateMap[T], + isRepo: boolean, id?: string, -) => ProjectSettingsInput; +) => ProjectSettingsInput | RepoSettingsInput; const { EventLog, ...WritableProjectSettingsTabs } = ProjectSettingsTabRoutes; export { WritableProjectSettingsTabs }; diff --git a/apps/spruce/src/pages/task/ActionButtons.tsx b/apps/spruce/src/pages/task/ActionButtons.tsx index 0268bbfc1..4c7ae99c0 100644 --- a/apps/spruce/src/pages/task/ActionButtons.tsx +++ b/apps/spruce/src/pages/task/ActionButtons.tsx @@ -70,7 +70,7 @@ export const ActionButtons: React.FC = ({ versionMetadata, } = task || {}; - const { isPatch, order } = versionMetadata || {}; + const { id: versionId, isPatch, order } = versionMetadata || {}; const { identifier: projectIdentifier } = project || {}; const isPatchOnCommitQueue = requester === commitQueueRequester; const allExecutionTasksSucceeded = @@ -88,7 +88,7 @@ export const ActionButtons: React.FC = ({ ScheduleTasksMutation, ScheduleTasksMutationVariables >(SCHEDULE_TASKS, { - variables: { taskIds: [taskId] }, + variables: { taskIds: [taskId], versionId }, onCompleted: () => { dispatchToast.success("Task marked as scheduled"); }, From 621c95560338689f26af1736dba298e5c87ed850 Mon Sep 17 00:00:00 2001 From: "malik.hadjri" Date: Wed, 3 Apr 2024 13:51:20 -0400 Subject: [PATCH 03/31] spruce/v4.0.4 --- apps/spruce/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/spruce/package.json b/apps/spruce/package.json index 14ff36f18..421b6e1e2 100644 --- a/apps/spruce/package.json +++ b/apps/spruce/package.json @@ -1,6 +1,6 @@ { "name": "spruce", - "version": "4.0.3", + "version": "4.0.4", "private": true, "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh", From 5cdb88d8fe4024d5759f252f83b7f678fc40f0c6 Mon Sep 17 00:00:00 2001 From: "malik.hadjri" Date: Wed, 3 Apr 2024 13:51:42 -0400 Subject: [PATCH 04/31] parsley/v2.0.2 --- apps/parsley/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/parsley/package.json b/apps/parsley/package.json index 339968773..3af1fa298 100644 --- a/apps/parsley/package.json +++ b/apps/parsley/package.json @@ -1,7 +1,7 @@ { "name": "parsley", "private": true, - "version": "2.0.1", + "version": "2.0.2", "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh", "build": "tsc && GIT_SHA=`git rev-parse HEAD` APP_VERSION=$npm_package_version vite build", From edb9f31633b6e0b1045251793457c3bcb9caf74f Mon Sep 17 00:00:00 2001 From: Sophie Stadler Date: Wed, 3 Apr 2024 15:07:50 -0400 Subject: [PATCH 05/31] DEVPROD-5140: Fix precommit config (#34) --- .husky/pre-commit | 1 + apps/parsley/.husky/pre-commit | 4 - apps/parsley/lint-staged.config.js | 11 +-- apps/parsley/package.json | 4 +- apps/spruce/.husky/pre-commit | 4 - apps/spruce/lint-staged.config.js | 16 +--- apps/spruce/package.json | 6 +- lint-staged.base.config.js | 8 ++ package.json | 5 ++ yarn.lock | 123 +++++------------------------ 10 files changed, 45 insertions(+), 137 deletions(-) create mode 100644 .husky/pre-commit delete mode 100755 apps/parsley/.husky/pre-commit delete mode 100755 apps/spruce/.husky/pre-commit create mode 100644 lint-staged.base.config.js diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..372362317 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +yarn lint-staged diff --git a/apps/parsley/.husky/pre-commit b/apps/parsley/.husky/pre-commit deleted file mode 100755 index 5a182ef10..000000000 --- a/apps/parsley/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -yarn lint-staged diff --git a/apps/parsley/lint-staged.config.js b/apps/parsley/lint-staged.config.js index da59af68f..9f6b6feb9 100644 --- a/apps/parsley/lint-staged.config.js +++ b/apps/parsley/lint-staged.config.js @@ -1,10 +1,5 @@ +const baseConfig = require("../../lint-staged.base.config"); + module.exports = { - "(?!src/)*.{js,ts,tsx}": ["yarn eslint:staged", "yarn prettier"], // For files that are not in src/, run eslint and prettier - "src/**/*.{js,ts,tsx}": ["yarn eslint:staged", "yarn prettier"], // For files in src/, run eslint and prettier - "cypress/**/*.{js,ts}": ["yarn eslint:staged", "yarn prettier"], // For files in cypress/, run eslint and prettier - "src/gql/**/*.graphql": [ - "yarn eslint:staged", - "yarn prettier --parser graphql", - ], // For GraphQL files, run eslint and prettier - "*.{ts,tsx}": () => "yarn check-types", // For TypeScript files, check types + ...baseConfig, }; diff --git a/apps/parsley/package.json b/apps/parsley/package.json index 3af1fa298..96f75bb89 100644 --- a/apps/parsley/package.json +++ b/apps/parsley/package.json @@ -24,7 +24,7 @@ "eslint:fix": "yarn eslint:strict --fix", "eslint:staged": "STRICT=1 eslint", "eslint:strict": "STRICT=1 eslint '*.{js,ts,tsx}' 'src/**/*.ts?(x)' 'cypress/**/*.ts' 'src/gql/**/*.graphql'", - "prepare": "husky install", + "prepare": "yarn --cwd='../..' prepare", "prettier": "prettier --write", "preview": "serve -s dist -p 4173", "snapshot": "jest snapshot.test.ts --watchAll=false", @@ -133,13 +133,11 @@ "eslint-plugin-sort-keys-plus": "^1.3.1", "eslint-plugin-storybook": "0.6.15", "eslint-plugin-testing-library": "6.0.1", - "husky": "8.0.3", "jest": "29.7.0", "jest-environment-jsdom": "29.6.4", "jest-junit": "15.0.0", "jest-specific-snapshot": "8.0.0", "jest-watch-typeahead": "2.2.2", - "lint-staged": "13.2.2", "prettier": "3.2.2", "prompts": "2.4.2", "replace-in-file": "7.0.1", diff --git a/apps/spruce/.husky/pre-commit b/apps/spruce/.husky/pre-commit deleted file mode 100755 index 5a182ef10..000000000 --- a/apps/spruce/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -yarn lint-staged diff --git a/apps/spruce/lint-staged.config.js b/apps/spruce/lint-staged.config.js index d1b17b518..48482b5e1 100644 --- a/apps/spruce/lint-staged.config.js +++ b/apps/spruce/lint-staged.config.js @@ -1,14 +1,6 @@ +const baseConfig = require("../../lint-staged.base.config"); + module.exports = { - "(?!src/)*.{js,ts,tsx}": ["yarn eslint:staged", "yarn prettier"], // For files that are not in src/, run eslint and prettier - "src/**/*.{js,ts,tsx}": ["yarn eslint:staged", "yarn prettier"], // For files in src/, run eslint and prettier - "cypress/**/*.{js,ts}": ["yarn eslint:staged", "yarn prettier"], // For files in cypress/, run eslint and prettier - "src/gql/**/*.{graphql,gql}": [ - "yarn eslint:staged", - "yarn prettier --parser graphql", - "yarn check-schema-and-codegen", - ], // For GraphQL files, run eslint and prettier, and gql schema check - "*.{ts,tsx}": () => [ - "tsc -p tsconfig.json --noEmit", - "yarn check-schema-and-codegen", - ], // For TypeScript files, run tsc, and gql schema check + ...baseConfig, + "*.{ts,tsx}": () => ["yarn check-types", "yarn check-schema-and-codegen"], // For TypeScript files, run tsc, and gql schema check }; diff --git a/apps/spruce/package.json b/apps/spruce/package.json index 421b6e1e2..ff29ac40d 100644 --- a/apps/spruce/package.json +++ b/apps/spruce/package.json @@ -26,8 +26,8 @@ "eslint:staged": "STRICT=1 eslint", "eslint:strict": "STRICT=1 eslint '*.{js,ts,tsx}' 'src/**/*.ts?(x)' 'scripts/**/*.js' 'cypress/**/*.ts' 'src/gql/**/*.graphql'", "evg-db-ops": "scripts/evg-db-ops.sh", - "prepare": "husky install", - "prettier": "prettier --write", + "prepare": "yarn --cwd='../..' prepare", + "prettier-run": "prettier --write", "prod": "env-cmd -e devProduction -r .env-cmdrc.local.json yarn start", "serve": "node scripts/prod-server.js", "snapshot": "jest snapshot.test.ts --watchAll=false", @@ -186,7 +186,6 @@ "eslint-plugin-storybook": "0.6.12", "eslint-plugin-testing-library": "^5.10.1", "http-proxy": "^1.18.1", - "husky": "8.0.1", "identity-obj-proxy": "3.0.0", "jest": "29.7.0", "jest-canvas-mock": "^2.5.2", @@ -196,7 +195,6 @@ "jest-specific-snapshot": "8.0.0", "jest-watch-typeahead": "2.2.2", "less": "^4.1.3", - "lint-staged": "15.2.0", "mutation-observer": "1.0.3", "path": "0.12.7", "prettier": "3.2.2", diff --git a/lint-staged.base.config.js b/lint-staged.base.config.js new file mode 100644 index 000000000..0c59faf62 --- /dev/null +++ b/lint-staged.base.config.js @@ -0,0 +1,8 @@ +module.exports = { + "**/*.{js,ts,tsx}": ["yarn eslint:staged", "yarn prettier"], + "src/gql/**/*.{graphql,gql}": [ + "yarn eslint:staged", + "yarn prettier --parser graphql", + ], // For GraphQL files, run eslint and prettier, and gql schema check + "*.{ts,tsx}": () => ["yarn check-types"], // For TypeScript files, run tsc, and gql schema check +}; diff --git a/package.json b/package.json index d8127efd3..a47f7a885 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,16 @@ ] }, "scripts": { + "prepare": "husky", "test": "jest" }, "resolutions": { "@tanstack/react-table": "8.9.3", "@types/react": "18.2.0", "@types/react-dom": "18.2.0" + }, + "devDependencies": { + "husky": "9.0.11", + "lint-staged": "15.2.2" } } diff --git a/yarn.lock b/yarn.lock index 74870c846..a3daf5dd1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8046,11 +8046,6 @@ chalk@5.0.1: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== -chalk@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" - integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== - chalk@5.3.0, chalk@^5.0.1, chalk@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" @@ -8228,14 +8223,6 @@ cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== - dependencies: - slice-ansi "^5.0.0" - string-width "^5.0.0" - cli-truncate@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" @@ -8333,7 +8320,7 @@ color-name@^1.1.4, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colorette@^2.0.16, colorette@^2.0.19, colorette@^2.0.20: +colorette@^2.0.16, colorette@^2.0.20: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== @@ -8350,11 +8337,6 @@ commander@11.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== -commander@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== - commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -10171,21 +10153,6 @@ execa@^5.0.0, execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - executable@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" @@ -10733,7 +10700,7 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0, get-stream@^6.0.1: +get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -11285,25 +11252,15 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== - human-signals@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== -husky@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9" - integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw== - -husky@8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" - integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== +husky@9.0.11: + version "9.0.11" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.0.11.tgz#fc91df4c756050de41b3e478b2158b87c1e79af9" + integrity sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw== iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" @@ -12754,11 +12711,6 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lilconfig@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== - lilconfig@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc" @@ -12789,45 +12741,26 @@ linkifyjs@4.1.3: resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.3.tgz#0edbc346428a7390a23ea2e5939f76112c9ae07f" integrity sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg== -lint-staged@13.2.2: - version "13.2.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.2.tgz#5e711d3139c234f73402177be2f8dd312e6508ca" - integrity sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA== - dependencies: - chalk "5.2.0" - cli-truncate "^3.1.0" - commander "^10.0.0" - debug "^4.3.4" - execa "^7.0.0" - lilconfig "2.1.0" - listr2 "^5.0.7" - micromatch "^4.0.5" - normalize-path "^3.0.0" - object-inspect "^1.12.3" - pidtree "^0.6.0" - string-argv "^0.3.1" - yaml "^2.2.2" - -lint-staged@15.2.0: - version "15.2.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.0.tgz#3111534ca58096a3c8f70b044b6e7fe21b36f859" - integrity sha512-TFZzUEV00f+2YLaVPWBWGAMq7So6yQx+GG8YRMDeOEIf95Zn5RyiLMsEiX4KTNl9vq/w+NqRJkLA1kPIo15ufQ== +lint-staged@15.2.2: + version "15.2.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.2.tgz#ad7cbb5b3ab70e043fa05bff82a09ed286bc4c5f" + integrity sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw== dependencies: chalk "5.3.0" commander "11.1.0" debug "4.3.4" execa "8.0.1" lilconfig "3.0.0" - listr2 "8.0.0" + listr2 "8.0.1" micromatch "4.0.5" pidtree "0.6.0" string-argv "0.3.2" yaml "2.3.4" -listr2@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.0.0.tgz#aa7c230995f8ce378585f7c96c0c6d1cefa4700d" - integrity sha512-u8cusxAcyqAiQ2RhYvV7kRKNLgUvtObIbhOX2NCXqvp1UU32xIg5CT22ykS2TPKJXZWJwtK3IKLiqAGlGNE+Zg== +listr2@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.0.1.tgz#4d3f50ae6cec3c62bdf0e94f5c2c9edebd4b9c34" + integrity sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA== dependencies: cli-truncate "^4.0.0" colorette "^2.0.20" @@ -12864,20 +12797,6 @@ listr2@^4.0.5: through "^2.3.8" wrap-ansi "^7.0.0" -listr2@^5.0.7: - version "5.0.8" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" - integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.19" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.8.0" - through "^2.3.8" - wrap-ansi "^7.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -13501,7 +13420,7 @@ object-assign@^4.1.0, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.3, object-inspect@^1.13.1: +object-inspect@^1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== @@ -13931,7 +13850,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatc resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pidtree@0.6.0, pidtree@^0.6.0: +pidtree@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== @@ -15293,7 +15212,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.5.1, rxjs@^7.5.5, rxjs@^7.8.0: +rxjs@^7.5.1, rxjs@^7.5.5: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== @@ -15823,7 +15742,7 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string-argv@0.3.2, string-argv@^0.3.1: +string-argv@0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== @@ -15863,7 +15782,7 @@ string-length@^5.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: +string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -17315,7 +17234,7 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^2.2.2, yaml@^2.3.1: +yaml@^2.3.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.1.tgz#2e57e0b5e995292c25c75d2658f0664765210eed" integrity sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg== From 6cda10b2ef41818594667e59b6d5358e599b55e1 Mon Sep 17 00:00:00 2001 From: Malik Hadjri <19805673+hadjri@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:48:22 -0400 Subject: [PATCH 06/31] DEVPROD-1008 Add new oldest allowed merge base field (#27) --- apps/parsley/src/gql/generated/types.ts | 4 ++++ .../projectSettings/githubCommitQueue.graphql | 2 ++ apps/spruce/src/gql/generated/types.ts | 18 +++++++++++++++++ .../projectSettings/CopyProjectModal.test.tsx | 1 + .../tabs/EventLogTab/EventLogTab.test.tsx | 2 ++ .../GithubCommitQueueTab/getFormSchema.tsx | 20 +++++++++++++++++++ .../GithubCommitQueueTab/transformers.test.ts | 5 +++++ .../tabs/GithubCommitQueueTab/transformers.ts | 4 ++++ .../tabs/GithubCommitQueueTab/types.ts | 1 + .../pages/projectSettings/tabs/testData.ts | 2 ++ 10 files changed, 59 insertions(+) diff --git a/apps/parsley/src/gql/generated/types.ts b/apps/parsley/src/gql/generated/types.ts index 24e9b8eb8..22f56ae77 100644 --- a/apps/parsley/src/gql/generated/types.ts +++ b/apps/parsley/src/gql/generated/types.ts @@ -1696,6 +1696,7 @@ export type Project = { isFavorite: Scalars["Boolean"]["output"]; manualPrTestingEnabled?: Maybe; notifyOnBuildFailure?: Maybe; + oldestAllowedMergeBase: Scalars["String"]["output"]; owner: Scalars["String"]["output"]; parsleyFilters?: Maybe>; patchTriggerAliases?: Maybe>; @@ -1832,6 +1833,7 @@ export type ProjectInput = { identifier?: InputMaybe; manualPrTestingEnabled?: InputMaybe; notifyOnBuildFailure?: InputMaybe; + oldestAllowedMergeBase?: InputMaybe; owner?: InputMaybe; parsleyFilters?: InputMaybe>; patchTriggerAliases?: InputMaybe>; @@ -2168,6 +2170,7 @@ export type RepoRef = { id: Scalars["String"]["output"]; manualPrTestingEnabled: Scalars["Boolean"]["output"]; notifyOnBuildFailure: Scalars["Boolean"]["output"]; + oldestAllowedMergeBase: Scalars["String"]["output"]; owner: Scalars["String"]["output"]; parsleyFilters?: Maybe>; patchTriggerAliases?: Maybe>; @@ -2211,6 +2214,7 @@ export type RepoRefInput = { id: Scalars["String"]["input"]; manualPrTestingEnabled?: InputMaybe; notifyOnBuildFailure?: InputMaybe; + oldestAllowedMergeBase?: InputMaybe; owner?: InputMaybe; parsleyFilters?: InputMaybe>; patchTriggerAliases?: InputMaybe>; diff --git a/apps/spruce/src/gql/fragments/projectSettings/githubCommitQueue.graphql b/apps/spruce/src/gql/fragments/projectSettings/githubCommitQueue.graphql index bd29f8813..2409f0627 100644 --- a/apps/spruce/src/gql/fragments/projectSettings/githubCommitQueue.graphql +++ b/apps/spruce/src/gql/fragments/projectSettings/githubCommitQueue.graphql @@ -11,6 +11,7 @@ fragment ProjectGithubSettings on Project { gitTagAuthorizedUsers gitTagVersionsEnabled manualPrTestingEnabled + oldestAllowedMergeBase prTestingEnabled } @@ -27,6 +28,7 @@ fragment RepoGithubSettings on RepoRef { gitTagAuthorizedUsers gitTagVersionsEnabled manualPrTestingEnabled + oldestAllowedMergeBase prTestingEnabled } diff --git a/apps/spruce/src/gql/generated/types.ts b/apps/spruce/src/gql/generated/types.ts index 1d4f15717..c32300857 100644 --- a/apps/spruce/src/gql/generated/types.ts +++ b/apps/spruce/src/gql/generated/types.ts @@ -1696,6 +1696,7 @@ export type Project = { isFavorite: Scalars["Boolean"]["output"]; manualPrTestingEnabled?: Maybe; notifyOnBuildFailure?: Maybe; + oldestAllowedMergeBase: Scalars["String"]["output"]; owner: Scalars["String"]["output"]; parsleyFilters?: Maybe>; patchTriggerAliases?: Maybe>; @@ -1832,6 +1833,7 @@ export type ProjectInput = { identifier?: InputMaybe; manualPrTestingEnabled?: InputMaybe; notifyOnBuildFailure?: InputMaybe; + oldestAllowedMergeBase?: InputMaybe; owner?: InputMaybe; parsleyFilters?: InputMaybe>; patchTriggerAliases?: InputMaybe>; @@ -2168,6 +2170,7 @@ export type RepoRef = { id: Scalars["String"]["output"]; manualPrTestingEnabled: Scalars["Boolean"]["output"]; notifyOnBuildFailure: Scalars["Boolean"]["output"]; + oldestAllowedMergeBase: Scalars["String"]["output"]; owner: Scalars["String"]["output"]; parsleyFilters?: Maybe>; patchTriggerAliases?: Maybe>; @@ -2211,6 +2214,7 @@ export type RepoRefInput = { id: Scalars["String"]["input"]; manualPrTestingEnabled?: InputMaybe; notifyOnBuildFailure?: InputMaybe; + oldestAllowedMergeBase?: InputMaybe; owner?: InputMaybe; parsleyFilters?: InputMaybe>; patchTriggerAliases?: InputMaybe>; @@ -3585,6 +3589,7 @@ export type ProjectGithubSettingsFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; commitQueue: { __typename?: "CommitQueueParams"; @@ -3603,6 +3608,7 @@ export type RepoGithubSettingsFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled: boolean; manualPrTestingEnabled: boolean; + oldestAllowedMergeBase: string; prTestingEnabled: boolean; commitQueue: { __typename?: "RepoCommitQueueParams"; @@ -3624,6 +3630,7 @@ export type ProjectGithubCommitQueueFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; commitQueue: { __typename?: "CommitQueueParams"; @@ -3646,6 +3653,7 @@ export type RepoGithubCommitQueueFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled: boolean; manualPrTestingEnabled: boolean; + oldestAllowedMergeBase: string; prTestingEnabled: boolean; commitQueue: { __typename?: "RepoCommitQueueParams"; @@ -3668,6 +3676,7 @@ export type ProjectEventGithubCommitQueueFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; commitQueue: { __typename?: "CommitQueueParams"; @@ -3727,6 +3736,7 @@ export type ProjectSettingsFieldsFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; containerSizeDefinitions?: Array<{ __typename?: "ContainerResources"; @@ -3933,6 +3943,7 @@ export type RepoSettingsFieldsFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled: boolean; manualPrTestingEnabled: boolean; + oldestAllowedMergeBase: string; prTestingEnabled: boolean; containerSizeDefinitions?: Array<{ __typename?: "ContainerResources"; @@ -4335,6 +4346,7 @@ export type ProjectEventSettingsFragment = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; taskSync: { __typename?: "TaskSyncOptions"; @@ -6806,6 +6818,7 @@ export type ProjectEventLogsQuery = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; taskSync: { __typename?: "TaskSyncOptions"; @@ -7019,6 +7032,7 @@ export type ProjectEventLogsQuery = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; taskSync: { __typename?: "TaskSyncOptions"; @@ -7305,6 +7319,7 @@ export type ProjectSettingsQuery = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; containerSizeDefinitions?: Array<{ __typename?: "ContainerResources"; @@ -7572,6 +7587,7 @@ export type RepoEventLogsQuery = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; taskSync: { __typename?: "TaskSyncOptions"; @@ -7785,6 +7801,7 @@ export type RepoEventLogsQuery = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled?: boolean | null; manualPrTestingEnabled?: boolean | null; + oldestAllowedMergeBase: string; prTestingEnabled?: boolean | null; taskSync: { __typename?: "TaskSyncOptions"; @@ -8002,6 +8019,7 @@ export type RepoSettingsQuery = { gitTagAuthorizedUsers?: Array | null; gitTagVersionsEnabled: boolean; manualPrTestingEnabled: boolean; + oldestAllowedMergeBase: string; prTestingEnabled: boolean; containerSizeDefinitions?: Array<{ __typename?: "ContainerResources"; diff --git a/apps/spruce/src/pages/projectSettings/CopyProjectModal.test.tsx b/apps/spruce/src/pages/projectSettings/CopyProjectModal.test.tsx index 431a2038c..2b111109a 100644 --- a/apps/spruce/src/pages/projectSettings/CopyProjectModal.test.tsx +++ b/apps/spruce/src/pages/projectSettings/CopyProjectModal.test.tsx @@ -300,6 +300,7 @@ const projectSettingsMock: ApolloMock< batchTime: 60, remotePath: ".arst.yml", spawnHostScriptPath: "", + oldestAllowedMergeBase: "", dispatchingDisabled: false, versionControlEnabled: false, deactivatePrevious: true, diff --git a/apps/spruce/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx b/apps/spruce/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx index b28061c8c..b06d166b5 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx +++ b/apps/spruce/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx @@ -94,6 +94,7 @@ const projectEventsQuery: ProjectEventLogsQuery = { displayName: "Spruce", batchTime: 60, remotePath: ".evergreen.yml", + oldestAllowedMergeBase: "", spawnHostScriptPath: "", dispatchingDisabled: false, versionControlEnabled: false, @@ -182,6 +183,7 @@ const projectEventsQuery: ProjectEventLogsQuery = { batchTime: 30, remotePath: ".srat.yml", spawnHostScriptPath: "", + oldestAllowedMergeBase: "", dispatchingDisabled: false, versionControlEnabled: false, deactivatePrevious: true, diff --git a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx index 339c68ebd..ae97604d6 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx +++ b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx @@ -85,6 +85,10 @@ export const getFormSchema = ( repoData?.github?.manualPrTestingEnabled, ), }, + oldestAllowedMergeBase: { + type: "string" as "string", + title: "Oldest Allowed Merge Base", + }, prTesting: { type: "object" as "object", title: "GitHub Patch Definitions", @@ -342,6 +346,22 @@ export const getFormSchema = ( "PR Testing", ), }, + oldestAllowedMergeBase: { + "ui:description": + "Specify the oldest commit SHA on your project branch that is allowed to be a merge base for a PR", + "ui:optional": true, + ...placeholderIf(repoData?.github?.oldestAllowedMergeBase), + ...hideIf( + fieldDisabled( + formData?.github?.prTestingEnabled, + repoData?.github?.prTestingEnabled, + ) && + fieldDisabled( + formData?.github?.manualPrTestingEnabled, + repoData?.github?.manualPrTestingEnabled, + ), + ), + }, prTesting: { ...hideIf( fieldDisabled( diff --git a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts index 7f2378cd2..c4fc5f30c 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.test.ts @@ -45,6 +45,7 @@ const projectForm: GCQFormState = { github: { prTestingEnabled: null, manualPrTestingEnabled: null, + oldestAllowedMergeBase: "abc", prTesting: { githubPrAliasesOverride: true, githubPrAliases: [ @@ -150,6 +151,7 @@ const projectResult: Pick< id: "project", prTestingEnabled: null, manualPrTestingEnabled: null, + oldestAllowedMergeBase: "abc", githubChecksEnabled: null, gitTagVersionsEnabled: null, gitTagAuthorizedUsers: ["privileged"], @@ -205,6 +207,7 @@ const repoForm: GCQFormState = { github: { prTestingEnabled: false, manualPrTestingEnabled: false, + oldestAllowedMergeBase: "abc", prTesting: { githubPrAliasesOverride: true, githubPrAliases: [], @@ -292,6 +295,7 @@ const repoResult: Pick = gitTagVersionsEnabled: false, gitTagAuthorizedUsers: ["admin"], gitTagAuthorizedTeams: [], + oldestAllowedMergeBase: "abc", commitQueue: { enabled: true, message: "Commit Queue Message", @@ -319,6 +323,7 @@ const mergedForm: GCQFormState = { github: { prTestingEnabled: null, manualPrTestingEnabled: null, + oldestAllowedMergeBase: "abc", prTesting: { githubPrAliasesOverride: true, githubPrAliases: [ diff --git a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts index 2d23f813c..6ecaf46ce 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/transformers.ts @@ -40,6 +40,7 @@ export const gqlToForm = ((data, options) => { gitTagVersionsEnabled, githubChecksEnabled, manualPrTestingEnabled, + oldestAllowedMergeBase, prTestingEnabled, } = projectRef; @@ -75,6 +76,7 @@ export const gqlToForm = ((data, options) => { githubCheckAliases, }, gitTagVersionsEnabled, + oldestAllowedMergeBase, users: { gitTagAuthorizedUsersOverride: projectType !== ProjectType.AttachedProject || @@ -121,6 +123,7 @@ export const formToGql = (( githubChecks, githubChecksEnabled, manualPrTestingEnabled, + oldestAllowedMergeBase, prTesting, prTestingEnabled, teams: { gitTagAuthorizedTeams, gitTagAuthorizedTeamsOverride }, @@ -136,6 +139,7 @@ export const formToGql = (( manualPrTestingEnabled, githubChecksEnabled, gitTagVersionsEnabled, + oldestAllowedMergeBase, gitTagAuthorizedUsers: gitTagAuthorizedUsersOverride ? gitTagAuthorizedUsers : null, diff --git a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/types.ts b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/types.ts index e64311469..102599b26 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/types.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/GithubCommitQueueTab/types.ts @@ -16,6 +16,7 @@ export interface GCQFormState { githubPrAliases: Array; }; }; + oldestAllowedMergeBase: string; githubTriggerAliases: ProjectPatchAliasSettingsFragment["patchTriggerAliases"]; githubChecksEnabled: boolean; githubChecks: { diff --git a/apps/spruce/src/pages/projectSettings/tabs/testData.ts b/apps/spruce/src/pages/projectSettings/tabs/testData.ts index 386f221cb..f439d09e8 100644 --- a/apps/spruce/src/pages/projectSettings/tabs/testData.ts +++ b/apps/spruce/src/pages/projectSettings/tabs/testData.ts @@ -44,6 +44,7 @@ const projectBase: ProjectSettingsQuery["projectSettings"] = { notifyOnBuildFailure: null, batchTime: 0, remotePath: null, + oldestAllowedMergeBase: "abc", spawnHostScriptPath: null, dispatchingDisabled: null, versionControlEnabled: true, @@ -178,6 +179,7 @@ const repoBase: RepoSettingsQuery["repoSettings"] = { batchTime: 12, remotePath: "evergreen.yml", spawnHostScriptPath: "/test/path", + oldestAllowedMergeBase: "abc", dispatchingDisabled: true, versionControlEnabled: false, deactivatePrevious: true, From 2d32c36e62cd8810ee22fdbc416d01cc4eb013ea Mon Sep 17 00:00:00 2001 From: "malik.hadjri" Date: Thu, 4 Apr 2024 12:00:58 -0400 Subject: [PATCH 07/31] spruce/v4.0.5 --- apps/spruce/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/spruce/package.json b/apps/spruce/package.json index ff29ac40d..5cca14dfc 100644 --- a/apps/spruce/package.json +++ b/apps/spruce/package.json @@ -1,6 +1,6 @@ { "name": "spruce", - "version": "4.0.4", + "version": "4.0.5", "private": true, "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh", From f99fbf43b1c76da8bb13bd127b911faa76dd51f8 Mon Sep 17 00:00:00 2001 From: "malik.hadjri" Date: Thu, 4 Apr 2024 12:01:32 -0400 Subject: [PATCH 08/31] parsley/v2.0.3 --- apps/parsley/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/parsley/package.json b/apps/parsley/package.json index 96f75bb89..174b9e222 100644 --- a/apps/parsley/package.json +++ b/apps/parsley/package.json @@ -1,7 +1,7 @@ { "name": "parsley", "private": true, - "version": "2.0.2", + "version": "2.0.3", "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh", "build": "tsc && GIT_SHA=`git rev-parse HEAD` APP_VERSION=$npm_package_version vite build", From c287f5dfd7a0111fb043318cffbcd06e3a632916 Mon Sep 17 00:00:00 2001 From: minnakt <47064971+minnakt@users.noreply.github.com> Date: Thu, 4 Apr 2024 17:06:31 -0400 Subject: [PATCH 09/31] DEVPROD-5460: Remove id argument from repo queries (#36) --- apps/spruce/src/gql/queries/repo-event-logs.graphql | 2 +- apps/spruce/src/gql/queries/repo-settings.graphql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/spruce/src/gql/queries/repo-event-logs.graphql b/apps/spruce/src/gql/queries/repo-event-logs.graphql index 57b703dee..abf304a6b 100644 --- a/apps/spruce/src/gql/queries/repo-event-logs.graphql +++ b/apps/spruce/src/gql/queries/repo-event-logs.graphql @@ -1,7 +1,7 @@ #import "../fragments/projectSettings/projectEventSettings.graphql" query RepoEventLogs($id: String!, $limit: Int, $before: Time) { - repoEvents(id: $id, repoId: $id, limit: $limit, before: $before) { + repoEvents(repoId: $id, limit: $limit, before: $before) { count eventLogEntries { after { diff --git a/apps/spruce/src/gql/queries/repo-settings.graphql b/apps/spruce/src/gql/queries/repo-settings.graphql index 138acaf45..7f36a9c65 100644 --- a/apps/spruce/src/gql/queries/repo-settings.graphql +++ b/apps/spruce/src/gql/queries/repo-settings.graphql @@ -1,7 +1,7 @@ #import "../fragments/projectSettings/index.graphql" query RepoSettings($repoId: String!) { - repoSettings(id: $repoId, repoId: $repoId) { + repoSettings(repoId: $repoId) { ...RepoSettingsFields } } From ba984e86825cb4308d774b1e4792b74ad4d816a0 Mon Sep 17 00:00:00 2001 From: minnakt <47064971+minnakt@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:42:49 -0400 Subject: [PATCH 10/31] DEVPROD-5277: Add user preference toggle for jump to failing line (#33) --- apps/parsley/package.json | 2 +- .../preferences/usePreferencesAnalytics.ts | 3 +- .../DetailsMenu/DetailsMenu.test.tsx | 27 ++++-- .../DetailsMenuCard/DetailsMenu.stories.tsx | 11 +++ .../JumpToFailingLineToggle.test.tsx | 91 +++++++++++++++++++ .../Toggles/JumpToFailingLineToggle/index.tsx | 35 +++++++ .../DetailsMenuCard/Toggles/index.tsx | 6 ++ .../DetailsMenu/DetailsMenuCard/index.tsx | 17 +++- apps/parsley/src/gql/generated/types.ts | 29 ++++++ apps/parsley/src/gql/mutations/index.ts | 3 + .../mutations/update-parsley-settings.graphql | 7 ++ apps/parsley/src/gql/queries/index.ts | 2 + .../src/gql/queries/parsley-settings.graphql | 8 ++ .../src/hooks/useParsleySettings/index.ts | 60 ++++++++++++ .../useParsleySettings.test.tsx | 57 ++++++++++++ apps/parsley/src/test_data/parsleySettings.ts | 27 ++++++ apps/spruce/package.json | 2 +- 17 files changed, 372 insertions(+), 15 deletions(-) create mode 100644 apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/JumpToFailingLineToggle.test.tsx create mode 100644 apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/index.tsx create mode 100644 apps/parsley/src/gql/mutations/index.ts create mode 100644 apps/parsley/src/gql/mutations/update-parsley-settings.graphql create mode 100644 apps/parsley/src/gql/queries/parsley-settings.graphql create mode 100644 apps/parsley/src/hooks/useParsleySettings/index.ts create mode 100644 apps/parsley/src/hooks/useParsleySettings/useParsleySettings.test.tsx create mode 100644 apps/parsley/src/test_data/parsleySettings.ts diff --git a/apps/parsley/package.json b/apps/parsley/package.json index 174b9e222..327e00d88 100644 --- a/apps/parsley/package.json +++ b/apps/parsley/package.json @@ -32,7 +32,7 @@ "verify-backend": "./scripts/verify-backend.sh", "storybook": "storybook dev -p 6006", "storybook:build": "env-cmd -e local -r .env-cmdrc.local.json storybook build", - "test": "yarn --cwd='../..' test --selectProjects parsley", + "test": "yarn --cwd='../..' test --selectProjects parsley --watchAll=false", "postversion": "scripts/push-version.sh" }, "dependencies": { diff --git a/apps/parsley/src/analytics/preferences/usePreferencesAnalytics.ts b/apps/parsley/src/analytics/preferences/usePreferencesAnalytics.ts index 91fd5b73b..34e901a26 100644 --- a/apps/parsley/src/analytics/preferences/usePreferencesAnalytics.ts +++ b/apps/parsley/src/analytics/preferences/usePreferencesAnalytics.ts @@ -14,7 +14,8 @@ type Action = | { name: "Toggled Pretty Print"; on: boolean } | { name: "Toggled Filter Logic"; logic: FilterLogic } | { name: "Toggled Expandable Rows"; on: boolean } - | { name: "Toggled Zebra Stripes"; on: boolean }; + | { name: "Toggled Zebra Stripes"; on: boolean } + | { name: "Toggled Jump to Failing Line"; on: boolean }; export const usePreferencesAnalytics = () => useAnalyticsRoot("Preferences"); diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenu.test.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenu.test.tsx index 7ad7c2d2d..458326890 100644 --- a/apps/parsley/src/components/DetailsMenu/DetailsMenu.test.tsx +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenu.test.tsx @@ -1,25 +1,32 @@ +import { MockedProvider } from "@apollo/client/testing"; import { act, waitFor } from "@testing-library/react"; import { QueryParams } from "constants/queryParams"; import { LogContextProvider, useLogContext } from "context/LogContext"; import { RenderFakeToastContext } from "context/toast/__mocks__"; import { useQueryParam } from "hooks/useQueryParam"; +import { parsleySettingsMock } from "test_data/parsleySettings"; import { renderWithRouterMatch as render, screen, userEvent } from "test_utils"; import { renderComponentWithHook } from "test_utils/TestHooks"; import DetailsMenu from "."; const wrapper = ({ children }: { children: React.ReactNode }) => ( - {children} + + + {children} + + ); -const logs = [ - "line 1", - "line 2", - "line 3", - "line 4", - "line 5", - "line 6", - "line 7", -]; /** * `renderSharingMenu` renders the sharing menu with the default open prop * @returns - hook and utils diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/DetailsMenu.stories.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/DetailsMenu.stories.tsx index 2867f54b5..ee7089e7c 100644 --- a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/DetailsMenu.stories.tsx +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/DetailsMenu.stories.tsx @@ -1,12 +1,23 @@ import { useEffect } from "react"; +import { MockedProvider } from "@apollo/client/testing"; import Card from "@leafygreen-ui/card"; import { LogTypes } from "constants/enums"; import { useLogContext } from "context/LogContext"; +import { parsleySettingsMock } from "test_data/parsleySettings"; +import WithToastContext from "test_utils/toast-decorator"; import { CustomMeta, CustomStoryObj } from "test_utils/types"; import DetailsMenu from "."; export default { component: DetailsMenu, + decorators: [ + (Story: () => JSX.Element) => ( + + + + ), + WithToastContext, + ], } satisfies CustomMeta; export const Default: CustomStoryObj = { diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/JumpToFailingLineToggle.test.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/JumpToFailingLineToggle.test.tsx new file mode 100644 index 000000000..17a45205f --- /dev/null +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/JumpToFailingLineToggle.test.tsx @@ -0,0 +1,91 @@ +import { LogTypes } from "constants/enums"; +import { LogContextProvider, useLogContext } from "context/LogContext"; +import { + act, + renderWithRouterMatch as render, + screen, + userEvent, +} from "test_utils"; +import { renderComponentWithHook } from "test_utils/TestHooks"; +import JumpToFailingLineToggle from "."; + +const wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} +); + +describe("jump to failing line toggle", () => { + it("should render as checked when 'checked' prop is true", () => { + render(, { + wrapper, + }); + const jumpToFailingLineToggle = screen.getByDataCy( + "jump-to-failing-line-toggle", + ); + expect(jumpToFailingLineToggle).toHaveAttribute("aria-checked", "true"); + }); + + it("should render as unchecked when 'checked' prop is false", () => { + render( + , + { wrapper }, + ); + const jumpToFailingLineToggle = screen.getByDataCy( + "jump-to-failing-line-toggle", + ); + expect(jumpToFailingLineToggle).toHaveAttribute("aria-checked", "false"); + }); + + it("should disable toggle if logType is not Evergreen task logs", () => { + const { Component, hook } = renderComponentWithHook( + useLogContext, + , + ); + render(, { wrapper }); + act(() => { + hook.current.setLogMetadata({ logType: LogTypes.RESMOKE_LOGS }); + }); + const jumpToFailingLineToggle = screen.getByDataCy( + "jump-to-failing-line-toggle", + ); + expect(jumpToFailingLineToggle).toHaveAttribute("aria-disabled", "true"); + }); + + it("should enable toggle if logType is Evergreen task logs", () => { + const { Component, hook } = renderComponentWithHook( + useLogContext, + , + ); + render(, { wrapper }); + act(() => { + hook.current.setLogMetadata({ logType: LogTypes.EVERGREEN_TASK_LOGS }); + }); + const jumpToFailingLineToggle = screen.getByDataCy( + "jump-to-failing-line-toggle", + ); + expect(jumpToFailingLineToggle).toHaveAttribute("aria-disabled", "false"); + }); + + it("should call update function with correct parameters, without updating the URL", async () => { + const user = userEvent.setup(); + const updateSettings = jest.fn(); + + const { Component, hook } = renderComponentWithHook( + useLogContext, + , + ); + const { router } = render(, { wrapper }); + act(() => { + hook.current.setLogMetadata({ logType: LogTypes.EVERGREEN_TASK_LOGS }); + }); + + const jumpToFailingLineToggle = screen.getByDataCy( + "jump-to-failing-line-toggle", + ); + await user.click(jumpToFailingLineToggle); + expect(updateSettings).toHaveBeenCalledTimes(1); + expect(updateSettings).toHaveBeenCalledWith({ + jumpToFailingLineEnabled: false, + }); + expect(router.state.location.search).toBe(""); + }); +}); diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/index.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/index.tsx new file mode 100644 index 000000000..c2f7b3233 --- /dev/null +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/JumpToFailingLineToggle/index.tsx @@ -0,0 +1,35 @@ +import { usePreferencesAnalytics } from "analytics"; +import { LogTypes } from "constants/enums"; +import { useLogContext } from "context/LogContext"; +import { ParsleySettingsInput } from "gql/generated/types"; +import BaseToggle from "../BaseToggle"; + +interface JumpToFailingLineToggleProps { + checked: boolean; + updateSettings: (parsleySettings: ParsleySettingsInput) => void; +} + +const JumpToFailingLineToggle: React.FC = ({ + checked, + updateSettings, +}) => { + const { sendEvent } = usePreferencesAnalytics(); + const { logMetadata } = useLogContext(); + const isTaskLog = logMetadata?.logType === LogTypes.EVERGREEN_TASK_LOGS; + + return ( + { + updateSettings({ jumpToFailingLineEnabled: value }); + sendEvent({ name: "Toggled Jump to Failing Line", on: value }); + }} + tooltip="Toggle scroll to failing line on page load. Only available for task logs." + value={checked} + /> + ); +}; + +export default JumpToFailingLineToggle; diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/index.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/index.tsx index e90be934e..3b6bb712d 100644 --- a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/index.tsx +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/index.tsx @@ -2,14 +2,20 @@ import BaseToggle from "./BaseToggle"; import CaseSensitiveToggle from "./CaseSensitiveToggle"; import ExpandableRowsToggle from "./ExpandableRowsToggle"; import FilterLogicToggle from "./FilterLogicToggle"; +import JumpToFailingLineToggle from "./JumpToFailingLineToggle"; import PrettyPrintToggle from "./PrettyPrintToggle"; +import WordWrapFormatToggle from "./WordWrapFormatToggle"; import WrapToggle from "./WrapToggle"; +import ZebraStripingToggle from "./ZebraStripingToggle"; export { BaseToggle, CaseSensitiveToggle, ExpandableRowsToggle, FilterLogicToggle, + JumpToFailingLineToggle, PrettyPrintToggle, WrapToggle, + WordWrapFormatToggle, + ZebraStripingToggle, }; diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/index.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/index.tsx index 847325930..568db2c3a 100644 --- a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/index.tsx +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/index.tsx @@ -3,6 +3,8 @@ import styled from "@emotion/styled"; import { Tab, Tabs } from "@leafygreen-ui/tabs"; import { H3 } from "@leafygreen-ui/typography"; import { size } from "constants/tokens"; +import { useParsleySettings } from "hooks/useParsleySettings"; +import { isProduction } from "utils/environmentVariables"; import ButtonRow from "./ButtonRow"; import CLIInstructions from "./CLIInstructions"; import SearchRangeInput from "./SearchRangeInput"; @@ -10,11 +12,12 @@ import { CaseSensitiveToggle, ExpandableRowsToggle, FilterLogicToggle, + JumpToFailingLineToggle, PrettyPrintToggle, + WordWrapFormatToggle, WrapToggle, + ZebraStripingToggle, } from "./Toggles"; -import WordWrapFormatToggle from "./Toggles/WordWrapFormatToggle"; -import ZebraStripingToggle from "./Toggles/ZebraStripingToggle"; interface DetailsMenuProps { "data-cy"?: string; @@ -23,6 +26,10 @@ interface DetailsMenuProps { const DetailsMenuCard = forwardRef( ({ "data-cy": dataCy }, ref) => { const [selectedTab, setSelectedTab] = useState(0); + + const { settings, updateSettings } = useParsleySettings(); + const { jumpToFailingLineEnabled = true } = settings ?? {}; + return (

Parsley Settings

@@ -50,6 +57,12 @@ const DetailsMenuCard = forwardRef( + {!isProduction() && ( + + )}
diff --git a/apps/parsley/src/gql/generated/types.ts b/apps/parsley/src/gql/generated/types.ts index 22f56ae77..82803caf0 100644 --- a/apps/parsley/src/gql/generated/types.ts +++ b/apps/parsley/src/gql/generated/types.ts @@ -3252,6 +3252,21 @@ export type BaseTaskFragment = { }; }; +export type UpdateParsleySettingsMutationVariables = Exact<{ + opts: UpdateParsleySettingsInput; +}>; + +export type UpdateParsleySettingsMutation = { + __typename?: "Mutation"; + updateParsleySettings?: { + __typename?: "UpdateParsleySettingsPayload"; + parsleySettings?: { + __typename?: "ParsleySettings"; + jumpToFailingLineEnabled: boolean; + } | null; + } | null; +}; + export type LogkeeperTaskQueryVariables = Exact<{ buildId: Scalars["String"]["input"]; }>; @@ -3356,6 +3371,20 @@ export type UserQuery = { user: { __typename?: "User"; userId: string }; }; +export type ParsleySettingsQueryVariables = Exact<{ [key: string]: never }>; + +export type ParsleySettingsQuery = { + __typename?: "Query"; + user: { + __typename?: "User"; + userId: string; + parsleySettings: { + __typename?: "ParsleySettings"; + jumpToFailingLineEnabled: boolean; + }; + }; +}; + export type ProjectFiltersQueryVariables = Exact<{ projectIdentifier: Scalars["String"]["input"]; }>; diff --git a/apps/parsley/src/gql/mutations/index.ts b/apps/parsley/src/gql/mutations/index.ts new file mode 100644 index 000000000..808f281fc --- /dev/null +++ b/apps/parsley/src/gql/mutations/index.ts @@ -0,0 +1,3 @@ +import UPDATE_PARSLEY_SETTINGS from "./update-parsley-settings.graphql"; + +export { UPDATE_PARSLEY_SETTINGS }; diff --git a/apps/parsley/src/gql/mutations/update-parsley-settings.graphql b/apps/parsley/src/gql/mutations/update-parsley-settings.graphql new file mode 100644 index 000000000..febe508ee --- /dev/null +++ b/apps/parsley/src/gql/mutations/update-parsley-settings.graphql @@ -0,0 +1,7 @@ +mutation UpdateParsleySettings($opts: UpdateParsleySettingsInput!) { + updateParsleySettings(opts: $opts) { + parsleySettings { + jumpToFailingLineEnabled + } + } +} diff --git a/apps/parsley/src/gql/queries/index.ts b/apps/parsley/src/gql/queries/index.ts index 3b94e8546..4a672f119 100644 --- a/apps/parsley/src/gql/queries/index.ts +++ b/apps/parsley/src/gql/queries/index.ts @@ -2,6 +2,7 @@ import GET_LOGKEEPER_TASK from "./get-logkeeper-task.graphql"; import GET_TASK from "./get-task.graphql"; import GET_TEST_LOG_URL_AND_RENDERING_TYPE from "./get-test-log-url-and-rendering-type.graphql"; import GET_USER from "./get-user.graphql"; +import PARSLEY_SETTINGS from "./parsley-settings.graphql"; import PROJECT_FILTERS from "./project-filters.graphql"; import TASK_FILES from "./task-files.graphql"; @@ -10,6 +11,7 @@ export { GET_TASK, GET_TEST_LOG_URL_AND_RENDERING_TYPE, GET_USER, + PARSLEY_SETTINGS, PROJECT_FILTERS, TASK_FILES, }; diff --git a/apps/parsley/src/gql/queries/parsley-settings.graphql b/apps/parsley/src/gql/queries/parsley-settings.graphql new file mode 100644 index 000000000..cbe3eff59 --- /dev/null +++ b/apps/parsley/src/gql/queries/parsley-settings.graphql @@ -0,0 +1,8 @@ +query ParsleySettings { + user { + parsleySettings { + jumpToFailingLineEnabled + } + userId + } +} diff --git a/apps/parsley/src/hooks/useParsleySettings/index.ts b/apps/parsley/src/hooks/useParsleySettings/index.ts new file mode 100644 index 000000000..d8f7a10a0 --- /dev/null +++ b/apps/parsley/src/hooks/useParsleySettings/index.ts @@ -0,0 +1,60 @@ +import { useMutation, useQuery } from "@apollo/client"; +import { useToastContext } from "context/toast"; +import { + ParsleySettings, + ParsleySettingsInput, + ParsleySettingsQuery, + ParsleySettingsQueryVariables, + UpdateParsleySettingsMutation, + UpdateParsleySettingsMutationVariables, +} from "gql/generated/types"; +import { UPDATE_PARSLEY_SETTINGS } from "gql/mutations"; +import { PARSLEY_SETTINGS } from "gql/queries"; + +type UseParsleySettingsReturnType = { + settings: Partial; // TODO: Remove Partial after completion of DEVPROD-1113. + updateSettings: (settings: ParsleySettingsInput) => void; +}; + +/** + * `useParsleySettings` fetches settings for the current user from the database. + * Eventually we will move the preferences stored in LogContext into the database. + * This means that preferences will no longer have to be stored centrally in the context. + * @returns Parsley settings for the user, function for updating Parsley settings + */ +const useParsleySettings = (): UseParsleySettingsReturnType => { + const { data } = useQuery< + ParsleySettingsQuery, + ParsleySettingsQueryVariables + >(PARSLEY_SETTINGS); + const { user } = data || {}; + const { parsleySettings } = user || {}; + + const dispatchToast = useToastContext(); + const [updateParsleySettings] = useMutation< + UpdateParsleySettingsMutation, + UpdateParsleySettingsMutationVariables + >(UPDATE_PARSLEY_SETTINGS, { + onError: (err) => { + dispatchToast.warning(`Failed to save preferences: ${err.message}`); + }, + refetchQueries: ["ParsleySettings"], + }); + + const updateSettings = (newSettings: ParsleySettingsInput) => { + updateParsleySettings({ + variables: { + opts: { + parsleySettings: newSettings, + }, + }, + }); + }; + + return { + settings: parsleySettings ?? {}, + updateSettings, + }; +}; + +export { useParsleySettings }; diff --git a/apps/parsley/src/hooks/useParsleySettings/useParsleySettings.test.tsx b/apps/parsley/src/hooks/useParsleySettings/useParsleySettings.test.tsx new file mode 100644 index 000000000..3d9b3d85f --- /dev/null +++ b/apps/parsley/src/hooks/useParsleySettings/useParsleySettings.test.tsx @@ -0,0 +1,57 @@ +import { MockedProvider } from "@apollo/client/testing"; +import { RenderFakeToastContext } from "context/toast/__mocks__"; +import { + UpdateParsleySettingsMutation, + UpdateParsleySettingsMutationVariables, +} from "gql/generated/types"; +import { UPDATE_PARSLEY_SETTINGS } from "gql/mutations"; +import { parsleySettingsMock } from "test_data/parsleySettings"; +import { act, renderHook, waitFor } from "test_utils"; +import { ApolloMock } from "types/gql"; +import { useParsleySettings } from "."; + +const wrapper = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); + +describe("useParsleySettings", () => { + it("fetches user settings", async () => { + RenderFakeToastContext(); + + const { result } = renderHook(() => useParsleySettings(), { wrapper }); + await waitFor(() => { + expect(result.current.settings.jumpToFailingLineEnabled).toBe(true); + }); + }); + + it("dispatches warning toast if an error occurs when saving preferences", async () => { + const { dispatchToast } = RenderFakeToastContext(); + + const { result } = renderHook(() => useParsleySettings(), { wrapper }); + act(() => { + result.current.updateSettings({ jumpToFailingLineEnabled: false }); + }); + await waitFor(() => { + expect(dispatchToast.warning).toHaveBeenCalledTimes(1); + }); + }); +}); + +const updateSettingsFailedMock: ApolloMock< + UpdateParsleySettingsMutation, + UpdateParsleySettingsMutationVariables +> = { + error: new Error("Failed to update Parsley settings!"), + request: { + query: UPDATE_PARSLEY_SETTINGS, + variables: { + opts: { + parsleySettings: { + jumpToFailingLineEnabled: false, + }, + }, + }, + }, +}; diff --git a/apps/parsley/src/test_data/parsleySettings.ts b/apps/parsley/src/test_data/parsleySettings.ts new file mode 100644 index 000000000..85cbbade1 --- /dev/null +++ b/apps/parsley/src/test_data/parsleySettings.ts @@ -0,0 +1,27 @@ +import { + ParsleySettingsQuery, + ParsleySettingsQueryVariables, +} from "gql/generated/types"; +import { PARSLEY_SETTINGS } from "gql/queries"; +import { ApolloMock } from "types/gql"; + +export const parsleySettingsMock: ApolloMock< + ParsleySettingsQuery, + ParsleySettingsQueryVariables +> = { + request: { + query: PARSLEY_SETTINGS, + }, + result: { + data: { + user: { + __typename: "User", + parsleySettings: { + __typename: "ParsleySettings", + jumpToFailingLineEnabled: true, + }, + userId: "me", + }, + }, + }, +}; diff --git a/apps/spruce/package.json b/apps/spruce/package.json index 5cca14dfc..bf4b529bf 100644 --- a/apps/spruce/package.json +++ b/apps/spruce/package.json @@ -34,7 +34,7 @@ "staging": "env-cmd -e devStaging -r .env-cmdrc.local.json yarn start", "start": "vite", "storybook": "storybook dev -p 6006", - "test": "yarn --cwd='../..' test --selectProjects spruce", + "test": "yarn --cwd='../..' test --selectProjects spruce --watchAll=false", "postversion": "scripts/push-version.sh" }, "browserslist": { From e9d59387e75ae5dd8e93d79feb158134f6db7c33 Mon Sep 17 00:00:00 2001 From: "malik.hadjri" Date: Fri, 5 Apr 2024 12:59:42 -0400 Subject: [PATCH 11/31] parsley/v2.0.4 --- apps/parsley/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/parsley/package.json b/apps/parsley/package.json index 327e00d88..f65fa0a5a 100644 --- a/apps/parsley/package.json +++ b/apps/parsley/package.json @@ -1,7 +1,7 @@ { "name": "parsley", "private": true, - "version": "2.0.3", + "version": "2.0.4", "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh", "build": "tsc && GIT_SHA=`git rev-parse HEAD` APP_VERSION=$npm_package_version vite build", From 628d55758780442b63b820dec7ff21cbd481c918 Mon Sep 17 00:00:00 2001 From: "malik.hadjri" Date: Fri, 5 Apr 2024 13:00:03 -0400 Subject: [PATCH 12/31] spruce/v4.0.6 --- apps/spruce/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/spruce/package.json b/apps/spruce/package.json index bf4b529bf..acffdc5b6 100644 --- a/apps/spruce/package.json +++ b/apps/spruce/package.json @@ -1,6 +1,6 @@ { "name": "spruce", - "version": "4.0.5", + "version": "4.0.6", "private": true, "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh", From 269eba373eb879ad083c585b03867609cf68d5ef Mon Sep 17 00:00:00 2001 From: Mohamed Khelif Date: Fri, 5 Apr 2024 13:07:34 -0400 Subject: [PATCH 13/31] DEVPROD-6012 Consolidate graphqlrc and move to root (#26) --- .graphqlrc | 2 ++ apps/parsley/.graphqlrc | 2 -- apps/spruce/.graphqlrc | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) create mode 100644 .graphqlrc delete mode 100644 apps/parsley/.graphqlrc delete mode 100644 apps/spruce/.graphqlrc diff --git a/.graphqlrc b/.graphqlrc new file mode 100644 index 000000000..7385d7966 --- /dev/null +++ b/.graphqlrc @@ -0,0 +1,2 @@ +schema: "apps/*/sdlschema/**/*.graphql" +documents: "apps/*/**/src/gql/**/*.graphql" diff --git a/apps/parsley/.graphqlrc b/apps/parsley/.graphqlrc deleted file mode 100644 index 58b742a8d..000000000 --- a/apps/parsley/.graphqlrc +++ /dev/null @@ -1,2 +0,0 @@ -schema: "sdlschema/**/*.graphql" -documents: "src/gql/**/*.graphql" diff --git a/apps/spruce/.graphqlrc b/apps/spruce/.graphqlrc deleted file mode 100644 index 58b742a8d..000000000 --- a/apps/spruce/.graphqlrc +++ /dev/null @@ -1,2 +0,0 @@ -schema: "sdlschema/**/*.graphql" -documents: "src/gql/**/*.graphql" From fbe57bbc082985d3734ee9498288e24044c0ce3b Mon Sep 17 00:00:00 2001 From: SupaJoon Date: Fri, 5 Apr 2024 14:20:49 -0400 Subject: [PATCH 14/31] DEVPROD-5130: Case on renderingType during log ingestion, introduce LOCAL_UPLOAD logType and fix bug related to exposing renderingType from hook (#25) --- .evergreen/shared.yml | 10 +- .../resmokeLogs/resmoke_evg_test_logView.ts | 318 ++++++++++++++++ apps/parsley/scripts/bootstrap-logkeeper.sh | 14 +- .../src/analytics/useAnalyticAttributes.ts | 7 +- .../PrettyPrintToggle.test.tsx | 10 +- .../Toggles/PrettyPrintToggle/index.tsx | 6 +- .../LogRow/AnsiRow/AnsiRow.stories.tsx | 11 +- .../BaseRow/SharingMenu/SharingMenu.test.tsx | 3 +- .../LogRow/BaseRow/SharingMenu/index.tsx | 3 +- .../CollapsedRow/CollapsedRow.stories.tsx | 16 +- .../LogRow/ResmokeRow/ResmokeRow.stories.tsx | 11 +- .../components/LogRow/RowRenderer/index.tsx | 7 +- .../src/components/LogWindow/index.tsx | 7 +- .../SubHeader/EvergreenTaskSubHeader.tsx | 43 ++- .../SubHeader/SubHeader.stories.tsx | 2 +- .../__snapshots__/SubHeader.stories.storyshot | 344 ++---------------- .../src/components/SubHeader/index.tsx | 13 +- apps/parsley/src/constants/enums.ts | 1 + .../context/LogContext/LogContext.test.tsx | 12 +- apps/parsley/src/context/LogContext/index.tsx | 15 +- apps/parsley/src/context/LogContext/state.ts | 11 +- apps/parsley/src/context/LogContext/types.ts | 10 +- apps/parsley/src/gql/generated/types.ts | 2 + ...et-test-log-url-and-rendering-type.graphql | 2 + apps/parsley/src/hooks/useTaskQuery/index.ts | 3 +- apps/parsley/src/pages/LogDrop.tsx | 9 +- .../parsley/src/pages/LogDrop/FileDropper.tsx | 8 +- apps/parsley/src/pages/LogView.tsx | 6 +- .../src/pages/LogView/LoadingPage/index.tsx | 3 +- .../useResolveLogURLAndRenderingType.test.tsx | 286 ++++++++++++++- .../useResolveLogURLAndRenderingType.ts | 8 +- 31 files changed, 773 insertions(+), 428 deletions(-) create mode 100644 apps/parsley/cypress/integration/resmokeLogs/resmoke_evg_test_logView.ts diff --git a/.evergreen/shared.yml b/.evergreen/shared.yml index 98d515913..a46336f85 100644 --- a/.evergreen/shared.yml +++ b/.evergreen/shared.yml @@ -67,21 +67,21 @@ functions: params: working_dir: ui/logkeeper background: true - script: go run main/logkeeper.go --localPath _bucketdata + script: go run main/logkeeper.go --localPath ../evergreen/_bucketdata shell: bash env: GOROOT: ${goroot} PATH: ${goroot}/bin:$PATH LK_CORS_ORIGINS: http:\/\/localhost:\d+ - seed-logkeeper: + seed-bucket-data: command: s3.get type: setup params: aws_key: ${AWS_ACCESS_KEY_ID} aws_secret: ${AWS_SECRET_ACCESS_KEY} aws_session_token: ${AWS_SESSION_TOKEN} - extract_to: ui/logkeeper + extract_to: ui/evergreen remote_file: _bucketdata.tar.gz bucket: parsley-test @@ -361,7 +361,7 @@ tasks: - func: run-make-background vars: target: local-evergreen - - func: seed-logkeeper + - func: seed-bucket-data - func: run-logkeeper - func: yarn-build - func: yarn-preview @@ -376,7 +376,7 @@ tasks: vars: target: local-evergreen - func: symlink - - func: seed-logkeeper + - func: seed-bucket-data - func: run-logkeeper - func: yarn-build - func: yarn-serve diff --git a/apps/parsley/cypress/integration/resmokeLogs/resmoke_evg_test_logView.ts b/apps/parsley/cypress/integration/resmokeLogs/resmoke_evg_test_logView.ts new file mode 100644 index 000000000..715275418 --- /dev/null +++ b/apps/parsley/cypress/integration/resmokeLogs/resmoke_evg_test_logView.ts @@ -0,0 +1,318 @@ +describe("Basic resmoke log view", () => { + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab"; + beforeEach(() => { + cy.visit(logLink); + }); + + it("should render resmoke lines", () => { + cy.dataCy("resmoke-row").should("be.visible"); + }); + it("by default should have wrapping turned off and should be able to scroll horizontally", () => { + cy.dataCy("log-row-16").should("be.visible"); + cy.dataCy("log-row-16").isNotContainedInViewport(); + + cy.dataCy("paginated-virtual-list").scrollTo(500, 0, { + ensureScrollable: true, + }); + }); + it("long lines with wrapping turned on should fit on screen", () => { + cy.clickToggle("wrap-toggle", true, "log-viewing"); + cy.dataCy("log-row-16").should("be.visible"); + cy.dataCy("log-row-16").isContainedInViewport(); + }); + it("should still allow horizontal scrolling when there are few logs on screen", () => { + cy.addFilter("Putting spruce/"); + cy.contains("Above & Below").click(); + cy.dataCy("paginated-virtual-list").scrollTo("right"); + }); + + it("log header should show breadcrumbs, including one for the test name", () => { + cy.dataCy("project-breadcrumb").should( + "contain.text", + "mongodb-mongo-master", + ); + + cy.dataCy("version-breadcrumb").should("contain.text", "Patch 973"); + cy.dataCy("version-breadcrumb").trigger("mouseover"); + cy.dataCy("breadcrumb-tooltip").should( + "contain.text", + "SERVER-45720 Create tests for Atlas Workflows", + ); + cy.dataCy("version-breadcrumb").trigger("mouseout"); + + cy.dataCy("task-breadcrumb") + .should("contain.text", "merge-patch") + .should( + "have.attr", + "href", + "http://localhost:9090/task/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0?redirect_spruce_users=true", + ); + cy.dataCy("task-status-badge").should("contain.text", "Succeeded"); + + cy.dataCy("test-breadcrumb").should( + "contain.text", + "internal_transactions_kill_sessions.js", + ); + cy.dataCy("test-status-badge").should("contain.text", "Pass"); + }); +}); + +describe("Resmoke syntax highlighting", () => { + // Although it isn't ideal to test for a specific color, this helps us ensure that the color is consistent and deterministic. + const colors = { + black: "rgb(0, 0, 0)", + blue: "rgb(8, 60, 144)", + green: "rgb(0, 163, 92)", + }; + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab"; + + beforeEach(() => { + cy.visit(logLink); + }); + it("should not color non-resmoke log lines", () => { + cy.dataCy("log-row-0").within(() => { + cy.dataCy("resmoke-row").should("have.css", "color", colors.black); + }); + }); + it("should color similar resmoke lines with the same color", () => { + cy.dataCy("log-row-20").should("be.visible"); + cy.dataCy("log-row-21").should("be.visible"); + cy.dataCy("log-row-20").should("contain", "[j0:s0:n1]"); + cy.dataCy("log-row-21").should("contain", "[j0:s0:n1]"); + cy.dataCy("log-row-20").within(() => { + cy.dataCy("resmoke-row").should("have.css", "color", colors.blue); + }); + cy.dataCy("log-row-21").within(() => { + cy.dataCy("resmoke-row").should("have.css", "color", colors.blue); + }); + }); + it("should color different resmoke lines with different colors if their resmoke state is different", () => { + cy.dataCy("log-row-19").should("be.visible"); + cy.dataCy("log-row-20").should("be.visible"); + cy.dataCy("log-row-19").should("contain", "[j0:s0:n0]"); + cy.dataCy("log-row-20").should("contain", "[j0:s0:n1]"); + cy.dataCy("log-row-19").within(() => { + cy.dataCy("resmoke-row").should("have.css", "color", colors.green); + }); + cy.dataCy("log-row-20").within(() => { + cy.dataCy("resmoke-row").should("have.css", "color", colors.blue); + }); + }); +}); + +describe("Bookmarking and selecting lines", () => { + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab"; + beforeEach(() => { + cy.visit(logLink); + }); + + it("should default to bookmarking 0 and the last log line on load", () => { + cy.location("search").should("equal", "?bookmarks=0,12568"); + cy.dataCy("bookmark-0").should("be.visible"); + cy.dataCy("bookmark-12568").should("be.visible"); + }); + + it("should be able to bookmark and unbookmark log lines", () => { + cy.dataCy("log-row-4").dblclick(); + cy.location("search").should("equal", "?bookmarks=0,4,12568"); + cy.dataCy("bookmark-0").should("be.visible"); + cy.dataCy("bookmark-4").should("be.visible"); + cy.dataCy("bookmark-12568").should("be.visible"); + cy.dataCy("log-row-4").dblclick(); + cy.location("search").should("equal", "?bookmarks=0,12568"); + cy.dataCy("bookmark-4").should("not.exist"); + }); + + it("should be able to set and unset the share line", () => { + cy.dataCy("log-link-5").click(); + cy.location("search").should("equal", "?bookmarks=0,12568&shareLine=5"); + cy.dataCy("bookmark-0").should("be.visible"); + cy.dataCy("bookmark-5").should("be.visible"); + cy.dataCy("bookmark-12568").should("be.visible"); + cy.dataCy("log-link-5").click(); + cy.location("search").should("equal", "?bookmarks=0,12568"); + cy.dataCy("bookmark-5").should("not.exist"); + }); + + it("should be able to copy bookmarks as JIRA format", () => { + cy.dataCy("log-row-10").dblclick({ scrollBehavior: false }); + cy.dataCy("log-row-11").dblclick({ scrollBehavior: false }); + + const logLine0 = + "[fsm_workload_test:internal_transactions_kill_sessions] Fixture status:"; + const logLine10 = + "|ShardedClusterFixture:job0:mongos0 |j0:s0 |20009|73157|"; + const logLine11 = + "|ShardedClusterFixture:job0:mongos1 |j0:s1 |20010|73217|"; + const logLine1638 = `[ContinuousStepdown:job0] Pausing the stepdown thread.`; + + cy.dataCy("details-button").click(); + // Need to fire a real click here because the copy to clipboard + cy.dataCy("jira-button").realClick(); + cy.assertValueCopiedToClipboard( + `{noformat}\n${logLine0}\n...\n${logLine10}\n${logLine11}\n...\n${logLine1638}\n{noformat}`, + ); + }); + + it("should be able to clear bookmarks", () => { + cy.location("search").should("equal", "?bookmarks=0,12568"); + cy.dataCy("clear-bookmarks").click(); + cy.location("search").should("equal", ""); + }); +}); + +describe("Jump to line", () => { + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab"; + + it("should be able to use the bookmarks bar to jump to a line when there are no collapsed rows", () => { + cy.visit(logLink); + cy.dataCy("log-row-4").should("be.visible").dblclick({ force: true }); + cy.dataCy("bookmark-4").should("be.visible"); + + cy.dataCy("bookmark-12568").click(); + cy.dataCy("log-row-12568").should("be.visible"); + cy.dataCy("log-row-4").should("not.exist"); + + cy.dataCy("bookmark-4").click(); + cy.dataCy("log-row-4").should("be.visible"); + }); + + it("should be able to use the bookmarks bar to jump to a line when there are collapsed rows", () => { + cy.visit(`${logLink}?filters=100repl_hb`); + cy.dataCy("log-row-30").should("be.visible").dblclick({ force: true }); + cy.url().should("include", "bookmarks=0,30,12568"); + cy.dataCy("bookmark-30").should("be.visible"); + cy.dataCy("bookmark-12568").click(); + cy.dataCy("log-row-12568").should("be.visible"); + cy.dataCy("log-row-30").should("not.exist"); + + cy.dataCy("bookmark-30").click(); + cy.dataCy("log-row-30").should("be.visible"); + }); + + it("visiting a log with a share line should jump to that line on page load", () => { + cy.visit(`${logLink}?shareLine=200`); + cy.dataCy("log-row-200").should("be.visible"); + }); +}); + +describe("expanding collapsed rows", () => { + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab?bookmarks=0,12568&filters=100ShardedClusterFixture%253Ajob0"; + beforeEach(() => { + cy.visit(logLink); + }); + + it("should be able to expand collapsed rows", () => { + cy.dataCy("log-row-1").should("not.exist"); + cy.dataCy("log-row-2").should("not.exist"); + cy.dataCy("log-row-3").should("not.exist"); + + cy.dataCy("collapsed-row-1-3").within(() => { + cy.contains("All").click(); + }); + + cy.dataCy("collapsed-row-1-3").should("not.exist"); + cy.dataCy("log-row-1").should("be.visible"); + cy.dataCy("log-row-2").should("be.visible"); + cy.dataCy("log-row-3").should("be.visible"); + }); + + it("should be able to see what rows have been expanded in the drawer", () => { + cy.dataCy("collapsed-row-1-3").within(() => { + cy.contains("All").click(); + }); + cy.toggleDrawer(); + cy.dataCy("expanded-row-1-to-3").should("be.visible"); + }); + + it("should be possible to re-collapse rows through the drawer", () => { + cy.dataCy("collapsed-row-1-3").within(() => { + cy.contains("All").click(); + }); + cy.dataCy("collapsed-row-1-3").should("not.exist"); + + cy.toggleDrawer(); + cy.dataCy("expanded-row-1-to-3").within(() => { + cy.get(`[aria-label="Delete range"]`).click(); + }); + cy.dataCy("collapsed-row-1-3").should("exist"); + }); +}); + +describe("pretty print", () => { + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab"; + beforeEach(() => { + cy.setCookie("pretty-print-bookmarks", "true"); + cy.visit(logLink); + }); + + it("should pretty print bookmarks if pretty print is enabled", () => { + const defaultRowHeight = 18; + + cy.dataCy("log-row-19").dblclick({ force: true }); + cy.dataCy("log-row-19") + .invoke("height") + .should("be.greaterThan", defaultRowHeight); + }); +}); + +describe("Sharing lines", () => { + const logLink = + "/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab"; + + beforeEach(() => { + cy.visit(logLink); + }); + + it("should present a share button with a menu when a line is selected", () => { + cy.dataCy("line-index-1").click(); + cy.dataCy("sharing-menu-button").should("be.visible"); + cy.dataCy("sharing-menu-button").click(); + cy.dataCy("sharing-menu").should("be.visible"); + }); + it("shift+click selecting a range of lines should automatically open the sharing menu", () => { + cy.dataCy("line-index-1").click(); + cy.dataCy("line-index-10").click({ shiftKey: true }); + cy.dataCy("sharing-menu").should("be.visible"); + }); + it("should be able to copy the selected lines as JIRA format", () => { + cy.dataCy("line-index-1").click(); + cy.dataCy("line-index-2").click({ shiftKey: true }); + cy.dataCy("sharing-menu").should("be.visible"); + cy.contains("Copy selected contents").should("be.visible"); + // Need to fire a real click here because the copy to clipboard + cy.contains("Copy selected contents").realClick(); + cy.validateToast("success", "Copied 2 lines to clipboard", true); + cy.assertValueCopiedToClipboard( + `{noformat}\n+------------------------------------------+--------+-----+-----+\n|full_name |name |port |pid |\n{noformat}`, + ); + }); + it("should be able to copy a link to the selected lines", () => { + cy.dataCy("line-index-1").click(); + cy.dataCy("line-index-2").click({ shiftKey: true }); + cy.dataCy("sharing-menu").should("be.visible"); + cy.contains("Copy share link to selected lines").should("be.visible"); + // Need to fire a real click here because the copy to clipboard + cy.contains("Copy share link to selected lines").realClick(); + cy.validateToast("success", "Copied link to clipboard", true); + cy.assertValueCopiedToClipboard( + "http://localhost:4173/test/mongodb_mongo_master_rhel80_debug_v4ubsan_all_feature_flags_experimental_concurrency_sharded_with_stepdowns_and_balancer_4_linux_enterprise_361789ed8a613a2dc0335a821ead0ab6205fbdaa_22_09_21_02_53_24/0/1716e11b4f8a4541c5e2faf70affbfab?bookmarks=0%2C12568&selectedLineRange=L1-L2&shareLine=1", + ); + }); + it("should be able to limit the search range to the selected lines", () => { + cy.dataCy("line-index-1").click(); + cy.dataCy("line-index-2").click({ shiftKey: true }); + cy.dataCy("sharing-menu").should("be.visible"); + cy.contains("Only search on range").should("be.visible"); + cy.contains("Only search on range").click(); + cy.toggleDetailsPanel(true); + cy.dataCy("range-lower-bound").should("have.value", "1"); + cy.dataCy("range-upper-bound").should("have.value", "2"); + }); +}); diff --git a/apps/parsley/scripts/bootstrap-logkeeper.sh b/apps/parsley/scripts/bootstrap-logkeeper.sh index c2d4337f8..bec3bcc45 100755 --- a/apps/parsley/scripts/bootstrap-logkeeper.sh +++ b/apps/parsley/scripts/bootstrap-logkeeper.sh @@ -1,4 +1,4 @@ -# This file downloads a resmoke log for use with the local logkeeper db +# This file downloads bucket data for task output. RED='\033[0;31m' @@ -14,7 +14,7 @@ if [ ! -d "bin/_bucketdata" ]; then # Use aws cli to download the bucket data echo "Downloading bucket data..." # Try to download the bucket data - aws s3 sync --content-encoding gzip s3://parsley-test/ ./bin + aws s3 cp s3://parsley-test/_bucketdata.tar.gz bin/_bucketdata.tar.gz # Check to see if the download was successful if [ $? -ne 0 ]; then echo "${RED}Failed to download bucket data!${NC}" @@ -26,12 +26,12 @@ if [ ! -d "bin/_bucketdata" ]; then fi # Uncompress the files in the _bucketdata directory echo "Uncompressing bucket data..." - tar -xzf ./bin/_bucketdata.tar.gz -C ./bin/ + tar -xzf bin/_bucketdata.tar.gz -C bin/ # Check to see if the uncompress was successful if [ $? -ne 0 ]; then echo "${RED}Failed to uncompress bucket data!${NC}" echo "Cleaning up _bucketdata directory..." - rm -rf _bucketdata + rm -rf bin/_bucketdata exit 1 fi echo "Finished uncompressing files." @@ -45,6 +45,8 @@ else echo "If you want to download the bucket data again, delete the _bucketdata directory and rerun this script." fi - -echo "Use the following command within the logkeeper directory to start logkeeper:" +echo "Use the following command to start logkeeper:" echo "${YELLOW}LK_CORS_ORIGINS=http:\/\/localhost:\\\d+ LK_EVERGREEN_ORIGIN=http://localhost:8080 LK_PARSLEY_ORIGIN=http://localhost:5173 go run main/logkeeper.go --localPath $PWD/bin/_bucketdata${NC}" + +echo "Create symlink in your local evergreen directory:" +echo "ln -s $PWD/bin/_bucketdata _bucketdata" diff --git a/apps/parsley/src/analytics/useAnalyticAttributes.ts b/apps/parsley/src/analytics/useAnalyticAttributes.ts index dbbc40716..c365c223a 100644 --- a/apps/parsley/src/analytics/useAnalyticAttributes.ts +++ b/apps/parsley/src/analytics/useAnalyticAttributes.ts @@ -5,7 +5,7 @@ export const useAnalyticAttributes = () => { const { newrelic } = window; const { logMetadata } = useLogContext(); - const { logType } = logMetadata || {}; + const { logType, renderingType } = logMetadata || {}; const userId = localStorage.getItem("userId"); @@ -21,5 +21,8 @@ export const useAnalyticAttributes = () => { if (userId !== null) { newrelic.setCustomAttribute("userId", userId); } - }, [userId, logType, newrelic]); + if (renderingType !== undefined) { + newrelic.setCustomAttribute("renderingType", renderingType); + } + }, [userId, logType, newrelic, renderingType]); }; diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/PrettyPrintToggle.test.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/PrettyPrintToggle.test.tsx index 5586190f3..d318b47c9 100644 --- a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/PrettyPrintToggle.test.tsx +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/PrettyPrintToggle.test.tsx @@ -1,5 +1,5 @@ import Cookie from "js-cookie"; -import { LogTypes } from "constants/enums"; +import { LogRenderingTypes } from "constants/enums"; import { LogContextProvider, useLogContext } from "context/LogContext"; import { act, @@ -42,21 +42,21 @@ describe("pretty print toggle", () => { ); render(, { wrapper }); act(() => { - hook.current.setLogMetadata({ logType: LogTypes.EVERGREEN_TASK_LOGS }); + hook.current.setLogMetadata({ renderingType: LogRenderingTypes.Default }); }); const prettyPrintToggle = screen.getByDataCy("pretty-print-toggle"); expect(prettyPrintToggle).toHaveAttribute("aria-disabled", "true"); }); - it("should not disable the toggle if the logType is resmoke", () => { + it("should not disable the toggle if the renderingType is resmoke", () => { const { Component, hook } = renderComponentWithHook( useLogContext, , ); render(, { wrapper }); act(() => { - hook.current.setLogMetadata({ logType: LogTypes.RESMOKE_LOGS }); + hook.current.setLogMetadata({ renderingType: LogRenderingTypes.Resmoke }); }); const prettyPrintToggle = screen.getByDataCy("pretty-print-toggle"); @@ -71,7 +71,7 @@ describe("pretty print toggle", () => { ); const { router } = render(, { wrapper }); act(() => { - hook.current.setLogMetadata({ logType: LogTypes.RESMOKE_LOGS }); + hook.current.setLogMetadata({ renderingType: LogRenderingTypes.Resmoke }); }); const prettyPrintToggle = screen.getByDataCy("pretty-print-toggle"); diff --git a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/index.tsx b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/index.tsx index 4f505acb9..d2af89bf8 100644 --- a/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/index.tsx +++ b/apps/parsley/src/components/DetailsMenu/DetailsMenuCard/Toggles/PrettyPrintToggle/index.tsx @@ -1,5 +1,5 @@ import { usePreferencesAnalytics } from "analytics"; -import { LogTypes } from "constants/enums"; +import { LogRenderingTypes } from "constants/enums"; import { useLogContext } from "context/LogContext"; import BaseToggle from "../BaseToggle"; @@ -8,8 +8,8 @@ const PrettyPrintToggle: React.FC = () => { const { logMetadata, preferences } = useLogContext(); const { prettyPrint, setPrettyPrint } = preferences; - const { logType } = logMetadata || {}; - const disablePrettyPrint = logType !== LogTypes.RESMOKE_LOGS; + const disablePrettyPrint = + logMetadata?.renderingType !== LogRenderingTypes.Resmoke; return ( { const { ingestLines, scrollToLine } = useLogContext(); useEffect(() => { - ingestLines(logLines, LogTypes.EVERGREEN_TASK_LOGS); + ingestLines(logLines, LogRenderingTypes.Default); }, []); // eslint-disable-line react-hooks/exhaustive-deps return ( @@ -57,11 +57,13 @@ export const SingleLine: CustomStoryObj = { // Multiple AnsiRows. const MultiLineStory = (args: any) => { - const { ingestLines, preferences, processedLogLines } = useLogContext(); + const { ingestLines, preferences, processedLogLines, setLogMetadata } = + useLogContext(); const { setWrap } = preferences; useEffect(() => { - ingestLines(logLines, LogTypes.EVERGREEN_TASK_LOGS); + setLogMetadata({ logType: LogTypes.EVERGREEN_TASK_LOGS }); + ingestLines(logLines, LogRenderingTypes.Default); }, []); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { @@ -73,7 +75,6 @@ const MultiLineStory = (args: any) => { diff --git a/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/SharingMenu.test.tsx b/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/SharingMenu.test.tsx index 6654edf0b..5eee59432 100644 --- a/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/SharingMenu.test.tsx +++ b/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/SharingMenu.test.tsx @@ -1,3 +1,4 @@ +import { LogTypes } from "constants/enums"; import { LogContextProvider, useLogContext } from "context/LogContext"; import { MultiLineSelectContextProvider, @@ -150,7 +151,7 @@ describe("sharingMenu", () => { }); act(() => { hook.current.useLogContextHook.setLogMetadata({ - isUploadedLog: true, + logType: LogTypes.LOCAL_UPLOAD, }); }); expect(screen.queryByText("Share link to selected lines")).toBeNull(); diff --git a/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/index.tsx b/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/index.tsx index df7276ac5..eb71bb5e6 100644 --- a/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/index.tsx +++ b/apps/parsley/src/components/LogRow/BaseRow/SharingMenu/index.tsx @@ -20,12 +20,11 @@ interface SharingMenuProps { const SharingMenu: React.FC = ({ defaultOpen }) => { const { clearSelection, selectedLines } = useMultiLineSelectContext(); - const { getLine, logMetadata, processedLogLines } = useLogContext(); + const { getLine, isUploadedLog, processedLogLines } = useLogContext(); const [params, setParams] = useQueryParams(); const dispatchToast = useToastContext(); const [open, setOpen] = useState(defaultOpen); const { sendEvent } = useLogWindowAnalytics(); - const { isUploadedLog } = logMetadata || {}; const setMenuOpen = () => { if (open) { sendEvent({ name: "Closed Share Menu" }); diff --git a/apps/parsley/src/components/LogRow/CollapsedRow/CollapsedRow.stories.tsx b/apps/parsley/src/components/LogRow/CollapsedRow/CollapsedRow.stories.tsx index 3c74954f5..d53665774 100644 --- a/apps/parsley/src/components/LogRow/CollapsedRow/CollapsedRow.stories.tsx +++ b/apps/parsley/src/components/LogRow/CollapsedRow/CollapsedRow.stories.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import styled from "@emotion/styled"; import LogPane from "components/LogPane"; import { ParsleyRow } from "components/LogRow/RowRenderer"; -import { LogTypes } from "constants/enums"; +import { LogRenderingTypes, LogTypes } from "constants/enums"; import { useLogContext } from "context/LogContext"; import { CustomMeta, CustomStoryObj } from "test_utils/types"; import { ExpandedLine, ExpandedLines } from "types/logs"; @@ -54,11 +54,13 @@ const CollapsedAnsiRowStory = ( wrap: boolean; }, ) => { - const { ingestLines, preferences, processedLogLines } = useLogContext(); + const { ingestLines, preferences, processedLogLines, setLogMetadata } = + useLogContext(); const { setWrap } = preferences; useEffect(() => { - ingestLines(ansiLogLines, LogTypes.EVERGREEN_TASK_LOGS); + setLogMetadata({ logType: LogTypes.EVERGREEN_TASK_LOGS }); + ingestLines(ansiLogLines, LogRenderingTypes.Default); }, []); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { @@ -70,7 +72,6 @@ const CollapsedAnsiRowStory = ( @@ -95,11 +96,13 @@ const CollapsedResmokeRowStory = ( wrap: boolean; }, ) => { - const { ingestLines, preferences, processedLogLines } = useLogContext(); + const { ingestLines, preferences, processedLogLines, setLogMetadata } = + useLogContext(); const { setWrap } = preferences; useEffect(() => { - ingestLines(resmokeLogLines, LogTypes.RESMOKE_LOGS); + setLogMetadata({ logType: LogTypes.RESMOKE_LOGS }); + ingestLines(resmokeLogLines, LogRenderingTypes.Resmoke); }, []); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { @@ -111,7 +114,6 @@ const CollapsedResmokeRowStory = ( diff --git a/apps/parsley/src/components/LogRow/ResmokeRow/ResmokeRow.stories.tsx b/apps/parsley/src/components/LogRow/ResmokeRow/ResmokeRow.stories.tsx index 7988200a5..4118df387 100644 --- a/apps/parsley/src/components/LogRow/ResmokeRow/ResmokeRow.stories.tsx +++ b/apps/parsley/src/components/LogRow/ResmokeRow/ResmokeRow.stories.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import styled from "@emotion/styled"; import LogPane from "components/LogPane"; import { ParsleyRow } from "components/LogRow/RowRenderer"; -import { LogTypes, WordWrapFormat } from "constants/enums"; +import { LogRenderingTypes, LogTypes, WordWrapFormat } from "constants/enums"; import { useLogContext } from "context/LogContext"; import { MultiLineSelectContextProvider } from "context/MultiLineSelectContext"; import WithToastContext from "test_utils/toast-decorator"; @@ -28,7 +28,7 @@ const SingleLineStory = (args: any) => { const { getResmokeLineColor, ingestLines, scrollToLine } = useLogContext(); useEffect(() => { - ingestLines(logLines, LogTypes.RESMOKE_LOGS); + ingestLines(logLines, LogRenderingTypes.Resmoke); }, []); // eslint-disable-line react-hooks/exhaustive-deps return ( @@ -60,11 +60,13 @@ export const SingleLine: CustomStoryObj = { // Multiple ResmokeRows. const MultipleLinesStory = (args: any) => { - const { ingestLines, preferences, processedLogLines } = useLogContext(); + const { ingestLines, preferences, processedLogLines, setLogMetadata } = + useLogContext(); const { setPrettyPrint, setWrap } = preferences; useEffect(() => { - ingestLines(logLines, LogTypes.RESMOKE_LOGS); + setLogMetadata({ logType: LogTypes.EVERGREEN_TASK_LOGS }); + ingestLines(logLines, LogRenderingTypes.Resmoke); }, []); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { @@ -80,7 +82,6 @@ const MultipleLinesStory = (args: any) => { diff --git a/apps/parsley/src/components/LogRow/RowRenderer/index.tsx b/apps/parsley/src/components/LogRow/RowRenderer/index.tsx index e05444fc4..fb7c7c49a 100644 --- a/apps/parsley/src/components/LogRow/RowRenderer/index.tsx +++ b/apps/parsley/src/components/LogRow/RowRenderer/index.tsx @@ -1,4 +1,4 @@ -import { LogRenderingTypes, LogTypes } from "constants/enums"; +import { LogRenderingTypes } from "constants/enums"; import { useLogContext } from "context/LogContext"; import { useHighlightParam } from "hooks/useHighlightParam"; import { ProcessedLogLines } from "types/logs"; @@ -9,10 +9,9 @@ import ResmokeRow from "../ResmokeRow"; type RowRendererFunction = (props: { processedLogLines: ProcessedLogLines; - logType: LogTypes; }) => (index: number) => JSX.Element; -const ParsleyRow: RowRendererFunction = ({ logType, processedLogLines }) => { +const ParsleyRow: RowRendererFunction = ({ processedLogLines }) => { const { expandLines, getLine, @@ -83,7 +82,7 @@ const ParsleyRow: RowRendererFunction = ({ logType, processedLogLines }) => { ); }; - result.displayName = `${logType}RowRenderer`; + result.displayName = `${logMetadata?.logType}RowRenderer`; return result; }; diff --git a/apps/parsley/src/components/LogWindow/index.tsx b/apps/parsley/src/components/LogWindow/index.tsx index 66a7df259..bb5cffb25 100644 --- a/apps/parsley/src/components/LogWindow/index.tsx +++ b/apps/parsley/src/components/LogWindow/index.tsx @@ -5,13 +5,9 @@ import LogPane from "components/LogPane"; import { ParsleyRow } from "components/LogRow/RowRenderer"; import SidePanel from "components/SidePanel"; import SubHeader from "components/SubHeader"; -import { LogTypes } from "constants/enums"; import { useLogContext } from "context/LogContext"; -interface LogWindowProps { - logType: LogTypes; -} -const LogWindow: React.FC = ({ logType }) => { +const LogWindow: React.FC = () => { const { clearExpandedLines, collapseLines, @@ -41,7 +37,6 @@ const LogWindow: React.FC = ({ logType }) => { diff --git a/apps/parsley/src/components/SubHeader/EvergreenTaskSubHeader.tsx b/apps/parsley/src/components/SubHeader/EvergreenTaskSubHeader.tsx index d41a63666..947abcf49 100644 --- a/apps/parsley/src/components/SubHeader/EvergreenTaskSubHeader.tsx +++ b/apps/parsley/src/components/SubHeader/EvergreenTaskSubHeader.tsx @@ -1,3 +1,4 @@ +import { useQuery } from "@apollo/client"; import { InlineCode } from "@leafygreen-ui/typography"; import { usePreferencesAnalytics } from "analytics"; import { TaskStatusBadge, TestStatusBadge } from "components/Badge"; @@ -6,6 +7,11 @@ import Icon from "components/Icon"; import { StyledLink } from "components/styles"; import { LogTypes } from "constants/enums"; import { getEvergreenTaskURL } from "constants/externalURLTemplates"; +import { + TestLogUrlAndRenderingTypeQuery, + TestLogUrlAndRenderingTypeQueryVariables, +} from "gql/generated/types"; +import { GET_TEST_LOG_URL_AND_RENDERING_TYPE } from "gql/queries"; import { useTaskQuery } from "hooks/useTaskQuery"; import { shortenGithash, trimStringFromMiddle } from "utils/string"; @@ -27,14 +33,25 @@ export const EvergreenTaskSubHeader: React.FC = ({ testID, }) => { const { sendEvent } = usePreferencesAnalytics(); - const { loading, task } = useTaskQuery({ + const { loading: isLoadingTask, task: taskData } = useTaskQuery({ buildID, execution, logType, taskID, }); - if (loading || !task) { + const { data: testData, loading: isLoadingTest } = useQuery< + TestLogUrlAndRenderingTypeQuery, + TestLogUrlAndRenderingTypeQueryVariables + >(GET_TEST_LOG_URL_AND_RENDERING_TYPE, { + skip: !(logType === LogTypes.EVERGREEN_TEST_LOGS && testID), + variables: { + execution, + taskID, + testName: `^${testID}$`, + }, + }); + if (isLoadingTask || isLoadingTest || !taskData) { return ( <> @@ -47,20 +64,30 @@ export const EvergreenTaskSubHeader: React.FC = ({ ); } - const { displayName, execution: taskExecution, patchNumber, status, versionMetadata, - } = task; + } = taskData; + const { isPatch, message, projectIdentifier, revision } = versionMetadata; - const currentTest = - task?.tests?.testResults?.find((test) => - test?.logs?.urlRaw?.match(new RegExp(`${testID}`)), - ) ?? null; + let currentTest: { testFile: string; status: string } | null = null; + switch (logType) { + case LogTypes.RESMOKE_LOGS: + currentTest = + taskData?.tests?.testResults?.find((test) => + test?.logs?.urlRaw?.match(new RegExp(`${testID}`)), + ) ?? null; + break; + case LogTypes.EVERGREEN_TEST_LOGS: + currentTest = testData?.task?.tests?.testResults?.[0] ?? null; + break; + default: + currentTest = null; + } const breadcrumbs = [ { diff --git a/apps/parsley/src/components/SubHeader/SubHeader.stories.tsx b/apps/parsley/src/components/SubHeader/SubHeader.stories.tsx index da0e7fe52..99df6e534 100644 --- a/apps/parsley/src/components/SubHeader/SubHeader.stories.tsx +++ b/apps/parsley/src/components/SubHeader/SubHeader.stories.tsx @@ -77,7 +77,7 @@ const SubheaderWrapper: React.FC = ({ const { setLogMetadata } = useLogContext(); useEffect(() => { - setLogMetadata({ ...metaData, isUploadedLog }); + setLogMetadata({ ...metaData, logType: LogTypes.LOCAL_UPLOAD }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ; diff --git a/apps/parsley/src/components/SubHeader/__snapshots__/SubHeader.stories.storyshot b/apps/parsley/src/components/SubHeader/__snapshots__/SubHeader.stories.storyshot index 3e53bb350..72eef0f4e 100644 --- a/apps/parsley/src/components/SubHeader/__snapshots__/SubHeader.stories.storyshot +++ b/apps/parsley/src/components/SubHeader/__snapshots__/SubHeader.stories.storyshot @@ -10,28 +10,21 @@ exports[`Snapshot Tests SubHeader.stories TaskFileLog 1`] = ` class="css-1xawlld" > - -