{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://json.schemastore.org/vss-extension",
  "definitions": {
    "id_pattern": {
      "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]+$"
    },
    "demand_pattern": {
      "pattern": "^((environment/cloud|environment/onprem)|(api-version|extension|contribution|contributionType)/.+)$"
    },
    "link_definition": {
      "type": "object",
      "required": ["uri"],
      "properties": {
        "uri": {
          "type": "string",
          "description": "Valid URI",
          "format": "uri"
        }
      }
    },
    "content_definition": {
      "type": "object",
      "required": ["path"],
      "properties": {
        "path": {
          "type": "string",
          "title": "Valid file path in the extension",
          "format": "uri-reference"
        }
      }
    },
    "contribution_definition": {
      "type": "object",
      "description": "A contribution that is part of this extension",
      "required": ["id", "type", "targets"],
      "properties": {
        "id": {
          "title": "Referencing contributions and types => https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#contributionIds",
          "description": "A reference ID (string) for the contribution. Each contribution's ID must be unique within an extension.",
          "type": "string"
        },
        "type": {
          "description": "The ID of the contributionType of this contribution.",
          "type": "string"
        },
        "description": {
          "type": "string",
          "description": "(Optional) A string describing what the contribution is providing."
        },
        "targets": {
          "type": "array",
          "description": "An array of contribution IDs that the contribution is targeting (contributing to).",
          "title": "Targeting Contributions: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#targeting-contributions",
          "items": {
            "type": "string",
            "description": "Contribution IDs that the contribution is targeting.",
            "title": "Targeting Contributions: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#targeting-contributions"
          }
        },
        "restrictedTo": {
          "type": "array",
          "description": "Valid Values: https://docs.microsoft.com/en-us/azure/devops/extend/develop/public-project?view=azure-devops#contribution-visibility",
          "title": "Contribution visibility: By default, contributions are only visible to organization members. To give non-member users visibility to a contribution, set the restrictedTo attribute on that contribution. The value is a string array that lists which types of users should have visibility to the contribution",
          "items": {
            "type": "string",
            "description": "Valid Values: https://docs.microsoft.com/en-us/azure/devops/extend/develop/public-project?view=azure-devops#contribution-visibility",
            "title": "Contribution visibility: By default, contributions are only visible to organization members. To give non-member users visibility to a contribution, set the restrictedTo attribute on that contribution. The value is a string array that lists which types of users should have visibility to the contribution",
            "enum": ["member", "public", "anonymous"]
          }
        },
        "properties": {
          "type": "object",
          "description": "(Optional) An object that includes properties for the contribution as defined in the contribution type.",
          "title": "For more information, see the contribution model overview => https://docs.microsoft.com/en-us/azure/devops/extend/develop/contributions-overview?view=azure-devops"
        }
      }
    },
    "contributionType_definition": {
      "type": "object",
      "description": "A contribution Type that is part of this extension",
      "required": ["id", "name"],
      "properties": {
        "id": {
          "title": "Referencing contributions and types => https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#contributionIds",
          "description": "A reference ID (string) for the contribution type. Each contribution type's ID must be unique within an extension.",
          "type": "string"
        },
        "name": {
          "description": "The friendly name of the contribution type.",
          "type": "string"
        },
        "description": {
          "type": "string",
          "description": "(Optional) A string describing in more detail what the contribution type is for."
        },
        "properties": {
          "type": "array",
          "description": "(Optional) A dictionary that maps property names to property descriptions. These properties describe the required and optional properties that can be used by contributions of this type.",
          "items": {
            "type": "object",
            "description": "Information about the contributionType Property",
            "required": ["type"],
            "properties": {
              "type": {
                "type": "string",
                "description": "The type of value that the property can have.",
                "enum": [
                  "string",
                  "uri",
                  "guid",
                  "boolean",
                  "integer",
                  "double",
                  "dateTime",
                  "array",
                  "object"
                ]
              },
              "required": {
                "type": "boolean",
                "default": false,
                "description": "(Optional) A boolean value which if true indicates that the property is required for all contributions of this type."
              },
              "description": {
                "type": "string",
                "description": "(Optional) A string describing what the property is used for."
              }
            }
          }
        }
      }
    }
  },
  "properties": {
    "manifestVersion": {
      "type": "integer",
      "title": "A number corresponding to the version of the manifest format.",
      "default": 1,
      "description": "This should be 1.",
      "enum": [1]
    },
    "id": {
      "type": "string",
      "title": "The extension's identifier",
      "description": "This is a string that must be unique among extensions from the same publisher.",
      "allOf": [
        {
          "$ref": "#/definitions/id_pattern"
        }
      ]
    },
    "version": {
      "type": "string",
      "title": "A string specifying the version of an extension.",
      "description": "Should be in the format major.minor.patch, for example 0.1.2 or 1.0.0. You can also add a fourth number for the following format: 0.1.2.3",
      "examples": ["1.0.0", "1.0.0.0"],
      "pattern": "^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$"
    },
    "name": {
      "type": "string",
      "title": "A short, human-readable name of the extension. Limited to 200 characters.",
      "maxLength": 200,
      "examples": [
        "Azure DevOps Extension Tasks",
        "Fabrikam Agile Board Extension"
      ]
    },
    "publisher": {
      "$comment": "This identifier must match the identifier the extension is published under.",
      "type": "string",
      "title": "The identifier of the publisher.",
      "description": "This identifier must match the identifier the extension is published under.",
      "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]+$"
    },
    "categories": {
      "type": "array",
      "uniqueItems": true,
      "title": "Array of strings representing the categories your extension belongs to.",
      "description": "At least one category must be provided and there is no limit to how many categories you may include.",
      "items": {
        "type": "string",
        "enum": [
          "Azure Repos",
          "Azure Boards",
          "Azure Pipelines",
          "Azure Test Plans",
          "Azure Artifacts"
        ]
      }
    },
    "targets": {
      "type": "array",
      "title": "The products and services supported by your integration or extension.",
      "items": {
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": {
            "type": "string",
            "title": "Installation targets: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#installation-targets",
            "description": "Id of the product or service which your integration/extension should support",
            "enum": [
              "Microsoft.VisualStudio.Services",
              "Microsoft.TeamFoundation.Server",
              "Microsoft.VisualStudio.Services.Integration",
              "Microsoft.TeamFoundation.Server.Integration",
              "Microsoft.VisualStudio.Services.Cloud",
              "Microsoft.VisualStudio.Services.Cloud.Integration"
            ]
          },
          "version": {
            "$comment": "Some installation target identifiers, like and , support an optional version range. This further clarifies the supported releases the extension or integration is supported on.Microsoft.TeamFoundation.ServerMicrosoft.TeamFoundation.Server.Integration",
            "type": "string",
            "title": "Installation target versions: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#installation-targets",
            "description": "Some installation target identifiers, like and , support an optional version range. This further clarifies the supported releases the extension or integration is supported on.Microsoft.TeamFoundation.ServerMicrosoft.TeamFoundation.Server.Integration",
            "examples": [
              "[17.0,)",
              "[15.0,)",
              "[14.0,)",
              "[12.0,)",
              "[11.0,)",
              "[10.0,)",
              "[12.0,15.0)",
              "[14.3,15.1]"
            ],
            "pattern": "^(\\[|\\()\\d{2}\\.\\d,(\\d{2}\\.\\d)?(\\)|\\])$"
          }
        }
      }
    },
    "scopes": {
      "type": "array",
      "title": "Authorization scopes required by your extension.",
      "description": "An array of authorization scopes (strings) listing permissions required by your extension.",
      "items": {
        "type": "string",
        "description": "Authorization Scope.",
        "title": "Valid Values: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#scopes",
        "enum": [
          "vso.acquisition_write",
          "vso.agentpools",
          "vso.agentpools_listen",
          "vso.agentpools_manage",
          "vso.analytics",
          "vso.auditlog",
          "vso.base",
          "vso.build",
          "vso.build_execute",
          "vso.build_fork",
          "vso.code",
          "vso.code_full",
          "vso.code_manage",
          "vso.code_status",
          "vso.code_write",
          "vso.commerce.write",
          "vso.connected_server",
          "vso.dashboards",
          "vso.dashboards_manage",
          "vso.entitlements",
          "vso.extension",
          "vso.extension.data",
          "vso.extension.data_write",
          "vso.extension.default",
          "vso.extension_manage",
          "vso.features",
          "vso.features_write",
          "vso.gallery",
          "vso.gallery_acquire",
          "vso.gallery_manage",
          "vso.gallery_publish",
          "vso.governance_manage",
          "vso.graph",
          "vso.graph_manage",
          "vso.graph_write",
          "vso.hooks",
          "vso.hooks_interact",
          "vso.hooks_write",
          "vso.identity",
          "vso.identity_manage",
          "vso.licensing",
          "vso.loadtest",
          "vso.loadtest_write",
          "vso.machinegroup_manage",
          "vso.memberentitlementmanagement",
          "vso.memberentitlementmanagement_write",
          "vso.notification",
          "vso.notification_diagnostics",
          "vso.notification_manage",
          "vso.notification_publish",
          "vso.notification_write",
          "vso.packaging",
          "vso.packaging_manage",
          "vso.packaging_write",
          "vso.profile",
          "vso.profile_write",
          "vso.project",
          "vso.project_manage",
          "vso.project_write",
          "vso.release",
          "vso.release_execute",
          "vso.release_logs",
          "vso.release_manage",
          "vso.security_manage",
          "vso.serviceendpoint",
          "vso.serviceendpoint_manage",
          "vso.serviceendpoint_query",
          "vso.settings",
          "vso.settings_write",
          "vso.symbols",
          "vso.symbols_manage",
          "vso.symbols_write",
          "vso.taskgroups_manage",
          "vso.taskgroups_read",
          "vso.taskgroups_write",
          "vso.test",
          "vso.test_write",
          "vso.tokenadministration",
          "vso.tokens",
          "vso.variablegroups_manage",
          "vso.variablegroups_read",
          "vso.variablegroups_write",
          "vso.wiki",
          "vso.wiki_write",
          "vso.work",
          "vso.work_full",
          "vso.work_write"
        ]
      }
    },
    "demands": {
      "type": "array",
      "title": "Capabilities required by your extension.",
      "description": "An array of demands (strings) listing the capabilities required by your extension.",
      "items": {
        "type": "string",
        "description": "Demand Scope.",
        "title": "Valid Values: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#demands",
        "allOf": [
          {
            "$ref": "#/definitions/demand_pattern"
          }
        ]
      }
    },
    "baseUri": {
      "type": "string",
      "description": "(Optional) base URL for all relative URLs specified by the extension's contributions.",
      "title": "This property should be left empty if your extension's contents are packaged with your extension.",
      "format": "uri"
    },
    "description": {
      "type": "string",
      "title": "A few sentences describing the extension.",
      "maxLength": 200
    },
    "icons": {
      "type": "object",
      "description": "Dictionary of icons representing the extension.",
      "required": ["default"],
      "properties": {
        "default": {
          "type": "string",
          "title": "(128x128 pixels) of type BMP, GIF, EXIF, JPG, PNG and TIFF.",
          "description": "The value must be the path to the icon file in the extension",
          "format": "uri-reference"
        }
      }
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags to help users find your extension.",
      "minItems": 1,
      "items": {
        "type": "string",
        "description": "A tag to help users find your extension.",
        "examples": [
          "Extension",
          "Marketplace",
          "Publish",
          "Package",
          "Install",
          "Continuous Integration",
          "Continuous Delivery",
          "Build",
          "Release",
          "Azure Pipelines",
          "Azure DevOps Extensions",
          "Visual Studio Extensions",
          "__BYOLENFORCED",
          "__DoNotDownload"
        ]
      }
    },
    "galleryFlags": {
      "type": "array",
      "description": "Array of string tags to classify your extension within the Visual Studio Marketplace",
      "minItems": 1,
      "items": {
        "type": "string",
        "description": "A string tag to classify your extension within the Visual Studio Marketplace",
        "enum": ["Paid", "Preview", "Public"]
      }
    },
    "licensing": {
      "type": "object",
      "description": "More information: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#mark-an-extension-as-paid"
    },
    "galleryproperties": {
      "type": "object",
      "description": "More information: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest?view=azure-devops#mark-an-extension-as-paid"
    },
    "screenshots": {
      "type": "array",
      "title": "Screenshots are more valuable when featured in your content, and should be used there to help make a quality market details page for your extension. Use screenshots for less important images not featured in your content.",
      "description": "Array of images that could not be included in your **content*.",
      "items": {
        "type": "object",
        "title": "An image that could not be included in your **content*.",
        "description": "Each image should be 1366x768 pixels.",
        "required": ["path"],
        "properties": {
          "path": {
            "type": "string",
            "title": "Each image should be 1366x768 pixels.",
            "description": "The path of each item is the path to the file in the extension.",
            "format": "uri-reference"
          }
        }
      }
    },
    "content": {
      "type": "object",
      "title": "Dictionary of content files that describe your extension to users.",
      "required": ["details"],
      "properties": {
        "details": {
          "title": "Extension Details (GitHub Flavored Markdown File)",
          "description": "GitHub Flavored Markdown file which describes the details of the Extension",
          "allOf": [
            {
              "$ref": "#/definitions/content_definition"
            }
          ]
        },
        "license": {
          "title": "Extension License Information (GitHub Flavored Markdown File)",
          "description": "GitHub Flavored Markdown file which describes the license information of the Extension",
          "allOf": [
            {
              "$ref": "#/definitions/content_definition"
            }
          ]
        },
        "pricing": {
          "title": "Extension Pricing Information (GitHub Flavored Markdown File)",
          "description": "GitHub Flavored Markdown file which describes the pricing information of the Extension",
          "allOf": [
            {
              "$ref": "#/definitions/content_definition"
            }
          ]
        }
      }
    },
    "links": {
      "type": "object",
      "title": "Dictionary of links that help users learn more about your extension, get support, and move.",
      "minProperties": 1,
      "properties": {
        "getstarted": {
          "title": "Get Started Documentation (GitHub Flavored Markdown File)",
          "description": "First steps, how to setup or use.",
          "allOf": [
            {
              "$ref": "#/definitions/link_definition"
            }
          ]
        },
        "learn": {
          "title": "Learning Documentation (GitHub Flavored Markdown File)",
          "description": "Deeper content to help users better understand your extension or service.",
          "allOf": [
            {
              "$ref": "#/definitions/link_definition"
            }
          ]
        },
        "license": {
          "title": "License Documentation (GitHub Flavored Markdown File)",
          "description": "End user license agreement.",
          "allOf": [
            {
              "$ref": "#/definitions/link_definition"
            }
          ]
        },
        "privacypolicy": {
          "title": "Privacy Policy (GitHub Flavored Markdown File)",
          "description": "Privacy policy for an extension.",
          "allOf": [
            {
              "$ref": "#/definitions/link_definition"
            }
          ]
        },
        "support": {
          "title": "Support Information (GitHub Flavored Markdown File)",
          "description": "Get help and support for an extension.",
          "allOf": [
            {
              "$ref": "#/definitions/link_definition"
            }
          ]
        }
      }
    },
    "repository": {
      "type": "object",
      "title": "The source code repository for the extension",
      "required": ["type", "uri"],
      "properties": {
        "type": {
          "type": "string",
          "title": "Type of the repository",
          "enum": ["git", "mercurial", "svn", "cvs"]
        },
        "uri": {
          "type": "string",
          "title": "Absolute URI of the repository",
          "format": "uri"
        }
      }
    },
    "badges": {
      "type": "array",
      "description": "Array of links to external metadata badges like TravisCI, Appveyor etc from the approved badges sites.",
      "title": "Approved Badge Sites: https://docs.microsoft.com/en-us/azure/devops/extend/develop/manifest.#approvedbadges",
      "items": {
        "type": "object",
        "title": "Badge Information",
        "required": ["href", "uri"],
        "properties": {
          "href": {
            "type": "string",
            "description": "Link the user navigates to when clicking the badge.",
            "format": "uri"
          },
          "uri": {
            "type": "string",
            "description": "The absolute URL of the badge image to be displayed.",
            "format": "uri"
          },
          "description": {
            "type": "string",
            "title": "Description of the badge, to be displayed on hover."
          }
        }
      }
    },
    "branding": {
      "type": "object",
      "description": "Dictionary of brand-related properties.",
      "required": ["color"],
      "properties": {
        "color": {
          "type": "string",
          "description": "Primary color of the extension or publisher; can be a hex (#ff00ff), RGB (rgb(100,200,50)), or supported HTML color names (blue)."
        },
        "theme": {
          "type": "string",
          "description": "Complements the color; use dark for dark branding colors, or light for lighter branding colors.",
          "enum": ["light", "dark"]
        }
      }
    },
    "public": {
      "type": "boolean",
      "description": "Set to true to make this extension public in the Visual Studio Market Place",
      "default": false
    },
    "files": {
      "type": "array",
      "title": "The files section is where you reference any files you wish to include in your extension. You can add both folders and individual files.",
      "items": {
        "type": "object",
        "description": "A file you wish to include in your extension. Both folders and individual files are acceptable",
        "required": ["path"],
        "properties": {
          "path": {
            "type": "string",
            "description": "Path of resource, root directory is where your manifest file is located",
            "format": "uri-reference"
          },
          "addressable": {
            "type": "boolean",
            "default": false,
            "description": "Set to true if you want your file to be URL-addressable"
          },
          "packagePath": {
            "type": "string",
            "description": "Places your resource from disk to the specified value when packaged",
            "format": "uri-reference"
          }
        }
      }
    },
    "contributions": {
      "type": "array",
      "title": "An array of contributions to the system.",
      "items": {
        "allOf": [
          {
            "$ref": "#/definitions/contribution_definition"
          }
        ]
      }
    },
    "contributionTypes": {
      "type": "array",
      "title": "An array of contribution types defined by the extension",
      "items": {
        "allOf": [
          {
            "$ref": "#/definitions/contributionType_definition"
          }
        ]
      }
    }
  },
  "required": [
    "manifestVersion",
    "id",
    "version",
    "name",
    "publisher",
    "categories",
    "targets"
  ],
  "title": "JSON Schema for Azure DevOps Extensions",
  "type": "object"
}
