diff --git a/docs/package.json b/docs/package.json index 5cc340acb870f..d75716fdaf78c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -7,7 +7,8 @@ "dev": "next", "start": "next start", "build": "next build", - "lint": "next lint" + "lint": "next lint", + "schema": "ts-json-schema-generator -p ./schema.d.ts -o ./public/schema.json -t Schema" }, "author": "Jared Palmer", "license": "MPL-2.0", @@ -65,6 +66,7 @@ "eslint-config-prettier": "^8.3.0", "postcss": "^8.3.5", "tailwindcss": "^3.0.15", + "ts-json-schema-generator": "^0.97.0", "typescript": "^4.5.5", "webpack": "^5.65.0" }, diff --git a/docs/pages/docs/features/caching.mdx b/docs/pages/docs/features/caching.mdx index 5edabf33e826b..8f79358cf7f2f 100644 --- a/docs/pages/docs/features/caching.mdx +++ b/docs/pages/docs/features/caching.mdx @@ -18,6 +18,7 @@ To override the default cache output behavior, pass an array of globs to a [`pip ```jsonc { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "outputs": ["dist/**", ".next/**"], @@ -63,6 +64,7 @@ You can also always disable caching on a specific task by setting `cache` to `fa ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "dev": { "cache": false @@ -84,6 +86,7 @@ Luckily, you can control `turbo`'s cache fingerprinting (a.k.a. hashing) behavio ```jsonc { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": { diff --git a/docs/pages/docs/features/pipelines.mdx b/docs/pages/docs/features/pipelines.mdx index 90911792d3d48..abc7da099b533 100644 --- a/docs/pages/docs/features/pipelines.mdx +++ b/docs/pages/docs/features/pipelines.mdx @@ -30,6 +30,7 @@ An example Pipeline configuration in `turbo.json`: ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": ["^build"] @@ -66,6 +67,7 @@ What you are declaring here in the `pipeline` object of the `turbo` configuratio ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { // A package's `build` task depends on that package's @@ -100,6 +102,7 @@ A common pattern in many TypeScript monorepos is to declare that a package's `bu ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { // "A package's `build` command depends on its dependencies' @@ -117,13 +120,13 @@ An empty dependency list (`dependsOn` is either undefined or `[]`) means that a ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { - // ... omitted for brevity - - // A package's `lint` command has no dependencies and can be run at - // whenever. - "lint": {} - } + // ... omitted for brevity + + // A package's `lint` command has no dependencies and can be run at + // whenever. + "lint": {} } } ``` @@ -145,22 +148,21 @@ For these cases, you can express these relationships in your `pipeline` configur ```json { - - "pipeline": { - "build": { - "dependsOn": ["^build"] - }, - "test": { - "dependsOn": ["build"] - }, - "deploy": { - "dependsOn": ["test"] - }, - "frontend#deploy": { - "dependsOn": ["ui#test", "backend#deploy", "backend#health-check"] - } + "$schema": "https://turborepo.org/schema.json", + "pipeline": { + "build": { + "dependsOn": ["^build"] + }, + "test": { + "dependsOn": ["build"] + }, + "deploy": { + "dependsOn": ["test"] + }, + "frontend#deploy": { + "dependsOn": ["ui#test", "backend#deploy", "backend#health-check"] } - + } } ``` diff --git a/docs/pages/docs/getting-started.mdx b/docs/pages/docs/getting-started.mdx index f719de5212a65..92d62020a61f4 100644 --- a/docs/pages/docs/getting-started.mdx +++ b/docs/pages/docs/getting-started.mdx @@ -64,6 +64,7 @@ If your git repo's base branch is NOT `origin/master` then you need to specify a ```json { + "$schema": "https://turborepo.org/schema.json", "baseBranch": "origin/main" } ``` @@ -76,6 +77,7 @@ Your pipeline both defines the way in which your NPM `package.json` scripts rela ```json { + "$schema": "https://turborepo.org/schema.json", "baseBranch": "origin/main", "pipeline": { "build": { diff --git a/docs/pages/docs/guides/migrate-from-lerna.mdx b/docs/pages/docs/guides/migrate-from-lerna.mdx index 6028c608b7818..8fb6aed8a657f 100644 --- a/docs/pages/docs/guides/migrate-from-lerna.mdx +++ b/docs/pages/docs/guides/migrate-from-lerna.mdx @@ -102,6 +102,7 @@ Create a `turbo.json` file in the root of your project. ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": ["^build"], diff --git a/docs/pages/docs/reference/codemods.mdx b/docs/pages/docs/reference/codemods.mdx index 3056e2a8a66ed..4db4b2d92639c 100644 --- a/docs/pages/docs/reference/codemods.mdx +++ b/docs/pages/docs/reference/codemods.mdx @@ -102,6 +102,7 @@ For example: // After, turbo.json { + "$schema": "https://turborepo.org/schema.json", "baseBranch": "origin/main", "pipeline": { ... diff --git a/docs/pages/docs/reference/command-line-reference.mdx b/docs/pages/docs/reference/command-line-reference.mdx index c71c170f6cee0..e83248ae1bf89 100644 --- a/docs/pages/docs/reference/command-line-reference.mdx +++ b/docs/pages/docs/reference/command-line-reference.mdx @@ -172,6 +172,7 @@ Given this pipeline in `turbo.json`: ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": [ diff --git a/docs/pages/docs/reference/configuration.mdx b/docs/pages/docs/reference/configuration.mdx index 158cfa1e01584..04097c8feb509 100644 --- a/docs/pages/docs/reference/configuration.mdx +++ b/docs/pages/docs/reference/configuration.mdx @@ -23,6 +23,7 @@ This is useful for busting the cache based on `.env` files (not in Git), environ ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { // ... omitted for brevity }, @@ -49,6 +50,7 @@ Each key in the `pipeline` object is the name of a task that can be executed by ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": ["^build"] @@ -80,6 +82,7 @@ Prefixing an item in `dependsOn` with a `$` tells `turbo` that this pipeline tas ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { // "A package's `build` command depends on its dependencies' @@ -106,6 +109,7 @@ Prefixing an item in `dependsOn` with a `$` tells `turbo` that this pipeline tas ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": { @@ -143,6 +147,7 @@ Passing an empty array can be used to tell `turbo` that a task is a side-effect ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { // "Cache all files emitted to package's dist/** or .next @@ -180,6 +185,7 @@ Defaults to `true`. Whether or not to cache the task [`outputs`](#outputs-1). Se ```json { + "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": ["^build"] diff --git a/docs/public/schema.json b/docs/public/schema.json new file mode 100644 index 0000000000000..d1164c1089101 --- /dev/null +++ b/docs/public/schema.json @@ -0,0 +1,71 @@ +{ + "$ref": "#/definitions/Schema", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "Pipeline": { + "additionalProperties": false, + "properties": { + "cache": { + "default": true, + "description": "Whether or not to cache the task outputs. Setting cache to false is useful for daemon or long-running \"watch\" or development mode tasks that you don't want to cache.", + "type": "boolean" + }, + "dependsOn": { + "default": [], + "description": "The list of tasks and environment variables that this task depends on.\n\nPrefixing an item in dependsOn with a ^ tells turbo that this pipeline task depends on the package's topological dependencies completing the task with the ^ prefix first (e.g. \"a package's build tasks should only run once all of its dependencies and devDependencies have completed their own build commands\").\n\nItems in dependsOn without ^ prefix, express the relationships between tasks at the package level (e.g. \"a package's test and lint commands depend on build being completed first\").\n\nPrefixing an item in dependsOn with a $ tells turbo that this pipeline task depends the value of that environment variable.", + "items": { + "type": "string" + }, + "type": "array" + }, + "outputs": { + "default": [ + "dist/**", + "build/**" + ], + "description": "The set of glob patterns of a task's cacheable filesystem outputs.\n\nNote: turbo automatically logs stderr/stdout to .turbo/run-.log. This file is always treated as a cacheable artifact and never needs to be specified.\n\nPassing an empty array can be used to tell turbo that a task is a side-effect and thus doesn't emit any filesystem artifacts (e.g. like a linter), but you still want to cache its logs (and treat them like an artifact).", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "Schema": { + "additionalProperties": false, + "properties": { + "$schema": { + "default": "https://turborepo.org/schema.json", + "type": "string" + }, + "baseBranch": { + "default": "origin/master", + "description": "The base branch or your git repository. Git is used by turbo in its hashing algorithm and --since CLI flag.", + "type": "string" + }, + "globalDependencies": { + "default": [], + "description": "A list of globs and environment variables for implicit global hash dependencies. Environment variables should be prefixed with $ (e.g. $GITHUB_TOKEN).\n\nAny other entry without this prefix, will be considered filesystem glob. The contents of these files will be included in the global hashing algorithm and affect the hashes of all tasks.\n\nThis is useful for busting the cache based on .env files (not in Git), environment variables, or any root level file that impacts package tasks (but are not represented in the traditional dependency graph\n\n(e.g. a root tsconfig.json, jest.config.js, .eslintrc, etc.)).", + "items": { + "type": "string" + }, + "type": "array" + }, + "pipeline": { + "additionalProperties": { + "$ref": "#/definitions/Pipeline", + "description": "The name of a task that can be executed by turbo run. If turbo finds a workspace package with a package.json scripts object with a matching key, it will apply the pipeline task configuration to that NPM script during execution. This allows you to use pipeline to set conventions across your entire Turborepo." + }, + "default": {}, + "description": "An object representing the task dependency graph of your project. turbo interprets these conventions to properly schedule, execute, and cache the outputs of tasks in your project.", + "type": "object" + } + }, + "required": [ + "pipeline" + ], + "type": "object" + } + } +} \ No newline at end of file diff --git a/docs/schema.d.ts b/docs/schema.d.ts new file mode 100644 index 0000000000000..6616283b79a70 --- /dev/null +++ b/docs/schema.d.ts @@ -0,0 +1,92 @@ +/* This file generates the `schema.json` file. */ + +export interface Schema { + /** @default https://turborepo.org/schema.json */ + $schema?: string; + + /** + * The base branch or your git repository. Git is used by turbo in its hashing algorithm + * and --since CLI flag. + * + * @default origin/master + */ + baseBranch?: string; + + /** + * A list of globs and environment variables for implicit global hash dependencies. + * Environment variables should be prefixed with $ (e.g. $GITHUB_TOKEN). + * + * Any other entry without this prefix, will be considered filesystem glob. The + * contents of these files will be included in the global hashing algorithm and affect + * the hashes of all tasks. + * + * This is useful for busting the cache based on .env files (not in Git), environment + * variables, or any root level file that impacts package tasks (but are not represented + * in the traditional dependency graph + * + * (e.g. a root tsconfig.json, jest.config.js, .eslintrc, etc.)). + * + * @default [] + */ + globalDependencies?: string[]; + + /** + * An object representing the task dependency graph of your project. turbo interprets + * these conventions to properly schedule, execute, and cache the outputs of tasks in + * your project. + * + * @default {} + */ + pipeline: { + /** + * The name of a task that can be executed by turbo run. If turbo finds a workspace + * package with a package.json scripts object with a matching key, it will apply the + * pipeline task configuration to that NPM script during execution. This allows you to + * use pipeline to set conventions across your entire Turborepo. + */ + [script: string]: Pipeline; + }; +} + +export interface Pipeline { + /** + * The list of tasks and environment variables that this task depends on. + * + * Prefixing an item in dependsOn with a ^ tells turbo that this pipeline task depends + * on the package's topological dependencies completing the task with the ^ prefix first + * (e.g. "a package's build tasks should only run once all of its dependencies and + * devDependencies have completed their own build commands"). + * + * Items in dependsOn without ^ prefix, express the relationships between tasks at the + * package level (e.g. "a package's test and lint commands depend on build being + * completed first"). + * + * Prefixing an item in dependsOn with a $ tells turbo that this pipeline task depends + * the value of that environment variable. + * + * @default [] + */ + dependsOn?: string[]; + + /** + * The set of glob patterns of a task's cacheable filesystem outputs. + * + * Note: turbo automatically logs stderr/stdout to .turbo/run-.log. This file is + * always treated as a cacheable artifact and never needs to be specified. + * + * Passing an empty array can be used to tell turbo that a task is a side-effect and + * thus doesn't emit any filesystem artifacts (e.g. like a linter), but you still want + * to cache its logs (and treat them like an artifact). + * + * @default ["dist/**", "build/**"] + */ + outputs?: string[]; + + /** + * Whether or not to cache the task outputs. Setting cache to false is useful for daemon + * or long-running "watch" or development mode tasks that you don't want to cache. + * + * @default true + */ + cache?: boolean; +} diff --git a/turbo.json b/turbo.json index 71fe99be76c2f..769a7f33276c1 100644 --- a/turbo.json +++ b/turbo.json @@ -1,4 +1,5 @@ { + "$schema": "./docs/public/schema.json", "baseBranch": "origin/main", "env": [ "CONVERTKIT_API_KEY", diff --git a/yarn.lock b/yarn.lock index b9665aaad5236..0436f02074a24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1180,7 +1180,7 @@ jest-diff "^27.0.0" pretty-format "^27.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== @@ -2214,7 +2214,7 @@ commander@^4.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== -commander@^8.3.0: +commander@^8.2.0, commander@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== @@ -3340,7 +3340,7 @@ glob@7.1.7, glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.4: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.4, glob@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -4443,7 +4443,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json5@2.x, json5@^2.1.2: +json5@2.x, json5@^2.1.2, json5@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== @@ -6263,6 +6263,11 @@ safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-stable-stringify@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz#ab67cbe1fe7d40603ca641c5e765cb942d04fc73" + integrity sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg== + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -6922,6 +6927,18 @@ ts-jest@^27.1.1: semver "7.x" yargs-parser "20.x" +ts-json-schema-generator@^0.97.0: + version "0.97.0" + resolved "https://registry.yarnpkg.com/ts-json-schema-generator/-/ts-json-schema-generator-0.97.0.tgz#ea4f2ddbcba1fb6c0a2f97d242783b7fdc8e203b" + integrity sha512-kPDq4ut8Mu1ZgSN7OeTXz+ueb1juFt2eyGd23lMr3WoN5sq4Xa9m22kDI46OlwapE0aF8e1pUesOFgDcATHcuA== + dependencies: + "@types/json-schema" "^7.0.9" + commander "^8.2.0" + glob "^7.2.0" + json5 "^2.2.0" + safe-stable-stringify "^2.2.0" + typescript "~4.4.3" + tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: version "3.12.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" @@ -7029,6 +7046,11 @@ typescript@^4.5.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== +typescript@~4.4.3: + version "4.4.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== + unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"