diff --git a/.gitignore b/.gitignore index 92329b3b996..54c2de8a9e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +bin/ out/ examples/bazel/bazel-* integration/examples/bazel/bazel-* diff --git a/.travis.yml b/.travis.yml index e42e73b8fa8..e6bf9810de8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,19 +21,12 @@ jobs: name: "Linux unit" script: - make - - make quicktest - after_success: - - bash <(curl -s https://codecov.io/bash) + - make coverage - os: osx name: "OSX unit" - env: - - GO111MODULE=on - - GOFLAGS="-mod=vendor" script: - - go build -o out/skaffold cmd/skaffold/skaffold.go - - go test -short -timeout 60s ./... - after_success: - - bash <(curl -s https://codecov.io/bash) + - make + - make quicktest - os: windows name: "Windows unit" env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 27067b563d0..93284350bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,87 @@ +# v0.37.0 Release - 08/29/2019 + +No new features in this release! + +Bug Fixes: + +* Use active gcloud credentials for executing cloudbuild when available [#2731](https://github.com/GoogleContainerTools/skaffold/pull/2731) +* Restore original images only if there are no remote manifests [#2746](https://github.com/GoogleContainerTools/skaffold/pull/2746) +* List manifests in the order given by the user [#2729](https://github.com/GoogleContainerTools/skaffold/pull/2729) +* Fix 'skaffold diagnose' for custom builder without dependencies [#2724](https://github.com/GoogleContainerTools/skaffold/pull/2724) +* Don't panic when dockerConfig isn't provided [#2735](https://github.com/GoogleContainerTools/skaffold/pull/2735) +* Don't set KanikoArtifact if CustomArtifact is set [#2716](https://github.com/GoogleContainerTools/skaffold/pull/2716) +* [Caching] Artifact’s config is an input to digest calculation [#2728](https://github.com/GoogleContainerTools/skaffold/pull/2728) +* Don’t fetch images that are aliases for scratch [#2720](https://github.com/GoogleContainerTools/skaffold/pull/2720) +* Implement exponential backoff for retrieving cloud build status [#2667](https://github.com/GoogleContainerTools/skaffold/pull/2667) +* Fix call to newPortForwardEntry constructor in kubectl_forwarder_test [#2703](https://github.com/GoogleContainerTools/skaffold/pull/2703) +* Add information about top level owner to port forward key [#2675](https://github.com/GoogleContainerTools/skaffold/pull/2675) +* Turn RPC State forwardedPorts into map keyed by the local port [#2659](https://github.com/GoogleContainerTools/skaffold/pull/2659) +* Show the duration of the deploy phase [#2739](https://github.com/GoogleContainerTools/skaffold/pull/2739) +* Configure jib.allowInsecureRegistries as required [#2674](https://github.com/GoogleContainerTools/skaffold/pull/2674) + +Updates & Refactors: + +* Pass extra env to the Docker CLI [#2737](https://github.com/GoogleContainerTools/skaffold/pull/2737) +* Improve manifest splitting. [#2727](https://github.com/GoogleContainerTools/skaffold/pull/2727) +* Bazel query should specify --output [#2712](https://github.com/GoogleContainerTools/skaffold/pull/2712) +* Print the output of failed integration tests [#2725](https://github.com/GoogleContainerTools/skaffold/pull/2725) +* We must handle every profile field type [#2726](https://github.com/GoogleContainerTools/skaffold/pull/2726) +* Fix CI scripts [#2736](https://github.com/GoogleContainerTools/skaffold/pull/2736) +* Directs "Download" button to Quickstart [#2695](https://github.com/GoogleContainerTools/skaffold/pull/2695) +* Small improvements to code coverage [#2719](https://github.com/GoogleContainerTools/skaffold/pull/2719) +* Don’t store log lines as mutable slices of bytes [#2721](https://github.com/GoogleContainerTools/skaffold/pull/2721) +* more debugging for kubectl portforward [#2707](https://github.com/GoogleContainerTools/skaffold/pull/2707) +* Remove time sensitive tests [#2655](https://github.com/GoogleContainerTools/skaffold/pull/2655) +* Log a warning and rebuild if needed when caching fails [#2685](https://github.com/GoogleContainerTools/skaffold/pull/2685) +* Improve logging warning when enountering profile field of unhandled type [#2691](https://github.com/GoogleContainerTools/skaffold/pull/2691) +* refactor: Add upgrade utility to handle all pipelines in a SkaffoldConfig [#2582](https://github.com/GoogleContainerTools/skaffold/pull/2582) +* Add struct for generate_pipeline to keep track of related data [#2686](https://github.com/GoogleContainerTools/skaffold/pull/2686) +* Add unit tests to kubectl forwarder [#2661](https://github.com/GoogleContainerTools/skaffold/pull/2661) +* separate checks + unit tests [#2676](https://github.com/GoogleContainerTools/skaffold/pull/2676) +* Add UPSTREAM_CLIENT_TYPE user agent environment variable to kaniko pod [#2723](https://github.com/GoogleContainerTools/skaffold/pull/2723) + +Docs: + +* Document Docker buildArgs as templated field [#2696](https://github.com/GoogleContainerTools/skaffold/pull/2696) +* Update cache-artifacts option usage language to reflect new default [#2711](https://github.com/GoogleContainerTools/skaffold/pull/2711) +* docs: clarify that tagged images in manifests are not replaced [#2598](https://github.com/GoogleContainerTools/skaffold/pull/2598) +* fix development guide link [#2710](https://github.com/GoogleContainerTools/skaffold/pull/2710) +* Update community section of README [#2682](https://github.com/GoogleContainerTools/skaffold/pull/2682) + +Huge thanks goes out to all of our contributors for this release: + +- Aaron Paz +- Andreas Sommer +- Appu +- Balint Pato +- bpopovschi +- Brian de Alwis +- Cedric Kring +- Chanseok Oh +- Charles-Henri GUERIN +- Cornelius Weig +- David Gageot +- Dmitri Moore +- Filip Krakowski +- Jason McClellan +- JieJhih Jhang +- Marlon Gamez +- Matt Brown +- Medya Ghazizadeh +- Michael Beaumont +- Nick Kubala +- Prashant Arya +- Priya Wadhwa +- Russell Wolf +- Sébastien Le Gall +- Sergei Morozov +- Tad Cordle +- Tanner Bruce +- Taylor Barrella +- Tejal Desai +- Tom Dickman + + # v0.36.0 Release - 08/15/2019 New Features: diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 9f933c47e3b..70e1e134836 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -119,7 +119,7 @@ To build with your local changes you have two options: If you are iterating on skaffold and want to see your changes in action, you can: 1. [Build skaffold](#building-skaffold) -2. [Use the quickstart example](README.md#iterative-development) +2. [Use the quickstart example](examples/getting-started/README.md) ## Testing skaffold diff --git a/Makefile b/Makefile index 626897cb4c4..434d6ca2e31 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,13 @@ cross: $(foreach platform, $(SUPPORTED_PLATFORMS), $(BUILD_DIR)/$(PROJECT)-$(pla .PHONY: test test: $(BUILD_DIR) @ ./hack/test.sh + @ ./hack/checks.sh + +.PHONY: coverage +coverage: $(BUILD_DIR) + @ ./hack/test.sh + @ curl -s https://codecov.io/bash > $(BUILD_DIR)/upload_coverage + @ bash $(BUILD_DIR)/upload_coverage .PHONY: checks checks: $(BUILD_DIR) diff --git a/cmd/skaffold/app/cmd/flags.go b/cmd/skaffold/app/cmd/flags.go index 6015d339498..565e24c7aab 100644 --- a/cmd/skaffold/app/cmd/flags.go +++ b/cmd/skaffold/app/cmd/flags.go @@ -82,7 +82,7 @@ var FlagRegistry = []Flag{ }, { Name: "cache-artifacts", - Usage: "Set to true to enable caching of artifacts", + Usage: "Set to false to disable default caching of artifacts", Value: &opts.CacheArtifacts, DefValue: true, FlagAddMethod: "BoolVar", diff --git a/docs/config.toml b/docs/config.toml index 562c28d6eff..379ee3a1209 100644 --- a/docs/config.toml +++ b/docs/config.toml @@ -70,7 +70,7 @@ weight = 1 #copyright = "Skaffold" #privacy_policy = "https://policies.google.com/privacy" github_repo = "https://github.com/GoogleContainerTools/skaffold" -skaffold_version = "skaffold/v1beta13" +skaffold_version = "skaffold/v1beta14" # Google Custom Search Engine ID. Remove or comment out to disable search. gcs_engine_id = "013756393218025596041:3nojel67sum" diff --git a/docs/content/en/_index.html b/docs/content/en/_index.html index cf9b7970c7b..a5328792d60 100644 --- a/docs/content/en/_index.html +++ b/docs/content/en/_index.html @@ -9,8 +9,8 @@ }}"> Learn More - - Download + + Download
{{< blocks/link-down color="info" >}} diff --git a/docs/content/en/docs/how-tos/deployers/_index.md b/docs/content/en/docs/how-tos/deployers/_index.md index 41cfbb32875..f8eedf49a1f 100755 --- a/docs/content/en/docs/how-tos/deployers/_index.md +++ b/docs/content/en/docs/how-tos/deployers/_index.md @@ -9,7 +9,7 @@ to deploy your app to a Kubernetes cluster. When Skaffold deploys an application the following steps happen: -* the Skaffold deployer _renders_ the final kubernetes manifests: Skaffold replaces the image names in the kubernetes manifests with the final tagged image names. +* the Skaffold deployer _renders_ the final kubernetes manifests: Skaffold replaces untagged image names in the kubernetes manifests with the final tagged image names. Also, in case of the more complicated deployers the rendering step involves expanding templates (in case of helm) or calculating overlays (in case of kustomize). * the Skaffold deployer _deploys_ the final kubernetes manifests to the cluster diff --git a/docs/content/en/docs/how-tos/templating/_index.md b/docs/content/en/docs/how-tos/templating/_index.md index 49222afc0ed..619df444480 100755 --- a/docs/content/en/docs/how-tos/templating/_index.md +++ b/docs/content/en/docs/how-tos/templating/_index.md @@ -14,6 +14,7 @@ will be `gcr.io/k8s-skaffold/example:v1`. List of fields that support templating: +* `build.artifacts.[].docker.buildArgs` (see [builders](/docs/how-tos/builders/)) * `build.tagPolicy.envTemplate.template` (see [envTemplate tagger](/docs/how-tos/taggers/##envtemplate-using-values-of-environment-variables-as-tags)) * `deploy.helm.releases.setValueTemplates` (see [Deploying with helm](/docs/how-tos/deployers/#deploying-with-helm)) diff --git a/docs/content/en/docs/references/cli/_index.md b/docs/content/en/docs/references/cli/_index.md index 5d37b48785e..888c6c99be8 100644 --- a/docs/content/en/docs/references/cli/_index.md +++ b/docs/content/en/docs/references/cli/_index.md @@ -116,7 +116,7 @@ Examples: Options: -b, --build-image=[]: Choose which artifacts to build. Artifacts with image names that contain the expression will be built only. Default is to build sources for all artifacts - --cache-artifacts=true: Set to true to enable caching of artifacts + --cache-artifacts=true: Set to false to disable default caching of artifacts --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache) -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config) -d, --default-repo='': Default repository value (overrides global config) @@ -287,7 +287,7 @@ Run a pipeline in debug mode Options: - --cache-artifacts=true: Set to true to enable caching of artifacts + --cache-artifacts=true: Set to false to disable default caching of artifacts --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache) --cleanup=true: Delete deployments after dev or debug mode is interrupted -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config) @@ -429,7 +429,7 @@ Run a pipeline in development mode Options: - --cache-artifacts=true: Set to true to enable caching of artifacts + --cache-artifacts=true: Set to false to disable default caching of artifacts --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache) --cleanup=true: Delete deployments after dev or debug mode is interrupted -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config) @@ -594,7 +594,7 @@ Examples: skaffold run -p Options: - --cache-artifacts=true: Set to true to enable caching of artifacts + --cache-artifacts=true: Set to false to disable default caching of artifacts --cache-file='': Specify the location of the cache file (default $HOME/.skaffold/cache) --cleanup=true: Delete deployments after dev or debug mode is interrupted -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config) diff --git a/docs/content/en/schemas/v1beta14.json b/docs/content/en/schemas/v1beta14.json new file mode 100755 index 00000000000..9081192176a --- /dev/null +++ b/docs/content/en/schemas/v1beta14.json @@ -0,0 +1,1921 @@ +{ + "type": "object", + "anyOf": [ + { + "$ref": "#/definitions/SkaffoldConfig" + } + ], + "$schema": "http://json-schema-org/draft-07/schema#", + "definitions": { + "Activation": { + "properties": { + "command": { + "type": "string", + "description": "a Skaffold command for which the profile is auto-activated.", + "x-intellij-html-description": "a Skaffold command for which the profile is auto-activated.", + "examples": [ + "dev" + ] + }, + "env": { + "type": "string", + "description": "a `key=value` pair. The profile is auto-activated if an Environment Variable `key` has value `value`.", + "x-intellij-html-description": "a key=value pair. The profile is auto-activated if an Environment Variable key has value value.", + "examples": [ + "ENV=production" + ] + }, + "kubeContext": { + "type": "string", + "description": "a Kubernetes context for which the profile is auto-activated.", + "x-intellij-html-description": "a Kubernetes context for which the profile is auto-activated.", + "examples": [ + "minikube" + ] + } + }, + "preferredOrder": [ + "env", + "kubeContext", + "command" + ], + "additionalProperties": false, + "description": "criteria by which a profile is auto-activated.", + "x-intellij-html-description": "criteria by which a profile is auto-activated." + }, + "Artifact": { + "required": [ + "image" + ], + "anyOf": [ + { + "properties": { + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync" + ], + "additionalProperties": false + }, + { + "properties": { + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "docker": { + "$ref": "#/definitions/DockerArtifact", + "description": "*beta* describes an artifact built from a Dockerfile.", + "x-intellij-html-description": "beta describes an artifact built from a Dockerfile." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync", + "docker" + ], + "additionalProperties": false + }, + { + "properties": { + "bazel": { + "$ref": "#/definitions/BazelArtifact", + "description": "*beta* requires bazel CLI to be installed and the sources to contain [Bazel](https://bazel.build/) configuration files.", + "x-intellij-html-description": "beta requires bazel CLI to be installed and the sources to contain Bazel configuration files." + }, + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync", + "bazel" + ], + "additionalProperties": false + }, + { + "properties": { + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "jibMaven": { + "$ref": "#/definitions/JibMavenArtifact", + "description": "*alpha* builds images using the [Jib plugin for Maven](https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin).", + "x-intellij-html-description": "alpha builds images using the Jib plugin for Maven." + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync", + "jibMaven" + ], + "additionalProperties": false + }, + { + "properties": { + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "jibGradle": { + "$ref": "#/definitions/JibGradleArtifact", + "description": "*alpha* builds images using the [Jib plugin for Gradle](https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin).", + "x-intellij-html-description": "alpha builds images using the Jib plugin for Gradle." + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync", + "jibGradle" + ], + "additionalProperties": false + }, + { + "properties": { + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "kaniko": { + "$ref": "#/definitions/KanikoArtifact", + "description": "*alpha* builds images using [kaniko](https://github.com/GoogleContainerTools/kaniko).", + "x-intellij-html-description": "alpha builds images using kaniko." + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync", + "kaniko" + ], + "additionalProperties": false + }, + { + "properties": { + "context": { + "type": "string", + "description": "directory containing the artifact's sources.", + "x-intellij-html-description": "directory containing the artifact's sources.", + "default": "." + }, + "custom": { + "$ref": "#/definitions/CustomArtifact", + "description": "*alpha* builds images using a custom build script written by the user.", + "x-intellij-html-description": "alpha builds images using a custom build script written by the user." + }, + "image": { + "type": "string", + "description": "name of the image to be built.", + "x-intellij-html-description": "name of the image to be built.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "sync": { + "$ref": "#/definitions/Sync", + "description": "*alpha* local files synced to pods instead of triggering an image build when modified.", + "x-intellij-html-description": "alpha local files synced to pods instead of triggering an image build when modified." + } + }, + "preferredOrder": [ + "image", + "context", + "sync", + "custom" + ], + "additionalProperties": false + } + ], + "description": "items that need to be built, along with the context in which they should be built.", + "x-intellij-html-description": "items that need to be built, along with the context in which they should be built." + }, + "BazelArtifact": { + "required": [ + "target" + ], + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional args to pass to `bazel build`.", + "x-intellij-html-description": "additional args to pass to bazel build.", + "default": "[]", + "examples": [ + "[\"-flag\", \"--otherflag\"]" + ] + }, + "target": { + "type": "string", + "description": "`bazel build` target to run.", + "x-intellij-html-description": "bazel build target to run.", + "examples": [ + "//:skaffold_example.tar" + ] + } + }, + "preferredOrder": [ + "target", + "args" + ], + "additionalProperties": false, + "description": "*beta* describes an artifact built with [Bazel](https://bazel.build/).", + "x-intellij-html-description": "beta describes an artifact built with Bazel." + }, + "BuildConfig": { + "anyOf": [ + { + "properties": { + "artifacts": { + "items": { + "$ref": "#/definitions/Artifact" + }, + "type": "array", + "description": "the images you're going to be building.", + "x-intellij-html-description": "the images you're going to be building." + }, + "insecureRegistries": { + "items": { + "type": "string" + }, + "type": "array", + "description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "x-intellij-html-description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "default": "[]" + }, + "tagPolicy": { + "$ref": "#/definitions/TagPolicy", + "description": "*beta* determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to `gitCommit: {variant: Tags}`.", + "x-intellij-html-description": "beta determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to gitCommit: {variant: Tags}." + } + }, + "preferredOrder": [ + "artifacts", + "insecureRegistries", + "tagPolicy" + ], + "additionalProperties": false + }, + { + "properties": { + "artifacts": { + "items": { + "$ref": "#/definitions/Artifact" + }, + "type": "array", + "description": "the images you're going to be building.", + "x-intellij-html-description": "the images you're going to be building." + }, + "insecureRegistries": { + "items": { + "type": "string" + }, + "type": "array", + "description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "x-intellij-html-description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "default": "[]" + }, + "local": { + "$ref": "#/definitions/LocalBuild", + "description": "*beta* describes how to do a build on the local docker daemon and optionally push to a repository.", + "x-intellij-html-description": "beta describes how to do a build on the local docker daemon and optionally push to a repository." + }, + "tagPolicy": { + "$ref": "#/definitions/TagPolicy", + "description": "*beta* determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to `gitCommit: {variant: Tags}`.", + "x-intellij-html-description": "beta determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to gitCommit: {variant: Tags}." + } + }, + "preferredOrder": [ + "artifacts", + "insecureRegistries", + "tagPolicy", + "local" + ], + "additionalProperties": false + }, + { + "properties": { + "artifacts": { + "items": { + "$ref": "#/definitions/Artifact" + }, + "type": "array", + "description": "the images you're going to be building.", + "x-intellij-html-description": "the images you're going to be building." + }, + "googleCloudBuild": { + "$ref": "#/definitions/GoogleCloudBuild", + "description": "*beta* describes how to do a remote build on [Google Cloud Build](https://cloud.google.com/cloud-build/).", + "x-intellij-html-description": "beta describes how to do a remote build on Google Cloud Build." + }, + "insecureRegistries": { + "items": { + "type": "string" + }, + "type": "array", + "description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "x-intellij-html-description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "default": "[]" + }, + "tagPolicy": { + "$ref": "#/definitions/TagPolicy", + "description": "*beta* determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to `gitCommit: {variant: Tags}`.", + "x-intellij-html-description": "beta determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to gitCommit: {variant: Tags}." + } + }, + "preferredOrder": [ + "artifacts", + "insecureRegistries", + "tagPolicy", + "googleCloudBuild" + ], + "additionalProperties": false + }, + { + "properties": { + "artifacts": { + "items": { + "$ref": "#/definitions/Artifact" + }, + "type": "array", + "description": "the images you're going to be building.", + "x-intellij-html-description": "the images you're going to be building." + }, + "cluster": { + "$ref": "#/definitions/ClusterDetails", + "description": "*beta* describes how to do an on-cluster build.", + "x-intellij-html-description": "beta describes how to do an on-cluster build." + }, + "insecureRegistries": { + "items": { + "type": "string" + }, + "type": "array", + "description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "x-intellij-html-description": "a list of registries declared by the user to be insecure. These registries will be connected to via HTTP instead of HTTPS.", + "default": "[]" + }, + "tagPolicy": { + "$ref": "#/definitions/TagPolicy", + "description": "*beta* determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to `gitCommit: {variant: Tags}`.", + "x-intellij-html-description": "beta determines how images are tagged. A few strategies are provided here, although you most likely won't need to care! If not specified, it defaults to gitCommit: {variant: Tags}." + } + }, + "preferredOrder": [ + "artifacts", + "insecureRegistries", + "tagPolicy", + "cluster" + ], + "additionalProperties": false + } + ], + "description": "contains all the configuration for the build steps.", + "x-intellij-html-description": "contains all the configuration for the build steps." + }, + "ClusterDetails": { + "properties": { + "HTTPS_PROXY": { + "type": "string", + "description": "for kaniko pod.", + "x-intellij-html-description": "for kaniko pod." + }, + "HTTP_PROXY": { + "type": "string", + "description": "for kaniko pod.", + "x-intellij-html-description": "for kaniko pod." + }, + "dockerConfig": { + "$ref": "#/definitions/DockerConfig", + "description": "describes how to mount the local Docker configuration into a pod.", + "x-intellij-html-description": "describes how to mount the local Docker configuration into a pod." + }, + "namespace": { + "type": "string", + "description": "Kubernetes namespace. Defaults to current namespace in Kubernetes configuration.", + "x-intellij-html-description": "Kubernetes namespace. Defaults to current namespace in Kubernetes configuration." + }, + "pullSecret": { + "type": "string", + "description": "path to the Google Cloud service account secret key file.", + "x-intellij-html-description": "path to the Google Cloud service account secret key file." + }, + "pullSecretName": { + "type": "string", + "description": "name of the Kubernetes secret for pulling the files from the build context and pushing the final image. If given, the secret needs to contain the Google Cloud service account secret key under the key `kaniko-secret`.", + "x-intellij-html-description": "name of the Kubernetes secret for pulling the files from the build context and pushing the final image. If given, the secret needs to contain the Google Cloud service account secret key under the key kaniko-secret.", + "default": "kaniko-secret" + }, + "resources": { + "$ref": "#/definitions/ResourceRequirements", + "description": "define the resource requirements for the kaniko pod.", + "x-intellij-html-description": "define the resource requirements for the kaniko pod." + }, + "timeout": { + "type": "string", + "description": "amount of time (in seconds) that this build is allowed to run. Defaults to 20 minutes (`20m`).", + "x-intellij-html-description": "amount of time (in seconds) that this build is allowed to run. Defaults to 20 minutes (20m)." + } + }, + "preferredOrder": [ + "HTTP_PROXY", + "HTTPS_PROXY", + "pullSecret", + "pullSecretName", + "namespace", + "timeout", + "dockerConfig", + "resources" + ], + "additionalProperties": false, + "description": "*beta* describes how to do an on-cluster build.", + "x-intellij-html-description": "beta describes how to do an on-cluster build." + }, + "CustomArtifact": { + "properties": { + "buildCommand": { + "type": "string", + "description": "command executed to build the image.", + "x-intellij-html-description": "command executed to build the image." + }, + "dependencies": { + "$ref": "#/definitions/CustomDependencies", + "description": "file dependencies that skaffold should watch for both rebuilding and file syncing for this artifact.", + "x-intellij-html-description": "file dependencies that skaffold should watch for both rebuilding and file syncing for this artifact." + } + }, + "preferredOrder": [ + "buildCommand", + "dependencies" + ], + "additionalProperties": false, + "description": "*alpha* describes an artifact built from a custom build script written by the user. It can be used to build images with builders that aren't directly integrated with skaffold.", + "x-intellij-html-description": "alpha describes an artifact built from a custom build script written by the user. It can be used to build images with builders that aren't directly integrated with skaffold." + }, + "CustomDependencies": { + "properties": { + "command": { + "type": "string", + "description": "represents a custom command that skaffold executes to obtain dependencies. The output of this command *must* be a valid JSON array.", + "x-intellij-html-description": "represents a custom command that skaffold executes to obtain dependencies. The output of this command must be a valid JSON array." + }, + "dockerfile": { + "$ref": "#/definitions/DockerfileDependency", + "description": "should be set if the artifact is built from a Dockerfile, from which skaffold can determine dependencies.", + "x-intellij-html-description": "should be set if the artifact is built from a Dockerfile, from which skaffold can determine dependencies." + }, + "ignore": { + "items": { + "type": "string" + }, + "type": "array", + "description": "specifies the paths that should be ignored by skaffold's file watcher. If a file exists in both `paths` and in `ignore`, it will be ignored, and will be excluded from both rebuilds and file synchronization. Will only work in conjunction with `paths`.", + "x-intellij-html-description": "specifies the paths that should be ignored by skaffold's file watcher. If a file exists in both paths and in ignore, it will be ignored, and will be excluded from both rebuilds and file synchronization. Will only work in conjunction with paths.", + "default": "[]" + }, + "paths": { + "items": { + "type": "string" + }, + "type": "array", + "description": "should be set to the file dependencies for this artifact, so that the skaffold file watcher knows when to rebuild and perform file synchronization.", + "x-intellij-html-description": "should be set to the file dependencies for this artifact, so that the skaffold file watcher knows when to rebuild and perform file synchronization.", + "default": "[]" + } + }, + "preferredOrder": [ + "dockerfile", + "command", + "paths", + "ignore" + ], + "additionalProperties": false, + "description": "*alpha* used to specify dependencies for an artifact built by a custom build script. Either `dockerfile` or `paths` should be specified for file watching to work as expected.", + "x-intellij-html-description": "alpha used to specify dependencies for an artifact built by a custom build script. Either dockerfile or paths should be specified for file watching to work as expected." + }, + "DateTimeTagger": { + "properties": { + "format": { + "type": "string", + "description": "formats the date and time. See [#Time.Format](https://golang.org/pkg/time/#Time.Format).", + "x-intellij-html-description": "formats the date and time. See #Time.Format.", + "default": "2006-01-02_15-04-05.999_MST" + }, + "timezone": { + "type": "string", + "description": "sets the timezone for the date and time. See [Time.LoadLocation](https://golang.org/pkg/time/#Time.LoadLocation). Defaults to the local timezone.", + "x-intellij-html-description": "sets the timezone for the date and time. See Time.LoadLocation. Defaults to the local timezone." + } + }, + "preferredOrder": [ + "format", + "timezone" + ], + "additionalProperties": false, + "description": "*beta* tags images with the build timestamp.", + "x-intellij-html-description": "beta tags images with the build timestamp." + }, + "DeployConfig": { + "anyOf": [ + { + "properties": { + "statusCheckDeadlineSeconds": { + "type": "integer", + "description": "*beta* deadline for deployments to stabilize in seconds.", + "x-intellij-html-description": "beta deadline for deployments to stabilize in seconds." + } + }, + "preferredOrder": [ + "statusCheckDeadlineSeconds" + ], + "additionalProperties": false + }, + { + "properties": { + "helm": { + "$ref": "#/definitions/HelmDeploy", + "description": "*beta* uses the `helm` CLI to apply the charts to the cluster.", + "x-intellij-html-description": "beta uses the helm CLI to apply the charts to the cluster." + }, + "statusCheckDeadlineSeconds": { + "type": "integer", + "description": "*beta* deadline for deployments to stabilize in seconds.", + "x-intellij-html-description": "beta deadline for deployments to stabilize in seconds." + } + }, + "preferredOrder": [ + "statusCheckDeadlineSeconds", + "helm" + ], + "additionalProperties": false + }, + { + "properties": { + "kubectl": { + "$ref": "#/definitions/KubectlDeploy", + "description": "*beta* uses a client side `kubectl apply` to deploy manifests. You'll need a `kubectl` CLI version installed that's compatible with your cluster.", + "x-intellij-html-description": "beta uses a client side kubectl apply to deploy manifests. You'll need a kubectl CLI version installed that's compatible with your cluster." + }, + "statusCheckDeadlineSeconds": { + "type": "integer", + "description": "*beta* deadline for deployments to stabilize in seconds.", + "x-intellij-html-description": "beta deadline for deployments to stabilize in seconds." + } + }, + "preferredOrder": [ + "statusCheckDeadlineSeconds", + "kubectl" + ], + "additionalProperties": false + }, + { + "properties": { + "kustomize": { + "$ref": "#/definitions/KustomizeDeploy", + "description": "*beta* uses the `kustomize` CLI to \"patch\" a deployment for a target environment.", + "x-intellij-html-description": "beta uses the kustomize CLI to "patch" a deployment for a target environment." + }, + "statusCheckDeadlineSeconds": { + "type": "integer", + "description": "*beta* deadline for deployments to stabilize in seconds.", + "x-intellij-html-description": "beta deadline for deployments to stabilize in seconds." + } + }, + "preferredOrder": [ + "statusCheckDeadlineSeconds", + "kustomize" + ], + "additionalProperties": false + } + ], + "description": "contains all the configuration needed by the deploy steps.", + "x-intellij-html-description": "contains all the configuration needed by the deploy steps." + }, + "DockerArtifact": { + "properties": { + "buildArgs": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "arguments passed to the docker build.", + "x-intellij-html-description": "arguments passed to the docker build.", + "default": "{}", + "examples": [ + "{\"key1\": \"value1\", \"key2\": \"value2\"}" + ] + }, + "cacheFrom": { + "items": { + "type": "string" + }, + "type": "array", + "description": "the Docker images used as cache sources.", + "x-intellij-html-description": "the Docker images used as cache sources.", + "default": "[]", + "examples": [ + "[\"golang:1.10.1-alpine3.7\", \"alpine:3.7\"]" + ] + }, + "dockerfile": { + "type": "string", + "description": "locates the Dockerfile relative to workspace.", + "x-intellij-html-description": "locates the Dockerfile relative to workspace.", + "default": "Dockerfile" + }, + "network": { + "type": "string", + "description": "passed through to docker and overrides the network configuration of docker builder. If unset, use whatever is configured in the underlying docker daemon. Valid modes are `host`: use the host's networking stack. `bridge`: use the bridged network configuration. `none`: no networking in the container.", + "x-intellij-html-description": "passed through to docker and overrides the network configuration of docker builder. If unset, use whatever is configured in the underlying docker daemon. Valid modes are host: use the host's networking stack. bridge: use the bridged network configuration. none: no networking in the container." + }, + "noCache": { + "type": "boolean", + "description": "used to pass in --no-cache to docker build to prevent caching.", + "x-intellij-html-description": "used to pass in --no-cache to docker build to prevent caching.", + "default": "false" + }, + "target": { + "type": "string", + "description": "Dockerfile target name to build.", + "x-intellij-html-description": "Dockerfile target name to build." + } + }, + "preferredOrder": [ + "dockerfile", + "target", + "buildArgs", + "network", + "cacheFrom", + "noCache" + ], + "additionalProperties": false, + "description": "*beta* describes an artifact built from a Dockerfile, usually using `docker build`.", + "x-intellij-html-description": "beta describes an artifact built from a Dockerfile, usually using docker build." + }, + "DockerConfig": { + "properties": { + "path": { + "type": "string", + "description": "path to the docker `config.json`.", + "x-intellij-html-description": "path to the docker config.json." + }, + "secretName": { + "type": "string", + "description": "Kubernetes secret that contains the `config.json` Docker configuration. Note that the expected secret type is not 'kubernetes.io/dockerconfigjson' but 'Opaque'.", + "x-intellij-html-description": "Kubernetes secret that contains the config.json Docker configuration. Note that the expected secret type is not 'kubernetes.io/dockerconfigjson' but 'Opaque'." + } + }, + "preferredOrder": [ + "path", + "secretName" + ], + "additionalProperties": false, + "description": "contains information about the docker `config.json` to mount.", + "x-intellij-html-description": "contains information about the docker config.json to mount." + }, + "DockerfileDependency": { + "properties": { + "buildArgs": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "arguments passed to the docker build. It also accepts environment variables via the go template syntax.", + "x-intellij-html-description": "arguments passed to the docker build. It also accepts environment variables via the go template syntax.", + "default": "{}", + "examples": [ + "{\"key1\": \"value1\", \"key2\": \"value2\", \"key3\": \"{{.ENV_VARIABLE}}\"}" + ] + }, + "path": { + "type": "string", + "description": "locates the Dockerfile relative to workspace.", + "x-intellij-html-description": "locates the Dockerfile relative to workspace." + } + }, + "preferredOrder": [ + "path", + "buildArgs" + ], + "additionalProperties": false, + "description": "*alpha* used to specify a custom build artifact that is built from a Dockerfile. This allows skaffold to determine dependencies from the Dockerfile.", + "x-intellij-html-description": "alpha used to specify a custom build artifact that is built from a Dockerfile. This allows skaffold to determine dependencies from the Dockerfile." + }, + "EnvTemplateTagger": { + "required": [ + "template" + ], + "properties": { + "template": { + "type": "string", + "description": "used to produce the image name and tag. See golang [text/template](https://golang.org/pkg/text/template/). The template is executed against the current environment, with those variables injected: IMAGE_NAME | Name of the image being built, as supplied in the artifacts section.", + "x-intellij-html-description": "used to produce the image name and tag. See golang text/template. The template is executed against the current environment, with those variables injected: IMAGE_NAME | Name of the image being built, as supplied in the artifacts section.", + "examples": [ + "{{.RELEASE}}-{{.IMAGE_NAME}}" + ] + } + }, + "preferredOrder": [ + "template" + ], + "additionalProperties": false, + "description": "*beta* tags images with a configurable template string.", + "x-intellij-html-description": "beta tags images with a configurable template string." + }, + "GitTagger": { + "properties": { + "variant": { + "type": "string", + "description": "determines the behavior of the git tagger. Valid variants are `Tags` (default): use git tags or fall back to abbreviated commit hash. `CommitSha`: use the full git commit sha. `AbbrevCommitSha`: use the abbreviated git commit sha. `TreeSha`: use the full tree hash of the artifact workingdir. `AbbrevTreeSha`: use the abbreviated tree hash of the artifact workingdir.", + "x-intellij-html-description": "determines the behavior of the git tagger. Valid variants are Tags (default): use git tags or fall back to abbreviated commit hash. CommitSha: use the full git commit sha. AbbrevCommitSha: use the abbreviated git commit sha. TreeSha: use the full tree hash of the artifact workingdir. AbbrevTreeSha: use the abbreviated tree hash of the artifact workingdir." + } + }, + "preferredOrder": [ + "variant" + ], + "additionalProperties": false, + "description": "*beta* tags images with the git tag or commit of the artifact's workspace.", + "x-intellij-html-description": "beta tags images with the git tag or commit of the artifact's workspace." + }, + "GoogleCloudBuild": { + "properties": { + "diskSizeGb": { + "type": "integer", + "description": "disk size of the VM that runs the build. See [Cloud Build Reference](https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds#buildoptions).", + "x-intellij-html-description": "disk size of the VM that runs the build. See Cloud Build Reference." + }, + "dockerImage": { + "type": "string", + "description": "image that runs a Docker build. See [Cloud Builders](https://cloud.google.com/cloud-build/docs/cloud-builders).", + "x-intellij-html-description": "image that runs a Docker build. See Cloud Builders.", + "default": "gcr.io/cloud-builders/docker" + }, + "gradleImage": { + "type": "string", + "description": "image that runs a Gradle build. See [Cloud Builders](https://cloud.google.com/cloud-build/docs/cloud-builders).", + "x-intellij-html-description": "image that runs a Gradle build. See Cloud Builders.", + "default": "gcr.io/cloud-builders/gradle" + }, + "machineType": { + "type": "string", + "description": "type of the VM that runs the build. See [Cloud Build Reference](https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds#buildoptions).", + "x-intellij-html-description": "type of the VM that runs the build. See Cloud Build Reference." + }, + "mavenImage": { + "type": "string", + "description": "image that runs a Maven build. See [Cloud Builders](https://cloud.google.com/cloud-build/docs/cloud-builders).", + "x-intellij-html-description": "image that runs a Maven build. See Cloud Builders.", + "default": "gcr.io/cloud-builders/mvn" + }, + "projectId": { + "type": "string", + "description": "ID of your Cloud Platform Project. If it is not provided, Skaffold will guess it from the image name. For example, given the artifact image name `gcr.io/myproject/image`, Skaffold will use the `myproject` GCP project.", + "x-intellij-html-description": "ID of your Cloud Platform Project. If it is not provided, Skaffold will guess it from the image name. For example, given the artifact image name gcr.io/myproject/image, Skaffold will use the myproject GCP project." + }, + "timeout": { + "type": "string", + "description": "amount of time (in seconds) that this build should be allowed to run. See [Cloud Build Reference](https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds#resource-build).", + "x-intellij-html-description": "amount of time (in seconds) that this build should be allowed to run. See Cloud Build Reference." + } + }, + "preferredOrder": [ + "projectId", + "diskSizeGb", + "machineType", + "timeout", + "dockerImage", + "mavenImage", + "gradleImage" + ], + "additionalProperties": false, + "description": "*beta* describes how to do a remote build on [Google Cloud Build](https://cloud.google.com/cloud-build/docs/). Docker and Jib artifacts can be built on Cloud Build. The `projectId` needs to be provided and the currently logged in user should be given permissions to trigger new builds.", + "x-intellij-html-description": "beta describes how to do a remote build on Google Cloud Build. Docker and Jib artifacts can be built on Cloud Build. The projectId needs to be provided and the currently logged in user should be given permissions to trigger new builds." + }, + "HelmConventionConfig": { + "properties": { + "explicitRegistry": { + "type": "boolean", + "description": "separates `image.registry` to the image config syntax. Useful for some charts e.g. `postgresql`.", + "x-intellij-html-description": "separates image.registry to the image config syntax. Useful for some charts e.g. postgresql.", + "default": "false" + } + }, + "preferredOrder": [ + "explicitRegistry" + ], + "additionalProperties": false, + "description": "image config in the syntax of image.repository and image.tag.", + "x-intellij-html-description": "image config in the syntax of image.repository and image.tag." + }, + "HelmDeploy": { + "required": [ + "releases" + ], + "properties": { + "flags": { + "$ref": "#/definitions/HelmDeployFlags", + "description": "additional option flags that are passed on the command line to `helm`.", + "x-intellij-html-description": "additional option flags that are passed on the command line to helm." + }, + "releases": { + "items": { + "$ref": "#/definitions/HelmRelease" + }, + "type": "array", + "description": "a list of Helm releases.", + "x-intellij-html-description": "a list of Helm releases." + } + }, + "preferredOrder": [ + "releases", + "flags" + ], + "additionalProperties": false, + "description": "*beta* uses the `helm` CLI to apply the charts to the cluster.", + "x-intellij-html-description": "beta uses the helm CLI to apply the charts to the cluster." + }, + "HelmDeployFlags": { + "properties": { + "global": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags passed on every command.", + "x-intellij-html-description": "additional flags passed on every command.", + "default": "[]" + }, + "install": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags passed to (`helm install`).", + "x-intellij-html-description": "additional flags passed to (helm install).", + "default": "[]" + }, + "upgrade": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags passed to (`helm upgrade`).", + "x-intellij-html-description": "additional flags passed to (helm upgrade).", + "default": "[]" + } + }, + "preferredOrder": [ + "global", + "install", + "upgrade" + ], + "additionalProperties": false, + "description": "additional option flags that are passed on the command line to `helm`.", + "x-intellij-html-description": "additional option flags that are passed on the command line to helm." + }, + "HelmFQNConfig": { + "properties": { + "property": { + "type": "string", + "description": "defines the image config.", + "x-intellij-html-description": "defines the image config." + } + }, + "preferredOrder": [ + "property" + ], + "additionalProperties": false, + "description": "image config to use the FullyQualifiedImageName as param to set.", + "x-intellij-html-description": "image config to use the FullyQualifiedImageName as param to set." + }, + "HelmImageStrategy": { + "anyOf": [ + { + "additionalProperties": false + }, + { + "properties": { + "fqn": { + "$ref": "#/definitions/HelmFQNConfig", + "description": "image configuration uses the syntax `IMAGE-NAME=IMAGE-REPOSITORY:IMAGE-TAG`.", + "x-intellij-html-description": "image configuration uses the syntax IMAGE-NAME=IMAGE-REPOSITORY:IMAGE-TAG." + } + }, + "preferredOrder": [ + "fqn" + ], + "additionalProperties": false + }, + { + "properties": { + "helm": { + "$ref": "#/definitions/HelmConventionConfig", + "description": "image configuration uses the syntax `IMAGE-NAME.repository=IMAGE-REPOSITORY, IMAGE-NAME.tag=IMAGE-TAG`.", + "x-intellij-html-description": "image configuration uses the syntax IMAGE-NAME.repository=IMAGE-REPOSITORY, IMAGE-NAME.tag=IMAGE-TAG." + } + }, + "preferredOrder": [ + "helm" + ], + "additionalProperties": false + } + ], + "description": "adds image configurations to the Helm `values` file.", + "x-intellij-html-description": "adds image configurations to the Helm values file." + }, + "HelmPackaged": { + "properties": { + "appVersion": { + "type": "string", + "description": "sets the `appVersion` on the chart to this version.", + "x-intellij-html-description": "sets the appVersion on the chart to this version." + }, + "version": { + "type": "string", + "description": "sets the `version` on the chart to this semver version.", + "x-intellij-html-description": "sets the version on the chart to this semver version." + } + }, + "preferredOrder": [ + "version", + "appVersion" + ], + "additionalProperties": false, + "description": "parameters for packaging helm chart (`helm package`).", + "x-intellij-html-description": "parameters for packaging helm chart (helm package)." + }, + "HelmRelease": { + "required": [ + "name", + "chartPath" + ], + "properties": { + "chartPath": { + "type": "string", + "description": "path to the Helm chart.", + "x-intellij-html-description": "path to the Helm chart." + }, + "imageStrategy": { + "$ref": "#/definitions/HelmImageStrategy", + "description": "adds image configurations to the Helm `values` file.", + "x-intellij-html-description": "adds image configurations to the Helm values file." + }, + "name": { + "type": "string", + "description": "name of the Helm release.", + "x-intellij-html-description": "name of the Helm release." + }, + "namespace": { + "type": "string", + "description": "Kubernetes namespace.", + "x-intellij-html-description": "Kubernetes namespace." + }, + "overrides": { + "description": "key-value pairs. If present, Skaffold will build a Helm `values` file that overrides the original and use it to call Helm CLI (`--f` flag).", + "x-intellij-html-description": "key-value pairs. If present, Skaffold will build a Helm values file that overrides the original and use it to call Helm CLI (--f flag)." + }, + "packaged": { + "$ref": "#/definitions/HelmPackaged", + "description": "parameters for packaging helm chart (`helm package`).", + "x-intellij-html-description": "parameters for packaging helm chart (helm package)." + }, + "recreatePods": { + "type": "boolean", + "description": "if `true`, Skaffold will send `--recreate-pods` flag to Helm CLI.", + "x-intellij-html-description": "if true, Skaffold will send --recreate-pods flag to Helm CLI.", + "default": "false" + }, + "remote": { + "type": "boolean", + "description": "specifies whether the chart path is remote, or exists on the host filesystem. `remote: true` implies `skipBuildDependencies: true`.", + "x-intellij-html-description": "specifies whether the chart path is remote, or exists on the host filesystem. remote: true implies skipBuildDependencies: true.", + "default": "false" + }, + "setValueTemplates": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "key-value pairs. If present, Skaffold will try to parse the value part of each key-value pair using environment variables in the system, then send `--set` flag to Helm CLI and append all parsed pairs after the flag.", + "x-intellij-html-description": "key-value pairs. If present, Skaffold will try to parse the value part of each key-value pair using environment variables in the system, then send --set flag to Helm CLI and append all parsed pairs after the flag.", + "default": "{}" + }, + "setValues": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "key-value pairs. If present, Skaffold will send `--set` flag to Helm CLI and append all pairs after the flag.", + "x-intellij-html-description": "key-value pairs. If present, Skaffold will send --set flag to Helm CLI and append all pairs after the flag.", + "default": "{}" + }, + "skipBuildDependencies": { + "type": "boolean", + "description": "should build dependencies be skipped.", + "x-intellij-html-description": "should build dependencies be skipped.", + "default": "false" + }, + "useHelmSecrets": { + "type": "boolean", + "description": "instructs skaffold to use secrets plugin on deployment.", + "x-intellij-html-description": "instructs skaffold to use secrets plugin on deployment.", + "default": "false" + }, + "values": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "key-value pairs supplementing the Helm `values` file.", + "x-intellij-html-description": "key-value pairs supplementing the Helm values file.", + "default": "{}" + }, + "valuesFiles": { + "items": { + "type": "string" + }, + "type": "array", + "description": "paths to the Helm `values` files.", + "x-intellij-html-description": "paths to the Helm values files.", + "default": "[]" + }, + "version": { + "type": "string", + "description": "version of the chart.", + "x-intellij-html-description": "version of the chart." + }, + "wait": { + "type": "boolean", + "description": "if `true`, Skaffold will send `--wait` flag to Helm CLI.", + "x-intellij-html-description": "if true, Skaffold will send --wait flag to Helm CLI.", + "default": "false" + } + }, + "preferredOrder": [ + "name", + "chartPath", + "valuesFiles", + "values", + "namespace", + "version", + "setValues", + "setValueTemplates", + "wait", + "recreatePods", + "skipBuildDependencies", + "useHelmSecrets", + "remote", + "overrides", + "packaged", + "imageStrategy" + ], + "additionalProperties": false, + "description": "describes a helm release to be deployed.", + "x-intellij-html-description": "describes a helm release to be deployed." + }, + "JSONPatch": { + "required": [ + "path" + ], + "properties": { + "from": { + "type": "string", + "description": "source position in the yaml, used for `copy` or `move` operations.", + "x-intellij-html-description": "source position in the yaml, used for copy or move operations." + }, + "op": { + "type": "string", + "description": "operation carried by the patch: `add`, `remove`, `replace`, `move`, `copy` or `test`.", + "x-intellij-html-description": "operation carried by the patch: add, remove, replace, move, copy or test.", + "default": "replace" + }, + "path": { + "type": "string", + "description": "position in the yaml where the operation takes place. For example, this targets the `dockerfile` of the first artifact built.", + "x-intellij-html-description": "position in the yaml where the operation takes place. For example, this targets the dockerfile of the first artifact built.", + "examples": [ + "/build/artifacts/0/docker/dockerfile" + ] + }, + "value": { + "type": "object", + "description": "value to apply. Can be any portion of yaml.", + "x-intellij-html-description": "value to apply. Can be any portion of yaml." + } + }, + "preferredOrder": [ + "op", + "path", + "from", + "value" + ], + "additionalProperties": false, + "description": "patch to be applied by a profile.", + "x-intellij-html-description": "patch to be applied by a profile." + }, + "JibGradleArtifact": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional build flags passed to Gradle.", + "x-intellij-html-description": "additional build flags passed to Gradle.", + "default": "[]", + "examples": [ + "[\"--no-build-cache\"]" + ] + }, + "project": { + "type": "string", + "description": "selects which Gradle project to build.", + "x-intellij-html-description": "selects which Gradle project to build." + } + }, + "preferredOrder": [ + "project", + "args" + ], + "additionalProperties": false, + "description": "*alpha* builds images using the [Jib plugin for Gradle](https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin).", + "x-intellij-html-description": "alpha builds images using the Jib plugin for Gradle." + }, + "JibMavenArtifact": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional build flags passed to Maven.", + "x-intellij-html-description": "additional build flags passed to Maven.", + "default": "[]", + "examples": [ + "[\"-x\", \"-DskipTests\"]" + ] + }, + "module": { + "type": "string", + "description": "selects which Maven module to build, for a multi module project.", + "x-intellij-html-description": "selects which Maven module to build, for a multi module project." + }, + "profile": { + "type": "string", + "description": "selects which Maven profile to activate.", + "x-intellij-html-description": "selects which Maven profile to activate." + } + }, + "preferredOrder": [ + "module", + "profile", + "args" + ], + "additionalProperties": false, + "description": "*alpha* builds images using the [Jib plugin for Maven](https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin).", + "x-intellij-html-description": "alpha builds images using the Jib plugin for Maven." + }, + "KanikoArtifact": { + "properties": { + "buildArgs": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "arguments passed to the docker build. It also accepts environment variables via the go template syntax.", + "x-intellij-html-description": "arguments passed to the docker build. It also accepts environment variables via the go template syntax.", + "default": "{}", + "examples": [ + "{\"key1\": \"value1\", \"key2\": \"value2\", \"key3\": \"{{.ENV_VARIABLE}}\"}" + ] + }, + "buildContext": { + "$ref": "#/definitions/KanikoBuildContext", + "description": "where the build context for this artifact resides.", + "x-intellij-html-description": "where the build context for this artifact resides." + }, + "cache": { + "$ref": "#/definitions/KanikoCache", + "description": "configures Kaniko caching. If a cache is specified, Kaniko will use a remote cache which will speed up builds.", + "x-intellij-html-description": "configures Kaniko caching. If a cache is specified, Kaniko will use a remote cache which will speed up builds." + }, + "dockerfile": { + "type": "string", + "description": "locates the Dockerfile relative to workspace.", + "x-intellij-html-description": "locates the Dockerfile relative to workspace.", + "default": "Dockerfile" + }, + "flags": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags to be passed to Kaniko command line. See [Kaniko Additional Flags](https://github.com/GoogleContainerTools/kaniko#additional-flags). Deprecated - instead the named, unique fields should be used, e.g. `buildArgs`, `cache`, `target`.", + "x-intellij-html-description": "additional flags to be passed to Kaniko command line. See Kaniko Additional Flags. Deprecated - instead the named, unique fields should be used, e.g. buildArgs, cache, target.", + "default": "[]" + }, + "image": { + "type": "string", + "description": "Docker image used by the Kaniko pod. Defaults to the latest released version of `gcr.io/kaniko-project/executor`.", + "x-intellij-html-description": "Docker image used by the Kaniko pod. Defaults to the latest released version of gcr.io/kaniko-project/executor." + }, + "reproducible": { + "type": "boolean", + "description": "used to strip timestamps out of the built image.", + "x-intellij-html-description": "used to strip timestamps out of the built image.", + "default": "false" + }, + "target": { + "type": "string", + "description": "Dockerfile target name to build.", + "x-intellij-html-description": "Dockerfile target name to build." + } + }, + "preferredOrder": [ + "flags", + "dockerfile", + "target", + "buildArgs", + "buildContext", + "image", + "cache", + "reproducible" + ], + "additionalProperties": false, + "description": "*alpha* describes an artifact built from a Dockerfile, with kaniko.", + "x-intellij-html-description": "alpha describes an artifact built from a Dockerfile, with kaniko." + }, + "KanikoBuildContext": { + "properties": { + "gcsBucket": { + "type": "string", + "description": "GCS bucket to which sources are uploaded. Kaniko will need access to that bucket to download the sources.", + "x-intellij-html-description": "GCS bucket to which sources are uploaded. Kaniko will need access to that bucket to download the sources." + }, + "localDir": { + "$ref": "#/definitions/LocalDir", + "description": "configures how Kaniko mounts sources directly via an `emptyDir` volume.", + "x-intellij-html-description": "configures how Kaniko mounts sources directly via an emptyDir volume." + } + }, + "preferredOrder": [ + "gcsBucket", + "localDir" + ], + "additionalProperties": false, + "description": "contains the different fields available to specify a Kaniko build context.", + "x-intellij-html-description": "contains the different fields available to specify a Kaniko build context." + }, + "KanikoCache": { + "properties": { + "hostPath": { + "type": "string", + "description": "specifies a path on the host that is mounted to each pod as read only cache volume containing base images. If set, must exist on each node and prepopulated with kaniko-warmer.", + "x-intellij-html-description": "specifies a path on the host that is mounted to each pod as read only cache volume containing base images. If set, must exist on each node and prepopulated with kaniko-warmer." + }, + "repo": { + "type": "string", + "description": "a remote repository to store cached layers. If none is specified, one will be inferred from the image name. See [Kaniko Caching](https://github.com/GoogleContainerTools/kaniko#caching).", + "x-intellij-html-description": "a remote repository to store cached layers. If none is specified, one will be inferred from the image name. See Kaniko Caching." + } + }, + "preferredOrder": [ + "repo", + "hostPath" + ], + "additionalProperties": false, + "description": "configures Kaniko caching. If a cache is specified, Kaniko will use a remote cache which will speed up builds.", + "x-intellij-html-description": "configures Kaniko caching. If a cache is specified, Kaniko will use a remote cache which will speed up builds." + }, + "KubectlDeploy": { + "properties": { + "flags": { + "$ref": "#/definitions/KubectlFlags", + "description": "additional flags passed to `kubectl`.", + "x-intellij-html-description": "additional flags passed to kubectl." + }, + "manifests": { + "items": { + "type": "string" + }, + "type": "array", + "description": "the Kubernetes yaml or json manifests.", + "x-intellij-html-description": "the Kubernetes yaml or json manifests.", + "default": "[\"k8s/*.yaml\"]" + }, + "remoteManifests": { + "items": { + "type": "string" + }, + "type": "array", + "description": "Kubernetes manifests in remote clusters.", + "x-intellij-html-description": "Kubernetes manifests in remote clusters.", + "default": "[]" + } + }, + "preferredOrder": [ + "manifests", + "remoteManifests", + "flags" + ], + "additionalProperties": false, + "description": "*beta* uses a client side `kubectl apply` to deploy manifests. You'll need a `kubectl` CLI version installed that's compatible with your cluster.", + "x-intellij-html-description": "beta uses a client side kubectl apply to deploy manifests. You'll need a kubectl CLI version installed that's compatible with your cluster." + }, + "KubectlFlags": { + "properties": { + "apply": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags passed on creations (`kubectl apply`).", + "x-intellij-html-description": "additional flags passed on creations (kubectl apply).", + "default": "[]" + }, + "delete": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags passed on deletions (`kubectl delete`).", + "x-intellij-html-description": "additional flags passed on deletions (kubectl delete).", + "default": "[]" + }, + "global": { + "items": { + "type": "string" + }, + "type": "array", + "description": "additional flags passed on every command.", + "x-intellij-html-description": "additional flags passed on every command.", + "default": "[]" + } + }, + "preferredOrder": [ + "global", + "apply", + "delete" + ], + "additionalProperties": false, + "description": "additional flags passed on the command line to kubectl either on every command (Global), on creations (Apply) or deletions (Delete).", + "x-intellij-html-description": "additional flags passed on the command line to kubectl either on every command (Global), on creations (Apply) or deletions (Delete)." + }, + "KustomizeDeploy": { + "properties": { + "flags": { + "$ref": "#/definitions/KubectlFlags", + "description": "additional flags passed to `kubectl`.", + "x-intellij-html-description": "additional flags passed to kubectl." + }, + "path": { + "type": "string", + "description": "path to Kustomization files.", + "x-intellij-html-description": "path to Kustomization files.", + "default": "." + } + }, + "preferredOrder": [ + "path", + "flags" + ], + "additionalProperties": false, + "description": "*beta* uses the `kustomize` CLI to \"patch\" a deployment for a target environment.", + "x-intellij-html-description": "beta uses the kustomize CLI to "patch" a deployment for a target environment." + }, + "LocalBuild": { + "properties": { + "push": { + "type": "boolean", + "description": "should images be pushed to a registry. If not specified, images are pushed only if the current Kubernetes context connects to a remote cluster.", + "x-intellij-html-description": "should images be pushed to a registry. If not specified, images are pushed only if the current Kubernetes context connects to a remote cluster." + }, + "useBuildkit": { + "type": "boolean", + "description": "use BuildKit to build Docker images.", + "x-intellij-html-description": "use BuildKit to build Docker images.", + "default": "false" + }, + "useDockerCLI": { + "type": "boolean", + "description": "use `docker` command-line interface instead of Docker Engine APIs.", + "x-intellij-html-description": "use docker command-line interface instead of Docker Engine APIs.", + "default": "false" + } + }, + "preferredOrder": [ + "push", + "useDockerCLI", + "useBuildkit" + ], + "additionalProperties": false, + "description": "*beta* describes how to do a build on the local docker daemon and optionally push to a repository.", + "x-intellij-html-description": "beta describes how to do a build on the local docker daemon and optionally push to a repository." + }, + "LocalDir": { + "properties": { + "initImage": { + "type": "string", + "description": "image used to run init container which mounts kaniko context.", + "x-intellij-html-description": "image used to run init container which mounts kaniko context." + } + }, + "preferredOrder": [ + "initImage" + ], + "additionalProperties": false, + "description": "configures how Kaniko mounts sources directly via an `emptyDir` volume.", + "x-intellij-html-description": "configures how Kaniko mounts sources directly via an emptyDir volume." + }, + "Metadata": { + "properties": { + "name": { + "type": "string", + "description": "an identifier for the project.", + "x-intellij-html-description": "an identifier for the project." + } + }, + "preferredOrder": [ + "name" + ], + "additionalProperties": false, + "description": "holds an optional name of the project.", + "x-intellij-html-description": "holds an optional name of the project." + }, + "PortForwardResource": { + "properties": { + "localPort": { + "type": "integer", + "description": "local port to forward to. If the port is unavailable, Skaffold will choose a random open port to forward to. *Optional*.", + "x-intellij-html-description": "local port to forward to. If the port is unavailable, Skaffold will choose a random open port to forward to. Optional." + }, + "namespace": { + "type": "string", + "description": "namespace of the resource to port forward.", + "x-intellij-html-description": "namespace of the resource to port forward." + }, + "port": { + "type": "integer", + "description": "resource port that will be forwarded.", + "x-intellij-html-description": "resource port that will be forwarded." + }, + "resourceName": { + "type": "string", + "description": "name of the Kubernetes resource to port forward.", + "x-intellij-html-description": "name of the Kubernetes resource to port forward." + }, + "resourceType": { + "$ref": "#/definitions/ResourceType", + "description": "Kubernetes type that should be port forwarded. Acceptable resource types include: `Service`, `Pod` and Controller resource type that has a pod spec: `ReplicaSet`, `ReplicationController`, `Deployment`, `StatefulSet`, `DaemonSet`, `Job`, `CronJob`.", + "x-intellij-html-description": "Kubernetes type that should be port forwarded. Acceptable resource types include: Service, Pod and Controller resource type that has a pod spec: ReplicaSet, ReplicationController, Deployment, StatefulSet, DaemonSet, Job, CronJob." + } + }, + "preferredOrder": [ + "resourceType", + "resourceName", + "namespace", + "port", + "localPort" + ], + "additionalProperties": false, + "description": "describes a resource to port forward.", + "x-intellij-html-description": "describes a resource to port forward." + }, + "Profile": { + "required": [ + "name" + ], + "properties": { + "activation": { + "items": { + "$ref": "#/definitions/Activation" + }, + "type": "array", + "description": "criteria by which a profile can be auto-activated. The profile is auto-activated if any one of the activations are triggered. An activation is triggered if all of the criteria (env, kubeContext, command) are triggered.", + "x-intellij-html-description": "criteria by which a profile can be auto-activated. The profile is auto-activated if any one of the activations are triggered. An activation is triggered if all of the criteria (env, kubeContext, command) are triggered." + }, + "build": { + "$ref": "#/definitions/BuildConfig", + "description": "describes how images are built.", + "x-intellij-html-description": "describes how images are built." + }, + "deploy": { + "$ref": "#/definitions/DeployConfig", + "description": "describes how images are deployed.", + "x-intellij-html-description": "describes how images are deployed." + }, + "name": { + "type": "string", + "description": "a unique profile name.", + "x-intellij-html-description": "a unique profile name.", + "examples": [ + "profile-prod" + ] + }, + "patches": { + "items": { + "$ref": "#/definitions/JSONPatch" + }, + "type": "array", + "description": "patches applied to the configuration. Patches use the JSON patch notation.", + "x-intellij-html-description": "patches applied to the configuration. Patches use the JSON patch notation." + }, + "portForward": { + "items": { + "$ref": "#/definitions/PortForwardResource" + }, + "type": "array", + "description": "describes user defined resources to port-forward.", + "x-intellij-html-description": "describes user defined resources to port-forward." + }, + "test": { + "items": { + "$ref": "#/definitions/TestCase" + }, + "type": "array", + "description": "describes how images are tested.", + "x-intellij-html-description": "describes how images are tested." + } + }, + "preferredOrder": [ + "name", + "build", + "test", + "deploy", + "portForward", + "patches", + "activation" + ], + "additionalProperties": false, + "description": "*beta* profiles are used to override any `build`, `test` or `deploy` configuration.", + "x-intellij-html-description": "beta profiles are used to override any build, test or deploy configuration." + }, + "ResourceRequirement": { + "properties": { + "cpu": { + "type": "string", + "description": "the number cores to be used.", + "x-intellij-html-description": "the number cores to be used.", + "examples": [ + "2`, `2.0` or `200m" + ] + }, + "memory": { + "type": "string", + "description": "the amount of memory to allocate to the pod.", + "x-intellij-html-description": "the amount of memory to allocate to the pod.", + "examples": [ + "1Gi` or `1000Mi" + ] + } + }, + "preferredOrder": [ + "cpu", + "memory" + ], + "additionalProperties": false, + "description": "stores the CPU/Memory requirements for the pod.", + "x-intellij-html-description": "stores the CPU/Memory requirements for the pod." + }, + "ResourceRequirements": { + "properties": { + "limits": { + "$ref": "#/definitions/ResourceRequirement", + "description": "[resource limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) for the Kaniko pod.", + "x-intellij-html-description": "resource limits for the Kaniko pod." + }, + "requests": { + "$ref": "#/definitions/ResourceRequirement", + "description": "[resource requests](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) for the Kaniko pod.", + "x-intellij-html-description": "resource requests for the Kaniko pod." + } + }, + "preferredOrder": [ + "requests", + "limits" + ], + "additionalProperties": false, + "description": "describes the resource requirements for the kaniko pod.", + "x-intellij-html-description": "describes the resource requirements for the kaniko pod." + }, + "ResourceType": { + "type": "string", + "description": "describes the Kubernetes resource types used for port forwarding.", + "x-intellij-html-description": "describes the Kubernetes resource types used for port forwarding." + }, + "ShaTagger": { + "description": "*beta* tags images with their sha256 digest.", + "x-intellij-html-description": "beta tags images with their sha256 digest." + }, + "SkaffoldConfig": { + "required": [ + "apiVersion", + "kind" + ], + "properties": { + "apiVersion": { + "type": "string", + "description": "version of the configuration.", + "x-intellij-html-description": "version of the configuration." + }, + "build": { + "$ref": "#/definitions/BuildConfig", + "description": "describes how images are built.", + "x-intellij-html-description": "describes how images are built." + }, + "deploy": { + "$ref": "#/definitions/DeployConfig", + "description": "describes how images are deployed.", + "x-intellij-html-description": "describes how images are deployed." + }, + "kind": { + "type": "string", + "description": "always `Config`.", + "x-intellij-html-description": "always Config.", + "default": "Config" + }, + "metadata": { + "$ref": "#/definitions/Metadata", + "description": "holds additional information about the config.", + "x-intellij-html-description": "holds additional information about the config." + }, + "portForward": { + "items": { + "$ref": "#/definitions/PortForwardResource" + }, + "type": "array", + "description": "describes user defined resources to port-forward.", + "x-intellij-html-description": "describes user defined resources to port-forward." + }, + "profiles": { + "items": { + "$ref": "#/definitions/Profile" + }, + "type": "array", + "description": "*beta* can override be used to `build`, `test` or `deploy` configuration.", + "x-intellij-html-description": "beta can override be used to build, test or deploy configuration." + }, + "test": { + "items": { + "$ref": "#/definitions/TestCase" + }, + "type": "array", + "description": "describes how images are tested.", + "x-intellij-html-description": "describes how images are tested." + } + }, + "preferredOrder": [ + "apiVersion", + "kind", + "metadata", + "build", + "test", + "deploy", + "portForward", + "profiles" + ], + "additionalProperties": false, + "description": "holds the fields parsed from the Skaffold configuration file (skaffold.yaml).", + "x-intellij-html-description": "holds the fields parsed from the Skaffold configuration file (skaffold.yaml)." + }, + "Sync": { + "properties": { + "infer": { + "items": { + "type": "string" + }, + "type": "array", + "description": "file patterns which may be synced into the container. The container destination is inferred by the builder. Currently only available for docker artifacts.", + "x-intellij-html-description": "file patterns which may be synced into the container. The container destination is inferred by the builder. Currently only available for docker artifacts.", + "default": "[]" + }, + "manual": { + "items": { + "$ref": "#/definitions/SyncRule" + }, + "type": "array", + "description": "manual sync rules indicating the source and destination.", + "x-intellij-html-description": "manual sync rules indicating the source and destination." + } + }, + "preferredOrder": [ + "manual", + "infer" + ], + "additionalProperties": false, + "description": "*alpha* specifies what files to sync into the container. This is a list of sync rules indicating the intent to sync for source files.", + "x-intellij-html-description": "alpha specifies what files to sync into the container. This is a list of sync rules indicating the intent to sync for source files." + }, + "SyncRule": { + "required": [ + "src", + "dest" + ], + "properties": { + "dest": { + "type": "string", + "description": "destination path in the container where the files should be synced to.", + "x-intellij-html-description": "destination path in the container where the files should be synced to.", + "examples": [ + "\"app/\"" + ] + }, + "src": { + "type": "string", + "description": "a glob pattern to match local paths against. Directories should be delimited by `/` on all platforms.", + "x-intellij-html-description": "a glob pattern to match local paths against. Directories should be delimited by / on all platforms.", + "examples": [ + "\"css/**/*.css\"" + ] + }, + "strip": { + "type": "string", + "description": "specifies the path prefix to remove from the source path when transplanting the files into the destination folder.", + "x-intellij-html-description": "specifies the path prefix to remove from the source path when transplanting the files into the destination folder.", + "examples": [ + "\"css/\"" + ] + } + }, + "preferredOrder": [ + "src", + "dest", + "strip" + ], + "additionalProperties": false, + "description": "specifies which local files to sync to remote folders.", + "x-intellij-html-description": "specifies which local files to sync to remote folders." + }, + "TagPolicy": { + "properties": { + "dateTime": { + "$ref": "#/definitions/DateTimeTagger", + "description": "*beta* tags images with the build timestamp.", + "x-intellij-html-description": "beta tags images with the build timestamp." + }, + "envTemplate": { + "$ref": "#/definitions/EnvTemplateTagger", + "description": "*beta* tags images with a configurable template string.", + "x-intellij-html-description": "beta tags images with a configurable template string." + }, + "gitCommit": { + "$ref": "#/definitions/GitTagger", + "description": "*beta* tags images with the git tag or commit of the artifact's workspace.", + "x-intellij-html-description": "beta tags images with the git tag or commit of the artifact's workspace." + }, + "sha256": { + "$ref": "#/definitions/ShaTagger", + "description": "*beta* tags images with their sha256 digest.", + "x-intellij-html-description": "beta tags images with their sha256 digest." + } + }, + "preferredOrder": [ + "gitCommit", + "sha256", + "envTemplate", + "dateTime" + ], + "additionalProperties": false, + "description": "contains all the configuration for the tagging step.", + "x-intellij-html-description": "contains all the configuration for the tagging step." + }, + "TestCase": { + "required": [ + "image" + ], + "properties": { + "image": { + "type": "string", + "description": "artifact on which to run those tests.", + "x-intellij-html-description": "artifact on which to run those tests.", + "examples": [ + "gcr.io/k8s-skaffold/example" + ] + }, + "structureTests": { + "items": { + "type": "string" + }, + "type": "array", + "description": "the [Container Structure Tests](https://github.com/GoogleContainerTools/container-structure-test) to run on that artifact.", + "x-intellij-html-description": "the Container Structure Tests to run on that artifact.", + "default": "[]", + "examples": [ + "[\"./test/*\"]" + ] + } + }, + "preferredOrder": [ + "image", + "structureTests" + ], + "additionalProperties": false, + "description": "a list of structure tests to run on images that Skaffold builds.", + "x-intellij-html-description": "a list of structure tests to run on images that Skaffold builds." + } + } +} diff --git a/examples/hot-reload/node/package-lock.json b/examples/hot-reload/node/package-lock.json index a3ae06edb4d..2fdf304744f 100644 --- a/examples/hot-reload/node/package-lock.json +++ b/examples/hot-reload/node/package-lock.json @@ -15,7 +15,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.21", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -25,7 +25,7 @@ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" } }, "ansi-regex": { @@ -40,7 +40,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -49,8 +49,19 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "arr-diff": { @@ -89,9 +100,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "atob": { @@ -112,13 +123,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -127,7 +138,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -136,7 +147,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -145,7 +156,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -154,17 +165,17 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "body-parser": { @@ -173,15 +184,15 @@ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" } }, "boxen": { @@ -190,13 +201,13 @@ "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "dev": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.4.1", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "2.0.1" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" } }, "brace-expansion": { @@ -205,7 +216,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -215,16 +226,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -233,7 +244,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -249,15 +260,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "camelcase": { @@ -278,30 +289,29 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.4", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.1.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "ci-info": { @@ -316,10 +326,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -328,7 +338,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -345,8 +355,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -365,9 +375,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "concat-map": { @@ -382,12 +392,12 @@ "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", "dev": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.15", - "make-dir": "1.3.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "content-disposition": { @@ -428,7 +438,7 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, "requires": { - "capture-stack-trace": "1.0.1" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { @@ -437,9 +447,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.4", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypto-random-string": { @@ -474,8 +484,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -484,7 +494,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -493,7 +503,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -502,9 +512,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -525,7 +535,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "duplexer3": { @@ -566,13 +576,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -581,13 +591,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -596,7 +606,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -605,7 +615,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -615,36 +625,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.4", + "proxy-addr": "~2.0.4", "qs": "6.5.2", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" } }, "extend-shallow": { @@ -653,8 +663,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -663,7 +673,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -674,14 +684,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -690,7 +700,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -699,7 +709,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -708,7 +718,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -717,7 +727,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -726,9 +736,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -739,10 +749,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -751,7 +761,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -762,12 +772,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, "for-in": { @@ -787,7 +797,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -796,14 +806,14 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "2.11.1", - "node-pre-gyp": "0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -824,13 +834,13 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { @@ -843,12 +853,12 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -875,16 +885,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -907,7 +917,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { @@ -922,28 +932,28 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { @@ -953,12 +963,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -967,7 +977,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -976,8 +986,8 @@ "dev": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -996,7 +1006,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -1010,7 +1020,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1019,21 +1029,21 @@ "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { @@ -1045,38 +1055,38 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.7", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { @@ -1085,24 +1095,24 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -1111,10 +1121,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -1133,7 +1143,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -1154,8 +1164,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -1171,15 +1181,15 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -1196,26 +1206,26 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true }, @@ -1232,7 +1242,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -1254,9 +1264,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -1265,7 +1275,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1273,7 +1283,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -1283,18 +1293,18 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" } }, "util-deprecate": { @@ -1304,12 +1314,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -1318,7 +1328,7 @@ "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true } @@ -1342,8 +1352,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -1352,7 +1362,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -1363,7 +1373,7 @@ "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, "requires": { - "ini": "1.3.5" + "ini": "^1.3.4" } }, "got": { @@ -1372,17 +1382,17 @@ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.1", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" } }, "graceful-fs": { @@ -1403,9 +1413,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -1414,8 +1424,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -1424,7 +1434,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1434,10 +1444,10 @@ "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -1445,7 +1455,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-by-default": { @@ -1488,7 +1498,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1497,7 +1507,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1508,7 +1518,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.12.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -1523,7 +1533,7 @@ "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "dev": true, "requires": { - "ci-info": "1.6.0" + "ci-info": "^1.5.0" } }, "is-data-descriptor": { @@ -1532,7 +1542,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1541,7 +1551,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1552,9 +1562,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -1584,12 +1594,12 @@ "dev": true }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-installed-globally": { @@ -1598,8 +1608,8 @@ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "global-dirs": "0.1.1", - "is-path-inside": "1.0.1" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-npm": { @@ -1614,7 +1624,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1623,7 +1633,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1640,7 +1650,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -1649,7 +1659,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-redirect": { @@ -1706,15 +1716,9 @@ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "dev": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1727,8 +1731,8 @@ "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "3.0.3" + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" } }, "make-dir": { @@ -1737,7 +1741,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "map-cache": { @@ -1752,7 +1756,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "media-typer": { @@ -1776,19 +1780,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "mime": { @@ -1806,7 +1810,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "requires": { - "mime-db": "1.37.0" + "mime-db": "~1.37.0" } }, "minimatch": { @@ -1815,7 +1819,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1825,13 +1829,13 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1840,7 +1844,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1851,9 +1855,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -1863,17 +1867,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" } }, "negotiator": { @@ -1887,16 +1891,16 @@ "integrity": "sha512-xuC1V0F5EcEyKQ1VhHYD13owznQbUw29JKvZ8bVH7TmuvVNHvvbp9pLgE4PjTMRJVe0pJ8fGRvwR2nMiosIsPQ==", "dev": true, "requires": { - "chokidar": "2.0.4", - "debug": "3.2.6", - "ignore-by-default": "1.0.1", - "minimatch": "3.0.4", - "pstree.remy": "1.1.2", - "semver": "5.6.0", - "supports-color": "5.5.0", - "touch": "3.1.0", - "undefsafe": "2.0.2", - "update-notifier": "2.5.0" + "chokidar": "^2.0.4", + "debug": "^3.1.0", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.2", + "semver": "^5.5.0", + "supports-color": "^5.2.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.3.0" }, "dependencies": { "debug": { @@ -1905,7 +1909,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -1922,17 +1926,14 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm-run-path": { "version": "2.0.2", @@ -1940,7 +1941,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "object-copy": { @@ -1949,9 +1950,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -1960,7 +1961,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -1969,7 +1970,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1980,7 +1981,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.pick": { @@ -1989,7 +1990,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "on-finished": { @@ -2012,10 +2013,10 @@ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "dev": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0", - "semver": "5.6.0" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "parseurl": { @@ -2077,9 +2078,9 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "proxy-addr": { @@ -2087,7 +2088,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" } }, @@ -2130,10 +2131,10 @@ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { - "deep-extend": "0.6.0", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "readable-stream": { @@ -2142,13 +2143,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -2157,9 +2158,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "micromatch": "3.1.10", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "regex-not": { @@ -2168,8 +2169,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "registry-auth-token": { @@ -2178,8 +2179,8 @@ "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", "dev": true, "requires": { - "rc": "1.2.8", - "safe-buffer": "5.1.2" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { @@ -2188,7 +2189,7 @@ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "dev": true, "requires": { - "rc": "1.2.8" + "rc": "^1.0.1" } }, "remove-trailing-separator": { @@ -2232,7 +2233,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -2252,7 +2253,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.0.3" } }, "send": { @@ -2261,18 +2262,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" } }, "serve-static": { @@ -2280,22 +2281,22 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2304,7 +2305,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2320,7 +2321,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -2341,14 +2342,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -2357,7 +2358,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -2366,7 +2367,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2377,9 +2378,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -2388,7 +2389,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -2397,7 +2398,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2406,7 +2407,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2415,9 +2416,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -2428,7 +2429,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -2437,7 +2438,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2454,11 +2455,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "2.1.2", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-url": { @@ -2473,7 +2474,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "static-extend": { @@ -2482,8 +2483,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -2492,7 +2493,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2508,8 +2509,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string_decoder": { @@ -2518,7 +2519,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -2527,7 +2528,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "strip-eof": { @@ -2548,7 +2549,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "term-size": { @@ -2557,7 +2558,7 @@ "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, "timed-out": { @@ -2572,7 +2573,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2581,7 +2582,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2592,10 +2593,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -2604,8 +2605,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "touch": { @@ -2614,7 +2615,7 @@ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" } }, "type-is": { @@ -2623,7 +2624,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.21" + "mime-types": "~2.1.18" } }, "undefsafe": { @@ -2632,42 +2633,19 @@ "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", "dev": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" - } - } + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" } }, "unique-string": { @@ -2676,7 +2654,7 @@ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "dev": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "unpipe": { @@ -2690,8 +2668,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -2700,9 +2678,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -2731,9 +2709,9 @@ "dev": true }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "update-notifier": { @@ -2742,16 +2720,16 @@ "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", "dev": true, "requires": { - "boxen": "1.3.0", - "chalk": "2.4.1", - "configstore": "3.1.2", - "import-lazy": "2.1.0", - "is-ci": "1.2.1", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "urix": { @@ -2766,7 +2744,7 @@ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "use": { @@ -2797,7 +2775,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "widest-line": { @@ -2806,7 +2784,7 @@ "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "write-file-atomic": { @@ -2815,9 +2793,9 @@ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { diff --git a/examples/hot-reload/node/package.json b/examples/hot-reload/node/package.json index 80ecc6e25dc..2de8036ec73 100644 --- a/examples/hot-reload/node/package.json +++ b/examples/hot-reload/node/package.json @@ -12,4 +12,4 @@ "devDependencies": { "nodemon": "^1.18.4" } -} \ No newline at end of file +} diff --git a/examples/nodejs/backend/package-lock.json b/examples/nodejs/backend/package-lock.json index a3ae06edb4d..2fdf304744f 100644 --- a/examples/nodejs/backend/package-lock.json +++ b/examples/nodejs/backend/package-lock.json @@ -15,7 +15,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.21", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -25,7 +25,7 @@ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" } }, "ansi-regex": { @@ -40,7 +40,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -49,8 +49,19 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "arr-diff": { @@ -89,9 +100,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "atob": { @@ -112,13 +123,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -127,7 +138,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -136,7 +147,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -145,7 +156,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -154,17 +165,17 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "body-parser": { @@ -173,15 +184,15 @@ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" } }, "boxen": { @@ -190,13 +201,13 @@ "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "dev": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.4.1", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "2.0.1" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" } }, "brace-expansion": { @@ -205,7 +216,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -215,16 +226,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -233,7 +244,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -249,15 +260,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "camelcase": { @@ -278,30 +289,29 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.4", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.1.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "ci-info": { @@ -316,10 +326,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -328,7 +338,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -345,8 +355,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -365,9 +375,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "concat-map": { @@ -382,12 +392,12 @@ "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", "dev": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.15", - "make-dir": "1.3.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "content-disposition": { @@ -428,7 +438,7 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, "requires": { - "capture-stack-trace": "1.0.1" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { @@ -437,9 +447,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.4", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypto-random-string": { @@ -474,8 +484,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -484,7 +494,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -493,7 +503,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -502,9 +512,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -525,7 +535,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "duplexer3": { @@ -566,13 +576,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -581,13 +591,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -596,7 +606,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -605,7 +615,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -615,36 +625,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.4", + "proxy-addr": "~2.0.4", "qs": "6.5.2", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" } }, "extend-shallow": { @@ -653,8 +663,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -663,7 +673,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -674,14 +684,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -690,7 +700,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -699,7 +709,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -708,7 +718,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -717,7 +727,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -726,9 +736,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -739,10 +749,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -751,7 +761,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -762,12 +772,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, "for-in": { @@ -787,7 +797,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -796,14 +806,14 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "2.11.1", - "node-pre-gyp": "0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -824,13 +834,13 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { @@ -843,12 +853,12 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -875,16 +885,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -907,7 +917,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { @@ -922,28 +932,28 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { @@ -953,12 +963,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -967,7 +977,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -976,8 +986,8 @@ "dev": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -996,7 +1006,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -1010,7 +1020,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1019,21 +1029,21 @@ "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { @@ -1045,38 +1055,38 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.7", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { @@ -1085,24 +1095,24 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -1111,10 +1121,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -1133,7 +1143,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -1154,8 +1164,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -1171,15 +1181,15 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -1196,26 +1206,26 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true }, @@ -1232,7 +1242,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -1254,9 +1264,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -1265,7 +1275,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1273,7 +1283,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -1283,18 +1293,18 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" } }, "util-deprecate": { @@ -1304,12 +1314,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -1318,7 +1328,7 @@ "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true } @@ -1342,8 +1352,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -1352,7 +1362,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -1363,7 +1373,7 @@ "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, "requires": { - "ini": "1.3.5" + "ini": "^1.3.4" } }, "got": { @@ -1372,17 +1382,17 @@ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.1", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" } }, "graceful-fs": { @@ -1403,9 +1413,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -1414,8 +1424,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -1424,7 +1434,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1434,10 +1444,10 @@ "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -1445,7 +1455,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-by-default": { @@ -1488,7 +1498,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1497,7 +1507,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1508,7 +1518,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.12.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -1523,7 +1533,7 @@ "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "dev": true, "requires": { - "ci-info": "1.6.0" + "ci-info": "^1.5.0" } }, "is-data-descriptor": { @@ -1532,7 +1542,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1541,7 +1551,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1552,9 +1562,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -1584,12 +1594,12 @@ "dev": true }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-installed-globally": { @@ -1598,8 +1608,8 @@ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "global-dirs": "0.1.1", - "is-path-inside": "1.0.1" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-npm": { @@ -1614,7 +1624,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1623,7 +1633,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1640,7 +1650,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -1649,7 +1659,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-redirect": { @@ -1706,15 +1716,9 @@ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "dev": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1727,8 +1731,8 @@ "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "3.0.3" + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" } }, "make-dir": { @@ -1737,7 +1741,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "map-cache": { @@ -1752,7 +1756,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "media-typer": { @@ -1776,19 +1780,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "mime": { @@ -1806,7 +1810,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "requires": { - "mime-db": "1.37.0" + "mime-db": "~1.37.0" } }, "minimatch": { @@ -1815,7 +1819,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1825,13 +1829,13 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1840,7 +1844,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1851,9 +1855,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -1863,17 +1867,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" } }, "negotiator": { @@ -1887,16 +1891,16 @@ "integrity": "sha512-xuC1V0F5EcEyKQ1VhHYD13owznQbUw29JKvZ8bVH7TmuvVNHvvbp9pLgE4PjTMRJVe0pJ8fGRvwR2nMiosIsPQ==", "dev": true, "requires": { - "chokidar": "2.0.4", - "debug": "3.2.6", - "ignore-by-default": "1.0.1", - "minimatch": "3.0.4", - "pstree.remy": "1.1.2", - "semver": "5.6.0", - "supports-color": "5.5.0", - "touch": "3.1.0", - "undefsafe": "2.0.2", - "update-notifier": "2.5.0" + "chokidar": "^2.0.4", + "debug": "^3.1.0", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.2", + "semver": "^5.5.0", + "supports-color": "^5.2.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.3.0" }, "dependencies": { "debug": { @@ -1905,7 +1909,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -1922,17 +1926,14 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm-run-path": { "version": "2.0.2", @@ -1940,7 +1941,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "object-copy": { @@ -1949,9 +1950,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -1960,7 +1961,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -1969,7 +1970,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1980,7 +1981,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.pick": { @@ -1989,7 +1990,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "on-finished": { @@ -2012,10 +2013,10 @@ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "dev": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0", - "semver": "5.6.0" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "parseurl": { @@ -2077,9 +2078,9 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "proxy-addr": { @@ -2087,7 +2088,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" } }, @@ -2130,10 +2131,10 @@ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { - "deep-extend": "0.6.0", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "readable-stream": { @@ -2142,13 +2143,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -2157,9 +2158,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "micromatch": "3.1.10", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "regex-not": { @@ -2168,8 +2169,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "registry-auth-token": { @@ -2178,8 +2179,8 @@ "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", "dev": true, "requires": { - "rc": "1.2.8", - "safe-buffer": "5.1.2" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { @@ -2188,7 +2189,7 @@ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "dev": true, "requires": { - "rc": "1.2.8" + "rc": "^1.0.1" } }, "remove-trailing-separator": { @@ -2232,7 +2233,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -2252,7 +2253,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.0.3" } }, "send": { @@ -2261,18 +2262,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" } }, "serve-static": { @@ -2280,22 +2281,22 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2304,7 +2305,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2320,7 +2321,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -2341,14 +2342,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -2357,7 +2358,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -2366,7 +2367,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2377,9 +2378,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -2388,7 +2389,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -2397,7 +2398,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2406,7 +2407,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2415,9 +2416,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -2428,7 +2429,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -2437,7 +2438,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2454,11 +2455,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "2.1.2", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-url": { @@ -2473,7 +2474,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "static-extend": { @@ -2482,8 +2483,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -2492,7 +2493,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2508,8 +2509,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string_decoder": { @@ -2518,7 +2519,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -2527,7 +2528,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "strip-eof": { @@ -2548,7 +2549,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "term-size": { @@ -2557,7 +2558,7 @@ "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, "timed-out": { @@ -2572,7 +2573,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2581,7 +2582,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2592,10 +2593,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -2604,8 +2605,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "touch": { @@ -2614,7 +2615,7 @@ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" } }, "type-is": { @@ -2623,7 +2624,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.21" + "mime-types": "~2.1.18" } }, "undefsafe": { @@ -2632,42 +2633,19 @@ "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", "dev": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" - } - } + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" } }, "unique-string": { @@ -2676,7 +2654,7 @@ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "dev": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "unpipe": { @@ -2690,8 +2668,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -2700,9 +2678,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -2731,9 +2709,9 @@ "dev": true }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "update-notifier": { @@ -2742,16 +2720,16 @@ "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", "dev": true, "requires": { - "boxen": "1.3.0", - "chalk": "2.4.1", - "configstore": "3.1.2", - "import-lazy": "2.1.0", - "is-ci": "1.2.1", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "urix": { @@ -2766,7 +2744,7 @@ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "use": { @@ -2797,7 +2775,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "widest-line": { @@ -2806,7 +2784,7 @@ "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "write-file-atomic": { @@ -2815,9 +2793,9 @@ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { diff --git a/examples/nodejs/backend/package.json b/examples/nodejs/backend/package.json index 66ddb0badf3..843517e9b4f 100644 --- a/examples/nodejs/backend/package.json +++ b/examples/nodejs/backend/package.json @@ -12,4 +12,4 @@ "devDependencies": { "nodemon": "^1.18.4" } -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 67d329eb50c..1efb5e766a2 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 // indirect github.com/prometheus/procfs v0.0.0-20181126161756-619930b0b471 // indirect github.com/rjeczalik/notify v0.9.2 + github.com/segmentio/textio v1.2.0 github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/sirupsen/logrus v1.4.1 github.com/spf13/cobra v0.0.4 diff --git a/go.sum b/go.sum index 2333c9c8ee9..3742a7e7e90 100644 --- a/go.sum +++ b/go.sum @@ -227,6 +227,8 @@ github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNue github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/segmentio/textio v1.2.0 h1:Ug4IkV3kh72juJbG8azoSBlgebIbUUxVNrfFcKHfTSQ= +github.com/segmentio/textio v1.2.0/go.mod h1:+Rb7v0YVODP+tK5F7FD9TCkV7gOYx9IgLHWiqtvY8ag= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -349,6 +351,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= @@ -402,6 +405,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.0.0-20190620073856-dcce3486da33 h1:aC/EvF9PT1h8NeMEOVwTel8xxbZwq0SZnxXNThEROnE= k8s.io/api v0.0.0-20190620073856-dcce3486da33/go.mod h1:ldk709UQo/iedNLOW7J06V9QSSGY5heETKeWqnPoqF8= +k8s.io/api v0.0.0-20190814101207-0772a1bdf941 h1:Y8yEkyPyJstRyZRD2qAVXeFfgilYKxdxB8zjO0cb/XY= k8s.io/apimachinery v0.0.0-20190620073744-d16981aedf33 h1:Lkd+QNFOB3DqrDyWo796aodJgFJautn/M+t9IGearPc= k8s.io/apimachinery v0.0.0-20190620073744-d16981aedf33/go.mod h1:9q5NW/mMno/nwbRZd/Ks2TECgi2PTZ9cwarf4q+ze6Q= k8s.io/client-go v0.0.0-20190620074045-585a16d2e773 h1:XyjDnwRO9icfyrN7HRSa8o3NqdPOEQoVW8vWizuqyQQ= diff --git a/hack/checks.sh b/hack/checks.sh index 22819fcc483..ca2bc97ccd1 100755 --- a/hack/checks.sh +++ b/hack/checks.sh @@ -14,6 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +RED='\033[0;31m' +GREEN='\033[0;32m' +RESET='\033[0m' + echo "Running validation scripts..." scripts=( "hack/boilerplate.sh" @@ -26,10 +30,10 @@ scripts=( fail=0 for s in "${scripts[@]}"; do echo "RUN ${s}" - set +e + ./$s result=$? - set -e + if [[ $result -eq 0 ]]; then echo -e "${GREEN}PASSED${RESET} ${s}" else diff --git a/hack/new_version.sh b/hack/new_version.sh index 16d02791d64..115e78df26b 100755 --- a/hack/new_version.sh +++ b/hack/new_version.sh @@ -14,6 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +echo "Current skaffold config version: " $(sed -n 's;.*Version.*"skaffold/\(.*\)";\1;p' pkg/skaffold/schema/latest/config.go) + +echo echo "Please enter new config version:" read NEW_VERSION diff --git a/hack/test.sh b/hack/test.sh index ecfebff2091..dd3344e5993 100755 --- a/hack/test.sh +++ b/hack/test.sh @@ -17,15 +17,9 @@ set -e RED='\033[0;31m' -GREEN='\033[0;32m' RESET='\033[0m' echo "Running go tests..." go test -count=1 -race -cover -short -timeout=60s -coverprofile=out/coverage.txt -coverpkg="./pkg/...,./cmd/..." ./... | awk -v FAIL="${RED}FAIL${RESET}" '! /no test files/ { gsub("FAIL", FAIL, $0); print $0 }' -GO_TEST_EXIT_CODE=${PIPESTATUS[0]} -if [[ $GO_TEST_EXIT_CODE -ne 0 ]]; then - exit $GO_TEST_EXIT_CODE -fi - -hack/checks.sh +exit ${PIPESTATUS[0]} diff --git a/integration/deploy_test.go b/integration/deploy_test.go index 085421e68a4..f6af05de9c7 100644 --- a/integration/deploy_test.go +++ b/integration/deploy_test.go @@ -128,7 +128,5 @@ func TestDeployWithInCorrectConfigWithNoStatusCheck(t *testing.T) { ns, _, deleteNs := SetupNamespace(t) defer deleteNs() - skaffold.Deploy().InDir("testdata/unstable-deployment").InNs(ns.Name).RunOrFailOutput(t) - - skaffold.Delete().InDir("testdata/unstable-deployment").InNs(ns.Name).RunOrFail(t) + skaffold.Deploy().InDir("testdata/unstable-deployment").InNs(ns.Name).RunOrFail(t) } diff --git a/integration/dev_test.go b/integration/dev_test.go index bc6b5dbc49e..0e717844a9b 100644 --- a/integration/dev_test.go +++ b/integration/dev_test.go @@ -389,7 +389,7 @@ func TestDev_WithKubecontextOverride(t *testing.T) { env := []string{fmt.Sprintf("KUBECONFIG=%s", kubeconfig)} // n.b. for the sake of this test the namespace must not be given explicitly - skaffold.Run("--kube-context", kubecontext).InDir(dir).WithEnv(env).RunOrFailOutput(t.T) + skaffold.Run("--kube-context", kubecontext).InDir(dir).WithEnv(env).RunOrFail(t.T) client.WaitForPodsReady(pods...) diff --git a/integration/diagnose_test.go b/integration/diagnose_test.go index 0612d2f59db..7d3740a745c 100644 --- a/integration/diagnose_test.go +++ b/integration/diagnose_test.go @@ -33,17 +33,17 @@ func TestDiagnose(t *testing.T) { tests := []struct { name string dir string - args []string }{ {name: "kaniko builder", dir: "examples/kaniko"}, {name: "docker builder", dir: "examples/nodejs"}, {name: "jib maven builder", dir: "testdata/jib"}, + {name: "jib gradle builder", dir: "testdata/jib-gradle"}, {name: "bazel builder", dir: "examples/bazel"}, - // todo add test cases for "jib gradle builder" and "custom builder" + {name: "custom builder", dir: "testdata/custom"}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - skaffold.Diagnose(test.args...).InDir(test.dir).RunOrFailOutput(t) + skaffold.Diagnose().InDir(test.dir).RunOrFail(t) }) } } diff --git a/integration/examples/bazel/skaffold.yaml b/integration/examples/bazel/skaffold.yaml index ef6b3b5b28a..05ce33d0f9f 100644 --- a/integration/examples/bazel/skaffold.yaml +++ b/integration/examples/bazel/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/getting-started/skaffold.yaml b/integration/examples/getting-started/skaffold.yaml index b98ebe9d6e1..0c6eeaed16d 100644 --- a/integration/examples/getting-started/skaffold.yaml +++ b/integration/examples/getting-started/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/google-cloud-build/skaffold.yaml b/integration/examples/google-cloud-build/skaffold.yaml index aa5fe57784f..0f13a8bf1ee 100644 --- a/integration/examples/google-cloud-build/skaffold.yaml +++ b/integration/examples/google-cloud-build/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: googleCloudBuild: diff --git a/integration/examples/helm-deployment-dependencies/skaffold.yaml b/integration/examples/helm-deployment-dependencies/skaffold.yaml index 8b806f35653..3b77eaf55af 100644 --- a/integration/examples/helm-deployment-dependencies/skaffold.yaml +++ b/integration/examples/helm-deployment-dependencies/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: tagPolicy: diff --git a/integration/examples/helm-deployment/skaffold.yaml b/integration/examples/helm-deployment/skaffold.yaml index 431e939060a..e0108781478 100644 --- a/integration/examples/helm-deployment/skaffold.yaml +++ b/integration/examples/helm-deployment/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: tagPolicy: diff --git a/integration/examples/hot-reload/node/package-lock.json b/integration/examples/hot-reload/node/package-lock.json index a3ae06edb4d..2fdf304744f 100644 --- a/integration/examples/hot-reload/node/package-lock.json +++ b/integration/examples/hot-reload/node/package-lock.json @@ -15,7 +15,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.21", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -25,7 +25,7 @@ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" } }, "ansi-regex": { @@ -40,7 +40,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -49,8 +49,19 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "arr-diff": { @@ -89,9 +100,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "atob": { @@ -112,13 +123,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -127,7 +138,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -136,7 +147,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -145,7 +156,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -154,17 +165,17 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "body-parser": { @@ -173,15 +184,15 @@ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" } }, "boxen": { @@ -190,13 +201,13 @@ "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "dev": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.4.1", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "2.0.1" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" } }, "brace-expansion": { @@ -205,7 +216,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -215,16 +226,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -233,7 +244,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -249,15 +260,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "camelcase": { @@ -278,30 +289,29 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.4", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.1.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "ci-info": { @@ -316,10 +326,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -328,7 +338,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -345,8 +355,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -365,9 +375,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "concat-map": { @@ -382,12 +392,12 @@ "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", "dev": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.15", - "make-dir": "1.3.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "content-disposition": { @@ -428,7 +438,7 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, "requires": { - "capture-stack-trace": "1.0.1" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { @@ -437,9 +447,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.4", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypto-random-string": { @@ -474,8 +484,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -484,7 +494,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -493,7 +503,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -502,9 +512,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -525,7 +535,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "duplexer3": { @@ -566,13 +576,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -581,13 +591,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -596,7 +606,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -605,7 +615,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -615,36 +625,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.4", + "proxy-addr": "~2.0.4", "qs": "6.5.2", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" } }, "extend-shallow": { @@ -653,8 +663,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -663,7 +673,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -674,14 +684,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -690,7 +700,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -699,7 +709,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -708,7 +718,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -717,7 +727,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -726,9 +736,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -739,10 +749,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -751,7 +761,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -762,12 +772,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, "for-in": { @@ -787,7 +797,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -796,14 +806,14 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "2.11.1", - "node-pre-gyp": "0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -824,13 +834,13 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { @@ -843,12 +853,12 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -875,16 +885,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -907,7 +917,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { @@ -922,28 +932,28 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { @@ -953,12 +963,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -967,7 +977,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -976,8 +986,8 @@ "dev": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -996,7 +1006,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -1010,7 +1020,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1019,21 +1029,21 @@ "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { @@ -1045,38 +1055,38 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.7", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { @@ -1085,24 +1095,24 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -1111,10 +1121,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -1133,7 +1143,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -1154,8 +1164,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -1171,15 +1181,15 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -1196,26 +1206,26 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true }, @@ -1232,7 +1242,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -1254,9 +1264,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -1265,7 +1275,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1273,7 +1283,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -1283,18 +1293,18 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" } }, "util-deprecate": { @@ -1304,12 +1314,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -1318,7 +1328,7 @@ "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true } @@ -1342,8 +1352,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -1352,7 +1362,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -1363,7 +1373,7 @@ "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, "requires": { - "ini": "1.3.5" + "ini": "^1.3.4" } }, "got": { @@ -1372,17 +1382,17 @@ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.1", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" } }, "graceful-fs": { @@ -1403,9 +1413,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -1414,8 +1424,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -1424,7 +1434,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1434,10 +1444,10 @@ "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -1445,7 +1455,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-by-default": { @@ -1488,7 +1498,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1497,7 +1507,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1508,7 +1518,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.12.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -1523,7 +1533,7 @@ "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "dev": true, "requires": { - "ci-info": "1.6.0" + "ci-info": "^1.5.0" } }, "is-data-descriptor": { @@ -1532,7 +1542,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1541,7 +1551,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1552,9 +1562,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -1584,12 +1594,12 @@ "dev": true }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-installed-globally": { @@ -1598,8 +1608,8 @@ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "global-dirs": "0.1.1", - "is-path-inside": "1.0.1" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-npm": { @@ -1614,7 +1624,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1623,7 +1633,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1640,7 +1650,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -1649,7 +1659,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-redirect": { @@ -1706,15 +1716,9 @@ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "dev": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1727,8 +1731,8 @@ "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "3.0.3" + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" } }, "make-dir": { @@ -1737,7 +1741,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "map-cache": { @@ -1752,7 +1756,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "media-typer": { @@ -1776,19 +1780,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "mime": { @@ -1806,7 +1810,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "requires": { - "mime-db": "1.37.0" + "mime-db": "~1.37.0" } }, "minimatch": { @@ -1815,7 +1819,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1825,13 +1829,13 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1840,7 +1844,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1851,9 +1855,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -1863,17 +1867,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" } }, "negotiator": { @@ -1887,16 +1891,16 @@ "integrity": "sha512-xuC1V0F5EcEyKQ1VhHYD13owznQbUw29JKvZ8bVH7TmuvVNHvvbp9pLgE4PjTMRJVe0pJ8fGRvwR2nMiosIsPQ==", "dev": true, "requires": { - "chokidar": "2.0.4", - "debug": "3.2.6", - "ignore-by-default": "1.0.1", - "minimatch": "3.0.4", - "pstree.remy": "1.1.2", - "semver": "5.6.0", - "supports-color": "5.5.0", - "touch": "3.1.0", - "undefsafe": "2.0.2", - "update-notifier": "2.5.0" + "chokidar": "^2.0.4", + "debug": "^3.1.0", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.2", + "semver": "^5.5.0", + "supports-color": "^5.2.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.3.0" }, "dependencies": { "debug": { @@ -1905,7 +1909,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -1922,17 +1926,14 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm-run-path": { "version": "2.0.2", @@ -1940,7 +1941,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "object-copy": { @@ -1949,9 +1950,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -1960,7 +1961,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -1969,7 +1970,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1980,7 +1981,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.pick": { @@ -1989,7 +1990,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "on-finished": { @@ -2012,10 +2013,10 @@ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "dev": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0", - "semver": "5.6.0" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "parseurl": { @@ -2077,9 +2078,9 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "proxy-addr": { @@ -2087,7 +2088,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" } }, @@ -2130,10 +2131,10 @@ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { - "deep-extend": "0.6.0", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "readable-stream": { @@ -2142,13 +2143,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -2157,9 +2158,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "micromatch": "3.1.10", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "regex-not": { @@ -2168,8 +2169,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "registry-auth-token": { @@ -2178,8 +2179,8 @@ "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", "dev": true, "requires": { - "rc": "1.2.8", - "safe-buffer": "5.1.2" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { @@ -2188,7 +2189,7 @@ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "dev": true, "requires": { - "rc": "1.2.8" + "rc": "^1.0.1" } }, "remove-trailing-separator": { @@ -2232,7 +2233,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -2252,7 +2253,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.0.3" } }, "send": { @@ -2261,18 +2262,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" } }, "serve-static": { @@ -2280,22 +2281,22 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2304,7 +2305,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2320,7 +2321,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -2341,14 +2342,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -2357,7 +2358,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -2366,7 +2367,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2377,9 +2378,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -2388,7 +2389,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -2397,7 +2398,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2406,7 +2407,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2415,9 +2416,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -2428,7 +2429,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -2437,7 +2438,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2454,11 +2455,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "2.1.2", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-url": { @@ -2473,7 +2474,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "static-extend": { @@ -2482,8 +2483,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -2492,7 +2493,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2508,8 +2509,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string_decoder": { @@ -2518,7 +2519,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -2527,7 +2528,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "strip-eof": { @@ -2548,7 +2549,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "term-size": { @@ -2557,7 +2558,7 @@ "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, "timed-out": { @@ -2572,7 +2573,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2581,7 +2582,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2592,10 +2593,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -2604,8 +2605,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "touch": { @@ -2614,7 +2615,7 @@ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" } }, "type-is": { @@ -2623,7 +2624,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.21" + "mime-types": "~2.1.18" } }, "undefsafe": { @@ -2632,42 +2633,19 @@ "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", "dev": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" - } - } + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" } }, "unique-string": { @@ -2676,7 +2654,7 @@ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "dev": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "unpipe": { @@ -2690,8 +2668,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -2700,9 +2678,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -2731,9 +2709,9 @@ "dev": true }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "update-notifier": { @@ -2742,16 +2720,16 @@ "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", "dev": true, "requires": { - "boxen": "1.3.0", - "chalk": "2.4.1", - "configstore": "3.1.2", - "import-lazy": "2.1.0", - "is-ci": "1.2.1", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "urix": { @@ -2766,7 +2744,7 @@ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "use": { @@ -2797,7 +2775,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "widest-line": { @@ -2806,7 +2784,7 @@ "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "write-file-atomic": { @@ -2815,9 +2793,9 @@ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { diff --git a/integration/examples/hot-reload/node/package.json b/integration/examples/hot-reload/node/package.json index 80ecc6e25dc..2de8036ec73 100644 --- a/integration/examples/hot-reload/node/package.json +++ b/integration/examples/hot-reload/node/package.json @@ -12,4 +12,4 @@ "devDependencies": { "nodemon": "^1.18.4" } -} \ No newline at end of file +} diff --git a/integration/examples/hot-reload/skaffold.yaml b/integration/examples/hot-reload/skaffold.yaml index 61d714ab9f2..0e7d0c41067 100644 --- a/integration/examples/hot-reload/skaffold.yaml +++ b/integration/examples/hot-reload/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/jib-gradle/skaffold.yaml b/integration/examples/jib-gradle/skaffold.yaml index e0335077904..51253318cd1 100644 --- a/integration/examples/jib-gradle/skaffold.yaml +++ b/integration/examples/jib-gradle/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/jib-multimodule/skaffold.yaml b/integration/examples/jib-multimodule/skaffold.yaml index 6d3ee648370..de437207070 100644 --- a/integration/examples/jib-multimodule/skaffold.yaml +++ b/integration/examples/jib-multimodule/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/jib/skaffold.yaml b/integration/examples/jib/skaffold.yaml index a8c68b8cff5..82f603cee09 100644 --- a/integration/examples/jib/skaffold.yaml +++ b/integration/examples/jib/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/kaniko-local/skaffold.yaml b/integration/examples/kaniko-local/skaffold.yaml index 2281ecef910..78c3099d375 100644 --- a/integration/examples/kaniko-local/skaffold.yaml +++ b/integration/examples/kaniko-local/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/kaniko/skaffold.yaml b/integration/examples/kaniko/skaffold.yaml index 810aa9b454d..5979d2ed478 100644 --- a/integration/examples/kaniko/skaffold.yaml +++ b/integration/examples/kaniko/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/kustomize/skaffold.yaml b/integration/examples/kustomize/skaffold.yaml index 76607ec33cb..8993e84ff81 100644 --- a/integration/examples/kustomize/skaffold.yaml +++ b/integration/examples/kustomize/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config deploy: kustomize: {} diff --git a/integration/examples/microservices/skaffold.yaml b/integration/examples/microservices/skaffold.yaml index bdf0fcb520c..e9e1a30c921 100644 --- a/integration/examples/microservices/skaffold.yaml +++ b/integration/examples/microservices/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/nodejs/backend/package-lock.json b/integration/examples/nodejs/backend/package-lock.json index a3ae06edb4d..2fdf304744f 100644 --- a/integration/examples/nodejs/backend/package-lock.json +++ b/integration/examples/nodejs/backend/package-lock.json @@ -15,7 +15,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.21", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -25,7 +25,7 @@ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.0.0" } }, "ansi-regex": { @@ -40,7 +40,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -49,8 +49,19 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, "arr-diff": { @@ -89,9 +100,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "atob": { @@ -112,13 +123,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -127,7 +138,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -136,7 +147,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -145,7 +156,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -154,17 +165,17 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "body-parser": { @@ -173,15 +184,15 @@ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" } }, "boxen": { @@ -190,13 +201,13 @@ "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "dev": true, "requires": { - "ansi-align": "2.0.0", - "camelcase": "4.1.0", - "chalk": "2.4.1", - "cli-boxes": "1.0.0", - "string-width": "2.1.1", - "term-size": "1.2.0", - "widest-line": "2.0.1" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" } }, "brace-expansion": { @@ -205,7 +216,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -215,16 +226,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -233,7 +244,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -249,15 +260,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "camelcase": { @@ -278,30 +289,29 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.4", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.1.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "ci-info": { @@ -316,10 +326,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -328,7 +338,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -345,8 +355,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -365,9 +375,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "concat-map": { @@ -382,12 +392,12 @@ "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", "dev": true, "requires": { - "dot-prop": "4.2.0", - "graceful-fs": "4.1.15", - "make-dir": "1.3.0", - "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", - "xdg-basedir": "3.0.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "content-disposition": { @@ -428,7 +438,7 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true, "requires": { - "capture-stack-trace": "1.0.1" + "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { @@ -437,9 +447,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.4", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypto-random-string": { @@ -474,8 +484,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -484,7 +494,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -493,7 +503,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -502,9 +512,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -525,7 +535,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "duplexer3": { @@ -566,13 +576,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -581,13 +591,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -596,7 +606,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -605,7 +615,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -615,36 +625,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.4", + "proxy-addr": "~2.0.4", "qs": "6.5.2", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" } }, "extend-shallow": { @@ -653,8 +663,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -663,7 +673,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -674,14 +684,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -690,7 +700,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -699,7 +709,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -708,7 +718,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -717,7 +727,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -726,9 +736,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -739,10 +749,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -751,7 +761,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -762,12 +772,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, "for-in": { @@ -787,7 +797,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -796,14 +806,14 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "2.11.1", - "node-pre-gyp": "0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -824,13 +834,13 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { @@ -843,12 +853,12 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -875,16 +885,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -907,7 +917,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { @@ -922,28 +932,28 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { @@ -953,12 +963,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -967,7 +977,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -976,8 +986,8 @@ "dev": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -996,7 +1006,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -1010,7 +1020,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1019,21 +1029,21 @@ "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { @@ -1045,38 +1055,38 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.7", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { @@ -1085,24 +1095,24 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -1111,10 +1121,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -1133,7 +1143,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -1154,8 +1164,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -1171,15 +1181,15 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -1196,26 +1206,26 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true }, @@ -1232,7 +1242,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -1254,9 +1264,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -1265,7 +1275,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1273,7 +1283,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -1283,18 +1293,18 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" } }, "util-deprecate": { @@ -1304,12 +1314,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -1318,7 +1328,7 @@ "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true } @@ -1342,8 +1352,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -1352,7 +1362,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -1363,7 +1373,7 @@ "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, "requires": { - "ini": "1.3.5" + "ini": "^1.3.4" } }, "got": { @@ -1372,17 +1382,17 @@ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { - "create-error-class": "3.0.2", - "duplexer3": "0.1.4", - "get-stream": "3.0.0", - "is-redirect": "1.0.0", - "is-retry-allowed": "1.1.0", - "is-stream": "1.1.0", - "lowercase-keys": "1.0.1", - "safe-buffer": "5.1.2", - "timed-out": "4.0.1", - "unzip-response": "2.0.1", - "url-parse-lax": "1.0.0" + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" } }, "graceful-fs": { @@ -1403,9 +1413,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -1414,8 +1424,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -1424,7 +1434,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1434,10 +1444,10 @@ "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -1445,7 +1455,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-by-default": { @@ -1488,7 +1498,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1497,7 +1507,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1508,7 +1518,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.12.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -1523,7 +1533,7 @@ "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "dev": true, "requires": { - "ci-info": "1.6.0" + "ci-info": "^1.5.0" } }, "is-data-descriptor": { @@ -1532,7 +1542,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1541,7 +1551,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1552,9 +1562,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -1584,12 +1594,12 @@ "dev": true }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-installed-globally": { @@ -1598,8 +1608,8 @@ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "global-dirs": "0.1.1", - "is-path-inside": "1.0.1" + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" } }, "is-npm": { @@ -1614,7 +1624,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1623,7 +1633,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1640,7 +1650,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -1649,7 +1659,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-redirect": { @@ -1706,15 +1716,9 @@ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "dev": true, "requires": { - "package-json": "4.0.1" + "package-json": "^4.0.0" } }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1727,8 +1731,8 @@ "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "3.0.3" + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" } }, "make-dir": { @@ -1737,7 +1741,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "map-cache": { @@ -1752,7 +1756,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "media-typer": { @@ -1776,19 +1780,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "mime": { @@ -1806,7 +1810,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "requires": { - "mime-db": "1.37.0" + "mime-db": "~1.37.0" } }, "minimatch": { @@ -1815,7 +1819,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1825,13 +1829,13 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1840,7 +1844,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1851,9 +1855,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -1863,17 +1867,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" } }, "negotiator": { @@ -1887,16 +1891,16 @@ "integrity": "sha512-xuC1V0F5EcEyKQ1VhHYD13owznQbUw29JKvZ8bVH7TmuvVNHvvbp9pLgE4PjTMRJVe0pJ8fGRvwR2nMiosIsPQ==", "dev": true, "requires": { - "chokidar": "2.0.4", - "debug": "3.2.6", - "ignore-by-default": "1.0.1", - "minimatch": "3.0.4", - "pstree.remy": "1.1.2", - "semver": "5.6.0", - "supports-color": "5.5.0", - "touch": "3.1.0", - "undefsafe": "2.0.2", - "update-notifier": "2.5.0" + "chokidar": "^2.0.4", + "debug": "^3.1.0", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.2", + "semver": "^5.5.0", + "supports-color": "^5.2.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.3.0" }, "dependencies": { "debug": { @@ -1905,7 +1909,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -1922,17 +1926,14 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm-run-path": { "version": "2.0.2", @@ -1940,7 +1941,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "object-copy": { @@ -1949,9 +1950,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -1960,7 +1961,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -1969,7 +1970,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1980,7 +1981,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.pick": { @@ -1989,7 +1990,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "on-finished": { @@ -2012,10 +2013,10 @@ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "dev": true, "requires": { - "got": "6.7.1", - "registry-auth-token": "3.3.2", - "registry-url": "3.1.0", - "semver": "5.6.0" + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" } }, "parseurl": { @@ -2077,9 +2078,9 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "proxy-addr": { @@ -2087,7 +2088,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" } }, @@ -2130,10 +2131,10 @@ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { - "deep-extend": "0.6.0", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "readable-stream": { @@ -2142,13 +2143,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -2157,9 +2158,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "micromatch": "3.1.10", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "regex-not": { @@ -2168,8 +2169,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "registry-auth-token": { @@ -2178,8 +2179,8 @@ "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", "dev": true, "requires": { - "rc": "1.2.8", - "safe-buffer": "5.1.2" + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" } }, "registry-url": { @@ -2188,7 +2189,7 @@ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "dev": true, "requires": { - "rc": "1.2.8" + "rc": "^1.0.1" } }, "remove-trailing-separator": { @@ -2232,7 +2233,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -2252,7 +2253,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.0.3" } }, "send": { @@ -2261,18 +2262,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" } }, "serve-static": { @@ -2280,22 +2281,22 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2304,7 +2305,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2320,7 +2321,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -2341,14 +2342,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -2357,7 +2358,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -2366,7 +2367,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2377,9 +2378,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -2388,7 +2389,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -2397,7 +2398,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2406,7 +2407,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2415,9 +2416,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -2428,7 +2429,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -2437,7 +2438,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2454,11 +2455,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "2.1.2", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-url": { @@ -2473,7 +2474,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "static-extend": { @@ -2482,8 +2483,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -2492,7 +2493,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2508,8 +2509,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string_decoder": { @@ -2518,7 +2519,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -2527,7 +2528,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "strip-eof": { @@ -2548,7 +2549,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "term-size": { @@ -2557,7 +2558,7 @@ "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true, "requires": { - "execa": "0.7.0" + "execa": "^0.7.0" } }, "timed-out": { @@ -2572,7 +2573,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2581,7 +2582,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2592,10 +2593,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -2604,8 +2605,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "touch": { @@ -2614,7 +2615,7 @@ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" } }, "type-is": { @@ -2623,7 +2624,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.21" + "mime-types": "~2.1.18" } }, "undefsafe": { @@ -2632,42 +2633,19 @@ "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", "dev": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" - } - } + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" } }, "unique-string": { @@ -2676,7 +2654,7 @@ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "dev": true, "requires": { - "crypto-random-string": "1.0.0" + "crypto-random-string": "^1.0.0" } }, "unpipe": { @@ -2690,8 +2668,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -2700,9 +2678,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -2731,9 +2709,9 @@ "dev": true }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "update-notifier": { @@ -2742,16 +2720,16 @@ "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", "dev": true, "requires": { - "boxen": "1.3.0", - "chalk": "2.4.1", - "configstore": "3.1.2", - "import-lazy": "2.1.0", - "is-ci": "1.2.1", - "is-installed-globally": "0.1.0", - "is-npm": "1.0.0", - "latest-version": "3.1.0", - "semver-diff": "2.1.0", - "xdg-basedir": "3.0.0" + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, "urix": { @@ -2766,7 +2744,7 @@ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, "requires": { - "prepend-http": "1.0.4" + "prepend-http": "^1.0.1" } }, "use": { @@ -2797,7 +2775,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "widest-line": { @@ -2806,7 +2784,7 @@ "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "dev": true, "requires": { - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "write-file-atomic": { @@ -2815,9 +2793,9 @@ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "xdg-basedir": { diff --git a/integration/examples/nodejs/backend/package.json b/integration/examples/nodejs/backend/package.json index 66ddb0badf3..843517e9b4f 100644 --- a/integration/examples/nodejs/backend/package.json +++ b/integration/examples/nodejs/backend/package.json @@ -12,4 +12,4 @@ "devDependencies": { "nodemon": "^1.18.4" } -} \ No newline at end of file +} diff --git a/integration/examples/nodejs/skaffold.yaml b/integration/examples/nodejs/skaffold.yaml index 606306520f0..2c761aa7bd6 100644 --- a/integration/examples/nodejs/skaffold.yaml +++ b/integration/examples/nodejs/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/react-reload/skaffold.yaml b/integration/examples/react-reload/skaffold.yaml index 8b3dd53d3e6..d929d264b39 100644 --- a/integration/examples/react-reload/skaffold.yaml +++ b/integration/examples/react-reload/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/structure-tests/skaffold.yaml b/integration/examples/structure-tests/skaffold.yaml index 7643f98be00..e836f9ed4bf 100644 --- a/integration/examples/structure-tests/skaffold.yaml +++ b/integration/examples/structure-tests/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/examples/tagging-with-environment-variables/skaffold.yaml b/integration/examples/tagging-with-environment-variables/skaffold.yaml index a2cf3058cfd..1e1d7b9fb40 100644 --- a/integration/examples/tagging-with-environment-variables/skaffold.yaml +++ b/integration/examples/tagging-with-environment-variables/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/helm_test.go b/integration/helm_test.go index 7e41882b2af..658fd065c5f 100644 --- a/integration/helm_test.go +++ b/integration/helm_test.go @@ -50,7 +50,7 @@ func TestHelmDeploy(t *testing.T) { runArgs := []string{"--images", "gcr.io/k8s-skaffold/skaffold-helm"} - skaffold.Deploy(runArgs...).InDir(helmDir).InNs(ns.Name).WithEnv(env).RunOrFailOutput(t) + skaffold.Deploy(runArgs...).InDir(helmDir).InNs(ns.Name).WithEnv(env).RunOrFail(t) client.WaitForDeploymentsToStabilize(depName) diff --git a/integration/port_forward_test.go b/integration/port_forward_test.go index 098de507140..1d0d04fbee6 100644 --- a/integration/port_forward_test.go +++ b/integration/port_forward_test.go @@ -45,7 +45,7 @@ func TestPortForward(t *testing.T) { defer deleteNs() dir := "examples/microservices" - skaffold.Run().InDir(dir).InNs(ns.Name).RunOrFailOutput(t) + skaffold.Run().InDir(dir).InNs(ns.Name).RunOrFail(t) cfg, err := kubectx.CurrentConfig() if err != nil { diff --git a/integration/run_test.go b/integration/run_test.go index 685a27875c2..f669c4ac746 100644 --- a/integration/run_test.go +++ b/integration/run_test.go @@ -17,6 +17,7 @@ limitations under the License. package integration import ( + "strings" "testing" "github.com/GoogleContainerTools/skaffold/integration/skaffold" @@ -137,7 +138,7 @@ func TestRun(t *testing.T) { ns, client, deleteNs := SetupNamespace(t) defer deleteNs() - skaffold.Run(test.args...).WithConfig(test.filename).InDir(test.dir).InNs(ns.Name).WithEnv(test.env).RunOrFailOutput(t) + skaffold.Run(test.args...).WithConfig(test.filename).InDir(test.dir).InNs(ns.Name).WithEnv(test.env).RunOrFail(t) client.WaitForPodsReady(test.pods...) client.WaitForDeploymentsToStabilize(test.deployments...) @@ -146,3 +147,34 @@ func TestRun(t *testing.T) { }) } } + +func TestRunIdempotent(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + if ShouldRunGCPOnlyTests() { + t.Skip("skipping test that is not gcp only") + } + + ns, _, deleteNs := SetupNamespace(t) + defer deleteNs() + + // The first `skaffold run` creates resources (deployment.apps/leeroy-web, service/leeroy-app, deployment.apps/leeroy-app) + out := skaffold.Run("-l", "skaffold.dev/run-id=notunique").InDir("examples/microservices").InNs(ns.Name).RunOrFailOutput(t) + firstOut := string(out) + if strings.Count(firstOut, "created") == 0 { + t.Errorf("resources should have been created: %s", firstOut) + } + + // Because we use the same custom `run-id`, the second `skaffold run` is idempotent: + // + It has nothing to rebuild + // + It leaves all resources unchanged + out = skaffold.Run("-l", "skaffold.dev/run-id=notunique").InDir("examples/microservices").InNs(ns.Name).RunOrFailOutput(t) + secondOut := string(out) + if strings.Count(secondOut, "created") != 0 { + t.Errorf("no resource should have been created: %s", secondOut) + } + if !strings.Contains(secondOut, "leeroy-web: Found") || !strings.Contains(secondOut, "leeroy-app: Found") { + t.Errorf("both artifacts should be in cache: %s", secondOut) + } +} diff --git a/integration/skaffold/helper.go b/integration/skaffold/helper.go index fa2eaf778f2..6dbe9b9d8cd 100644 --- a/integration/skaffold/helper.go +++ b/integration/skaffold/helper.go @@ -154,10 +154,7 @@ func (b *RunBuilder) RunBackground(t *testing.T) context.CancelFunc { // RunOrFail runs the skaffold command and fails the test // if the command returns an error. func (b *RunBuilder) RunOrFail(t *testing.T) { - t.Helper() - if err := b.Run(t); err != nil { - t.Fatal(err) - } + b.RunOrFailOutput(t) } // Run runs the skaffold command. diff --git a/integration/testdata/build/skaffold.yaml b/integration/testdata/build/skaffold.yaml index a15ef4abccb..63fd6cc5424 100644 --- a/integration/testdata/build/skaffold.yaml +++ b/integration/testdata/build/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: local: diff --git a/integration/testdata/custom/skaffold.yaml b/integration/testdata/custom/skaffold.yaml index eae53603e0c..d2099e279eb 100644 --- a/integration/testdata/custom/skaffold.yaml +++ b/integration/testdata/custom/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/dev/skaffold.yaml b/integration/testdata/dev/skaffold.yaml index b75f781e4f6..505b14a3ec4 100644 --- a/integration/testdata/dev/skaffold.yaml +++ b/integration/testdata/dev/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/gke_loadbalancer/skaffold.yaml b/integration/testdata/gke_loadbalancer/skaffold.yaml index ba1d0f37efe..5f2287b6a5e 100644 --- a/integration/testdata/gke_loadbalancer/skaffold.yaml +++ b/integration/testdata/gke_loadbalancer/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/jib-gradle/skaffold.yaml b/integration/testdata/jib-gradle/skaffold.yaml index 993a3ea4d5d..034798a8091 100644 --- a/integration/testdata/jib-gradle/skaffold.yaml +++ b/integration/testdata/jib-gradle/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/jib/skaffold.yaml b/integration/testdata/jib/skaffold.yaml index 2464a19bfe5..b2ac251cdda 100644 --- a/integration/testdata/jib/skaffold.yaml +++ b/integration/testdata/jib/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/kaniko-microservices/skaffold.yaml b/integration/testdata/kaniko-microservices/skaffold.yaml index 7acc19f08db..83f1ae31656 100644 --- a/integration/testdata/kaniko-microservices/skaffold.yaml +++ b/integration/testdata/kaniko-microservices/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/kaniko-sub-folder/skaffold.yaml b/integration/testdata/kaniko-sub-folder/skaffold.yaml index baac0705c7b..ccfb6a3f5c8 100644 --- a/integration/testdata/kaniko-sub-folder/skaffold.yaml +++ b/integration/testdata/kaniko-sub-folder/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/kaniko-target/skaffold.yaml b/integration/testdata/kaniko-target/skaffold.yaml index e273b412c7f..31c64888ab7 100644 --- a/integration/testdata/kaniko-target/skaffold.yaml +++ b/integration/testdata/kaniko-target/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/integration/testdata/tagPolicy/skaffold.yaml b/integration/testdata/tagPolicy/skaffold.yaml index 4fcd0f1d2f3..2a8372905af 100644 --- a/integration/testdata/tagPolicy/skaffold.yaml +++ b/integration/testdata/tagPolicy/skaffold.yaml @@ -1,4 +1,4 @@ -apiVersion: skaffold/v1beta13 +apiVersion: skaffold/v1beta14 kind: Config build: artifacts: diff --git a/pkg/skaffold/build/bazel/dependencies.go b/pkg/skaffold/build/bazel/dependencies.go index 2a0c81317d3..4776f40f805 100644 --- a/pkg/skaffold/build/bazel/dependencies.go +++ b/pkg/skaffold/build/bazel/dependencies.go @@ -58,7 +58,7 @@ func GetDependencies(ctx context.Context, dir string, a *latest.BazelArtifact) ( return nil, errors.Wrapf(err, "unable to find absolute path for %s", dir) } - cmd := exec.CommandContext(ctx, "bazel", "query", query(a.BuildTarget), "--noimplicit_deps", "--order_output=no") + cmd := exec.CommandContext(ctx, "bazel", "query", query(a.BuildTarget), "--noimplicit_deps", "--order_output=no", "--output=label") cmd.Dir = dir stdout, err := util.RunCmdOut(cmd) if err != nil { diff --git a/pkg/skaffold/build/bazel/dependencies_test.go b/pkg/skaffold/build/bazel/dependencies_test.go index 79ad916f5f2..dc6b38dc074 100644 --- a/pkg/skaffold/build/bazel/dependencies_test.go +++ b/pkg/skaffold/build/bazel/dependencies_test.go @@ -47,7 +47,7 @@ func TestGetDependencies(t *testing.T) { "dep1": "", "dep2": "", }, - expectedQuery: "bazel query kind('source file', deps('target')) union buildfiles('target') --noimplicit_deps --order_output=no", + expectedQuery: "bazel query kind('source file', deps('target')) union buildfiles('target') --noimplicit_deps --order_output=no --output=label", output: "@ignored\n//:BUILD\n//external/ignored\n\n//:dep1\n//:dep2\n", expected: []string{"BUILD", "dep1", "dep2", "WORKSPACE"}, }, @@ -63,7 +63,7 @@ func TestGetDependencies(t *testing.T) { "sub/folder/dep2": "", "sub/folder/baz/dep3": "", }, - expectedQuery: "bazel query kind('source file', deps('target2')) union buildfiles('target2') --noimplicit_deps --order_output=no", + expectedQuery: "bazel query kind('source file', deps('target2')) union buildfiles('target2') --noimplicit_deps --order_output=no --output=label", output: "@ignored\n//:BUILD\n//sub/folder:BUILD\n//external/ignored\n\n//sub/folder:dep1\n//sub/folder:dep2\n//sub/folder/baz:dep3\n", expected: []string{filepath.Join("..", "..", "BUILD"), "BUILD", "dep1", "dep2", filepath.Join("baz", "dep3"), filepath.Join("..", "..", "WORKSPACE")}, }, diff --git a/pkg/skaffold/build/cache/hash.go b/pkg/skaffold/build/cache/hash.go index 2a29f1c43d4..b04f9cb88fa 100644 --- a/pkg/skaffold/build/cache/hash.go +++ b/pkg/skaffold/build/cache/hash.go @@ -30,37 +30,56 @@ import ( "github.com/pkg/errors" ) +// For testing var ( - // For testing - hashFunction = cacheHasher + hashFunction = cacheHasher + artifactConfigFunction = artifactConfig ) func getHashForArtifact(ctx context.Context, depLister DependencyLister, a *latest.Artifact) (string, error) { + var inputs []string + + // Append the artifact's configuration + config, err := artifactConfigFunction(a) + if err != nil { + return "", errors.Wrapf(err, "getting artifact's configuration for %s", a.ImageName) + } + inputs = append(inputs, config) + + // Append the digest of each input file deps, err := depLister.DependenciesForArtifact(ctx, a) if err != nil { return "", errors.Wrapf(err, "getting dependencies for %s", a.ImageName) } sort.Strings(deps) - var hashes []string for _, d := range deps { h, err := hashFunction(d) if err != nil { return "", errors.Wrapf(err, "getting hash for %s", d) } - hashes = append(hashes, h) + inputs = append(inputs, h) } // get a key for the hashes hasher := sha256.New() enc := json.NewEncoder(hasher) - if err := enc.Encode(hashes); err != nil { + if err := enc.Encode(inputs); err != nil { return "", err } return hex.EncodeToString(hasher.Sum(nil)), nil } +func artifactConfig(a *latest.Artifact) (string, error) { + buf, err := json.Marshal(a.ArtifactType) + if err != nil { + return "", errors.Wrapf(err, "marshalling the artifact's configuration for %s", a.ImageName) + } + + return string(buf), nil +} + // cacheHasher takes hashes the contents and name of a file func cacheHasher(p string) (string, error) { h := md5.New() @@ -70,7 +89,6 @@ func cacheHasher(p string) (string, error) { } h.Write([]byte(fi.Mode().String())) h.Write([]byte(fi.Name())) - // TODO: empty folder and empty files should not have the same hash if fi.Mode().IsRegular() { f, err := os.Open(p) if err != nil { diff --git a/pkg/skaffold/build/cache/hash_test.go b/pkg/skaffold/build/cache/hash_test.go index 3ce9f7532a8..247b1cfaf51 100644 --- a/pkg/skaffold/build/cache/hash_test.go +++ b/pkg/skaffold/build/cache/hash_test.go @@ -36,36 +36,100 @@ var mockCacheHasher = func(s string) (string, error) { return s, nil } +var fakeArtifactConfig = func(a *latest.Artifact) (string, error) { + if a.ArtifactType.DockerArtifact != nil { + return "docker/target=" + a.ArtifactType.DockerArtifact.Target, nil + } + return "other", nil +} + func TestGetHashForArtifact(t *testing.T) { tests := []struct { description string - dependencies [][]string + dependencies []string + artifact *latest.Artifact expected string }{ { - description: "check dependencies in different orders", - dependencies: [][]string{ - {"a", "b"}, - {"b", "a"}, + description: "hash for artifact", + dependencies: []string{"a", "b"}, + artifact: &latest.Artifact{}, + expected: "1caa15f7ce87536bddbac30a39768e8e3b212bf591f9b64926fa50c40b614c66", + }, + { + description: "dependencies in different orders", + dependencies: []string{"b", "a"}, + artifact: &latest.Artifact{}, + expected: "1caa15f7ce87536bddbac30a39768e8e3b212bf591f9b64926fa50c40b614c66", + }, + { + description: "no dependencies", + artifact: &latest.Artifact{}, + expected: "53ebd85adc9b03923a7dacfe6002879af526ef6067d441419d6e62fb9bf608ab", + }, + { + description: "docker target", + artifact: &latest.Artifact{ + ArtifactType: latest.ArtifactType{ + DockerArtifact: &latest.DockerArtifact{ + Target: "target", + }, + }, + }, + expected: "f947b5aad32734914aa2dea0ec95bceff257037e6c2a529007183c3f21547eae", + }, + { + description: "different docker target", + artifact: &latest.Artifact{ + ArtifactType: latest.ArtifactType{ + DockerArtifact: &latest.DockerArtifact{ + Target: "other", + }, + }, }, - expected: "eb394fd4559b1d9c383f4359667a508a615b82a74e1b160fce539f86ae0842e8", + expected: "09b366c764d0e39f942283cc081d5522b9dde52e725376661808054e3ed0177f", }, } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { t.Override(&hashFunction, mockCacheHasher) + t.Override(&artifactConfigFunction, fakeArtifactConfig) - for _, d := range test.dependencies { - depLister := &stubDependencyLister{dependencies: d} - actual, err := getHashForArtifact(context.Background(), depLister, nil) + depLister := &stubDependencyLister{dependencies: test.dependencies} + actual, err := getHashForArtifact(context.Background(), depLister, test.artifact) - t.CheckNoError(err) - t.CheckDeepEqual(test.expected, actual) - } + t.CheckNoError(err) + t.CheckDeepEqual(test.expected, actual) }) } } +func TestArtifactConfig(t *testing.T) { + testutil.Run(t, "", func(t *testutil.T) { + config1, err := artifactConfig(&latest.Artifact{ + ArtifactType: latest.ArtifactType{ + DockerArtifact: &latest.DockerArtifact{ + Target: "target", + }, + }, + }) + t.CheckNoError(err) + + config2, err := artifactConfig(&latest.Artifact{ + ArtifactType: latest.ArtifactType{ + DockerArtifact: &latest.DockerArtifact{ + Target: "other", + }, + }, + }) + t.CheckNoError(err) + + if config1 == config2 { + t.Errorf("configs should be different: [%s] [%s]", config1, config2) + } + }) +} + func TestCacheHasher(t *testing.T) { tests := []struct { description string @@ -114,7 +178,7 @@ func TestCacheHasher(t *testing.T) { path := originalFile depLister := &stubDependencyLister{dependencies: []string{tmpDir.Path(originalFile)}} - oldHash, err := getHashForArtifact(context.Background(), depLister, nil) + oldHash, err := getHashForArtifact(context.Background(), depLister, &latest.Artifact{}) t.CheckNoError(err) test.update(originalFile, tmpDir) @@ -123,7 +187,7 @@ func TestCacheHasher(t *testing.T) { } depLister = &stubDependencyLister{dependencies: []string{tmpDir.Path(path)}} - newHash, err := getHashForArtifact(context.Background(), depLister, nil) + newHash, err := getHashForArtifact(context.Background(), depLister, &latest.Artifact{}) t.CheckNoError(err) t.CheckDeepEqual(false, test.differentHash && oldHash == newHash) diff --git a/pkg/skaffold/build/cache/lookup.go b/pkg/skaffold/build/cache/lookup.go index fe71ff5d15c..0e0ee2548c9 100644 --- a/pkg/skaffold/build/cache/lookup.go +++ b/pkg/skaffold/build/cache/lookup.go @@ -25,7 +25,6 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" - "github.com/pkg/errors" ) var ( @@ -56,7 +55,7 @@ func (c *cache) lookupArtifacts(ctx context.Context, tags tag.ImageTags, artifac func (c *cache) lookup(ctx context.Context, a *latest.Artifact, tag string) cacheDetails { hash, err := hashForArtifact(ctx, c.dependencies, a) if err != nil { - return failed{err: errors.Wrapf(err, "getting hash for artifact %s", a.ImageName)} + return failed{err: fmt.Errorf("getting hash for artifact %s: %v", a.ImageName, err)} } entry, cacheHit := c.artifactCache[hash] diff --git a/pkg/skaffold/build/cache/lookup_test.go b/pkg/skaffold/build/cache/lookup_test.go index 80aef350a12..f881e759dc5 100644 --- a/pkg/skaffold/build/cache/lookup_test.go +++ b/pkg/skaffold/build/cache/lookup_test.go @@ -30,16 +30,24 @@ import ( func TestLookupLocal(t *testing.T) { tests := []struct { description string + hasher func(context.Context, DependencyLister, *latest.Artifact) (string, error) cache map[string]ImageDetails api *testutil.FakeAPIClient expected cacheDetails }{ { description: "miss", - expected: needsBuilding{hash: "hash"}, + hasher: mockHasher("thehash"), + expected: needsBuilding{hash: "thehash"}, + }, + { + description: "hash failure", + hasher: failingHasher("BUG"), + expected: failed{err: errors.New("getting hash for artifact artifact: BUG")}, }, { description: "miss no imageID", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {Digest: "ignored"}, }, @@ -47,6 +55,7 @@ func TestLookupLocal(t *testing.T) { }, { description: "hit but not found", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -55,6 +64,7 @@ func TestLookupLocal(t *testing.T) { }, { description: "hit but not found with error", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -65,6 +75,7 @@ func TestLookupLocal(t *testing.T) { }, { description: "hit", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -73,6 +84,7 @@ func TestLookupLocal(t *testing.T) { }, { description: "hit but different tag", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -81,6 +93,7 @@ func TestLookupLocal(t *testing.T) { }, { description: "hit but imageID not found", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -90,10 +103,8 @@ func TestLookupLocal(t *testing.T) { } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { - t.Override(&hashForArtifact, func(context.Context, DependencyLister, *latest.Artifact) (string, error) { - return "hash", nil - }) - t.Override(&buildInProgress, func(_ string) {}) + t.Override(&hashForArtifact, test.hasher) + t.Override(&buildInProgress, func(string) {}) cache := &cache{ imagesAreLocal: true, @@ -115,16 +126,24 @@ func TestLookupLocal(t *testing.T) { func TestLookupRemote(t *testing.T) { tests := []struct { description string + hasher func(context.Context, DependencyLister, *latest.Artifact) (string, error) cache map[string]ImageDetails api *testutil.FakeAPIClient expected cacheDetails }{ { description: "miss", + hasher: mockHasher("hash"), expected: needsBuilding{hash: "hash"}, }, + { + description: "hash failure", + hasher: failingHasher("BUG"), + expected: failed{err: errors.New("getting hash for artifact artifact: BUG")}, + }, { description: "hit", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {Digest: "digest"}, }, @@ -132,6 +151,7 @@ func TestLookupRemote(t *testing.T) { }, { description: "hit with different tag", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {Digest: "otherdigest"}, }, @@ -139,6 +159,7 @@ func TestLookupRemote(t *testing.T) { }, { description: "found locally", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -147,6 +168,7 @@ func TestLookupRemote(t *testing.T) { }, { description: "not found", + hasher: mockHasher("hash"), cache: map[string]ImageDetails{ "hash": {ID: "imageID"}, }, @@ -156,9 +178,7 @@ func TestLookupRemote(t *testing.T) { } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { - t.Override(&hashForArtifact, func(context.Context, DependencyLister, *latest.Artifact) (string, error) { - return "hash", nil - }) + t.Override(&hashForArtifact, test.hasher) t.Override(&docker.RemoteDigest, func(identifier string, _ map[string]bool) (string, error) { switch { case identifier == "tag": @@ -169,7 +189,7 @@ func TestLookupRemote(t *testing.T) { return "", errors.New("unknown remote tag") } }) - t.Override(&buildInProgress, func(_ string) {}) + t.Override(&buildInProgress, func(string) {}) cache := &cache{ imagesAreLocal: false, @@ -187,3 +207,15 @@ func TestLookupRemote(t *testing.T) { }) } } + +func mockHasher(value string) func(context.Context, DependencyLister, *latest.Artifact) (string, error) { + return func(context.Context, DependencyLister, *latest.Artifact) (string, error) { + return value, nil + } +} + +func failingHasher(errMessage string) func(context.Context, DependencyLister, *latest.Artifact) (string, error) { + return func(context.Context, DependencyLister, *latest.Artifact) (string, error) { + return "", errors.New(errMessage) + } +} diff --git a/pkg/skaffold/build/cache/retrieve.go b/pkg/skaffold/build/cache/retrieve.go index 5beb75a3a8c..ad1be619f11 100644 --- a/pkg/skaffold/build/cache/retrieve.go +++ b/pkg/skaffold/build/cache/retrieve.go @@ -28,6 +28,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) var ( @@ -62,11 +63,14 @@ func (c *cache) Build(ctx context.Context, out io.Writer, tags tag.ImageTags, ar result := results[i] switch result := result.(type) { case failed: - return nil, errors.Wrap(result.err, "checking cache") + logrus.Warnf("error checking cache, caching may not work as expected: %v", result.err) + color.Yellow.Fprintln(out, "Error checking cache. Rebuilding.") + needToBuild = append(needToBuild, artifact) + continue case needsBuilding: - color.Red.Fprintln(out, "Not found. Building") - hashByName[artifact.ImageName] = result.hash + color.Yellow.Fprintln(out, "Not found. Building") + hashByName[artifact.ImageName] = result.Hash() needToBuild = append(needToBuild, artifact) continue @@ -114,11 +118,13 @@ func (c *cache) Build(ctx context.Context, out io.Writer, tags tag.ImageTags, ar } if err := c.addArtifacts(ctx, bRes, hashByName); err != nil { - return nil, errors.Wrap(err, "adding artifacts to cache") + logrus.Warnf("error adding artifacts to cache; caching may not work as expected: %v", err) + return append(bRes, alreadyBuilt...), nil } if err := saveArtifactCache(c.cacheFile, c.artifactCache); err != nil { - return nil, errors.Wrap(err, "saving cache") + logrus.Warnf("error saving cache file; caching may not work as expected: %v", err) + return append(bRes, alreadyBuilt...), nil } return append(bRes, alreadyBuilt...), err diff --git a/pkg/skaffold/build/cache/retrieve_test.go b/pkg/skaffold/build/cache/retrieve_test.go index 6da6766ab9c..1d5920fafb0 100644 --- a/pkg/skaffold/build/cache/retrieve_test.go +++ b/pkg/skaffold/build/cache/retrieve_test.go @@ -91,8 +91,8 @@ func (t stubAuth) GetAllAuthConfigs() (map[string]types.AuthConfig, error) { ret func TestCacheBuildLocal(t *testing.T) { testutil.Run(t, "", func(t *testutil.T) { - t.Override(&buildComplete, func(_ string) {}) - t.Override(&buildInProgress, func(_ string) {}) + t.Override(&buildComplete, func(string) {}) + t.Override(&buildInProgress, func(string) {}) tmpDir := t.NewTempDir(). Write("dep1", "content1"). @@ -146,6 +146,9 @@ func TestCacheBuildLocal(t *testing.T) { t.CheckNoError(err) t.CheckDeepEqual(0, len(builder.built)) t.CheckDeepEqual(2, len(bRes)) + // Artifacts should always be returned in their original order + t.CheckDeepEqual("artifact1", bRes[0].ImageName) + t.CheckDeepEqual("artifact2", bRes[1].ImageName) // Third build: change one artifact's dependencies tmpDir.Write("dep1", "new content") @@ -155,13 +158,15 @@ func TestCacheBuildLocal(t *testing.T) { t.CheckNoError(err) t.CheckDeepEqual(1, len(builder.built)) t.CheckDeepEqual(2, len(bRes)) + t.CheckDeepEqual("artifact1", bRes[0].ImageName) + t.CheckDeepEqual("artifact2", bRes[1].ImageName) }) } func TestCacheBuildRemote(t *testing.T) { testutil.Run(t, "", func(t *testutil.T) { - t.Override(&buildComplete, func(_ string) {}) - t.Override(&buildInProgress, func(_ string) {}) + t.Override(&buildComplete, func(string) {}) + t.Override(&buildInProgress, func(string) {}) tmpDir := t.NewTempDir(). Write("dep1", "content1"). @@ -218,6 +223,9 @@ func TestCacheBuildRemote(t *testing.T) { t.CheckNoError(err) t.CheckDeepEqual(2, len(builder.built)) t.CheckDeepEqual(2, len(bRes)) + // Artifacts should always be returned in their original order + t.CheckDeepEqual("artifact1", bRes[0].ImageName) + t.CheckDeepEqual("artifact2", bRes[1].ImageName) // Second build: both artifacts are read from cache builder = &mockBuilder{dockerDaemon: dockerDaemon, push: true} @@ -226,6 +234,8 @@ func TestCacheBuildRemote(t *testing.T) { t.CheckNoError(err) t.CheckDeepEqual(0, len(builder.built)) t.CheckDeepEqual(2, len(bRes)) + t.CheckDeepEqual("artifact1", bRes[0].ImageName) + t.CheckDeepEqual("artifact2", bRes[1].ImageName) // Third build: change one artifact's dependencies tmpDir.Write("dep1", "new content") @@ -235,5 +245,7 @@ func TestCacheBuildRemote(t *testing.T) { t.CheckNoError(err) t.CheckDeepEqual(1, len(builder.built)) t.CheckDeepEqual(2, len(bRes)) + t.CheckDeepEqual("artifact1", bRes[0].ImageName) + t.CheckDeepEqual("artifact2", bRes[1].ImageName) }) } diff --git a/pkg/skaffold/build/cluster/cluster.go b/pkg/skaffold/build/cluster/cluster.go index 1389cec98aa..7898bdc5f48 100644 --- a/pkg/skaffold/build/cluster/cluster.go +++ b/pkg/skaffold/build/cluster/cluster.go @@ -72,13 +72,16 @@ func (b *Builder) buildArtifactWithCustomBuilder(ctx context.Context, out io.Wri } func (b *Builder) retrieveExtraEnv() []string { - return []string{ + env := []string{ fmt.Sprintf("%s=%s", constants.KubeContext, b.kubeContext), fmt.Sprintf("%s=%s", constants.Namespace, b.ClusterDetails.Namespace), fmt.Sprintf("%s=%s", constants.PullSecretName, b.ClusterDetails.PullSecretName), - fmt.Sprintf("%s=%s", constants.DockerConfigSecretName, b.ClusterDetails.DockerConfig.SecretName), fmt.Sprintf("%s=%s", constants.Timeout, b.ClusterDetails.Timeout), } + if b.ClusterDetails.DockerConfig != nil { + env = append(env, fmt.Sprintf("%s=%s", constants.DockerConfigSecretName, b.ClusterDetails.DockerConfig.SecretName)) + } + return env } func (b *Builder) buildArtifactWithKaniko(ctx context.Context, out io.Writer, artifact *latest.Artifact, tag string) (string, error) { diff --git a/pkg/skaffold/build/cluster/cluster_test.go b/pkg/skaffold/build/cluster/cluster_test.go index 390e49d6b87..c34e0c76ff9 100644 --- a/pkg/skaffold/build/cluster/cluster_test.go +++ b/pkg/skaffold/build/cluster/cluster_test.go @@ -49,6 +49,25 @@ func TestRetrieveEnv(t *testing.T) { testutil.CheckError(t, false, err) actual := builder.retrieveExtraEnv() - expected := []string{"KUBE_CONTEXT=kubecontext", "NAMESPACE=namespace", "PULL_SECRET_NAME=pullSecret", "DOCKER_CONFIG_SECRET_NAME=dockerconfig", "TIMEOUT=2m"} + expected := []string{"KUBE_CONTEXT=kubecontext", "NAMESPACE=namespace", "PULL_SECRET_NAME=pullSecret", "TIMEOUT=2m", "DOCKER_CONFIG_SECRET_NAME=dockerconfig"} + testutil.CheckDeepEqual(t, expected, actual) +} + +func TestRetrieveEnvMinimal(t *testing.T) { + builder, err := NewBuilder(&runcontext.RunContext{ + Cfg: latest.Pipeline{ + Build: latest.BuildConfig{ + BuildType: latest.BuildType{ + Cluster: &latest.ClusterDetails{ + Timeout: "20m", + }, + }, + }, + }, + }) + testutil.CheckError(t, false, err) + + actual := builder.retrieveExtraEnv() + expected := []string{"KUBE_CONTEXT=", "NAMESPACE=", "PULL_SECRET_NAME=", "TIMEOUT=20m"} testutil.CheckDeepEqual(t, expected, actual) } diff --git a/pkg/skaffold/build/cluster/sources/gcs.go b/pkg/skaffold/build/cluster/sources/gcs.go index 58c2b8dcab0..6e8a9aa4cb0 100644 --- a/pkg/skaffold/build/cluster/sources/gcs.go +++ b/pkg/skaffold/build/cluster/sources/gcs.go @@ -26,6 +26,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/gcp" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/sources" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/version" "github.com/pkg/errors" v1 "k8s.io/api/core/v1" ) @@ -51,7 +52,12 @@ func (g *GCSBucket) Setup(ctx context.Context, out io.Writer, artifact *latest.A color.Default.Fprintln(out, "Uploading sources to", bucket, "GCS bucket") g.tarName = fmt.Sprintf("context-%s.tar.gz", initialTag) - if err := sources.UploadToGCS(ctx, artifact, bucket, g.tarName, dependencies); err != nil { + c, err := gcp.CloudStorageClient() + if err != nil { + return "", errors.Wrap(err, "getting cloud storage client") + } + defer c.Close() + if err := sources.UploadToGCS(ctx, c, artifact, bucket, g.tarName, dependencies); err != nil { return "", errors.Wrap(err, "uploading sources to GCS") } @@ -61,7 +67,7 @@ func (g *GCSBucket) Setup(ctx context.Context, out io.Writer, artifact *latest.A // Pod returns the pod template for this builder func (g *GCSBucket) Pod(args []string) *v1.Pod { - return podTemplate(g.clusterDetails, g.artifact, args) + return podTemplate(g.clusterDetails, g.artifact, args, version.Get().Version) } // ModifyPod does nothing here, since we just need to let kaniko run to completion diff --git a/pkg/skaffold/build/cluster/sources/localdir.go b/pkg/skaffold/build/cluster/sources/localdir.go index 5966a81a1c5..16f547ccdde 100644 --- a/pkg/skaffold/build/cluster/sources/localdir.go +++ b/pkg/skaffold/build/cluster/sources/localdir.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/version" "github.com/pkg/errors" v1 "k8s.io/api/core/v1" @@ -86,7 +87,7 @@ func (g *LocalDir) Pod(args []string) *v1.Pod { Resources: resourceRequirements(g.clusterDetails.Resources), } - p := podTemplate(g.clusterDetails, g.artifact, args) + p := podTemplate(g.clusterDetails, g.artifact, args, version.Get().Version) p.Spec.InitContainers = []v1.Container{ic} p.Spec.Containers[0].VolumeMounts = append(p.Spec.Containers[0].VolumeMounts, vm) p.Spec.Volumes = append(p.Spec.Volumes, v) diff --git a/pkg/skaffold/build/cluster/sources/localdir_test.go b/pkg/skaffold/build/cluster/sources/localdir_test.go index 41db72e10aa..2daeb94be0d 100644 --- a/pkg/skaffold/build/cluster/sources/localdir_test.go +++ b/pkg/skaffold/build/cluster/sources/localdir_test.go @@ -30,6 +30,9 @@ func TestPod(t *testing.T) { env := []v1.EnvVar{{ Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/secret/kaniko-secret", + }, { + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-)", }} reqs := &latest.ResourceRequirements{ Requests: &latest.ResourceRequirement{ diff --git a/pkg/skaffold/build/cluster/sources/sources.go b/pkg/skaffold/build/cluster/sources/sources.go index 19cddd61045..06b816eefaf 100644 --- a/pkg/skaffold/build/cluster/sources/sources.go +++ b/pkg/skaffold/build/cluster/sources/sources.go @@ -18,6 +18,7 @@ package sources import ( "context" + "fmt" "io" v1 "k8s.io/api/core/v1" @@ -53,10 +54,16 @@ func Retrieve(cli *kubectl.CLI, clusterDetails *latest.ClusterDetails, artifact } } -func podTemplate(clusterDetails *latest.ClusterDetails, artifact *latest.KanikoArtifact, args []string) *v1.Pod { +func podTemplate(clusterDetails *latest.ClusterDetails, artifact *latest.KanikoArtifact, args []string, version string) *v1.Pod { + userAgent := fmt.Sprintf("UpstreamClient(skaffold-%s)", version) + env := []v1.EnvVar{{ Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/secret/kaniko-secret", + }, { + // This should be same https://github.com/GoogleContainerTools/kaniko/blob/77cfb912f3483c204bfd09e1ada44fd200b15a78/pkg/executor/push.go#L49 + Name: "UPSTREAM_CLIENT_TYPE", + Value: userAgent, }} env = setProxy(clusterDetails, env) diff --git a/pkg/skaffold/build/cluster/sources/sources_test.go b/pkg/skaffold/build/cluster/sources/sources_test.go index 737b1194dfd..bb1093a004c 100644 --- a/pkg/skaffold/build/cluster/sources/sources_test.go +++ b/pkg/skaffold/build/cluster/sources/sources_test.go @@ -55,6 +55,9 @@ func TestPodTemplate(t *testing.T) { Env: []v1.EnvVar{{ Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/secret/kaniko-secret", + }, { + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-test)", }}, VolumeMounts: []v1.VolumeMount{{ Name: "kaniko-secret", @@ -99,6 +102,9 @@ func TestPodTemplate(t *testing.T) { Env: []v1.EnvVar{{ Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/secret/kaniko-secret", + }, { + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-test)", }}, VolumeMounts: []v1.VolumeMount{ { @@ -163,6 +169,9 @@ func TestPodTemplate(t *testing.T) { Env: []v1.EnvVar{{ Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/secret/kaniko-secret", + }, { + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-test)", }}, VolumeMounts: []v1.VolumeMount{{ Name: "kaniko-secret", @@ -208,6 +217,9 @@ func TestPodTemplate(t *testing.T) { Env: []v1.EnvVar{{ Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/secret/kaniko-secret", + }, { + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-test)", }}, VolumeMounts: []v1.VolumeMount{{ Name: "kaniko-secret", @@ -244,7 +256,7 @@ func TestPodTemplate(t *testing.T) { for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { - actual := podTemplate(test.initial, test.artifact, test.args) + actual := podTemplate(test.initial, test.artifact, test.args, "test") t.CheckDeepEqual(test.expected, actual, opt) }) diff --git a/pkg/skaffold/build/gcb/cloud_build.go b/pkg/skaffold/build/gcb/cloud_build.go index 1643a06ee43..37fbdbb9181 100644 --- a/pkg/skaffold/build/gcb/cloud_build.go +++ b/pkg/skaffold/build/gcb/cloud_build.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "net/http" + "strings" "time" cstorage "cloud.google.com/go/storage" @@ -34,12 +35,12 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/sources" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/version" "github.com/pkg/errors" "github.com/sirupsen/logrus" cloudbuild "google.golang.org/api/cloudbuild/v1" "google.golang.org/api/googleapi" "google.golang.org/api/iterator" + "k8s.io/apimachinery/pkg/util/wait" ) // Build builds a list of artifacts with Google Cloud Build. @@ -48,13 +49,12 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, tags tag.ImageTags, } func (b *Builder) buildArtifactWithCloudBuild(ctx context.Context, out io.Writer, artifact *latest.Artifact, tag string) (string, error) { - cbclient, err := cloudbuild.NewService(ctx) + cbclient, err := gcp.CloudBuildClient() if err != nil { return "", errors.Wrap(err, "getting cloudbuild client") } - cbclient.UserAgent = version.UserAgent() - c, err := cstorage.NewClient(ctx) + c, err := gcp.CloudStorageClient() if err != nil { return "", errors.Wrap(err, "getting cloud storage client") } @@ -73,10 +73,10 @@ func (b *Builder) buildArtifactWithCloudBuild(ctx context.Context, out io.Writer cbBucket := fmt.Sprintf("%s%s", projectID, constants.GCSBucketSuffix) buildObject := fmt.Sprintf("source/%s-%s.tar.gz", projectID, util.RandomID()) - if err := b.createBucketIfNotExists(ctx, projectID, cbBucket); err != nil { + if err := b.createBucketIfNotExists(ctx, c, projectID, cbBucket); err != nil { return "", errors.Wrap(err, "creating bucket if not exists") } - if err := b.checkBucketProjectCorrect(ctx, projectID, cbBucket); err != nil { + if err := b.checkBucketProjectCorrect(ctx, c, projectID, cbBucket); err != nil { return "", errors.Wrap(err, "checking bucket is in correct project") } @@ -86,7 +86,7 @@ func (b *Builder) buildArtifactWithCloudBuild(ctx context.Context, out io.Writer } color.Default.Fprintf(out, "Pushing code to gs://%s/%s\n", cbBucket, buildObject) - if err := sources.UploadToGCS(ctx, artifact, cbBucket, buildObject, dependencies); err != nil { + if err := sources.UploadToGCS(ctx, c, artifact, cbBucket, buildObject, dependencies); err != nil { return "", errors.Wrap(err, "uploading source tarball") } @@ -112,13 +112,29 @@ func (b *Builder) buildArtifactWithCloudBuild(ctx context.Context, out io.Writer offset := int64(0) watch: for { + var cb *cloudbuild.Build + var err error logrus.Debugf("current offset %d", offset) - cb, err := cbclient.Projects.Builds.Get(projectID, remoteID).Do() - if err != nil { + backoff := NewStatusBackoff() + if waitErr := wait.Poll(backoff.Duration, RetryTimeout, func() (bool, error) { + backoff.Step() + cb, err = cbclient.Projects.Builds.Get(projectID, remoteID).Do() + if err == nil { + return true, nil + } + if strings.Contains(err.Error(), "Error 429: Quota exceeded for quota metric 'cloudbuild.googleapis.com/get_requests'") { + // if we hit the rate limit, continue to retry + return false, nil + } + return false, err + }); waitErr != nil { + return "", errors.Wrap(waitErr, "getting build status") + } + if cb == nil { return "", errors.Wrap(err, "getting build status") } - r, err := b.getLogs(ctx, offset, cbBucket, logsObject) + r, err := b.getLogs(ctx, c, offset, cbBucket, logsObject) if err != nil { return "", errors.Wrap(err, "getting logs") } @@ -180,13 +196,7 @@ func getDigest(b *cloudbuild.Build, defaultToTag string) (string, error) { return docker.RemoteDigest(defaultToTag, nil) } -func (b *Builder) getLogs(ctx context.Context, offset int64, bucket, objectName string) (io.ReadCloser, error) { - c, err := cstorage.NewClient(ctx) - if err != nil { - return nil, errors.Wrap(err, "getting storage client") - } - defer c.Close() - +func (b *Builder) getLogs(ctx context.Context, c *cstorage.Client, offset int64, bucket, objectName string) (io.ReadCloser, error) { r, err := c.Bucket(bucket).Object(objectName).NewRangeReader(ctx, offset, -1) if err != nil { if gerr, ok := err.(*googleapi.Error); ok { @@ -206,11 +216,7 @@ func (b *Builder) getLogs(ctx context.Context, offset int64, bucket, objectName return r, nil } -func (b *Builder) checkBucketProjectCorrect(ctx context.Context, projectID, bucket string) error { - c, err := cstorage.NewClient(ctx) - if err != nil { - return errors.Wrap(err, "getting storage client") - } +func (b *Builder) checkBucketProjectCorrect(ctx context.Context, c *cstorage.Client, projectID, bucket string) error { it := c.Buckets(ctx, projectID) // Set the prefix to the bucket we're looking for to only return that bucket and buckets with that prefix // that we'll filter further later on @@ -230,12 +236,8 @@ func (b *Builder) checkBucketProjectCorrect(ctx context.Context, projectID, buck } } -func (b *Builder) createBucketIfNotExists(ctx context.Context, projectID, bucket string) error { - c, err := cstorage.NewClient(ctx) - if err != nil { - return errors.Wrap(err, "getting storage client") - } - defer c.Close() +func (b *Builder) createBucketIfNotExists(ctx context.Context, c *cstorage.Client, projectID, bucket string) error { + var err error _, err = c.Bucket(bucket).Attrs(ctx) diff --git a/pkg/skaffold/build/gcb/jib.go b/pkg/skaffold/build/gcb/jib.go index f42415b064b..3f90509c370 100644 --- a/pkg/skaffold/build/gcb/jib.go +++ b/pkg/skaffold/build/gcb/jib.go @@ -29,7 +29,7 @@ func (b *Builder) jibMavenBuildSpec(artifact *latest.JibMavenArtifact, tag strin Steps: []*cloudbuild.BuildStep{{ Name: b.MavenImage, Entrypoint: "sh", - Args: fixHome("mvn", jib.GenerateMavenArgs("build", tag, artifact, b.skipTests)), + Args: fixHome("mvn", jib.GenerateMavenArgs("build", tag, artifact, b.skipTests, b.insecureRegistries)), }}, } } @@ -39,7 +39,7 @@ func (b *Builder) jibGradleBuildSpec(artifact *latest.JibGradleArtifact, tag str Steps: []*cloudbuild.BuildStep{{ Name: b.GradleImage, Entrypoint: "sh", - Args: fixHome("gradle", jib.GenerateGradleArgs("jib", tag, artifact, b.skipTests)), + Args: fixHome("gradle", jib.GenerateGradleArgs("jib", tag, artifact, b.skipTests, b.insecureRegistries)), }}, } } diff --git a/pkg/skaffold/build/gcb/types.go b/pkg/skaffold/build/gcb/types.go index c6b73f82824..bbca7602148 100644 --- a/pkg/skaffold/build/gcb/types.go +++ b/pkg/skaffold/build/gcb/types.go @@ -29,6 +29,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/wait" ) const ( @@ -58,8 +59,26 @@ const ( // RetryDelay is the time to wait in between polling the status of the cloud build RetryDelay = 1 * time.Second + + // BackoffFactor is the exponent for exponential backoff during build status polling + BackoffFactor = 1.5 + + // BackoffSteps is the number of times we increase the backoff time during exponential backoff + BackoffSteps = 10 + + // RetryTimeout is the max amount of time to retry getting the status of the build before erroring + RetryTimeout = 3 * time.Minute ) +func NewStatusBackoff() *wait.Backoff { + return &wait.Backoff{ + Duration: RetryDelay, + Factor: float64(BackoffFactor), + Steps: BackoffSteps, + Cap: 60 * time.Second, + } +} + // Builder builds artifacts with Google Cloud Build. type Builder struct { *latest.GoogleCloudBuild diff --git a/pkg/skaffold/build/local/docker.go b/pkg/skaffold/build/local/docker.go index ef35c5218bb..20fe508deb5 100644 --- a/pkg/skaffold/build/local/docker.go +++ b/pkg/skaffold/build/local/docker.go @@ -73,8 +73,9 @@ func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, workspace s } cmd := exec.CommandContext(ctx, "docker", args...) + cmd.Env = append(util.OSEnviron(), b.retrieveExtraEnv()...) if b.cfg.UseBuildkit { - cmd.Env = append(util.OSEnviron(), "DOCKER_BUILDKIT=1") + cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=1") } cmd.Stdout = out cmd.Stderr = out diff --git a/pkg/skaffold/build/local/docker_test.go b/pkg/skaffold/build/local/docker_test.go new file mode 100644 index 00000000000..ee17db6b116 --- /dev/null +++ b/pkg/skaffold/build/local/docker_test.go @@ -0,0 +1,96 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package local + +import ( + "context" + "io/ioutil" + "path/filepath" + "testing" + + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" + "github.com/GoogleContainerTools/skaffold/testutil" +) + +func TestDockerCLIBuild(t *testing.T) { + tests := []struct { + description string + localBuild latest.LocalBuild + extraEnv []string + expectedEnv []string + }{ + { + description: "docker build", + localBuild: latest.LocalBuild{}, + expectedEnv: []string{"KEY=VALUE"}, + }, + { + description: "extra env", + localBuild: latest.LocalBuild{}, + extraEnv: []string{"OTHER=VALUE"}, + expectedEnv: []string{"KEY=VALUE", "OTHER=VALUE"}, + }, + { + description: "buildkit", + localBuild: latest.LocalBuild{UseBuildkit: true}, + expectedEnv: []string{"KEY=VALUE", "DOCKER_BUILDKIT=1"}, + }, + { + description: "buildkit and extra env", + localBuild: latest.LocalBuild{UseBuildkit: true}, + extraEnv: []string{"OTHER=VALUE"}, + expectedEnv: []string{"KEY=VALUE", "OTHER=VALUE", "DOCKER_BUILDKIT=1"}, + }, + { + description: "env var collisions", + localBuild: latest.LocalBuild{UseBuildkit: true}, + extraEnv: []string{"KEY=OTHER_VALUE", "DOCKER_BUILDKIT=0"}, + // env var collisions are handled by cmd.Run(). Last one wins. + expectedEnv: []string{"KEY=VALUE", "KEY=OTHER_VALUE", "DOCKER_BUILDKIT=0", "DOCKER_BUILDKIT=1"}, + }, + } + + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + t.NewTempDir().Chdir() + dockerfilePath, _ := filepath.Abs("Dockerfile") + t.Override(&util.DefaultExecCommand, t.NewFakeCmd().WithRunEnv("docker build . --file "+dockerfilePath+" -t tag --force-rm", test.expectedEnv)) + t.Override(&util.OSEnviron, func() []string { return []string{"KEY=VALUE"} }) + t.Override(&docker.NewAPIClient, func(*runcontext.RunContext) (docker.LocalDaemon, error) { + return docker.NewLocalDaemon(&testutil.FakeAPIClient{}, test.extraEnv, false, nil), nil + }) + + builder, err := NewBuilder(stubRunContext(test.localBuild)) + t.CheckNoError(err) + + artifact := &latest.Artifact{ + Workspace: ".", + ArtifactType: latest.ArtifactType{ + DockerArtifact: &latest.DockerArtifact{ + DockerfilePath: "Dockerfile", + }, + }, + } + + _, err = builder.buildDocker(context.Background(), ioutil.Discard, artifact, "tag") + t.CheckNoError(err) + }) + } +} diff --git a/pkg/skaffold/build/local/jib_gradle.go b/pkg/skaffold/build/local/jib_gradle.go index 545772c6460..2578baf3607 100644 --- a/pkg/skaffold/build/local/jib_gradle.go +++ b/pkg/skaffold/build/local/jib_gradle.go @@ -36,7 +36,7 @@ func (b *Builder) buildJibGradle(ctx context.Context, out io.Writer, workspace s } func (b *Builder) buildJibGradleToDocker(ctx context.Context, out io.Writer, workspace string, artifact *latest.JibGradleArtifact, tag string) (string, error) { - args := jib.GenerateGradleArgs("jibDockerBuild", tag, artifact, b.skipTests) + args := jib.GenerateGradleArgs("jibDockerBuild", tag, artifact, b.skipTests, b.insecureRegistries) if err := b.runGradleCommand(ctx, out, workspace, args); err != nil { return "", err } @@ -45,7 +45,7 @@ func (b *Builder) buildJibGradleToDocker(ctx context.Context, out io.Writer, wor } func (b *Builder) buildJibGradleToRegistry(ctx context.Context, out io.Writer, workspace string, artifact *latest.JibGradleArtifact, tag string) (string, error) { - args := jib.GenerateGradleArgs("jib", tag, artifact, b.skipTests) + args := jib.GenerateGradleArgs("jib", tag, artifact, b.skipTests, b.insecureRegistries) if err := b.runGradleCommand(ctx, out, workspace, args); err != nil { return "", err } diff --git a/pkg/skaffold/build/local/jib_maven.go b/pkg/skaffold/build/local/jib_maven.go index 0e44964b1f8..e35309cd260 100644 --- a/pkg/skaffold/build/local/jib_maven.go +++ b/pkg/skaffold/build/local/jib_maven.go @@ -36,7 +36,7 @@ func (b *Builder) buildJibMaven(ctx context.Context, out io.Writer, workspace st } func (b *Builder) buildJibMavenToDocker(ctx context.Context, out io.Writer, workspace string, artifact *latest.JibMavenArtifact, tag string) (string, error) { - args := jib.GenerateMavenArgs("dockerBuild", tag, artifact, b.skipTests) + args := jib.GenerateMavenArgs("dockerBuild", tag, artifact, b.skipTests, b.insecureRegistries) if err := b.runMavenCommand(ctx, out, workspace, args); err != nil { return "", err } @@ -45,7 +45,7 @@ func (b *Builder) buildJibMavenToDocker(ctx context.Context, out io.Writer, work } func (b *Builder) buildJibMavenToRegistry(ctx context.Context, out io.Writer, workspace string, artifact *latest.JibMavenArtifact, tag string) (string, error) { - args := jib.GenerateMavenArgs("build", tag, artifact, b.skipTests) + args := jib.GenerateMavenArgs("build", tag, artifact, b.skipTests, b.insecureRegistries) if err := b.runMavenCommand(ctx, out, workspace, args); err != nil { return "", err } diff --git a/pkg/skaffold/build/parallel.go b/pkg/skaffold/build/parallel.go index eca0b37742f..96698e7fd38 100644 --- a/pkg/skaffold/build/parallel.go +++ b/pkg/skaffold/build/parallel.go @@ -57,12 +57,12 @@ func InParallel(ctx context.Context, out io.Writer, tags tag.ImageTags, artifact defer cancel() results := new(sync.Map) - outputs := make([]chan []byte, len(artifacts)) + outputs := make([]chan string, len(artifacts)) // Run builds in // wg.Add(len(artifacts)) for i := range artifacts { - outputs[i] = make(chan []byte, buffSize) + outputs[i] = make(chan string, buffSize) r, w := io.Pipe() cw := setUpColorWriter(w, out) @@ -95,10 +95,10 @@ func runBuild(ctx context.Context, cw io.WriteCloser, tags tag.ImageTags, artifa cw.Close() } -func readOutputAndWriteToChannel(r io.Reader, lines chan []byte) { +func readOutputAndWriteToChannel(r io.Reader, lines chan string) { scanner := bufio.NewScanner(r) for scanner.Scan() { - lines <- scanner.Bytes() + lines <- scanner.Text() } close(lines) } @@ -119,7 +119,7 @@ func getBuildResult(ctx context.Context, cw io.Writer, tags tag.ImageTags, artif return build(ctx, cw, artifact, tag) } -func collectResults(out io.Writer, artifacts []*latest.Artifact, results *sync.Map, outputs []chan []byte) ([]Artifact, error) { +func collectResults(out io.Writer, artifacts []*latest.Artifact, results *sync.Map, outputs []chan string) ([]Artifact, error) { var built []Artifact for i, artifact := range artifacts { // Wait for build to complete. @@ -140,9 +140,8 @@ func collectResults(out io.Writer, artifacts []*latest.Artifact, results *sync.M return built, nil } -func printResult(out io.Writer, output chan []byte) { +func printResult(out io.Writer, output chan string) { for line := range output { - out.Write(line) - fmt.Fprintln(out) + fmt.Fprintln(out, line) } } diff --git a/pkg/skaffold/build/parallel_test.go b/pkg/skaffold/build/parallel_test.go index be6feca30b1..817836e0ef0 100644 --- a/pkg/skaffold/build/parallel_test.go +++ b/pkg/skaffold/build/parallel_test.go @@ -325,10 +325,10 @@ func TestColoredOutput(t *testing.T) { } } -func setUpChannels(n int) []chan []byte { - outputs := make([]chan []byte, n) +func setUpChannels(n int) []chan string { + outputs := make([]chan string, n) for i := 0; i < n; i++ { - outputs[i] = make(chan []byte, 10) + outputs[i] = make(chan string, 10) close(outputs[i]) } return outputs diff --git a/pkg/skaffold/build/util.go b/pkg/skaffold/build/util.go index 9c6442622b6..f9301f4a837 100644 --- a/pkg/skaffold/build/util.go +++ b/pkg/skaffold/build/util.go @@ -18,19 +18,28 @@ package build // MergeWithPreviousBuilds merges previous or prebuilt build artifacts with // builds. If an artifact is already present in builds, the same artifact from -// previous will be ignored. +// previous will be replaced at the same position. func MergeWithPreviousBuilds(builds, previous []Artifact) []Artifact { - updatedBuilds := map[string]bool{} + updatedBuilds := map[string]Artifact{} for _, build := range builds { - updatedBuilds[build.ImageName] = true + updatedBuilds[build.ImageName] = build } + added := map[string]bool{} var merged []Artifact - merged = append(merged, builds...) - for _, b := range previous { - if !updatedBuilds[b.ImageName] { - merged = append(merged, b) + for _, artifact := range previous { + if updated, found := updatedBuilds[artifact.ImageName]; found { + merged = append(merged, updated) + } else { + merged = append(merged, artifact) + } + added[artifact.ImageName] = true + } + + for _, artifact := range builds { + if !added[artifact.ImageName] { + merged = append(merged, artifact) } } diff --git a/pkg/skaffold/build/util_test.go b/pkg/skaffold/build/util_test.go new file mode 100644 index 00000000000..0d95b7f17ee --- /dev/null +++ b/pkg/skaffold/build/util_test.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package build + +import ( + "fmt" + "testing" + + "github.com/GoogleContainerTools/skaffold/testutil" +) + +// TestMergeWithPreviousBuilds tests that artifacts are always kept in the same order +func TestMergeWithPreviousBuilds(t *testing.T) { + builds := MergeWithPreviousBuilds([]Artifact{artifact("img1", "tag1_1"), artifact("img2", "tag2_1")}, nil) + testutil.CheckDeepEqual(t, "img1:tag1_1,img2:tag2_1", tags(builds)) + + builds = MergeWithPreviousBuilds([]Artifact{artifact("img1", "tag1_2")}, builds) + testutil.CheckDeepEqual(t, "img1:tag1_2,img2:tag2_1", tags(builds)) + + builds = MergeWithPreviousBuilds([]Artifact{artifact("img2", "tag2_2")}, builds) + testutil.CheckDeepEqual(t, "img1:tag1_2,img2:tag2_2", tags(builds)) + + builds = MergeWithPreviousBuilds([]Artifact{artifact("img1", "tag1_3"), artifact("img2", "tag2_3")}, builds) + testutil.CheckDeepEqual(t, "img1:tag1_3,img2:tag2_3", tags(builds)) +} + +func artifact(image, tag string) Artifact { + return Artifact{ + ImageName: image, + Tag: tag, + } +} + +func tags(artifacts []Artifact) string { + var tags string + + for i, a := range artifacts { + if i > 0 { + tags += "," + } + tags += fmt.Sprintf("%s:%s", a.ImageName, a.Tag) + } + + return tags +} diff --git a/pkg/skaffold/deploy/kubectl.go b/pkg/skaffold/deploy/kubectl.go index a9ad476934c..46458c818aa 100644 --- a/pkg/skaffold/deploy/kubectl.go +++ b/pkg/skaffold/deploy/kubectl.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/pkg/errors" + "github.com/segmentio/textio" "github.com/sirupsen/logrus" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" @@ -72,8 +73,8 @@ func (k *KubectlDeployer) Labels() map[string]string { // Deploy templates the provided manifests with a simple `find and replace` and // runs `kubectl apply` on those manifests func (k *KubectlDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact, labellers []Labeller) *Result { - color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx)) if err := k.kubectl.CheckVersion(ctx); err != nil { + color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx)) color.Default.Fprintln(out, err) } @@ -133,7 +134,7 @@ func (k *KubectlDeployer) Deploy(ctx context.Context, out io.Writer, builds []bu } } - if err := k.kubectl.Apply(ctx, out, manifests); err != nil { + if err := k.kubectl.Apply(ctx, textio.NewPrefixWriter(out, " - "), manifests); err != nil { event.DeployFailed(err) return NewDeployErrorResult(errors.Wrap(err, "kubectl error")) } @@ -149,22 +150,27 @@ func (k *KubectlDeployer) Cleanup(ctx context.Context, out io.Writer) error { return errors.Wrap(err, "reading manifests") } - // pull remote manifests - var rm deploy.ManifestList - for _, m := range k.RemoteManifests { - manifest, err := k.readRemoteManifest(ctx, m) + // revert remote manifests + // TODO(dgageot): That seems super dangerous and I don't understand + // why we need to update resources just before we delete them. + if len(k.RemoteManifests) > 0 { + var rm deploy.ManifestList + for _, m := range k.RemoteManifests { + manifest, err := k.readRemoteManifest(ctx, m) + if err != nil { + return errors.Wrap(err, "get remote manifests") + } + rm = append(rm, manifest) + } + upd, err := rm.ReplaceImages(k.originalImages, k.defaultRepo) if err != nil { - return errors.Wrap(err, "get remote manifests") + return errors.Wrap(err, "replacing with originals") + } + if err := k.kubectl.Apply(ctx, out, upd); err != nil { + return errors.Wrap(err, "apply original") } - rm = append(rm, manifest) - } - upd, err := rm.ReplaceImages(k.originalImages, k.defaultRepo) - if err != nil { - return errors.Wrap(err, "replacing with originals") - } - if err := k.kubectl.Apply(ctx, out, upd); err != nil { - return errors.Wrap(err, "apply original") } + if err := k.kubectl.Delete(ctx, out, manifests); err != nil { return errors.Wrap(err, "delete") } diff --git a/pkg/skaffold/deploy/kubectl/manifests.go b/pkg/skaffold/deploy/kubectl/manifests.go index c2b1de22ba3..204f7b1fb3f 100644 --- a/pkg/skaffold/deploy/kubectl/manifests.go +++ b/pkg/skaffold/deploy/kubectl/manifests.go @@ -38,17 +38,53 @@ func (l *ManifestList) String() string { } // Append appends the yaml manifests defined in the given buffer. +// `buf` can contain concatenated manifests without `---` separators +// because `kubectl create --dry-run -oyaml` produces such output. func (l *ManifestList) Append(buf []byte) { - // `kubectl create --dry-run -oyaml` outputs manifests without --- separator - // But we can rely on `apiVersion:` being here as a "separator". - buf = regexp. - MustCompile("\n(|---\n)apiVersion: "). - ReplaceAll(buf, []byte("\n---\napiVersion: ")) + // If there's at most one `apiVersion` field, then append the `buf` as is. + if len(regexp.MustCompile("(?m)^apiVersion:").FindAll(buf, -1)) <= 1 { + *l = append(*l, buf) + return + } + + // If there are `---` separators, then append each individual manifest as is. parts := bytes.Split(buf, []byte("\n---\n")) - for _, part := range parts { - *l = append(*l, part) + if len(parts) > 1 { + *l = append(*l, parts...) + return } + + // There are no `---` separators, let's identify each individual manifest + // based on the top level keys lexicographical order. + yaml := string(buf) + + var part string + var previousKey = "" + + for _, line := range strings.Split(yaml, "\n") { + // Not a top level key. + if strings.HasPrefix(line, " ") || !strings.Contains(line, ":") { + part += "\n" + line + continue + } + + // Top level key. + key := line[0:strings.Index(line, ":")] + if strings.Compare(key, previousKey) > 0 { + if part != "" { + part += "\n" + } + part += line + } else { + *l = append(*l, []byte(part)) + part = line + } + + previousKey = key + } + + *l = append(*l, []byte(part)) } // Diff computes the list of manifests that have changed. diff --git a/pkg/skaffold/deploy/kubectl/manifests_test.go b/pkg/skaffold/deploy/kubectl/manifests_test.go index df8a9c87a8d..d7604a3e394 100644 --- a/pkg/skaffold/deploy/kubectl/manifests_test.go +++ b/pkg/skaffold/deploy/kubectl/manifests_test.go @@ -38,24 +38,77 @@ metadata: spec: containers: - name: leeroy-app - image: leeroy-app` + image: leeroy-app` -func TestAppend(t *testing.T) { +const clusterRole = `aggregationRule: {} +apiVersion: v1 +kind: ClusterRole` + +const podUnordered = `kind: Pod +metadata: + name: leeroy-web +apiVersion: v1 +spec: + containers: + - name: leeroy-web + image: leeroy-web` + +func TestEmpty(t *testing.T) { var manifests ManifestList - manifests.Append([]byte(pod1 + "\n---\n" + pod2)) + testutil.CheckDeepEqual(t, 0, len(manifests)) - testutil.CheckDeepEqual(t, 2, len(manifests)) + manifests.Append(nil) + + testutil.CheckDeepEqual(t, 1, len(manifests)) +} + +func TestAppendSingle(t *testing.T) { + var manifests ManifestList + + manifests.Append([]byte(pod1)) + + testutil.CheckDeepEqual(t, 1, len(manifests)) + testutil.CheckDeepEqual(t, pod1, string(manifests[0])) +} + +func TestAppendUnordered(t *testing.T) { + var manifests ManifestList + + manifests.Append([]byte(podUnordered)) + + testutil.CheckDeepEqual(t, 1, len(manifests)) + testutil.CheckDeepEqual(t, podUnordered, string(manifests[0])) +} + +func TestAppendWithSeparators(t *testing.T) { + var manifests ManifestList + + manifests.Append([]byte(pod1 + "\n---\n" + pod2 + "\n---\n" + podUnordered)) + + testutil.CheckDeepEqual(t, 3, len(manifests)) testutil.CheckDeepEqual(t, pod1, string(manifests[0])) testutil.CheckDeepEqual(t, pod2, string(manifests[1])) + testutil.CheckDeepEqual(t, podUnordered, string(manifests[2])) } -func TestAppendWithoutSeperator(t *testing.T) { +func TestAppendWithoutSeparators(t *testing.T) { var manifests ManifestList - manifests.Append([]byte(pod1 + "\n" + pod2)) + manifests.Append([]byte(pod1 + "\n" + pod2 + "\n" + clusterRole)) - testutil.CheckDeepEqual(t, 2, len(manifests)) + testutil.CheckDeepEqual(t, 3, len(manifests)) testutil.CheckDeepEqual(t, pod1, string(manifests[0])) testutil.CheckDeepEqual(t, pod2, string(manifests[1])) + testutil.CheckDeepEqual(t, clusterRole, string(manifests[2])) +} + +func TestAppendDifferentApiVersion(t *testing.T) { + var manifests ManifestList + + manifests.Append([]byte("apiVersion: v1\napiVersion: v2")) + + testutil.CheckDeepEqual(t, 2, len(manifests)) + testutil.CheckDeepEqual(t, "apiVersion: v1", string(manifests[0])) + testutil.CheckDeepEqual(t, "apiVersion: v2", string(manifests[1])) } diff --git a/pkg/skaffold/deploy/kubectl_test.go b/pkg/skaffold/deploy/kubectl_test.go index b4fbf028052..5aa97231593 100644 --- a/pkg/skaffold/deploy/kubectl_test.go +++ b/pkg/skaffold/deploy/kubectl_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "io/ioutil" + "path/filepath" "testing" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" @@ -56,33 +57,18 @@ spec: func TestKubectlDeploy(t *testing.T) { tests := []struct { - description string - cfg *latest.KubectlDeploy - builds []build.Artifact - command util.Command - shouldErr bool - forceDeploy bool - expectedDependencies []string + description string + cfg *latest.KubectlDeploy + builds []build.Artifact + command util.Command + shouldErr bool + forceDeploy bool }{ { description: "no manifest", cfg: &latest.KubectlDeploy{}, command: testutil.FakeRunOut(t, "kubectl version --client -ojson", kubectlVersion), }, - { - description: "missing manifest file", - cfg: &latest.KubectlDeploy{ - Manifests: []string{"missing.yaml"}, - }, - command: testutil.FakeRunOut(t, "kubectl version --client -ojson", kubectlVersion), - }, - { - description: "ignore non-manifest", - cfg: &latest.KubectlDeploy{ - Manifests: []string{"*.ignored"}, - }, - command: testutil.FakeRunOut(t, "kubectl version --client -ojson", kubectlVersion), - }, { description: "deploy success (forced)", cfg: &latest.KubectlDeploy{ @@ -96,8 +82,7 @@ func TestKubectlDeploy(t *testing.T) { ImageName: "leeroy-web", Tag: "leeroy-web:123", }}, - forceDeploy: true, - expectedDependencies: []string{"deployment.yaml"}, + forceDeploy: true, }, { description: "deploy success", @@ -112,7 +97,6 @@ func TestKubectlDeploy(t *testing.T) { ImageName: "leeroy-web", Tag: "leeroy-web:123", }}, - expectedDependencies: []string{"deployment.yaml"}, }, { description: "http manifest", @@ -127,7 +111,6 @@ func TestKubectlDeploy(t *testing.T) { ImageName: "leeroy-web", Tag: "leeroy-web:123", }}, - expectedDependencies: []string{"deployment.yaml"}, }, { description: "deploy command error", @@ -142,8 +125,7 @@ func TestKubectlDeploy(t *testing.T) { ImageName: "leeroy-web", Tag: "leeroy-web:123", }}, - shouldErr: true, - expectedDependencies: []string{"deployment.yaml"}, + shouldErr: true, }, { description: "additional flags", @@ -163,8 +145,7 @@ func TestKubectlDeploy(t *testing.T) { ImageName: "leeroy-web", Tag: "leeroy-web:123", }}, - shouldErr: true, - expectedDependencies: []string{"deployment.yaml"}, + shouldErr: true, }, } for _, test := range tests { @@ -191,11 +172,8 @@ func TestKubectlDeploy(t *testing.T) { }, }) - dependencies, err := k.Dependencies() - t.CheckNoError(err) - t.CheckDeepEqual(test.expectedDependencies, dependencies) + err := k.Deploy(context.Background(), ioutil.Discard, test.builds, nil).GetError() - err = k.Deploy(context.Background(), ioutil.Discard, test.builds, nil).GetError() t.CheckError(test.shouldErr, err) }) } @@ -410,3 +388,72 @@ spec: t.CheckNoError(err) }) } + +func TestDependencies(t *testing.T) { + tests := []struct { + description string + manifests []string + expected []string + }{ + { + description: "no manifest", + manifests: []string(nil), + expected: []string(nil), + }, + { + description: "missing manifest file", + manifests: []string{"missing.yaml"}, + expected: []string(nil), + }, + { + description: "ignore non-manifest", + manifests: []string{"*.ignored"}, + expected: []string(nil), + }, + { + description: "single manifest", + manifests: []string{"deployment.yaml"}, + expected: []string{"deployment.yaml"}, + }, + { + description: "keep manifests order", + manifests: []string{"01_name.yaml", "00_service.yaml"}, + expected: []string{"01_name.yaml", "00_service.yaml"}, + }, + { + description: "sort children", + manifests: []string{"01/*.yaml", "00/*.yaml"}, + expected: []string{filepath.Join("01", "a.yaml"), filepath.Join("01", "b.yaml"), filepath.Join("00", "a.yaml"), filepath.Join("00", "b.yaml")}, + }, + { + description: "http manifest", + manifests: []string{"deployment.yaml", "http://remote.yaml"}, + expected: []string{"deployment.yaml"}, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + t.NewTempDir(). + Touch("deployment.yaml", "01_name.yaml", "00_service.yaml", "empty.ignored"). + Touch("01/a.yaml", "01/b.yaml"). + Touch("00/b.yaml", "00/a.yaml"). + Chdir() + + k := NewKubectlDeployer(&runcontext.RunContext{ + Cfg: latest.Pipeline{ + Deploy: latest.DeployConfig{ + DeployType: latest.DeployType{ + KubectlDeploy: &latest.KubectlDeploy{ + Manifests: test.manifests, + }, + }, + }, + }, + }) + dependencies, err := k.Dependencies() + + t.CheckNoError(err) + t.CheckDeepEqual(test.expected, dependencies) + }) + } +} diff --git a/pkg/skaffold/deploy/kustomize.go b/pkg/skaffold/deploy/kustomize.go index 46c8a4bde98..7303e428515 100644 --- a/pkg/skaffold/deploy/kustomize.go +++ b/pkg/skaffold/deploy/kustomize.go @@ -37,6 +37,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" + "github.com/segmentio/textio" ) // kustomization is the content of a kustomization.yaml file. @@ -94,8 +95,8 @@ func (k *KustomizeDeployer) Labels() map[string]string { // Deploy runs `kubectl apply` on the manifest generated by kustomize. func (k *KustomizeDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact, labellers []Labeller) *Result { - color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx)) if err := k.kubectl.CheckVersion(ctx); err != nil { + color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx)) color.Default.Fprintln(out, err) } @@ -136,7 +137,7 @@ func (k *KustomizeDeployer) Deploy(ctx context.Context, out io.Writer, builds [] } } - if err := k.kubectl.Apply(ctx, out, manifests); err != nil { + if err := k.kubectl.Apply(ctx, textio.NewPrefixWriter(out, " - "), manifests); err != nil { event.DeployFailed(err) return NewDeployErrorResult(errors.Wrap(err, "kubectl error")) } diff --git a/pkg/skaffold/deploy/status_check_test.go b/pkg/skaffold/deploy/status_check_test.go index 16c246d7410..6b63a395a1f 100644 --- a/pkg/skaffold/deploy/status_check_test.go +++ b/pkg/skaffold/deploy/status_check_test.go @@ -207,13 +207,6 @@ func TestPollDeploymentRolloutStatus(t *testing.T) { WithRunOutErr(rolloutCmd, "could not find", errors.New("deployment.apps/dep could not be found")), shouldErr: true, duration: 50, - }, { - description: "rollout returns success before time out", - command: testutil.NewFakeCmd(t). - WithRunOut(rolloutCmd, "Waiting for rollout to finish: 0 of 1 updated replicas are available..."). - WithRunOut(rolloutCmd, "Waiting for rollout to finish: 0 of 1 updated replicas are available..."). - WithRunOut(rolloutCmd, "deployment.apps/dep successfully rolled out"), - duration: 80, }, { description: "rollout returns did not stabilize within the given timeout", command: testutil.NewFakeCmd(t). diff --git a/pkg/skaffold/docker/dependencies_test.go b/pkg/skaffold/docker/dependencies_test.go index f121e95599a..6afd5a96dc0 100644 --- a/pkg/skaffold/docker/dependencies_test.go +++ b/pkg/skaffold/docker/dependencies_test.go @@ -203,6 +203,12 @@ FROM jboss/wildfly:14.0.1.Final ADD ./file /etc/file ` +const fromScratchWithStageName = ` +FROM scratch as stage +FROM stage +ADD ./file /etc/file +` + type fakeImageFetcher struct{} func (f *fakeImageFetcher) fetch(image string, _ map[string]bool) (*v1.ConfigFile, error) { @@ -498,6 +504,12 @@ func TestGetDependencies(t *testing.T) { ignore: "**\n!server.go", expected: []string{"Dockerfile", "server.go"}, }, + { + description: "from scratch witch stage name", + dockerfile: fromScratchWithStageName, + workspace: ".", + expected: []string{"Dockerfile", "file"}, + }, } for _, test := range tests { diff --git a/pkg/skaffold/docker/parse.go b/pkg/skaffold/docker/parse.go index bd83e714cf0..7340d81496a 100644 --- a/pkg/skaffold/docker/parse.go +++ b/pkg/skaffold/docker/parse.go @@ -275,18 +275,15 @@ func readCopyCommand(value *parser.Node, envs []string, workdir string) (*copyCo } func expandOnbuildInstructions(nodes []*parser.Node, insecureRegistries map[string]bool) ([]*parser.Node, error) { - onbuildNodesCache := map[string][]*parser.Node{} + onbuildNodesCache := map[string][]*parser.Node{ + "scratch": nil, + } var expandedNodes []*parser.Node n := 0 for m, node := range nodes { if node.Value == command.From { from := fromInstruction(node) - // `scratch` is case insensitive - if strings.ToLower(from.image) == "scratch" { - continue - } - // onbuild should immediately follow the from command expandedNodes = append(expandedNodes, nodes[n:m+1]...) n = m + 1 diff --git a/pkg/skaffold/docker/remote.go b/pkg/skaffold/docker/remote.go index c9879b0f760..ae616f377de 100644 --- a/pkg/skaffold/docker/remote.go +++ b/pkg/skaffold/docker/remote.go @@ -97,7 +97,7 @@ func remoteImage(identifier string, insecureRegistries map[string]bool) (v1.Imag return nil, errors.Wrapf(err, "parsing reference [%s]", identifier) } - if isInsecure(ref.Context().Registry.Name(), insecureRegistries) { + if IsInsecure(ref.Context().Registry.Name(), insecureRegistries) { ref, err = getInsecureRegistryImpl(identifier) if err != nil { logrus.Warnf("error getting insecure registry: %s\nremote references may not be retrieved", err.Error()) @@ -115,9 +115,9 @@ func getInsecureRegistry(identifier string) (name.Reference, error) { return ref, nil } -func isInsecure(ref string, insecureRegistries map[string]bool) bool { - _, ok := insecureRegistries[ref] - return ok +// IsInsecure tests if the registry is listed as an insecure registry; default is false +func IsInsecure(reg string, insecureRegistries map[string]bool) bool { + return insecureRegistries[reg] } func getRemoteImage(ref name.Reference) (v1.Image, error) { diff --git a/pkg/skaffold/docker/remote_test.go b/pkg/skaffold/docker/remote_test.go new file mode 100644 index 00000000000..8e5dbc8ed19 --- /dev/null +++ b/pkg/skaffold/docker/remote_test.go @@ -0,0 +1,44 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package docker + +import ( + "testing" + + "github.com/GoogleContainerTools/skaffold/testutil" +) + +func TestIsInsecure(t *testing.T) { + tests := []struct { + description string + registry string + insecureRegistries map[string]bool + result bool + }{ + {"nil registries", "localhost:5000", nil, false}, + {"unlisted registry", "other.tld", map[string]bool{"registry.tld": true}, false}, + {"listed insecure", "registry.tld", map[string]bool{"registry.tld": true}, true}, + {"listed secure", "registry.tld", map[string]bool{"registry.tld": false}, false}, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + result := IsInsecure(test.registry, test.insecureRegistries) + + t.CheckDeepEqual(test.result, result) + }) + } +} diff --git a/pkg/skaffold/gcp/auth.go b/pkg/skaffold/gcp/auth.go index 694e439abbb..5ea360b2f36 100644 --- a/pkg/skaffold/gcp/auth.go +++ b/pkg/skaffold/gcp/auth.go @@ -17,11 +17,23 @@ limitations under the License. package gcp import ( + "context" + "encoding/json" "os/exec" "strings" + "sync" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" "github.com/docker/cli/cli/config/configfile" + "github.com/pkg/errors" "github.com/sirupsen/logrus" + "golang.org/x/oauth2/google" +) + +var ( + creds *google.Credentials + credsOnce sync.Once + credsErr error ) // AutoConfigureGCRCredentialHelper automatically adds the `gcloud` credential helper @@ -50,3 +62,34 @@ func AutoConfigureGCRCredentialHelper(cf *configfile.ConfigFile, registry string } cf.CredentialHelpers[registry] = "gcloud" } + +func activeUserCredentials() (*google.Credentials, error) { + credsOnce.Do(func() { + cmd := exec.Command("gcloud", "auth", "print-access-token", "--format=json") + body, err := util.RunCmdOut(cmd) + if err != nil { + credsErr = errors.Wrap(err, "retrieving gcloud access token") + return + } + jsonCreds := make(map[string]interface{}) + json.Unmarshal(body, &jsonCreds) + jsonCreds["type"] = "authorized_user" + body, _ = json.Marshal(jsonCreds) + + c, err := google.CredentialsFromJSON(context.Background(), body) + if err != nil { + logrus.Infof("unable to retrieve google creds: %v", err) + logrus.Infof("falling back to application default credentials") + return + } + _, err = c.TokenSource.Token() + if err != nil { + logrus.Infof("unable to retrieve token: %v", err) + logrus.Infof("falling back to application default credentials") + return + } + creds = c + }) + + return creds, credsErr +} diff --git a/pkg/skaffold/gcp/client.go b/pkg/skaffold/gcp/client.go new file mode 100644 index 00000000000..b8e68a1748b --- /dev/null +++ b/pkg/skaffold/gcp/client.go @@ -0,0 +1,76 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gcp + +import ( + "context" + "sync" + + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/version" + + cstorage "cloud.google.com/go/storage" + "github.com/pkg/errors" + cloudbuild "google.golang.org/api/cloudbuild/v1" + "google.golang.org/api/option" +) + +var ( + cbclient *cloudbuild.Service + cbOnce sync.Once + cbErr error +) + +// CloudBuildClient returns an authenticated client for interacting with +// the Google Cloud Build API. This client is created once and cached +// for repeated use in Skaffold. +func CloudBuildClient() (*cloudbuild.Service, error) { + cbOnce.Do(func() { + var options []option.ClientOption + var err error + creds, cErr := activeUserCredentials() + if cErr == nil && creds != nil { + options = append(options, option.WithCredentials(creds)) + } + + c, err := cloudbuild.NewService(context.Background(), options...) + if err != nil { + cbErr = err + return + } + c.UserAgent = version.UserAgent() + cbclient = c + }) + + return cbclient, cbErr +} + +// CloudStorageClient returns an authenticated client for interacting with +// the Google Cloud Storage API. This client is not cached by Skaffold, +// because it needs to be closed each time it is done being used by the caller. +func CloudStorageClient() (*cstorage.Client, error) { + var options []option.ClientOption + var err error + creds, cErr := activeUserCredentials() + if cErr == nil && creds != nil { + options = append(options, option.WithCredentials(creds)) + } + c, err := cstorage.NewClient(context.Background(), options...) + if err != nil { + return nil, errors.Wrap(err, "getting cloud storage client") + } + return c, nil +} diff --git a/pkg/skaffold/generate_pipeline/tasks.go b/pkg/skaffold/generate_pipeline/tasks.go index 05d7a09c3c3..3fc76fbd2bd 100644 --- a/pkg/skaffold/generate_pipeline/tasks.go +++ b/pkg/skaffold/generate_pipeline/tasks.go @@ -81,30 +81,32 @@ func generateBuildTask(configFile *ConfigFile) (*tekton.Task, error) { }, } - // Add secret volume mounting for artifacts that need to be built with kaniko + // Add secret volume mounting if any artifacts in config need to be built with kaniko var volumes []corev1.Volume - if buildConfig.Artifacts[0].KanikoArtifact != nil { - volumes = []corev1.Volume{ - { - Name: kanikoSecretName, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: kanikoSecretName, + for _, artifact := range buildConfig.Artifacts { + if artifact.KanikoArtifact != nil { + volumes = []corev1.Volume{ + { + Name: kanikoSecretName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: kanikoSecretName, + }, }, }, - }, - } - steps[0].VolumeMounts = []corev1.VolumeMount{ - { - Name: kanikoSecretName, - MountPath: "/secret", - }, - } - steps[0].Env = []corev1.EnvVar{ - { - Name: "GOOGLE_APPLICATION_CREDENTIALS", - Value: "/secret/" + kanikoSecretName, - }, + } + steps[0].VolumeMounts = []corev1.VolumeMount{ + { + Name: kanikoSecretName, + MountPath: "/secret", + }, + } + steps[0].Env = []corev1.EnvVar{ + { + Name: "GOOGLE_APPLICATION_CREDENTIALS", + Value: "/secret/" + kanikoSecretName, + }, + } } } diff --git a/pkg/skaffold/initializer/init.go b/pkg/skaffold/initializer/init.go index 443f3b664af..2517895d255 100644 --- a/pkg/skaffold/initializer/init.go +++ b/pkg/skaffold/initializer/init.go @@ -281,7 +281,8 @@ func processCliArtifacts(artifacts []string) ([]builderImagePair, error) { pair := builderImagePair{Builder: parsed.Payload, ImageName: a.Image} pairs = append(pairs, pair) - case jib.JibGradle, jib.JibMaven: + // FIXME: shouldn't use a human-readable name? + case jib.JibGradle.Name(), jib.JibMaven.Name(): parsed := struct { Payload jib.Jib `json:"payload"` }{} diff --git a/pkg/skaffold/initializer/init_test.go b/pkg/skaffold/initializer/init_test.go index 0fe5f5c5f95..5fe38213eff 100644 --- a/pkg/skaffold/initializer/init_test.go +++ b/pkg/skaffold/initializer/init_test.go @@ -38,14 +38,14 @@ func TestPrintAnalyzeJSON(t *testing.T) { }{ { description: "builders and images with pairs", - pairs: []builderImagePair{{jib.Jib{BuilderName: jib.JibGradle, Image: "image1", FilePath: "build.gradle", Project: "project"}, "image1"}}, + pairs: []builderImagePair{{jib.Jib{BuilderName: jib.JibGradle.Name(), Image: "image1", FilePath: "build.gradle", Project: "project"}, "image1"}}, builders: []InitBuilder{docker.Docker{File: "Dockerfile"}}, images: []string{"image2"}, expected: `{"builders":[{"name":"Jib Gradle Plugin","payload":{"image":"image1","path":"build.gradle","project":"project"}},{"name":"Docker","payload":{"path":"Dockerfile"}}],"images":[{"name":"image1","foundMatch":true},{"name":"image2","foundMatch":false}]}`, }, { description: "builders and images with no pairs", - builders: []InitBuilder{jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle", Project: "project"}, docker.Docker{File: "Dockerfile"}}, + builders: []InitBuilder{jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle", Project: "project"}, docker.Docker{File: "Dockerfile"}}, images: []string{"image1", "image2"}, expected: `{"builders":[{"name":"Jib Gradle Plugin","payload":{"path":"build.gradle","project":"project"}},{"name":"Docker","payload":{"path":"Dockerfile"}}],"images":[{"name":"image1","foundMatch":false},{"name":"image2","foundMatch":false}]}`, }, @@ -289,10 +289,10 @@ func fakeValidateDockerfile(path string) bool { func fakeValidateJibConfig(path string) []jib.Jib { if strings.HasSuffix(path, "build.gradle") { - return []jib.Jib{{BuilderName: jib.JibGradle, FilePath: path}} + return []jib.Jib{{BuilderName: jib.JibGradle.Name(), FilePath: path}} } if strings.HasSuffix(path, "pom.xml") { - return []jib.Jib{{BuilderName: jib.JibMaven, FilePath: path}} + return []jib.Jib{{BuilderName: jib.JibMaven.Name(), FilePath: path}} } return nil } @@ -326,7 +326,7 @@ func TestResolveBuilderImages(t *testing.T) { }, { description: "prompt for multiple builders and images", - buildConfigs: []InitBuilder{docker.Docker{File: "Dockerfile1"}, jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle"}, jib.Jib{BuilderName: jib.JibMaven, Project: "project", FilePath: "pom.xml"}}, + buildConfigs: []InitBuilder{docker.Docker{File: "Dockerfile1"}, jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle"}, jib.Jib{BuilderName: jib.JibMaven.Name(), Project: "project", FilePath: "pom.xml"}}, images: []string{"image1", "image2"}, shouldMakeChoice: true, expectedPairs: []builderImagePair{ @@ -335,7 +335,7 @@ func TestResolveBuilderImages(t *testing.T) { ImageName: "image1", }, { - Builder: jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle"}, + Builder: jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle"}, ImageName: "image2", }, }, @@ -371,15 +371,15 @@ func TestAutoSelectBuilders(t *testing.T) { description: "no automatic matches", builderConfigs: []InitBuilder{ docker.Docker{File: "Dockerfile"}, - jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle"}, - jib.Jib{BuilderName: jib.JibMaven, FilePath: "pom.xml", Image: "not a k8s image"}, + jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle"}, + jib.Jib{BuilderName: jib.JibMaven.Name(), FilePath: "pom.xml", Image: "not a k8s image"}, }, images: []string{"image1", "image2"}, expectedPairs: nil, expectedBuildersLeft: []InitBuilder{ docker.Docker{File: "Dockerfile"}, - jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle"}, - jib.Jib{BuilderName: jib.JibMaven, FilePath: "pom.xml", Image: "not a k8s image"}, + jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle"}, + jib.Jib{BuilderName: jib.JibMaven.Name(), FilePath: "pom.xml", Image: "not a k8s image"}, }, expectedFilteredImages: []string{"image1", "image2"}, }, @@ -387,17 +387,17 @@ func TestAutoSelectBuilders(t *testing.T) { description: "automatic jib matches", builderConfigs: []InitBuilder{ docker.Docker{File: "Dockerfile"}, - jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle", Image: "image1"}, - jib.Jib{BuilderName: jib.JibMaven, FilePath: "pom.xml", Image: "image2"}, + jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle", Image: "image1"}, + jib.Jib{BuilderName: jib.JibMaven.Name(), FilePath: "pom.xml", Image: "image2"}, }, images: []string{"image1", "image2", "image3"}, expectedPairs: []builderImagePair{ { - jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle", Image: "image1"}, + jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle", Image: "image1"}, "image1", }, { - jib.Jib{BuilderName: jib.JibMaven, FilePath: "pom.xml", Image: "image2"}, + jib.Jib{BuilderName: jib.JibMaven.Name(), FilePath: "pom.xml", Image: "image2"}, "image2", }, }, @@ -407,14 +407,14 @@ func TestAutoSelectBuilders(t *testing.T) { { description: "multiple matches for one image", builderConfigs: []InitBuilder{ - jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle", Image: "image1"}, - jib.Jib{BuilderName: jib.JibMaven, FilePath: "pom.xml", Image: "image1"}, + jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle", Image: "image1"}, + jib.Jib{BuilderName: jib.JibMaven.Name(), FilePath: "pom.xml", Image: "image1"}, }, images: []string{"image1", "image2"}, expectedPairs: nil, expectedBuildersLeft: []InitBuilder{ - jib.Jib{BuilderName: jib.JibGradle, FilePath: "build.gradle", Image: "image1"}, - jib.Jib{BuilderName: jib.JibMaven, FilePath: "pom.xml", Image: "image1"}, + jib.Jib{BuilderName: jib.JibGradle.Name(), FilePath: "build.gradle", Image: "image1"}, + jib.Jib{BuilderName: jib.JibMaven.Name(), FilePath: "pom.xml", Image: "image1"}, }, expectedFilteredImages: []string{"image1", "image2"}, }, diff --git a/pkg/skaffold/jib/jib.go b/pkg/skaffold/jib/jib.go index 04062797718..200a8c31743 100644 --- a/pkg/skaffold/jib/jib.go +++ b/pkg/skaffold/jib/jib.go @@ -27,7 +27,9 @@ import ( "strings" "time" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" + "github.com/google/go-containerregistry/pkg/name" "github.com/karrick/godirwalk" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -37,6 +39,37 @@ const ( dotDotSlash = ".." + string(filepath.Separator) ) +// PluginType is an enum for the different supported Jib plugins. +type PluginType int + +// Define the different plugin types supported by Jib. +const ( + JibMaven PluginType = iota + JibGradle +) + +// ID returns the identifier for a Jib plugin type, suitable for external references (YAML, JSON, command-line, etc). +func (t PluginType) ID() string { + switch t { + case JibMaven: + return "maven" + case JibGradle: + return "gradle" + } + panic("Unknown Jib Plugin Type: " + string(t)) +} + +// Name provides a human-oriented label for a plugin type. +func (t PluginType) Name() string { + switch t { + case JibMaven: + return "Jib Maven Plugin" + case JibGradle: + return "Jib Gradle Plugin" + } + panic("Unknown Jib Plugin Type: " + string(t)) +} + // filesLists contains cached build/input dependencies type filesLists struct { // BuildDefinitions lists paths to build definitions that trigger a call out to Jib to refresh the pathMap, as well as a rebuild, upon changing @@ -229,3 +262,14 @@ func relativize(path string, roots ...string) (string, error) { } return "", errors.New("could not relativize path") } + +// isOnInsecureRegistry checks if the given image specifies an insecure registry +func isOnInsecureRegistry(image string, insecureRegistries map[string]bool) (bool, error) { + ref, err := name.ParseReference(image) + if err != nil { + return false, err + } + + registry := ref.Context().Registry.Name() + return docker.IsInsecure(registry, insecureRegistries), nil +} diff --git a/pkg/skaffold/jib/jib_gradle.go b/pkg/skaffold/jib/jib_gradle.go index df1be577feb..5e5923a8c42 100644 --- a/pkg/skaffold/jib/jib_gradle.go +++ b/pkg/skaffold/jib/jib_gradle.go @@ -51,11 +51,17 @@ func getCommandGradle(ctx context.Context, workspace string, a *latest.JibGradle } // GenerateGradleArgs generates the arguments to Gradle for building the project as an image. -func GenerateGradleArgs(task string, imageName string, a *latest.JibGradleArtifact, skipTests bool) []string { +func GenerateGradleArgs(task string, imageName string, a *latest.JibGradleArtifact, skipTests bool, insecureRegistries map[string]bool) []string { // disable jib's rich progress footer; we could use `--console=plain` // but it also disables colour which can be helpful args := []string{"-Djib.console=plain"} args = append(args, gradleCommand(a, task)...) + + if insecure, err := isOnInsecureRegistry(imageName, insecureRegistries); err == nil && insecure { + // jib doesn't support marking specific registries as insecure + args = append(args, "-Djib.allowInsecureRegistries=true") + } + args = append(args, "--image="+imageName) if skipTests { args = append(args, "-x", "test") diff --git a/pkg/skaffold/jib/jib_gradle_test.go b/pkg/skaffold/jib/jib_gradle_test.go index 9ae2467d949..9c7d7445d6b 100644 --- a/pkg/skaffold/jib/jib_gradle_test.go +++ b/pkg/skaffold/jib/jib_gradle_test.go @@ -164,18 +164,21 @@ func TestGetCommandGradle(t *testing.T) { func TestGenerateGradleArgs(t *testing.T) { tests := []struct { - in latest.JibGradleArtifact - skipTests bool - out []string + in latest.JibGradleArtifact + image string + skipTests bool + insecureRegistries map[string]bool + out []string }{ - {latest.JibGradleArtifact{}, false, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":task", "--image=image"}}, - {latest.JibGradleArtifact{Flags: []string{"-extra", "args"}}, false, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":task", "--image=image", "-extra", "args"}}, - {latest.JibGradleArtifact{}, true, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":task", "--image=image", "-x", "test"}}, - {latest.JibGradleArtifact{Project: "project"}, false, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":project:task", "--image=image"}}, - {latest.JibGradleArtifact{Project: "project"}, true, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":project:task", "--image=image", "-x", "test"}}, + {latest.JibGradleArtifact{}, "image", false, nil, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":task", "--image=image"}}, + {latest.JibGradleArtifact{Flags: []string{"-extra", "args"}}, "image", false, nil, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":task", "--image=image", "-extra", "args"}}, + {latest.JibGradleArtifact{}, "image", true, nil, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":task", "--image=image", "-x", "test"}}, + {latest.JibGradleArtifact{Project: "project"}, "image", false, nil, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":project:task", "--image=image"}}, + {latest.JibGradleArtifact{Project: "project"}, "image", true, nil, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":project:task", "--image=image", "-x", "test"}}, + {latest.JibGradleArtifact{Project: "project"}, "registry.tld/image", true, map[string]bool{"registry.tld": true}, []string{"-Djib.console=plain", "_skaffoldFailIfJibOutOfDate", "-Djib.requiredVersion=" + MinimumJibGradleVersion, ":project:task", "-Djib.allowInsecureRegistries=true", "--image=registry.tld/image", "-x", "test"}}, } for _, test := range tests { - command := GenerateGradleArgs("task", "image", &test.in, test.skipTests) + command := GenerateGradleArgs("task", test.image, &test.in, test.skipTests, test.insecureRegistries) testutil.CheckDeepEqual(t, test.out, command) } diff --git a/pkg/skaffold/jib/jib_init.go b/pkg/skaffold/jib/jib_init.go index bab53f2f56e..a1485adece3 100644 --- a/pkg/skaffold/jib/jib_init.go +++ b/pkg/skaffold/jib/jib_init.go @@ -35,13 +35,6 @@ var ( ValidateJibConfigFunc = ValidateJibConfig ) -const ( - // JibGradle the name of the Jib Gradle Plugin - JibGradle = "Jib Gradle Plugin" - // JibMaven the name of the Jib Maven Plugin - JibMaven = "Jib Maven Plugin" -) - // Jib holds information about a Jib project type Jib struct { BuilderName string `json:"-"` @@ -76,7 +69,7 @@ func (j Jib) CreateArtifact(manifestImage string) *latest.Artifact { a.Workspace = workspace } - if j.BuilderName == JibMaven { + if j.BuilderName == JibMaven.Name() { jibMaven := &latest.JibMavenArtifact{} if j.Project != "" { jibMaven.Module = j.Project @@ -86,7 +79,7 @@ func (j Jib) CreateArtifact(manifestImage string) *latest.Artifact { } a.ArtifactType = latest.ArtifactType{JibMavenArtifact: jibMaven} - } else if j.BuilderName == JibGradle { + } else if j.BuilderName == JibGradle.Name() { jibGradle := &latest.JibGradleArtifact{} if j.Project != "" { jibGradle.Project = j.Project @@ -119,7 +112,8 @@ type jibJSON struct { // ValidateJibConfig checks if a file is a valid Jib configuration. Returns the list of Config objects corresponding to each Jib project built by the file, or nil if Jib is not configured. func ValidateJibConfig(path string) []Jib { // Determine whether maven or gradle - var builderType, executable, wrapper, taskName string + var builderType PluginType + var executable, wrapper, taskName string switch { case strings.HasSuffix(path, "pom.xml"): builderType = JibMaven @@ -162,7 +156,7 @@ func ValidateJibConfig(path string) []Jib { return nil } - results[i] = Jib{BuilderName: builderType, Image: parsedJSON.Image, FilePath: path, Project: parsedJSON.Project} + results[i] = Jib{BuilderName: builderType.Name(), Image: parsedJSON.Image, FilePath: path, Project: parsedJSON.Project} } return results } diff --git a/pkg/skaffold/jib/jib_init_test.go b/pkg/skaffold/jib/jib_init_test.go index ac643d06cc8..12fae3a5302 100644 --- a/pkg/skaffold/jib/jib_init_test.go +++ b/pkg/skaffold/jib/jib_init_test.go @@ -53,7 +53,7 @@ func TestValidateJibConfig(t *testing.T) { {"image":"image","project":"project"} `, expectedConfig: []Jib{ - {BuilderName: JibGradle, FilePath: "path/to/build.gradle", Image: "image", Project: "project"}, + {BuilderName: JibGradle.Name(), FilePath: "path/to/build.gradle", Image: "image", Project: "project"}, }, }, { @@ -67,8 +67,8 @@ BEGIN JIB JSON {"project":"project2"} `, expectedConfig: []Jib{ - {BuilderName: JibGradle, FilePath: "path/to/build.gradle", Image: "image", Project: "project1"}, - {BuilderName: JibGradle, FilePath: "path/to/build.gradle", Project: "project2"}, + {BuilderName: JibGradle.Name(), FilePath: "path/to/build.gradle", Image: "image", Project: "project1"}, + {BuilderName: JibGradle.Name(), FilePath: "path/to/build.gradle", Project: "project2"}, }, }, { @@ -78,7 +78,7 @@ BEGIN JIB JSON stdout: `BEGIN JIB JSON {"image":"image","project":"project"}`, expectedConfig: []Jib{ - {BuilderName: JibMaven, FilePath: "path/to/pom.xml", Image: "image", Project: "project"}, + {BuilderName: JibMaven.Name(), FilePath: "path/to/pom.xml", Image: "image", Project: "project"}, }, }, { @@ -92,8 +92,8 @@ BEGIN JIB JSON {"project":"project2"} `, expectedConfig: []Jib{ - {BuilderName: JibMaven, FilePath: "path/to/pom.xml", Image: "image", Project: "project1"}, - {BuilderName: JibMaven, FilePath: "path/to/pom.xml", Project: "project2"}, + {BuilderName: JibMaven.Name(), FilePath: "path/to/pom.xml", Image: "image", Project: "project1"}, + {BuilderName: JibMaven.Name(), FilePath: "path/to/pom.xml", Project: "project2"}, }, }, } @@ -113,22 +113,22 @@ func TestDescribe(t *testing.T) { }{ { description: "gradle without project", - config: Jib{BuilderName: JibGradle, FilePath: "path/to/build.gradle"}, + config: Jib{BuilderName: JibGradle.Name(), FilePath: "path/to/build.gradle"}, expectedPrompt: "Jib Gradle Plugin (path/to/build.gradle)", }, { description: "gradle with project", - config: Jib{BuilderName: JibGradle, Project: "project", FilePath: "path/to/build.gradle"}, + config: Jib{BuilderName: JibGradle.Name(), Project: "project", FilePath: "path/to/build.gradle"}, expectedPrompt: "Jib Gradle Plugin (project, path/to/build.gradle)", }, { description: "maven without project", - config: Jib{BuilderName: JibMaven, FilePath: "path/to/pom.xml"}, + config: Jib{BuilderName: JibMaven.Name(), FilePath: "path/to/pom.xml"}, expectedPrompt: "Jib Maven Plugin (path/to/pom.xml)", }, { description: "maven with project", - config: Jib{BuilderName: JibMaven, Project: "project", FilePath: "path/to/pom.xml"}, + config: Jib{BuilderName: JibMaven.Name(), Project: "project", FilePath: "path/to/pom.xml"}, expectedPrompt: "Jib Maven Plugin (project, path/to/pom.xml)", }, } @@ -149,7 +149,7 @@ func TestCreateArtifact(t *testing.T) { }{ { description: "jib gradle with image and project", - config: Jib{BuilderName: JibGradle, FilePath: filepath.Join("path", "to", "build.gradle"), Image: "image", Project: "project"}, + config: Jib{BuilderName: JibGradle.Name(), FilePath: filepath.Join("path", "to", "build.gradle"), Image: "image", Project: "project"}, manifestImage: "different-image", expectedArtifact: latest.Artifact{ ImageName: "image", @@ -161,7 +161,7 @@ func TestCreateArtifact(t *testing.T) { }, { description: "jib gradle without image and project", - config: Jib{BuilderName: JibGradle, FilePath: filepath.Join("path", "to", "build.gradle")}, + config: Jib{BuilderName: JibGradle.Name(), FilePath: filepath.Join("path", "to", "build.gradle")}, manifestImage: "different-image", expectedArtifact: latest.Artifact{ ImageName: "different-image", @@ -175,7 +175,7 @@ func TestCreateArtifact(t *testing.T) { }, { description: "jib maven with image and project", - config: Jib{BuilderName: JibMaven, FilePath: filepath.Join("path", "to", "pom.xml"), Image: "image", Project: "project"}, + config: Jib{BuilderName: JibMaven.Name(), FilePath: filepath.Join("path", "to", "pom.xml"), Image: "image", Project: "project"}, manifestImage: "different-image", expectedArtifact: latest.Artifact{ ImageName: "image", @@ -187,7 +187,7 @@ func TestCreateArtifact(t *testing.T) { }, { description: "jib maven without image and project", - config: Jib{BuilderName: JibMaven, FilePath: filepath.Join("path", "to", "pom.xml")}, + config: Jib{BuilderName: JibMaven.Name(), FilePath: filepath.Join("path", "to", "pom.xml")}, manifestImage: "different-image", expectedArtifact: latest.Artifact{ ImageName: "different-image", @@ -201,7 +201,7 @@ func TestCreateArtifact(t *testing.T) { }, { description: "ignore workspace", - config: Jib{BuilderName: JibGradle, FilePath: "build.gradle", Image: "image"}, + config: Jib{BuilderName: JibGradle.Name(), FilePath: "build.gradle", Image: "image"}, manifestImage: "different-image", expectedArtifact: latest.Artifact{ ImageName: "image", diff --git a/pkg/skaffold/jib/jib_maven.go b/pkg/skaffold/jib/jib_maven.go index 16de4e7a99f..1ac7885d993 100644 --- a/pkg/skaffold/jib/jib_maven.go +++ b/pkg/skaffold/jib/jib_maven.go @@ -51,7 +51,7 @@ func getCommandMaven(ctx context.Context, workspace string, a *latest.JibMavenAr } // GenerateMavenArgs generates the arguments to Maven for building the project as an image. -func GenerateMavenArgs(goal string, imageName string, a *latest.JibMavenArtifact, skipTests bool) []string { +func GenerateMavenArgs(goal string, imageName string, a *latest.JibMavenArtifact, skipTests bool, insecureRegistries map[string]bool) []string { // disable jib's rich progress footer on builds; we could use --batch-mode // but it also disables colour which can be helpful args := []string{"-Djib.console=plain"} @@ -69,6 +69,10 @@ func GenerateMavenArgs(goal string, imageName string, a *latest.JibMavenArtifact args = append(args, "package", "jib:"+goal, "-Djib.containerize="+a.Module) } + if insecure, err := isOnInsecureRegistry(imageName, insecureRegistries); err == nil && insecure { + // jib doesn't support marking specific registries as insecure + args = append(args, "-Djib.allowInsecureRegistries=true") + } args = append(args, "-Dimage="+imageName) return args diff --git a/pkg/skaffold/jib/jib_maven_test.go b/pkg/skaffold/jib/jib_maven_test.go index fd061ecee05..e3ee1e0e908 100644 --- a/pkg/skaffold/jib/jib_maven_test.go +++ b/pkg/skaffold/jib/jib_maven_test.go @@ -189,21 +189,24 @@ func TestGetCommandMaven(t *testing.T) { func TestGenerateMavenArgs(t *testing.T) { tests := []struct { - in latest.JibMavenArtifact - skipTests bool - out []string + in latest.JibMavenArtifact + image string + skipTests bool + insecureRegistries map[string]bool + out []string }{ - {latest.JibMavenArtifact{}, false, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--non-recursive", "prepare-package", "jib:goal", "-Dimage=image"}}, - {latest.JibMavenArtifact{}, true, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--non-recursive", "-DskipTests=true", "prepare-package", "jib:goal", "-Dimage=image"}}, - {latest.JibMavenArtifact{Profile: "profile"}, false, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--non-recursive", "prepare-package", "jib:goal", "-Dimage=image"}}, - {latest.JibMavenArtifact{Profile: "profile"}, true, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--non-recursive", "-DskipTests=true", "prepare-package", "jib:goal", "-Dimage=image"}}, - {latest.JibMavenArtifact{Module: "module"}, false, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--projects", "module", "--also-make", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, - {latest.JibMavenArtifact{Module: "module"}, true, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--projects", "module", "--also-make", "-DskipTests=true", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, - {latest.JibMavenArtifact{Module: "module", Profile: "profile"}, false, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--projects", "module", "--also-make", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, - {latest.JibMavenArtifact{Module: "module", Profile: "profile"}, true, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--projects", "module", "--also-make", "-DskipTests=true", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, + {latest.JibMavenArtifact{}, "image", false, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--non-recursive", "prepare-package", "jib:goal", "-Dimage=image"}}, + {latest.JibMavenArtifact{}, "image", true, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--non-recursive", "-DskipTests=true", "prepare-package", "jib:goal", "-Dimage=image"}}, + {latest.JibMavenArtifact{Profile: "profile"}, "image", false, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--non-recursive", "prepare-package", "jib:goal", "-Dimage=image"}}, + {latest.JibMavenArtifact{Profile: "profile"}, "image", true, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--non-recursive", "-DskipTests=true", "prepare-package", "jib:goal", "-Dimage=image"}}, + {latest.JibMavenArtifact{Module: "module"}, "image", false, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--projects", "module", "--also-make", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, + {latest.JibMavenArtifact{Module: "module"}, "image", true, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--projects", "module", "--also-make", "-DskipTests=true", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, + {latest.JibMavenArtifact{Module: "module", Profile: "profile"}, "image", false, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--projects", "module", "--also-make", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, + {latest.JibMavenArtifact{Module: "module", Profile: "profile"}, "image", true, nil, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--projects", "module", "--also-make", "-DskipTests=true", "package", "jib:goal", "-Djib.containerize=module", "-Dimage=image"}}, + {latest.JibMavenArtifact{Module: "module", Profile: "profile"}, "registry.tld/image", true, map[string]bool{"registry.tld": true}, []string{"-Djib.console=plain", "jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + MinimumJibMavenVersion, "--activate-profiles", "profile", "--projects", "module", "--also-make", "-DskipTests=true", "package", "jib:goal", "-Djib.containerize=module", "-Djib.allowInsecureRegistries=true", "-Dimage=registry.tld/image"}}, } for _, test := range tests { - args := GenerateMavenArgs("goal", "image", &test.in, test.skipTests) + args := GenerateMavenArgs("goal", test.image, &test.in, test.skipTests, test.insecureRegistries) testutil.CheckDeepEqual(t, test.out, args) } diff --git a/pkg/skaffold/jib/jib_test.go b/pkg/skaffold/jib/jib_test.go index f2ee3a26842..ae80e13ed80 100644 --- a/pkg/skaffold/jib/jib_test.go +++ b/pkg/skaffold/jib/jib_test.go @@ -26,6 +26,13 @@ import ( "github.com/GoogleContainerTools/skaffold/testutil" ) +func TestPluginType(t *testing.T) { + testutil.CheckDeepEqual(t, "maven", JibMaven.ID()) + testutil.CheckDeepEqual(t, "Jib Maven Plugin", JibMaven.Name()) + testutil.CheckDeepEqual(t, "gradle", JibGradle.ID()) + testutil.CheckDeepEqual(t, "Jib Gradle Plugin", JibGradle.Name()) +} + func TestGetDependencies(t *testing.T) { tmpDir, cleanup := testutil.NewTempDir(t) defer cleanup() diff --git a/pkg/skaffold/kubectl/version.go b/pkg/skaffold/kubectl/version.go index 3cc1841880b..bfe76ae4731 100644 --- a/pkg/skaffold/kubectl/version.go +++ b/pkg/skaffold/kubectl/version.go @@ -23,10 +23,9 @@ import ( "strconv" "strings" - "github.com/pkg/errors" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings" + "github.com/pkg/errors" ) const unknown = "unknown" diff --git a/pkg/skaffold/kubectl/version_test.go b/pkg/skaffold/kubectl/version_test.go index f59cfea689f..9d0be318c52 100644 --- a/pkg/skaffold/kubectl/version_test.go +++ b/pkg/skaffold/kubectl/version_test.go @@ -20,44 +20,49 @@ import ( "context" "testing" - "github.com/pkg/errors" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings" "github.com/GoogleContainerTools/skaffold/testutil" + "github.com/pkg/errors" ) func TestCheckVersion(t *testing.T) { tests := []struct { - description string - command util.Command - shouldErr bool - warnings []string + description string + command util.Command + shouldErr bool + warnings []string + expectedVersion string }{ { - description: "1.12 is valid", - command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `{"clientVersion":{"major":"1","minor":"12"}}`), + description: "1.12 is valid", + command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `{"clientVersion":{"major":"1","minor":"12"}}`), + expectedVersion: "1.12", }, { - description: "1.12+ is valid", - command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `{"clientVersion":{"major":"1","minor":"12+"}}`), + description: "1.12+ is valid", + command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `{"clientVersion":{"major":"1","minor":"12+"}}`), + expectedVersion: "1.12+", }, { - description: "1.11 is too old", - command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `{"clientVersion":{"major":"1","minor":"11"}}`), - shouldErr: true, + description: "1.11 is too old", + command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `{"clientVersion":{"major":"1","minor":"11"}}`), + shouldErr: true, + expectedVersion: "1.11", }, { - description: "invalid version", - command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `not json`), - shouldErr: true, - warnings: []string{"unable to parse client version: invalid character 'o' in literal null (expecting 'u')"}, + description: "invalid version", + command: testutil.FakeRunOut(t, "kubectl version --client -ojson", `not json`), + shouldErr: true, + warnings: []string{"unable to parse client version: invalid character 'o' in literal null (expecting 'u')"}, + expectedVersion: "unknown", }, { - description: "cli not found", - command: testutil.FakeRunOutErr(t, "kubectl version --client -ojson", ``, errors.New("not found")), - shouldErr: true, - warnings: []string{"unable to get kubectl client version: not found"}, + description: "cli not found", + command: testutil.FakeRunOutErr(t, "kubectl version --client -ojson", ``, errors.New("not found")), + shouldErr: true, + warnings: []string{"unable to get kubectl client version: not found"}, + expectedVersion: "unknown", }, } for _, test := range tests { @@ -67,8 +72,11 @@ func TestCheckVersion(t *testing.T) { t.Override(&util.DefaultExecCommand, test.command) cli := CLI{} - err := cli.CheckVersion(context.Background()) + version := cli.Version(context.Background()).String() + t.CheckDeepEqual(test.expectedVersion, version) + + err := cli.CheckVersion(context.Background()) t.CheckErrorAndDeepEqual(test.shouldErr, err, test.warnings, fakeWarner.Warnings) }) } diff --git a/pkg/skaffold/kubernetes/owner.go b/pkg/skaffold/kubernetes/owner.go new file mode 100644 index 00000000000..d4b5e449afa --- /dev/null +++ b/pkg/skaffold/kubernetes/owner.go @@ -0,0 +1,73 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubernetes + +import ( + "fmt" + + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ( + // For testing + getClientSet = GetClientset +) + +// TopLevelOwnerKey returns a key associated with the top level +// owner of a Kubernetes resource in the form Kind-Name +func TopLevelOwnerKey(obj metav1.Object, kind string) string { + for { + or := obj.GetOwnerReferences() + if or == nil { + return fmt.Sprintf("%s-%s", kind, obj.GetName()) + } + var err error + kind = or[0].Kind + obj, err = ownerMetaObject(obj.GetNamespace(), or[0]) + if err != nil { + logrus.Warnf("unable to get owner from reference: %v", or[0]) + return "" + } + } +} + +func ownerMetaObject(ns string, owner metav1.OwnerReference) (metav1.Object, error) { + client, err := getClientSet() + if err != nil { + return nil, err + } + + switch owner.Kind { + case "Deployment": + return client.AppsV1().Deployments(ns).Get(owner.Name, metav1.GetOptions{}) + case "ReplicaSet": + return client.AppsV1().ReplicaSets(ns).Get(owner.Name, metav1.GetOptions{}) + case "Job": + return client.BatchV1().Jobs(ns).Get(owner.Name, metav1.GetOptions{}) + case "CronJob": + return client.BatchV1beta1().CronJobs(ns).Get(owner.Name, metav1.GetOptions{}) + case "StatefulSet": + return client.AppsV1().StatefulSets(ns).Get(owner.Name, metav1.GetOptions{}) + case "ReplicationController": + return client.CoreV1().ReplicationControllers(ns).Get(owner.Name, metav1.GetOptions{}) + case "Pod": + return client.CoreV1().Pods(ns).Get(owner.Name, metav1.GetOptions{}) + default: + return nil, fmt.Errorf("kind %s is not supported", owner.Kind) + } +} diff --git a/pkg/skaffold/kubernetes/owner_test.go b/pkg/skaffold/kubernetes/owner_test.go new file mode 100644 index 00000000000..6f9a00283a3 --- /dev/null +++ b/pkg/skaffold/kubernetes/owner_test.go @@ -0,0 +1,286 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubernetes + +import ( + "testing" + + v1 "k8s.io/api/core/v1" + + batchv1 "k8s.io/api/batch/v1" + batchv1beta1 "k8s.io/api/batch/v1beta1" + + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/GoogleContainerTools/skaffold/testutil" + "k8s.io/client-go/kubernetes" + fakekubeclientset "k8s.io/client-go/kubernetes/fake" +) + +func mockClient(m kubernetes.Interface) func() (kubernetes.Interface, error) { + return func() (kubernetes.Interface, error) { + return m, nil + } +} + +func TestTopLevelOwnerKey(t *testing.T) { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod", + Namespace: "ns", + OwnerReferences: []metav1.OwnerReference{ + { + Name: "rs", + Kind: "ReplicaSet", + }, + }, + }, + } + + rs := &appsv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rs", + Namespace: "ns", + OwnerReferences: []metav1.OwnerReference{ + { + Name: "dep", + Kind: "Deployment", + }, + }, + }, + } + + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dep", + Namespace: "ns", + }, + } + + tests := []struct { + description string + initialObject metav1.Object + kind string + objects []runtime.Object + expected string + }{ + { + description: "owner is two levels up", + initialObject: pod, + kind: "Pod", + objects: []runtime.Object{pod, rs, deployment}, + expected: "Deployment-dep", + }, { + description: "object is owner", + initialObject: deployment, + kind: "Deployment", + objects: []runtime.Object{pod, rs, deployment}, + expected: "Deployment-dep", + }, { + description: "error, owner doesn't exist", + initialObject: pod, + kind: "Pod", + objects: []runtime.Object{pod, rs}, + }, + } + + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + client := fakekubeclientset.NewSimpleClientset(test.objects...) + t.Override(&getClientSet, mockClient(client)) + actual := TopLevelOwnerKey(test.initialObject, test.kind) + t.CheckDeepEqual(test.expected, actual) + }) + } +} + +func TestOwnerMetaObject(t *testing.T) { + tests := []struct { + description string + or metav1.OwnerReference + objects []runtime.Object + expected metav1.Object + }{ + { + description: "getting a deployment", + or: metav1.OwnerReference{ + Kind: "Deployment", + Name: "dep", + }, + objects: []runtime.Object{ + &v1.Service{}, + &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dep", + Namespace: "ns", + }, + }, + &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dep", + Namespace: "ns2", + }, + }, + }, + expected: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dep", + Namespace: "ns", + }, + }, + }, { + description: "getting a replica set", + or: metav1.OwnerReference{ + Kind: "ReplicaSet", + Name: "rs", + }, + objects: []runtime.Object{ + &v1.Service{}, + &appsv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rs", + Namespace: "ns", + }, + }, + &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dep", + Namespace: "ns2", + }, + }, + }, + expected: &appsv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rs", + Namespace: "ns", + }, + }, + }, { + description: "getting a job", + or: metav1.OwnerReference{ + Kind: "Job", + Name: "job", + }, + objects: []runtime.Object{ + &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job", + Namespace: "ns", + }, + }, + }, + expected: &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job", + Namespace: "ns", + }, + }, + }, { + description: "getting a cronjob", + or: metav1.OwnerReference{ + Kind: "CronJob", + Name: "cj", + }, + objects: []runtime.Object{ + &batchv1beta1.CronJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cj", + Namespace: "ns", + }, + }, + }, + expected: &batchv1beta1.CronJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cj", + Namespace: "ns", + }, + }, + }, { + description: "getting a statefulset", + or: metav1.OwnerReference{ + Kind: "StatefulSet", + Name: "ss", + }, + objects: []runtime.Object{ + &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ss", + Namespace: "ns", + }, + }, + }, + expected: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ss", + Namespace: "ns", + }, + }, + }, { + description: "getting a replicationcontroller", + or: metav1.OwnerReference{ + Kind: "ReplicationController", + Name: "rc", + }, + objects: []runtime.Object{ + &v1.ReplicationController{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rc", + Namespace: "ns", + }, + }, + }, + expected: &v1.ReplicationController{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rc", + Namespace: "ns", + }, + }, + }, { + description: "getting a pod", + or: metav1.OwnerReference{ + Kind: "Pod", + Name: "po", + }, + objects: []runtime.Object{ + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "po", + Namespace: "ns", + }, + }, + }, + expected: &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "po", + Namespace: "ns", + }, + }, + }, + } + + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + client := fakekubeclientset.NewSimpleClientset(test.objects...) + t.Override(&getClientSet, mockClient(client)) + actual, err := ownerMetaObject("ns", test.or) + t.CheckNoError(err) + t.CheckDeepEqual(test.expected, actual) + }) + } +} diff --git a/pkg/skaffold/kubernetes/portforward/entry_manager_test.go b/pkg/skaffold/kubernetes/portforward/entry_manager_test.go index ed25d5e49a3..f58192029d0 100644 --- a/pkg/skaffold/kubernetes/portforward/entry_manager_test.go +++ b/pkg/skaffold/kubernetes/portforward/entry_manager_test.go @@ -52,13 +52,13 @@ func TestStop(t *testing.T) { Type: constants.Pod, Name: "resource", Namespace: "default", - }, "", "", "", 9000, false) + }, "", "", "", "", 9000, false) pfe2 := newPortForwardEntry(0, latest.PortForwardResource{ Type: constants.Pod, Name: "resource2", Namespace: "default", - }, "", "", "", 9001, false) + }, "", "", "", "", 9001, false) em := NewEntryManager(ioutil.Discard, nil) diff --git a/pkg/skaffold/kubernetes/portforward/kubectl_forwarder.go b/pkg/skaffold/kubernetes/portforward/kubectl_forwarder.go index 1722fa8bbad..c4937dac8fd 100644 --- a/pkg/skaffold/kubernetes/portforward/kubectl_forwarder.go +++ b/pkg/skaffold/kubernetes/portforward/kubectl_forwarder.go @@ -100,6 +100,7 @@ func (k *KubectlForwarder) forward(parentCtx context.Context, pfe *portForwardEn buf := &bytes.Buffer{} cmd := portForwardCmd(ctx, k.kubectl, pfe, buf) + logrus.Debugf("Running command: %s", cmd.Args) if err := cmd.Start(); err != nil { if ctx.Err() == context.Canceled { logrus.Debugf("couldn't start %v due to context cancellation", pfe) diff --git a/pkg/skaffold/kubernetes/portforward/kubectl_forwarder_test.go b/pkg/skaffold/kubernetes/portforward/kubectl_forwarder_test.go index 847dbe0c200..f2007deee79 100644 --- a/pkg/skaffold/kubernetes/portforward/kubectl_forwarder_test.go +++ b/pkg/skaffold/kubernetes/portforward/kubectl_forwarder_test.go @@ -55,7 +55,8 @@ func TestUnavailablePort(t *testing.T) { k := KubectlForwarder{ out: buf, } - pfe := newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", 8080, false) + pfe := newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", "", 8080, false) + k.Forward(context.Background(), pfe) // wait for isPortFree to be called @@ -77,7 +78,7 @@ func TestUnavailablePort(t *testing.T) { func TestTerminate(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - pfe := newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", 8080, false) + pfe := newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", "", 8080, false) pfe.cancel = cancel k := &KubectlForwarder{} diff --git a/pkg/skaffold/kubernetes/portforward/pod_forwarder.go b/pkg/skaffold/kubernetes/portforward/pod_forwarder.go index 159a2bf9f57..6c585bc20ed 100644 --- a/pkg/skaffold/kubernetes/portforward/pod_forwarder.go +++ b/pkg/skaffold/kubernetes/portforward/pod_forwarder.go @@ -33,6 +33,7 @@ import ( var ( // For testing aggregatePodWatcher = kubernetes.AggregatePodWatcher + topLevelOwnerKey = kubernetes.TopLevelOwnerKey ) // WatchingPodForwarder is responsible for selecting pods satisfying a certain condition and port-forwarding the exposed @@ -101,6 +102,7 @@ func (p *WatchingPodForwarder) Start(ctx context.Context) error { } func (p *WatchingPodForwarder) portForwardPod(ctx context.Context, pod *v1.Pod) error { + ownerReference := topLevelOwnerKey(pod, pod.Kind) for _, c := range pod.Spec.Containers { for _, port := range c.Ports { // get current entry for this container @@ -112,7 +114,7 @@ func (p *WatchingPodForwarder) portForwardPod(ctx context.Context, pod *v1.Pod) LocalPort: int(port.ContainerPort), } - entry, err := p.podForwardingEntry(pod.ResourceVersion, c.Name, port.Name, resource) + entry, err := p.podForwardingEntry(pod.ResourceVersion, c.Name, port.Name, ownerReference, resource) if err != nil { return errors.Wrap(err, "getting pod forwarding entry") } @@ -132,12 +134,12 @@ func (p *WatchingPodForwarder) portForwardPod(ctx context.Context, pod *v1.Pod) return nil } -func (p *WatchingPodForwarder) podForwardingEntry(resourceVersion, containerName, portName string, resource latest.PortForwardResource) (*portForwardEntry, error) { +func (p *WatchingPodForwarder) podForwardingEntry(resourceVersion, containerName, portName, ownerReference string, resource latest.PortForwardResource) (*portForwardEntry, error) { rv, err := strconv.Atoi(resourceVersion) if err != nil { return nil, errors.Wrap(err, "converting resource version to integer") } - entry := newPortForwardEntry(rv, resource, resource.Name, containerName, portName, 0, true) + entry := newPortForwardEntry(rv, resource, resource.Name, containerName, portName, ownerReference, 0, true) // If we have, return the current entry oldEntry, ok := p.forwardedResources.Load(entry.key()) diff --git a/pkg/skaffold/kubernetes/portforward/pod_forwarder_test.go b/pkg/skaffold/kubernetes/portforward/pod_forwarder_test.go index fd5ce3ca1b2..ed30fe0b627 100644 --- a/pkg/skaffold/kubernetes/portforward/pod_forwarder_test.go +++ b/pkg/skaffold/kubernetes/portforward/pod_forwarder_test.go @@ -52,7 +52,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { expectedPorts: map[int]struct{}{8080: {}}, availablePorts: []int{8080}, expectedEntries: map[string]*portForwardEntry{ - "containername-namespace-portname-8080": { + "owner-containername-namespace-portname-8080": { resourceVersion: 1, podName: "podname", containerName: "containername", @@ -63,6 +63,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 8080, LocalPort: 8080, }, + ownerReference: "owner", automaticPodForwarding: true, portName: "portname", localPort: 8080, @@ -96,7 +97,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { description: "unavailable container port", expectedPorts: map[int]struct{}{9000: {}}, expectedEntries: map[string]*portForwardEntry{ - "containername-namespace-portname-8080": { + "owner-containername-namespace-portname-8080": { resourceVersion: 1, podName: "podname", resource: latest.PortForwardResource{ @@ -106,6 +107,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 8080, LocalPort: 8080, }, + ownerReference: "owner", automaticPodForwarding: true, containerName: "containername", portName: "portname", @@ -171,7 +173,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { expectedPorts: map[int]struct{}{8080: {}, 50051: {}}, availablePorts: []int{8080, 50051}, expectedEntries: map[string]*portForwardEntry{ - "containername-namespace-portname-8080": { + "owner-containername-namespace-portname-8080": { resourceVersion: 1, podName: "podname", containerName: "containername", @@ -182,12 +184,13 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 8080, LocalPort: 8080, }, + ownerReference: "owner", portName: "portname", automaticPodForwarding: true, localPort: 8080, terminationLock: &sync.Mutex{}, }, - "containername2-namespace2-portname2-50051": { + "owner-containername2-namespace2-portname2-50051": { resourceVersion: 1, podName: "podname2", containerName: "containername2", @@ -198,6 +201,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 50051, LocalPort: 50051, }, + ownerReference: "owner", portName: "portname2", automaticPodForwarding: true, localPort: 50051, @@ -252,7 +256,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { expectedPorts: map[int]struct{}{8080: {}, 9000: {}}, availablePorts: []int{8080, 9000}, expectedEntries: map[string]*portForwardEntry{ - "containername-namespace-portname-8080": { + "owner-containername-namespace-portname-8080": { resourceVersion: 1, podName: "podname", containerName: "containername", @@ -264,11 +268,12 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 8080, LocalPort: 8080, }, + ownerReference: "owner", automaticPodForwarding: true, localPort: 8080, terminationLock: &sync.Mutex{}, }, - "containername2-namespace2-portname2-8080": { + "owner-containername2-namespace2-portname2-8080": { resourceVersion: 1, podName: "podname2", containerName: "containername2", @@ -280,6 +285,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 8080, LocalPort: 8080, }, + ownerReference: "owner", automaticPodForwarding: true, localPort: 9000, terminationLock: &sync.Mutex{}, @@ -333,7 +339,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { expectedPorts: map[int]struct{}{8080: {}}, availablePorts: []int{8080}, expectedEntries: map[string]*portForwardEntry{ - "containername-namespace-portname-8080": { + "owner-containername-namespace-portname-8080": { resourceVersion: 2, podName: "podname", containerName: "containername", @@ -345,6 +351,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { Port: 8080, LocalPort: 8080, }, + ownerReference: "owner", automaticPodForwarding: true, localPort: 8080, terminationLock: &sync.Mutex{}, @@ -400,6 +407,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { taken := map[int]struct{}{} t.Override(&retrieveAvailablePort, mockRetrieveAvailablePort(taken, test.availablePorts)) + t.Override(&topLevelOwnerKey, func(_ metav1.Object, _ string) string { return "owner" }) entryManager := EntryManager{ output: ioutil.Discard, @@ -425,7 +433,7 @@ func TestAutomaticPortForwardPod(t *testing.T) { actualForwardedResources := test.forwarder.forwardedResources.resources // cmp.Diff cannot access unexported fields, so use reflect.DeepEqual here directly if !reflect.DeepEqual(test.expectedEntries, actualForwardedResources) { - t.Errorf("Forwarded entries differs from expected entries. Expected: %s, Actual: %v", test.expectedEntries, actualForwardedResources) + t.Errorf("Forwarded entries differs from expected entries. Expected: %v, Actual: %v", test.expectedEntries, actualForwardedResources) } }) } @@ -475,6 +483,7 @@ func TestStartPodForwarder(t *testing.T) { }() return func() {}, nil }) + t.Override(&topLevelOwnerKey, func(_ metav1.Object, _ string) string { return "owner" }) imageList := kubernetes.NewImageList() imageList.Add("image") @@ -517,7 +526,7 @@ func TestStartPodForwarder(t *testing.T) { // wait for the pod resource to be forwarded err := wait.PollImmediate(10*time.Millisecond, 100*time.Millisecond, func() (bool, error) { - _, ok := fakeForwarder.forwardedResources.Load("mycontainer-default-myport-8080") + _, ok := fakeForwarder.forwardedResources.Load("owner-mycontainer-default-myport-8080") return ok, nil }) if err != nil && test.entryExpected { diff --git a/pkg/skaffold/kubernetes/portforward/port_forward_entry.go b/pkg/skaffold/kubernetes/portforward/port_forward_entry.go index bf2439ba6c4..17e0be6d6fd 100644 --- a/pkg/skaffold/kubernetes/portforward/port_forward_entry.go +++ b/pkg/skaffold/kubernetes/portforward/port_forward_entry.go @@ -30,6 +30,7 @@ type portForwardEntry struct { podName string containerName string portName string + ownerReference string localPort int automaticPodForwarding bool terminated bool @@ -38,13 +39,14 @@ type portForwardEntry struct { } // newPortForwardEntry returns a port forward entry. -func newPortForwardEntry(resourceVersion int, resource latest.PortForwardResource, podName, containerName, portName string, localPort int, automaticPodForwarding bool) *portForwardEntry { +func newPortForwardEntry(resourceVersion int, resource latest.PortForwardResource, podName, containerName, portName, ownerReference string, localPort int, automaticPodForwarding bool) *portForwardEntry { return &portForwardEntry{ resourceVersion: resourceVersion, resource: resource, podName: podName, containerName: containerName, portName: portName, + ownerReference: ownerReference, localPort: localPort, automaticPodForwarding: automaticPodForwarding, terminationLock: &sync.Mutex{}, @@ -56,7 +58,7 @@ func newPortForwardEntry(resourceVersion int, resource latest.PortForwardResourc // to be the same whenever pods restart func (p *portForwardEntry) key() string { if p.automaticPodForwarding { - return fmt.Sprintf("%s-%s-%s-%d", p.containerName, p.resource.Namespace, p.portName, p.resource.Port) + return fmt.Sprintf("%s-%s-%s-%s-%d", p.ownerReference, p.containerName, p.resource.Namespace, p.portName, p.resource.Port) } return fmt.Sprintf("%s-%s-%s-%d", p.resource.Type, p.resource.Name, p.resource.Namespace, p.resource.Port) } diff --git a/pkg/skaffold/kubernetes/portforward/port_forward_entry_test.go b/pkg/skaffold/kubernetes/portforward/port_forward_entry_test.go index 0e730bff31a..6d3237474ba 100644 --- a/pkg/skaffold/kubernetes/portforward/port_forward_entry_test.go +++ b/pkg/skaffold/kubernetes/portforward/port_forward_entry_test.go @@ -37,7 +37,7 @@ func TestPortForwardEntryKey(t *testing.T) { Name: "podName", Namespace: "default", Port: 8080, - }, "", "", "", 0, false), + }, "", "", "", "", 0, false), expected: "pod-podName-default-8080", }, { description: "entry for deploy", @@ -46,7 +46,7 @@ func TestPortForwardEntryKey(t *testing.T) { Name: "depName", Namespace: "namespace", Port: 9000, - }, "", "", "", 0, false), + }, "", "", "", "", 0, false), expected: "deployment-depName-namespace-9000", }, } @@ -79,8 +79,8 @@ func TestAutomaticPodForwardingKey(t *testing.T) { Name: "podName", Namespace: "default", Port: 8080, - }, "", "containerName", "portName", 0, true), - expected: "containerName-default-portName-8080", + }, "", "containerName", "portName", "owner", 0, true), + expected: "owner-containerName-default-portName-8080", }, } diff --git a/pkg/skaffold/kubernetes/portforward/port_forward_integration.go b/pkg/skaffold/kubernetes/portforward/port_forward_integration.go index fb6d885b183..6e41c5dfebe 100644 --- a/pkg/skaffold/kubernetes/portforward/port_forward_integration.go +++ b/pkg/skaffold/kubernetes/portforward/port_forward_integration.go @@ -42,7 +42,7 @@ func WhiteBoxPortForwardCycle(t *testing.T, kubectlCLI *kubectl.CLI, namespace s Name: "leeroy-web", Namespace: namespace, Port: 8080, - }, "", "dummy container", "", localPort, false) + }, "", "dummy container", "", "", localPort, false) defer em.Stop() em.forwardPortForwardEntry(ctx, pfe) em.Stop() diff --git a/pkg/skaffold/kubernetes/portforward/resource_forwarder.go b/pkg/skaffold/kubernetes/portforward/resource_forwarder.go index 985e275b527..608d08296aa 100644 --- a/pkg/skaffold/kubernetes/portforward/resource_forwarder.go +++ b/pkg/skaffold/kubernetes/portforward/resource_forwarder.go @@ -83,7 +83,7 @@ func (p *ResourceForwarder) portForwardResource(ctx context.Context, resource la func (p *ResourceForwarder) getCurrentEntry(resource latest.PortForwardResource) *portForwardEntry { // determine if we have seen this before - entry := newPortForwardEntry(0, resource, "", "", "", 0, false) + entry := newPortForwardEntry(0, resource, "", "", "", "", 0, false) // If we have, return the current entry oldEntry, ok := p.forwardedResources.Load(entry.key()) diff --git a/pkg/skaffold/kubernetes/portforward/resource_forwarder_test.go b/pkg/skaffold/kubernetes/portforward/resource_forwarder_test.go index 373b8921fac..0cb138eee13 100644 --- a/pkg/skaffold/kubernetes/portforward/resource_forwarder_test.go +++ b/pkg/skaffold/kubernetes/portforward/resource_forwarder_test.go @@ -161,7 +161,7 @@ func TestGetCurrentEntryFunc(t *testing.T) { Port: 8080, }, availablePorts: []int{8080}, - expected: newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", 8080, false), + expected: newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", "", 8080, false), }, { description: "port forward existing deployment", resource: latest.PortForwardResource{ @@ -181,7 +181,7 @@ func TestGetCurrentEntryFunc(t *testing.T) { localPort: 9000, }, }, - expected: newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", 9000, false), + expected: newPortForwardEntry(0, latest.PortForwardResource{}, "", "", "", "", 9000, false), }, } diff --git a/pkg/skaffold/runner/dev.go b/pkg/skaffold/runner/dev.go index 503cdbfeab8..64a7f602973 100644 --- a/pkg/skaffold/runner/dev.go +++ b/pkg/skaffold/runner/dev.go @@ -120,28 +120,38 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la defer r.forwarderManager.Stop() // Watch artifacts + start := time.Now() + color.Default.Fprintln(out, "Listing files to watch...") + for i := range artifacts { artifact := artifacts[i] if !r.runCtx.Opts.IsTargetImage(artifact) { continue } - if err := r.monitor.Register( - func() ([]string, error) { return r.builder.DependenciesForArtifact(ctx, artifact) }, - func(e filemon.Events) { - syncMap := func() (map[string][]string, error) { return r.builder.SyncMap(ctx, artifact) } - s, err := sync.NewItem(artifact, e, r.builds, r.runCtx.InsecureRegistries, syncMap) - switch { - case err != nil: - logrus.Warnf("error adding dirty artifact to changeset: %s", err.Error()) - case s != nil: - r.changeSet.AddResync(s) - default: - r.changeSet.AddRebuild(artifact) - } - }, - ); err != nil { - return errors.Wrapf(err, "watching files for artifact %s", artifact.ImageName) + color.Default.Fprintf(out, " - %s\n", artifact.ImageName) + + select { + case <-ctx.Done(): + return context.Canceled + default: + if err := r.monitor.Register( + func() ([]string, error) { return r.builder.DependenciesForArtifact(ctx, artifact) }, + func(e filemon.Events) { + syncMap := func() (map[string][]string, error) { return r.builder.SyncMap(ctx, artifact) } + s, err := sync.NewItem(artifact, e, r.builds, r.runCtx.InsecureRegistries, syncMap) + switch { + case err != nil: + logrus.Warnf("error adding dirty artifact to changeset: %s", err.Error()) + case s != nil: + r.changeSet.AddResync(s) + default: + r.changeSet.AddRebuild(artifact) + } + }, + ); err != nil { + return errors.Wrapf(err, "watching files for artifact %s", artifact.ImageName) + } } } @@ -169,6 +179,8 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la return errors.Wrapf(err, "watching skaffold configuration %s", r.runCtx.Opts.ConfigurationFile) } + color.Default.Fprintln(out, "List generated in", time.Since(start)) + // First build if _, err := r.BuildAndTest(ctx, out, artifacts); err != nil { return errors.Wrap(err, "exiting dev mode because first build failed") diff --git a/pkg/skaffold/runner/dev_test.go b/pkg/skaffold/runner/dev_test.go index 6f0ec7fc4a3..b93d97187cb 100644 --- a/pkg/skaffold/runner/dev_test.go +++ b/pkg/skaffold/runner/dev_test.go @@ -232,7 +232,7 @@ func TestDev(t *testing.T) { { Built: []string{"img2:2"}, Tested: []string{"img2:2"}, - Deployed: []string{"img2:2", "img1:1"}, + Deployed: []string{"img1:1", "img2:2"}, }, }, }, diff --git a/pkg/skaffold/runner/new.go b/pkg/skaffold/runner/new.go index 5fa0aaa4cda..6bdc072eee7 100644 --- a/pkg/skaffold/runner/new.go +++ b/pkg/skaffold/runner/new.go @@ -71,7 +71,8 @@ func NewForConfig(runCtx *runcontext.RunContext) (*SkaffoldRunner, error) { } defaultLabeller := deploy.NewLabeller("") - labellers := []deploy.Labeller{&runCtx.Opts, builder, deployer, tagger, defaultLabeller} + // runCtx.Opts is last to let users override/remove any label + labellers := []deploy.Labeller{builder, deployer, tagger, defaultLabeller, &runCtx.Opts} builder, tester, deployer = WithTimings(builder, tester, deployer, runCtx.Opts.CacheArtifacts) if runCtx.Opts.Notification { diff --git a/pkg/skaffold/runner/timings.go b/pkg/skaffold/runner/timings.go index 795fb38efed..c6f69bc44fa 100644 --- a/pkg/skaffold/runner/timings.go +++ b/pkg/skaffold/runner/timings.go @@ -88,8 +88,10 @@ func (w withTimings) Deploy(ctx context.Context, out io.Writer, builds []build.A dr := w.Deployer.Deploy(ctx, out, builds, labellers) if err := dr.GetError(); err != nil { - color.Default.Fprintln(out, "Deploy complete in", time.Since(start)) + return dr } + + color.Default.Fprintln(out, "Deploy complete in", time.Since(start)) return dr } diff --git a/pkg/skaffold/runner/timings_test.go b/pkg/skaffold/runner/timings_test.go new file mode 100644 index 00000000000..c71dad06a7f --- /dev/null +++ b/pkg/skaffold/runner/timings_test.go @@ -0,0 +1,237 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package runner + +import ( + "bytes" + "context" + "io" + "testing" + + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/test" + "github.com/GoogleContainerTools/skaffold/testutil" + "github.com/pkg/errors" +) + +type mockBuilder struct { + build.Builder + err bool +} + +func (m *mockBuilder) Build(context.Context, io.Writer, tag.ImageTags, []*latest.Artifact) ([]build.Artifact, error) { + if m.err { + return nil, errors.New("Unable to build") + } + return nil, nil +} + +func (m *mockBuilder) Prune(context.Context, io.Writer) error { + if m.err { + return errors.New("Unable to prune") + } + return nil +} + +type mockTester struct { + test.Tester + err bool +} + +func (m *mockTester) Test(context.Context, io.Writer, []build.Artifact) error { + if m.err { + return errors.New("Unable to test") + } + return nil +} + +type mockDeployer struct { + deploy.Deployer + err bool +} + +func (m *mockDeployer) Deploy(context.Context, io.Writer, []build.Artifact, []deploy.Labeller) *deploy.Result { + if m.err { + return deploy.NewDeployErrorResult(errors.New("Unable to deploy")) + } + return deploy.NewDeploySuccessResult(nil) +} + +func (m *mockDeployer) Cleanup(context.Context, io.Writer) error { + if m.err { + return errors.New("Unable to cleanup") + } + return nil +} + +func TestTimingsBuild(t *testing.T) { + tests := []struct { + description string + shouldOutput string + shouldErr bool + }{ + { + description: "build success", + shouldOutput: "(?m)^Starting build...\nBuild complete in .+$", + shouldErr: false, + }, + { + description: "build failure", + shouldOutput: "^Starting build...\n$", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + b := &mockBuilder{err: test.shouldErr} + builder, _, _ := WithTimings(b, nil, nil, false) + + var out bytes.Buffer + _, err := builder.Build(context.Background(), &out, nil, nil) + + t.CheckError(test.shouldErr, err) + t.CheckMatches(test.shouldOutput, out.String()) + }) + } +} + +func TestTimingsPrune(t *testing.T) { + tests := []struct { + description string + shouldOutput string + shouldErr bool + }{ + { + description: "test success", + shouldOutput: "(?m)^Pruning images...\nImage prune complete in .+$", + shouldErr: false, + }, + { + description: "test failure", + shouldOutput: "^Pruning images...\n$", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + b := &mockBuilder{err: test.shouldErr} + builder, _, _ := WithTimings(b, nil, nil, false) + + var out bytes.Buffer + err := builder.Prune(context.Background(), &out) + + t.CheckError(test.shouldErr, err) + t.CheckMatches(test.shouldOutput, out.String()) + }) + } +} + +func TestTimingsTest(t *testing.T) { + tests := []struct { + description string + shouldOutput string + shouldErr bool + }{ + { + description: "test success", + shouldOutput: "(?m)^Starting test...\nTest complete in .+$", + shouldErr: false, + }, + { + description: "test failure", + shouldOutput: "^Starting test...\n$", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + tt := &mockTester{err: test.shouldErr} + _, tester, _ := WithTimings(nil, tt, nil, false) + + var out bytes.Buffer + err := tester.Test(context.Background(), &out, nil) + + t.CheckError(test.shouldErr, err) + t.CheckMatches(test.shouldOutput, out.String()) + }) + } +} + +func TestTimingsDeploy(t *testing.T) { + tests := []struct { + description string + shouldOutput string + shouldErr bool + }{ + { + description: "prune success", + shouldOutput: "(?m)^Starting deploy...\nDeploy complete in .+$", + shouldErr: false, + }, + { + description: "prune failure", + shouldOutput: "^Starting deploy...\n$", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + d := &mockDeployer{err: test.shouldErr} + _, _, deployer := WithTimings(nil, nil, d, false) + + var out bytes.Buffer + res := deployer.Deploy(context.Background(), &out, nil, nil) + + t.CheckError(test.shouldErr, res.GetError()) + t.CheckMatches(test.shouldOutput, out.String()) + }) + } +} + +func TestTimingsCleanup(t *testing.T) { + tests := []struct { + description string + shouldOutput string + shouldErr bool + }{ + { + description: "cleanup success", + shouldOutput: "(?m)^Cleaning up...\nCleanup complete in .+$", + shouldErr: false, + }, + { + description: "cleanup failure", + shouldOutput: "^Cleaning up...\n$", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + d := &mockDeployer{err: test.shouldErr} + _, _, deployer := WithTimings(nil, nil, d, false) + + var out bytes.Buffer + err := deployer.Cleanup(context.Background(), &out) + + t.CheckError(test.shouldErr, err) + t.CheckMatches(test.shouldOutput, out.String()) + }) + } +} diff --git a/pkg/skaffold/schema/defaults/defaults.go b/pkg/skaffold/schema/defaults/defaults.go index e7029881996..201f5b783a9 100644 --- a/pkg/skaffold/schema/defaults/defaults.go +++ b/pkg/skaffold/schema/defaults/defaults.go @@ -19,7 +19,7 @@ package defaults import ( "fmt" - "github.com/mitchellh/go-homedir" + homedir "github.com/mitchellh/go-homedir" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -43,8 +43,11 @@ func Set(c *latest.SkaffoldConfig) error { ) if c.Build.Cluster != nil { - // All artifacts should be built with kaniko + // All artifacts should be built with kaniko or a custom command for _, a := range c.Build.Artifacts { + if a.CustomArtifact != nil { + continue + } setDefaultKanikoArtifact(a) setDefaultKanikoArtifactImage(a) setDefaultKanikoArtifactBuildContext(a) @@ -65,6 +68,7 @@ func Set(c *latest.SkaffoldConfig) error { setDefaultWorkspace(a) defaultToDockerArtifact(a) setDefaultDockerfile(a) + setDefaultCustomDependencies(a) } for _, pf := range c.PortForward { @@ -151,6 +155,14 @@ func setDefaultDockerfile(a *latest.Artifact) { } } +func setDefaultCustomDependencies(a *latest.Artifact) { + if a.CustomArtifact != nil { + if a.CustomArtifact.Dependencies == nil { + a.CustomArtifact.Dependencies = &latest.CustomDependencies{} + } + } +} + // SetDefaultDockerArtifact sets defaults on docker artifacts func SetDefaultDockerArtifact(a *latest.DockerArtifact) { a.DockerfilePath = valueOrDefault(a.DockerfilePath, constants.DefaultDockerfilePath) diff --git a/pkg/skaffold/schema/defaults/defaults_test.go b/pkg/skaffold/schema/defaults/defaults_test.go index dda45adefaa..09d72099cbb 100644 --- a/pkg/skaffold/schema/defaults/defaults_test.go +++ b/pkg/skaffold/schema/defaults/defaults_test.go @@ -42,6 +42,12 @@ func TestSetDefaults(t *testing.T) { }, }, }, + { + ImageName: "third", + ArtifactType: latest.ArtifactType{ + CustomArtifact: &latest.CustomArtifact{}, + }, + }, }, }, }, @@ -58,6 +64,10 @@ func TestSetDefaults(t *testing.T) { testutil.CheckDeepEqual(t, "second", cfg.Build.Artifacts[1].ImageName) testutil.CheckDeepEqual(t, "folder", cfg.Build.Artifacts[1].Workspace) testutil.CheckDeepEqual(t, "Dockerfile.second", cfg.Build.Artifacts[1].DockerArtifact.DockerfilePath) + + testutil.CheckDeepEqual(t, "third", cfg.Build.Artifacts[2].ImageName) + testutil.CheckDeepEqual(t, []string(nil), cfg.Build.Artifacts[2].CustomArtifact.Dependencies.Paths) + testutil.CheckDeepEqual(t, []string(nil), cfg.Build.Artifacts[2].CustomArtifact.Dependencies.Ignore) } func TestSetDefaultsOnCluster(t *testing.T) { @@ -115,6 +125,33 @@ func TestSetDefaultsOnCluster(t *testing.T) { }) } +func TestCustomBuildWithCluster(t *testing.T) { + cfg := &latest.SkaffoldConfig{ + Pipeline: latest.Pipeline{ + Build: latest.BuildConfig{ + Artifacts: []*latest.Artifact{ + { + ImageName: "image", + ArtifactType: latest.ArtifactType{ + CustomArtifact: &latest.CustomArtifact{ + BuildCommand: "./build.sh", + }, + }, + }, + }, + BuildType: latest.BuildType{ + Cluster: &latest.ClusterDetails{}, + }, + }, + }, + } + + err := Set(cfg) + + testutil.CheckError(t, false, err) + testutil.CheckDeepEqual(t, (*latest.KanikoArtifact)(nil), cfg.Build.Artifacts[0].KanikoArtifact) +} + func TestSetDefaultsOnCloudBuild(t *testing.T) { cfg := &latest.SkaffoldConfig{ Pipeline: latest.Pipeline{ diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go index 4b132fb548c..b3a69a54d3b 100644 --- a/pkg/skaffold/schema/latest/config.go +++ b/pkg/skaffold/schema/latest/config.go @@ -20,7 +20,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" ) -const Version string = "skaffold/v1beta13" +const Version string = "skaffold/v1beta14" // NewSkaffoldConfig creates a SkaffoldConfig func NewSkaffoldConfig() util.VersionedConfig { diff --git a/pkg/skaffold/schema/profiles.go b/pkg/skaffold/schema/profiles.go index 9c5a8cd0706..19060f5033f 100644 --- a/pkg/skaffold/schema/profiles.go +++ b/pkg/skaffold/schema/profiles.go @@ -27,6 +27,7 @@ import ( kubectx "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/context" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/yamltags" yamlpatch "github.com/krishicks/yaml-patch" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -148,17 +149,21 @@ func matches(expected, actual string) bool { func applyProfile(config *latest.SkaffoldConfig, profile latest.Profile) error { logrus.Infof("applying profile: %s", profile.Name) - // this intentionally removes the Profiles field from the returned config - *config = latest.SkaffoldConfig{ - APIVersion: config.APIVersion, - Kind: config.Kind, - Pipeline: latest.Pipeline{ - Build: overlayProfileField(config.Build, profile.Build).(latest.BuildConfig), - Deploy: overlayProfileField(config.Deploy, profile.Deploy).(latest.DeployConfig), - Test: overlayProfileField(config.Test, profile.Test).([]*latest.TestCase), - }, + // Apply profile, field by field + mergedV := reflect.Indirect(reflect.ValueOf(&config.Pipeline)) + configV := reflect.ValueOf(config.Pipeline) + profileV := reflect.ValueOf(profile.Pipeline) + + profileT := profileV.Type() + for i := 0; i < profileT.NumField(); i++ { + name := profileT.Field(i).Name + merged := overlayProfileField(name, configV.FieldByName(name).Interface(), profileV.FieldByName(name).Interface()) + mergedV.FieldByName(name).Set(reflect.ValueOf(merged)) } + // Remove the Profiles field from the returned config + config.Profiles = nil + if len(profile.Patches) == 0 { return nil } @@ -256,16 +261,16 @@ func overlayStructField(config interface{}, profile interface{}) interface{} { for i := 0; i < profileValue.NumField(); i++ { fieldType := t.Field(i) - overlay := overlayProfileField(configValue.Field(i).Interface(), profileValue.Field(i).Interface()) + overlay := overlayProfileField(yamltags.YamlName(fieldType), configValue.Field(i).Interface(), profileValue.Field(i).Interface()) finalConfig.Elem().FieldByName(fieldType.Name).Set(reflect.ValueOf(overlay)) } return reflect.Indirect(finalConfig).Interface() // since finalConfig is a pointer, dereference it } -func overlayProfileField(config interface{}, profile interface{}) interface{} { +func overlayProfileField(fieldName string, config interface{}, profile interface{}) interface{} { v := reflect.ValueOf(profile) // the profile itself t := reflect.TypeOf(profile) // the type of the profile, used for getting struct field types - logrus.Debugf("overlaying profile on config for field %s", t.Name()) + logrus.Debugf("overlaying profile on config for field %s", fieldName) switch v.Kind() { case reflect.Struct: // check the first field of the struct for a oneOf yamltag. @@ -291,7 +296,7 @@ func overlayProfileField(config interface{}, profile interface{}) interface{} { } return v.Interface() default: - logrus.Warnf("unknown field type in profile overlay: %s. falling back to original config values", v.Kind()) + logrus.Fatalf("Type mismatch in profile overlay for field '%s' with type %s; falling back to original config values", fieldName, v.Kind()) return config } } diff --git a/pkg/skaffold/schema/profiles_test.go b/pkg/skaffold/schema/profiles_test.go index 0a7b457a215..fd1866153b9 100644 --- a/pkg/skaffold/schema/profiles_test.go +++ b/pkg/skaffold/schema/profiles_test.go @@ -303,6 +303,39 @@ func TestApplyProfiles(t *testing.T) { }), ), }, + { + description: "port forwarding", + profile: "profile", + config: config( + withLocalBuild( + withGitTagger(), + ), + withProfiles(latest.Profile{ + Name: "profile", + Pipeline: latest.Pipeline{ + PortForward: []*latest.PortForwardResource{{ + Namespace: "ns", + Name: "name", + Type: "service", + Port: 8080, + LocalPort: 8888, + }}, + }, + }), + ), + expected: config( + withLocalBuild( + withGitTagger(), + ), + withPortForward(&latest.PortForwardResource{ + Namespace: "ns", + Name: "name", + Type: "service", + Port: 8080, + LocalPort: 8888, + }), + ), + }, } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { diff --git a/pkg/skaffold/schema/v1alpha2/upgrade.go b/pkg/skaffold/schema/v1alpha2/upgrade.go index abb4783af84..06a9458cda9 100644 --- a/pkg/skaffold/schema/v1alpha2/upgrade.go +++ b/pkg/skaffold/schema/v1alpha2/upgrade.go @@ -20,7 +20,6 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha3" pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" - "github.com/pkg/errors" ) // Upgrade upgrades a configuration to the next version. @@ -33,9 +32,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { // convert Deploy (should be the same) var newDeploy next.DeployConfig - if err := pkgutil.CloneThroughJSON(config.Deploy, &newDeploy); err != nil { - return nil, errors.Wrap(err, "converting deploy config") - } + pkgutil.CloneThroughJSON(config.Deploy, &newDeploy) + // if the helm deploy config was set, then convert ValueFilePath to ValuesFiles if oldHelmDeploy := config.Deploy.DeployType.HelmDeploy; oldHelmDeploy != nil { for i, oldHelmRelease := range oldHelmDeploy.Releases { @@ -48,9 +46,7 @@ func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { // convert Profiles (should be the same) var newProfiles []next.Profile if config.Profiles != nil { - if err := pkgutil.CloneThroughJSON(config.Profiles, &newProfiles); err != nil { - return nil, errors.Wrap(err, "converting new profile") - } + pkgutil.CloneThroughJSON(config.Profiles, &newProfiles) } // if the helm deploy config was set for a profile, then convert ValueFilePath to ValuesFiles @@ -70,9 +66,8 @@ func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { // copy over old build config to new build config var newBuild next.BuildConfig - if err := pkgutil.CloneThroughJSON(config.Build, &newBuild); err != nil { - return nil, errors.Wrap(err, "converting new build") - } + pkgutil.CloneThroughJSON(config.Build, &newBuild) + // if the kaniko build was set, then convert it if oldKanikoBuilder != nil { newBuild.BuildType.KanikoBuild = &next.KanikoBuild{ diff --git a/pkg/skaffold/schema/v1alpha3/upgrade.go b/pkg/skaffold/schema/v1alpha3/upgrade.go index 278e8e8a4c0..1a19078df00 100644 --- a/pkg/skaffold/schema/v1alpha3/upgrade.go +++ b/pkg/skaffold/schema/v1alpha3/upgrade.go @@ -20,7 +20,6 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha4" pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" - "github.com/pkg/errors" ) // Upgrade upgrades a configuration to the next version. @@ -43,16 +42,13 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { // convert Deploy (should be the same) var newDeploy next.DeployConfig - if err := pkgutil.CloneThroughJSON(config.Deploy, &newDeploy); err != nil { - return nil, errors.Wrap(err, "converting deploy config") - } + pkgutil.CloneThroughJSON(config.Deploy, &newDeploy) // convert Profiles (should be the same) var newProfiles []next.Profile if config.Profiles != nil { - if err := pkgutil.CloneThroughJSON(config.Profiles, &newProfiles); err != nil { - return nil, errors.Wrap(err, "converting new profile") - } + pkgutil.CloneThroughJSON(config.Profiles, &newProfiles) + for i, oldProfile := range config.Profiles { convertBuild(oldProfile.Build, newProfiles[i].Build) } @@ -61,9 +57,7 @@ func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { // convert Build (should be the same) var newBuild next.BuildConfig oldBuild := config.Build - if err := pkgutil.CloneThroughJSON(oldBuild, &newBuild); err != nil { - return nil, errors.Wrap(err, "converting new build") - } + pkgutil.CloneThroughJSON(oldBuild, &newBuild) convertBuild(oldBuild, newBuild) return &next.SkaffoldConfig{ diff --git a/pkg/skaffold/schema/v1alpha4/upgrade.go b/pkg/skaffold/schema/v1alpha4/upgrade.go index c921170e88a..1f3a4c6c5ee 100644 --- a/pkg/skaffold/schema/v1alpha4/upgrade.go +++ b/pkg/skaffold/schema/v1alpha4/upgrade.go @@ -32,8 +32,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1alpha5/upgrade.go b/pkg/skaffold/schema/v1alpha5/upgrade.go index 6961e4d0e4f..29c78d1c6d3 100644 --- a/pkg/skaffold/schema/v1alpha5/upgrade.go +++ b/pkg/skaffold/schema/v1alpha5/upgrade.go @@ -44,8 +44,8 @@ func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta1/upgrade.go b/pkg/skaffold/schema/v1beta1/upgrade.go index 7c1f645169d..c8a3d1b4f37 100644 --- a/pkg/skaffold/schema/v1beta1/upgrade.go +++ b/pkg/skaffold/schema/v1beta1/upgrade.go @@ -31,8 +31,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta10/upgrade.go b/pkg/skaffold/schema/v1beta10/upgrade.go index ffa447c3b06..62f893da957 100644 --- a/pkg/skaffold/schema/v1beta10/upgrade.go +++ b/pkg/skaffold/schema/v1beta10/upgrade.go @@ -23,7 +23,7 @@ import ( ) // Upgrade upgrades a configuration to the next version. -// Config changes from v1beta9 to v1beta10 +// Config changes from v1beta10 to v1beta11 // 1. Additions: // - GitTagger variants `TreeSha` and `AbbrevTreeSha` // 2. No removals @@ -31,8 +31,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta11/upgrade.go b/pkg/skaffold/schema/v1beta11/upgrade.go index 59f0ee8d98c..f439470c8e9 100644 --- a/pkg/skaffold/schema/v1beta11/upgrade.go +++ b/pkg/skaffold/schema/v1beta11/upgrade.go @@ -23,15 +23,15 @@ import ( ) // Upgrade upgrades a configuration to the next version. -// Config changes from v1beta9 to v1beta10 +// Config changes from v1beta11 to v1beta12 // 1. No Additions // 2. No removals // 3. No Updates func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta12/upgrade.go b/pkg/skaffold/schema/v1beta12/upgrade.go index a5c7d5205a4..457d94e9a33 100755 --- a/pkg/skaffold/schema/v1beta12/upgrade.go +++ b/pkg/skaffold/schema/v1beta12/upgrade.go @@ -17,21 +17,21 @@ limitations under the License. package v1beta12 import ( - next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" + next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta13" pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" ) // Upgrade upgrades a configuration to the next version. -// Config changes from v1beta9 to v1beta10 +// Config changes from v1beta12 to v1beta13 // 1. No Additions // 2. No removals // 3. No Updates func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta12/upgrade_test.go b/pkg/skaffold/schema/v1beta12/upgrade_test.go index 2bf81c45024..f772925c031 100755 --- a/pkg/skaffold/schema/v1beta12/upgrade_test.go +++ b/pkg/skaffold/schema/v1beta12/upgrade_test.go @@ -19,7 +19,7 @@ package v1beta12 import ( "testing" - next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" + next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta13" "github.com/GoogleContainerTools/skaffold/testutil" yaml "gopkg.in/yaml.v2" ) diff --git a/pkg/skaffold/schema/v1beta13/config.go b/pkg/skaffold/schema/v1beta13/config.go new file mode 100755 index 00000000000..5cf08646c11 --- /dev/null +++ b/pkg/skaffold/schema/v1beta13/config.go @@ -0,0 +1,772 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta13 + +import ( + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" +) + +const Version string = "skaffold/v1beta13" + +// NewSkaffoldConfig creates a SkaffoldConfig +func NewSkaffoldConfig() util.VersionedConfig { + return new(SkaffoldConfig) +} + +// SkaffoldConfig holds the fields parsed from the Skaffold configuration file (skaffold.yaml). +type SkaffoldConfig struct { + // APIVersion is the version of the configuration. + APIVersion string `yaml:"apiVersion" yamltags:"required"` + + // Kind is always `Config`. Defaults to `Config`. + Kind string `yaml:"kind" yamltags:"required"` + + // Metadata holds additional information about the config. + Metadata Metadata `yaml:"metadata,omitempty"` + + // Pipeline defines the Build/Test/Deploy phases. + Pipeline `yaml:",inline"` + + // Profiles *beta* can override be used to `build`, `test` or `deploy` configuration. + Profiles []Profile `yaml:"profiles,omitempty"` +} + +// Metadata holds an optional name of the project. +type Metadata struct { + // Name is an identifier for the project. + Name string `yaml:"name,omitempty"` +} + +// Pipeline describes a Skaffold pipeline. +type Pipeline struct { + // Build describes how images are built. + Build BuildConfig `yaml:"build,omitempty"` + + // Test describes how images are tested. + Test []*TestCase `yaml:"test,omitempty"` + + // Deploy describes how images are deployed. + Deploy DeployConfig `yaml:"deploy,omitempty"` + + // PortForward describes user defined resources to port-forward. + PortForward []*PortForwardResource `yaml:"portForward,omitempty"` +} + +func (c *SkaffoldConfig) GetVersion() string { + return c.APIVersion +} + +// ResourceType describes the Kubernetes resource types used for port forwarding. +type ResourceType string + +// PortForwardResource describes a resource to port forward. +type PortForwardResource struct { + // Type is the Kubernetes type that should be port forwarded. + // Acceptable resource types include: `Service`, `Pod` and Controller resource type that has a pod spec: `ReplicaSet`, `ReplicationController`, `Deployment`, `StatefulSet`, `DaemonSet`, `Job`, `CronJob`. + Type ResourceType `yaml:"resourceType,omitempty"` + + // Name is the name of the Kubernetes resource to port forward. + Name string `yaml:"resourceName,omitempty"` + + // Namespace is the namespace of the resource to port forward. + Namespace string `yaml:"namespace,omitempty"` + + // Port is the resource port that will be forwarded. + Port int `yaml:"port,omitempty"` + + // LocalPort is the local port to forward to. If the port is unavailable, Skaffold will choose a random open port to forward to. *Optional*. + LocalPort int `yaml:"localPort,omitempty"` +} + +// BuildConfig contains all the configuration for the build steps. +type BuildConfig struct { + // Artifacts lists the images you're going to be building. + Artifacts []*Artifact `yaml:"artifacts,omitempty"` + + // InsecureRegistries is a list of registries declared by the user to be insecure. + // These registries will be connected to via HTTP instead of HTTPS. + InsecureRegistries []string `yaml:"insecureRegistries,omitempty"` + + // TagPolicy *beta* determines how images are tagged. + // A few strategies are provided here, although you most likely won't need to care! + // If not specified, it defaults to `gitCommit: {variant: Tags}`. + TagPolicy TagPolicy `yaml:"tagPolicy,omitempty"` + + BuildType `yaml:",inline"` +} + +// TagPolicy contains all the configuration for the tagging step. +type TagPolicy struct { + // GitTagger *beta* tags images with the git tag or commit of the artifact's workspace. + GitTagger *GitTagger `yaml:"gitCommit,omitempty" yamltags:"oneOf=tag"` + + // ShaTagger *beta* tags images with their sha256 digest. + ShaTagger *ShaTagger `yaml:"sha256,omitempty" yamltags:"oneOf=tag"` + + // EnvTemplateTagger *beta* tags images with a configurable template string. + EnvTemplateTagger *EnvTemplateTagger `yaml:"envTemplate,omitempty" yamltags:"oneOf=tag"` + + // DateTimeTagger *beta* tags images with the build timestamp. + DateTimeTagger *DateTimeTagger `yaml:"dateTime,omitempty" yamltags:"oneOf=tag"` +} + +// ShaTagger *beta* tags images with their sha256 digest. +type ShaTagger struct{} + +// GitTagger *beta* tags images with the git tag or commit of the artifact's workspace. +type GitTagger struct { + // Variant determines the behavior of the git tagger. Valid variants are + // `Tags` (default): use git tags or fall back to abbreviated commit hash. + // `CommitSha`: use the full git commit sha. + // `AbbrevCommitSha`: use the abbreviated git commit sha. + // `TreeSha`: use the full tree hash of the artifact workingdir. + // `AbbrevTreeSha`: use the abbreviated tree hash of the artifact workingdir. + Variant string `yaml:"variant,omitempty"` +} + +// EnvTemplateTagger *beta* tags images with a configurable template string. +type EnvTemplateTagger struct { + // Template used to produce the image name and tag. + // See golang [text/template](https://golang.org/pkg/text/template/). + // The template is executed against the current environment, + // with those variables injected: + // IMAGE_NAME | Name of the image being built, as supplied in the artifacts section. + // For example: `{{.RELEASE}}-{{.IMAGE_NAME}}`. + Template string `yaml:"template,omitempty" yamltags:"required"` +} + +// DateTimeTagger *beta* tags images with the build timestamp. +type DateTimeTagger struct { + // Format formats the date and time. + // See [#Time.Format](https://golang.org/pkg/time/#Time.Format). + // Defaults to `2006-01-02_15-04-05.999_MST`. + Format string `yaml:"format,omitempty"` + + // TimeZone sets the timezone for the date and time. + // See [Time.LoadLocation](https://golang.org/pkg/time/#Time.LoadLocation). + // Defaults to the local timezone. + TimeZone string `yaml:"timezone,omitempty"` +} + +// BuildType contains the specific implementation and parameters needed +// for the build step. Only one field should be populated. +type BuildType struct { + // LocalBuild *beta* describes how to do a build on the local docker daemon + // and optionally push to a repository. + LocalBuild *LocalBuild `yaml:"local,omitempty" yamltags:"oneOf=build"` + + // GoogleCloudBuild *beta* describes how to do a remote build on + // [Google Cloud Build](https://cloud.google.com/cloud-build/). + GoogleCloudBuild *GoogleCloudBuild `yaml:"googleCloudBuild,omitempty" yamltags:"oneOf=build"` + + // Cluster *beta* describes how to do an on-cluster build. + Cluster *ClusterDetails `yaml:"cluster,omitempty" yamltags:"oneOf=build"` +} + +// LocalBuild *beta* describes how to do a build on the local docker daemon +// and optionally push to a repository. +type LocalBuild struct { + // Push should images be pushed to a registry. + // If not specified, images are pushed only if the current Kubernetes context + // connects to a remote cluster. + Push *bool `yaml:"push,omitempty"` + + // UseDockerCLI use `docker` command-line interface instead of Docker Engine APIs. + UseDockerCLI bool `yaml:"useDockerCLI,omitempty"` + + // UseBuildkit use BuildKit to build Docker images. + UseBuildkit bool `yaml:"useBuildkit,omitempty"` +} + +// GoogleCloudBuild *beta* describes how to do a remote build on +// [Google Cloud Build](https://cloud.google.com/cloud-build/docs/). +// Docker and Jib artifacts can be built on Cloud Build. The `projectId` needs +// to be provided and the currently logged in user should be given permissions to trigger +// new builds. +type GoogleCloudBuild struct { + // ProjectID is the ID of your Cloud Platform Project. + // If it is not provided, Skaffold will guess it from the image name. + // For example, given the artifact image name `gcr.io/myproject/image`, Skaffold + // will use the `myproject` GCP project. + ProjectID string `yaml:"projectId,omitempty"` + + // DiskSizeGb is the disk size of the VM that runs the build. + // See [Cloud Build Reference](https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds#buildoptions). + DiskSizeGb int64 `yaml:"diskSizeGb,omitempty"` + + // MachineType is the type of the VM that runs the build. + // See [Cloud Build Reference](https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds#buildoptions). + MachineType string `yaml:"machineType,omitempty"` + + // Timeout is the amount of time (in seconds) that this build should be allowed to run. + // See [Cloud Build Reference](https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.builds#resource-build). + Timeout string `yaml:"timeout,omitempty"` + + // DockerImage is the image that runs a Docker build. + // See [Cloud Builders](https://cloud.google.com/cloud-build/docs/cloud-builders). + // Defaults to `gcr.io/cloud-builders/docker`. + DockerImage string `yaml:"dockerImage,omitempty"` + + // MavenImage is the image that runs a Maven build. + // See [Cloud Builders](https://cloud.google.com/cloud-build/docs/cloud-builders). + // Defaults to `gcr.io/cloud-builders/mvn`. + MavenImage string `yaml:"mavenImage,omitempty"` + + // GradleImage is the image that runs a Gradle build. + // See [Cloud Builders](https://cloud.google.com/cloud-build/docs/cloud-builders). + // Defaults to `gcr.io/cloud-builders/gradle`. + GradleImage string `yaml:"gradleImage,omitempty"` +} + +// LocalDir configures how Kaniko mounts sources directly via an `emptyDir` volume. +type LocalDir struct { + // InitImage is the image used to run init container which mounts kaniko context. + InitImage string `yaml:"initImage,omitempty"` +} + +// KanikoBuildContext contains the different fields available to specify +// a Kaniko build context. +type KanikoBuildContext struct { + // GCSBucket is the GCS bucket to which sources are uploaded. + // Kaniko will need access to that bucket to download the sources. + GCSBucket string `yaml:"gcsBucket,omitempty" yamltags:"oneOf=buildContext"` + + // LocalDir configures how Kaniko mounts sources directly via an `emptyDir` volume. + LocalDir *LocalDir `yaml:"localDir,omitempty" yamltags:"oneOf=buildContext"` +} + +// KanikoCache configures Kaniko caching. If a cache is specified, Kaniko will +// use a remote cache which will speed up builds. +type KanikoCache struct { + // Repo is a remote repository to store cached layers. If none is specified, one will be + // inferred from the image name. See [Kaniko Caching](https://github.com/GoogleContainerTools/kaniko#caching). + Repo string `yaml:"repo,omitempty"` + // HostPath specifies a path on the host that is mounted to each pod as read only cache volume containing base images. + // If set, must exist on each node and prepopulated with kaniko-warmer. + HostPath string `yaml:"hostPath,omitempty"` +} + +// ClusterDetails *beta* describes how to do an on-cluster build. +type ClusterDetails struct { + // HTTPProxy for kaniko pod. + HTTPProxy string `yaml:"HTTP_PROXY,omitempty"` + + // HTTPSProxy for kaniko pod. + HTTPSProxy string `yaml:"HTTPS_PROXY,omitempty"` + + // PullSecret is the path to the Google Cloud service account secret key file. + PullSecret string `yaml:"pullSecret,omitempty"` + + // PullSecretName is the name of the Kubernetes secret for pulling the files + // from the build context and pushing the final image. If given, the secret needs to + // contain the Google Cloud service account secret key under the key `kaniko-secret`. + // Defaults to `kaniko-secret`. + PullSecretName string `yaml:"pullSecretName,omitempty"` + + // Namespace is the Kubernetes namespace. + // Defaults to current namespace in Kubernetes configuration. + Namespace string `yaml:"namespace,omitempty"` + + // Timeout is the amount of time (in seconds) that this build is allowed to run. + // Defaults to 20 minutes (`20m`). + Timeout string `yaml:"timeout,omitempty"` + + // DockerConfig describes how to mount the local Docker configuration into a pod. + DockerConfig *DockerConfig `yaml:"dockerConfig,omitempty"` + + // Resources define the resource requirements for the kaniko pod. + Resources *ResourceRequirements `yaml:"resources,omitempty"` +} + +// DockerConfig contains information about the docker `config.json` to mount. +type DockerConfig struct { + // Path is the path to the docker `config.json`. + Path string `yaml:"path,omitempty"` + + // SecretName is the Kubernetes secret that contains the `config.json` Docker configuration. + // Note that the expected secret type is not 'kubernetes.io/dockerconfigjson' but 'Opaque'. + SecretName string `yaml:"secretName,omitempty"` +} + +// ResourceRequirements describes the resource requirements for the kaniko pod. +type ResourceRequirements struct { + // Requests [resource requests](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) for the Kaniko pod. + Requests *ResourceRequirement `yaml:"requests,omitempty"` + + // Limits [resource limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) for the Kaniko pod. + Limits *ResourceRequirement `yaml:"limits,omitempty"` +} + +// ResourceRequirement stores the CPU/Memory requirements for the pod. +type ResourceRequirement struct { + // CPU the number cores to be used. + // For example: `2`, `2.0` or `200m`. + CPU string `yaml:"cpu,omitempty"` + + // Memory the amount of memory to allocate to the pod. + // For example: `1Gi` or `1000Mi`. + Memory string `yaml:"memory,omitempty"` +} + +// TestCase is a list of structure tests to run on images that Skaffold builds. +type TestCase struct { + // ImageName is the artifact on which to run those tests. + // For example: `gcr.io/k8s-skaffold/example`. + ImageName string `yaml:"image" yamltags:"required"` + + // StructureTests lists the [Container Structure Tests](https://github.com/GoogleContainerTools/container-structure-test) + // to run on that artifact. + // For example: `["./test/*"]`. + StructureTests []string `yaml:"structureTests,omitempty"` +} + +// DeployConfig contains all the configuration needed by the deploy steps. +type DeployConfig struct { + // StatusCheckDeadlineSeconds *beta* is the deadline for deployments to stabilize in seconds. + StatusCheckDeadlineSeconds int `yaml:"statusCheckDeadlineSeconds,omitempty"` + DeployType `yaml:",inline"` +} + +// DeployType contains the specific implementation and parameters needed +// for the deploy step. Only one field should be populated. +type DeployType struct { + // HelmDeploy *beta* uses the `helm` CLI to apply the charts to the cluster. + HelmDeploy *HelmDeploy `yaml:"helm,omitempty" yamltags:"oneOf=deploy"` + + // KubectlDeploy *beta* uses a client side `kubectl apply` to deploy manifests. + // You'll need a `kubectl` CLI version installed that's compatible with your cluster. + KubectlDeploy *KubectlDeploy `yaml:"kubectl,omitempty" yamltags:"oneOf=deploy"` + + // KustomizeDeploy *beta* uses the `kustomize` CLI to "patch" a deployment for a target environment. + KustomizeDeploy *KustomizeDeploy `yaml:"kustomize,omitempty" yamltags:"oneOf=deploy"` +} + +// KubectlDeploy *beta* uses a client side `kubectl apply` to deploy manifests. +// You'll need a `kubectl` CLI version installed that's compatible with your cluster. +type KubectlDeploy struct { + // Manifests lists the Kubernetes yaml or json manifests. + // Defaults to `["k8s/*.yaml"]`. + Manifests []string `yaml:"manifests,omitempty"` + + // RemoteManifests lists Kubernetes manifests in remote clusters. + RemoteManifests []string `yaml:"remoteManifests,omitempty"` + + // Flags are additional flags passed to `kubectl`. + Flags KubectlFlags `yaml:"flags,omitempty"` +} + +// KubectlFlags are additional flags passed on the command +// line to kubectl either on every command (Global), on creations (Apply) +// or deletions (Delete). +type KubectlFlags struct { + // Global are additional flags passed on every command. + Global []string `yaml:"global,omitempty"` + + // Apply are additional flags passed on creations (`kubectl apply`). + Apply []string `yaml:"apply,omitempty"` + + // Delete are additional flags passed on deletions (`kubectl delete`). + Delete []string `yaml:"delete,omitempty"` +} + +// HelmDeploy *beta* uses the `helm` CLI to apply the charts to the cluster. +type HelmDeploy struct { + // Releases is a list of Helm releases. + Releases []HelmRelease `yaml:"releases,omitempty" yamltags:"required"` + + // Flags are additional option flags that are passed on the command + // line to `helm`. + Flags HelmDeployFlags `yaml:"flags,omitempty"` +} + +// HelmDeployFlags are additional option flags that are passed on the command +// line to `helm`. +type HelmDeployFlags struct { + // Global are additional flags passed on every command. + Global []string `yaml:"global,omitempty"` + + // Install are additional flags passed to (`helm install`). + Install []string `yaml:"install,omitempty"` + + // Upgrade are additional flags passed to (`helm upgrade`). + Upgrade []string `yaml:"upgrade,omitempty"` +} + +// KustomizeDeploy *beta* uses the `kustomize` CLI to "patch" a deployment for a target environment. +type KustomizeDeploy struct { + // KustomizePath is the path to Kustomization files. + // Defaults to `.`. + KustomizePath string `yaml:"path,omitempty"` + + // Flags are additional flags passed to `kubectl`. + Flags KubectlFlags `yaml:"flags,omitempty"` +} + +// HelmRelease describes a helm release to be deployed. +type HelmRelease struct { + // Name is the name of the Helm release. + Name string `yaml:"name,omitempty" yamltags:"required"` + + // ChartPath is the path to the Helm chart. + ChartPath string `yaml:"chartPath,omitempty" yamltags:"required"` + + // ValuesFiles are the paths to the Helm `values` files. + ValuesFiles []string `yaml:"valuesFiles,omitempty"` + + // Values are key-value pairs supplementing the Helm `values` file. + Values map[string]string `yaml:"values,omitempty,omitempty"` + + // Namespace is the Kubernetes namespace. + Namespace string `yaml:"namespace,omitempty"` + + // Version is the version of the chart. + Version string `yaml:"version,omitempty"` + + // SetValues are key-value pairs. + // If present, Skaffold will send `--set` flag to Helm CLI and append all pairs after the flag. + SetValues map[string]string `yaml:"setValues,omitempty"` + + // SetValueTemplates are key-value pairs. + // If present, Skaffold will try to parse the value part of each key-value pair using + // environment variables in the system, then send `--set` flag to Helm CLI and append + // all parsed pairs after the flag. + SetValueTemplates map[string]string `yaml:"setValueTemplates,omitempty"` + + // Wait if `true`, Skaffold will send `--wait` flag to Helm CLI. + // Defaults to `false`. + Wait bool `yaml:"wait,omitempty"` + + // RecreatePods if `true`, Skaffold will send `--recreate-pods` flag to Helm CLI. + // Defaults to `false`. + RecreatePods bool `yaml:"recreatePods,omitempty"` + + // SkipBuildDependencies should build dependencies be skipped. + SkipBuildDependencies bool `yaml:"skipBuildDependencies,omitempty"` + + // UseHelmSecrets instructs skaffold to use secrets plugin on deployment. + UseHelmSecrets bool `yaml:"useHelmSecrets,omitempty"` + + // Remote specifies whether the chart path is remote, or exists on the host filesystem. + // `remote: true` implies `skipBuildDependencies: true`. + Remote bool `yaml:"remote,omitempty"` + + // Overrides are key-value pairs. + // If present, Skaffold will build a Helm `values` file that overrides + // the original and use it to call Helm CLI (`--f` flag). + Overrides util.HelmOverrides `yaml:"overrides,omitempty"` + + // Packaged parameters for packaging helm chart (`helm package`). + Packaged *HelmPackaged `yaml:"packaged,omitempty"` + + // ImageStrategy adds image configurations to the Helm `values` file. + ImageStrategy HelmImageStrategy `yaml:"imageStrategy,omitempty"` +} + +// HelmPackaged parameters for packaging helm chart (`helm package`). +type HelmPackaged struct { + // Version sets the `version` on the chart to this semver version. + Version string `yaml:"version,omitempty"` + + // AppVersion sets the `appVersion` on the chart to this version. + AppVersion string `yaml:"appVersion,omitempty"` +} + +// HelmImageStrategy adds image configurations to the Helm `values` file. +type HelmImageStrategy struct { + HelmImageConfig `yaml:",inline"` +} + +// HelmImageConfig describes an image configuration. +type HelmImageConfig struct { + // HelmFQNConfig is the image configuration uses the syntax `IMAGE-NAME=IMAGE-REPOSITORY:IMAGE-TAG`. + HelmFQNConfig *HelmFQNConfig `yaml:"fqn,omitempty" yamltags:"oneOf=helmImageStrategy"` + + // HelmConventionConfig is the image configuration uses the syntax `IMAGE-NAME.repository=IMAGE-REPOSITORY, IMAGE-NAME.tag=IMAGE-TAG`. + HelmConventionConfig *HelmConventionConfig `yaml:"helm,omitempty" yamltags:"oneOf=helmImageStrategy"` +} + +// HelmFQNConfig is the image config to use the FullyQualifiedImageName as param to set. +type HelmFQNConfig struct { + // Property defines the image config. + Property string `yaml:"property,omitempty"` +} + +// HelmConventionConfig is the image config in the syntax of image.repository and image.tag. +type HelmConventionConfig struct { + // ExplicitRegistry separates `image.registry` to the image config syntax. Useful for some charts e.g. `postgresql`. + ExplicitRegistry bool `yaml:"explicitRegistry,omitempty"` +} + +// Artifact are the items that need to be built, along with the context in which +// they should be built. +type Artifact struct { + // ImageName is the name of the image to be built. + // For example: `gcr.io/k8s-skaffold/example`. + ImageName string `yaml:"image,omitempty" yamltags:"required"` + + // Workspace is the directory containing the artifact's sources. + // Defaults to `.`. + Workspace string `yaml:"context,omitempty"` + + // Sync *alpha* lists local files synced to pods instead + // of triggering an image build when modified. + Sync *Sync `yaml:"sync,omitempty"` + + // ArtifactType describes how to build an artifact. + ArtifactType `yaml:",inline"` +} + +// Sync *alpha* specifies what files to sync into the container. +// This is a list of sync rules indicating the intent to sync for source files. +type Sync struct { + // Manual lists manual sync rules indicating the source and destination. + Manual []*SyncRule `yaml:"manual,omitempty" yamltags:"oneOf=sync"` + + // Infer lists file patterns which may be synced into the container. + // The container destination is inferred by the builder. + // Currently only available for docker artifacts. + Infer []string `yaml:"infer,omitempty" yamltags:"oneOf=sync"` +} + +// SyncRule specifies which local files to sync to remote folders. +type SyncRule struct { + // Src is a glob pattern to match local paths against. + // Directories should be delimited by `/` on all platforms. + // For example: `"css/**/*.css"`. + Src string `yaml:"src,omitempty" yamltags:"required"` + + // Dest is the destination path in the container where the files should be synced to. + // For example: `"app/"` + Dest string `yaml:"dest,omitempty" yamltags:"required"` + + // Strip specifies the path prefix to remove from the source path when + // transplanting the files into the destination folder. + // For example: `"css/"` + Strip string `yaml:"strip,omitempty"` +} + +// Profile *beta* profiles are used to override any `build`, `test` or `deploy` configuration. +type Profile struct { + // Name is a unique profile name. + // For example: `profile-prod`. + Name string `yaml:"name,omitempty" yamltags:"required"` + + // Pipeline contains the definitions to replace the default skaffold pipeline. + Pipeline `yaml:",inline"` + + // Patches lists patches applied to the configuration. + // Patches use the JSON patch notation. + Patches []JSONPatch `yaml:"patches,omitempty"` + + // Activation criteria by which a profile can be auto-activated. + // The profile is auto-activated if any one of the activations are triggered. + // An activation is triggered if all of the criteria (env, kubeContext, command) are triggered. + Activation []Activation `yaml:"activation,omitempty"` +} + +// JSONPatch patch to be applied by a profile. +type JSONPatch struct { + // Op is the operation carried by the patch: `add`, `remove`, `replace`, `move`, `copy` or `test`. + // Defaults to `replace`. + Op string `yaml:"op,omitempty"` + + // Path is the position in the yaml where the operation takes place. + // For example, this targets the `dockerfile` of the first artifact built. + // For example: `/build/artifacts/0/docker/dockerfile`. + Path string `yaml:"path,omitempty" yamltags:"required"` + + // From is the source position in the yaml, used for `copy` or `move` operations. + From string `yaml:"from,omitempty"` + + // Value is the value to apply. Can be any portion of yaml. + Value *util.YamlpatchNode `yaml:"value,omitempty"` +} + +// Activation criteria by which a profile is auto-activated. +type Activation struct { + // Env is a `key=value` pair. The profile is auto-activated if an Environment + // Variable `key` has value `value`. + // For example: `ENV=production`. + Env string `yaml:"env,omitempty"` + + // KubeContext is a Kubernetes context for which the profile is auto-activated. + // For example: `minikube`. + KubeContext string `yaml:"kubeContext,omitempty"` + + // Command is a Skaffold command for which the profile is auto-activated. + // For example: `dev`. + Command string `yaml:"command,omitempty"` +} + +// ArtifactType describes how to build an artifact. +type ArtifactType struct { + // DockerArtifact *beta* describes an artifact built from a Dockerfile. + DockerArtifact *DockerArtifact `yaml:"docker,omitempty" yamltags:"oneOf=artifact"` + + // BazelArtifact *beta* requires bazel CLI to be installed and the sources to + // contain [Bazel](https://bazel.build/) configuration files. + BazelArtifact *BazelArtifact `yaml:"bazel,omitempty" yamltags:"oneOf=artifact"` + + // JibMavenArtifact *alpha* builds images using the + // [Jib plugin for Maven](https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin). + JibMavenArtifact *JibMavenArtifact `yaml:"jibMaven,omitempty" yamltags:"oneOf=artifact"` + + // JibGradleArtifact *alpha* builds images using the + // [Jib plugin for Gradle](https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin). + JibGradleArtifact *JibGradleArtifact `yaml:"jibGradle,omitempty" yamltags:"oneOf=artifact"` + + // KanikoArtifact *alpha* builds images using [kaniko](https://github.com/GoogleContainerTools/kaniko). + KanikoArtifact *KanikoArtifact `yaml:"kaniko,omitempty" yamltags:"oneOf=artifact"` + + // CustomArtifact *alpha* builds images using a custom build script written by the user. + CustomArtifact *CustomArtifact `yaml:"custom,omitempty" yamltags:"oneOf=artifact"` +} + +// CustomArtifact *alpha* describes an artifact built from a custom build script +// written by the user. It can be used to build images with builders that aren't directly integrated with skaffold. +type CustomArtifact struct { + // BuildCommand is the command executed to build the image. + BuildCommand string `yaml:"buildCommand,omitempty"` + // Dependencies are the file dependencies that skaffold should watch for both rebuilding and file syncing for this artifact. + Dependencies *CustomDependencies `yaml:"dependencies,omitempty"` +} + +// CustomDependencies *alpha* is used to specify dependencies for an artifact built by a custom build script. +// Either `dockerfile` or `paths` should be specified for file watching to work as expected. +type CustomDependencies struct { + // Dockerfile should be set if the artifact is built from a Dockerfile, from which skaffold can determine dependencies. + Dockerfile *DockerfileDependency `yaml:"dockerfile,omitempty" yamltags:"oneOf=dependency"` + // Command represents a custom command that skaffold executes to obtain dependencies. The output of this command *must* be a valid JSON array. + Command string `yaml:"command,omitempty" yamltags:"oneOf=dependency"` + // Paths should be set to the file dependencies for this artifact, so that the skaffold file watcher knows when to rebuild and perform file synchronization. + Paths []string `yaml:"paths,omitempty" yamltags:"oneOf=dependency"` + // Ignore specifies the paths that should be ignored by skaffold's file watcher. If a file exists in both `paths` and in `ignore`, it will be ignored, and will be excluded from both rebuilds and file synchronization. + // Will only work in conjunction with `paths`. + Ignore []string `yaml:"ignore,omitempty"` +} + +// DockerfileDependency *alpha* is used to specify a custom build artifact that is built from a Dockerfile. This allows skaffold to determine dependencies from the Dockerfile. +type DockerfileDependency struct { + // Path locates the Dockerfile relative to workspace. + Path string `yaml:"path,omitempty"` + + // BuildArgs are arguments passed to the docker build. + // It also accepts environment variables via the go template syntax. + // For example: `{"key1": "value1", "key2": "value2", "key3": "{{.ENV_VARIABLE}}"}`. + BuildArgs map[string]*string `yaml:"buildArgs,omitempty"` +} + +// KanikoArtifact *alpha* describes an artifact built from a Dockerfile, +// with kaniko. +type KanikoArtifact struct { + // AdditionalFlags are additional flags to be passed to Kaniko command line. + // See [Kaniko Additional Flags](https://github.com/GoogleContainerTools/kaniko#additional-flags). + // Deprecated - instead the named, unique fields should be used, e.g. `buildArgs`, `cache`, `target`. + AdditionalFlags []string `yaml:"flags,omitempty"` + + // DockerfilePath locates the Dockerfile relative to workspace. + // Defaults to `Dockerfile`. + DockerfilePath string `yaml:"dockerfile,omitempty"` + + // Target is the Dockerfile target name to build. + Target string `yaml:"target,omitempty"` + + // BuildArgs are arguments passed to the docker build. + // It also accepts environment variables via the go template syntax. + // For example: `{"key1": "value1", "key2": "value2", "key3": "{{.ENV_VARIABLE}}"}`. + BuildArgs map[string]*string `yaml:"buildArgs,omitempty"` + + // BuildContext is where the build context for this artifact resides. + BuildContext *KanikoBuildContext `yaml:"buildContext,omitempty"` + + // Image is the Docker image used by the Kaniko pod. + // Defaults to the latest released version of `gcr.io/kaniko-project/executor`. + Image string `yaml:"image,omitempty"` + + // Cache configures Kaniko caching. If a cache is specified, Kaniko will + // use a remote cache which will speed up builds. + Cache *KanikoCache `yaml:"cache,omitempty"` + + // Reproducible is used to strip timestamps out of the built image. + Reproducible bool `yaml:"reproducible,omitempty"` +} + +// DockerArtifact *beta* describes an artifact built from a Dockerfile, +// usually using `docker build`. +type DockerArtifact struct { + // DockerfilePath locates the Dockerfile relative to workspace. + // Defaults to `Dockerfile`. + DockerfilePath string `yaml:"dockerfile,omitempty"` + + // Target is the Dockerfile target name to build. + Target string `yaml:"target,omitempty"` + + // BuildArgs are arguments passed to the docker build. + // For example: `{"key1": "value1", "key2": "value2"}`. + BuildArgs map[string]*string `yaml:"buildArgs,omitempty"` + + // NetworkMode is passed through to docker and overrides the + // network configuration of docker builder. If unset, use whatever + // is configured in the underlying docker daemon. Valid modes are + // `host`: use the host's networking stack. + // `bridge`: use the bridged network configuration. + // `none`: no networking in the container. + NetworkMode string `yaml:"network,omitempty"` + + // CacheFrom lists the Docker images used as cache sources. + // For example: `["golang:1.10.1-alpine3.7", "alpine:3.7"]`. + CacheFrom []string `yaml:"cacheFrom,omitempty"` + + // NoCache used to pass in --no-cache to docker build to prevent caching. + NoCache bool `yaml:"noCache,omitempty"` +} + +// BazelArtifact *beta* describes an artifact built with [Bazel](https://bazel.build/). +type BazelArtifact struct { + // BuildTarget is the `bazel build` target to run. + // For example: `//:skaffold_example.tar`. + BuildTarget string `yaml:"target,omitempty" yamltags:"required"` + + // BuildArgs are additional args to pass to `bazel build`. + // For example: `["-flag", "--otherflag"]`. + BuildArgs []string `yaml:"args,omitempty"` +} + +// JibMavenArtifact *alpha* builds images using the +// [Jib plugin for Maven](https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin). +type JibMavenArtifact struct { + // Module selects which Maven module to build, for a multi module project. + Module string `yaml:"module,omitempty"` + + // Profile selects which Maven profile to activate. + Profile string `yaml:"profile,omitempty"` + + // Flags are additional build flags passed to Maven. + // For example: `["-x", "-DskipTests"]`. + Flags []string `yaml:"args,omitempty"` +} + +// JibGradleArtifact *alpha* builds images using the +// [Jib plugin for Gradle](https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin). +type JibGradleArtifact struct { + // Project selects which Gradle project to build. + Project string `yaml:"project,omitempty"` + + // Flags are additional build flags passed to Gradle. + // For example: `["--no-build-cache"]`. + Flags []string `yaml:"args,omitempty"` +} diff --git a/pkg/skaffold/schema/v1beta13/upgrade.go b/pkg/skaffold/schema/v1beta13/upgrade.go new file mode 100755 index 00000000000..8af20dff5d6 --- /dev/null +++ b/pkg/skaffold/schema/v1beta13/upgrade.go @@ -0,0 +1,37 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta13 + +import ( + next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" + pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" +) + +// Upgrade upgrades a configuration to the next version. +// Config changes from v1beta13 to v1beta14 +// 1. No Additions +// 2. No removals +// 3. No Updates +func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { + var newConfig next.SkaffoldConfig + + pkgutil.CloneThroughJSON(config, &newConfig) + newConfig.APIVersion = next.Version + + return &newConfig, nil +} diff --git a/pkg/skaffold/schema/v1beta13/upgrade_test.go b/pkg/skaffold/schema/v1beta13/upgrade_test.go new file mode 100755 index 00000000000..390fc9b30cd --- /dev/null +++ b/pkg/skaffold/schema/v1beta13/upgrade_test.go @@ -0,0 +1,149 @@ +/* +Copyright 2019 The Skaffold Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta13 + +import ( + "testing" + + next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/testutil" + yaml "gopkg.in/yaml.v2" +) + +func TestUpgrade(t *testing.T) { + yaml := `apiVersion: skaffold/v1beta13 +kind: Config +build: + artifacts: + - image: gcr.io/k8s-skaffold/skaffold-example + docker: + dockerfile: path/to/Dockerfile + - image: gcr.io/k8s-skaffold/bazel + bazel: + target: //mytarget + googleCloudBuild: + projectId: test-project +test: + - image: gcr.io/k8s-skaffold/skaffold-example + structureTests: + - ./test/* +deploy: + kubectl: + manifests: + - k8s-* +profiles: + - name: test profile + build: + artifacts: + - image: gcr.io/k8s-skaffold/skaffold-example + kaniko: + buildContext: + gcsBucket: skaffold-kaniko + cache: {} + cluster: + pullSecretName: e2esecret + namespace: default + test: + - image: gcr.io/k8s-skaffold/skaffold-example + structureTests: + - ./test/* + deploy: + kubectl: + manifests: + - k8s-* + - name: test local + build: + artifacts: + - image: gcr.io/k8s-skaffold/skaffold-example + docker: + dockerfile: path/to/Dockerfile + local: + push: false + deploy: + kubectl: + manifests: + - k8s-* +` + expected := `apiVersion: skaffold/v1beta14 +kind: Config +build: + artifacts: + - image: gcr.io/k8s-skaffold/skaffold-example + docker: + dockerfile: path/to/Dockerfile + - image: gcr.io/k8s-skaffold/bazel + bazel: + target: //mytarget + googleCloudBuild: + projectId: test-project +test: + - image: gcr.io/k8s-skaffold/skaffold-example + structureTests: + - ./test/* +deploy: + kubectl: + manifests: + - k8s-* +profiles: + - name: test profile + build: + artifacts: + - image: gcr.io/k8s-skaffold/skaffold-example + kaniko: + buildContext: + gcsBucket: skaffold-kaniko + cache: {} + cluster: + pullSecretName: e2esecret + namespace: default + test: + - image: gcr.io/k8s-skaffold/skaffold-example + structureTests: + - ./test/* + deploy: + kubectl: + manifests: + - k8s-* + - name: test local + build: + artifacts: + - image: gcr.io/k8s-skaffold/skaffold-example + docker: + dockerfile: path/to/Dockerfile + local: + push: false + deploy: + kubectl: + manifests: + - k8s-* +` + verifyUpgrade(t, yaml, expected) +} + +func verifyUpgrade(t *testing.T, input, output string) { + config := NewSkaffoldConfig() + err := yaml.UnmarshalStrict([]byte(input), config) + testutil.CheckErrorAndDeepEqual(t, false, err, Version, config.GetVersion()) + + upgraded, err := config.Upgrade() + testutil.CheckError(t, false, err) + + expected := next.NewSkaffoldConfig() + err = yaml.UnmarshalStrict([]byte(output), expected) + + testutil.CheckErrorAndDeepEqual(t, false, err, expected, upgraded) +} diff --git a/pkg/skaffold/schema/v1beta2/upgrade.go b/pkg/skaffold/schema/v1beta2/upgrade.go index daa88868291..3e5dd00c3cc 100644 --- a/pkg/skaffold/schema/v1beta2/upgrade.go +++ b/pkg/skaffold/schema/v1beta2/upgrade.go @@ -33,8 +33,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta3/upgrade.go b/pkg/skaffold/schema/v1beta3/upgrade.go index e38ef8b8b13..0ce7c115423 100644 --- a/pkg/skaffold/schema/v1beta3/upgrade.go +++ b/pkg/skaffold/schema/v1beta3/upgrade.go @@ -33,8 +33,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta4/upgrade.go b/pkg/skaffold/schema/v1beta4/upgrade.go index 48e04c91325..f06da68f9ed 100644 --- a/pkg/skaffold/schema/v1beta4/upgrade.go +++ b/pkg/skaffold/schema/v1beta4/upgrade.go @@ -34,8 +34,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta5/upgrade.go b/pkg/skaffold/schema/v1beta5/upgrade.go index 82209e2e99c..8e0d2fa77a3 100644 --- a/pkg/skaffold/schema/v1beta5/upgrade.go +++ b/pkg/skaffold/schema/v1beta5/upgrade.go @@ -31,8 +31,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta6/upgrade.go b/pkg/skaffold/schema/v1beta6/upgrade.go index 31f31d37f70..5430103edf1 100644 --- a/pkg/skaffold/schema/v1beta6/upgrade.go +++ b/pkg/skaffold/schema/v1beta6/upgrade.go @@ -20,7 +20,6 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta7" pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" - "github.com/pkg/errors" ) // Upgrade upgrades a configuration to the next version. @@ -34,39 +33,27 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { // convert Deploy (should be the same) var newDeploy next.DeployConfig - if err := pkgutil.CloneThroughJSON(config.Deploy, &newDeploy); err != nil { - return nil, errors.Wrap(err, "converting deploy config") - } + pkgutil.CloneThroughJSON(config.Deploy, &newDeploy) // convert Profiles (should be the same) var newProfiles []next.Profile if config.Profiles != nil { - if err := pkgutil.CloneThroughJSON(config.Profiles, &newProfiles); err != nil { - return nil, errors.Wrap(err, "converting new profile") - } + pkgutil.CloneThroughJSON(config.Profiles, &newProfiles) } // Update profile if kaniko build exists for i, p := range config.Profiles { - if err := upgradeKanikoBuild(p.Build, &newProfiles[i].Build); err != nil { - return nil, errors.Wrap(err, "upgrading kaniko build") - } + upgradeKanikoBuild(p.Build, &newProfiles[i].Build) } // convert Kaniko if needed var newBuild next.BuildConfig - if err := pkgutil.CloneThroughJSON(config.Build, &newBuild); err != nil { - return nil, errors.Wrap(err, "converting new build") - } - if err := upgradeKanikoBuild(config.Build, &newBuild); err != nil { - return nil, errors.Wrap(err, "upgrading kaniko build") - } + pkgutil.CloneThroughJSON(config.Build, &newBuild) + upgradeKanikoBuild(config.Build, &newBuild) // convert Test (should be the same) var newTest []*next.TestCase - if err := pkgutil.CloneThroughJSON(config.Test, &newTest); err != nil { - return nil, errors.Wrap(err, "converting new test") - } + pkgutil.CloneThroughJSON(config.Test, &newTest) return &next.SkaffoldConfig{ APIVersion: next.Version, @@ -78,20 +65,16 @@ func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { }, nil } -func upgradeKanikoBuild(build BuildConfig, newConfig *next.BuildConfig) error { - if build.KanikoBuild == nil { - return nil - } +func upgradeKanikoBuild(build BuildConfig, newConfig *next.BuildConfig) { kaniko := build.KanikoBuild + if kaniko == nil { + return + } + // Else, transition values from old config to new config artifacts for _, a := range newConfig.Artifacts { - if err := pkgutil.CloneThroughJSON(kaniko, &a.KanikoArtifact); err != nil { - return errors.Wrap(err, "cloning kaniko artifact") - } + pkgutil.CloneThroughJSON(kaniko, &a.KanikoArtifact) } // Transition values from old config to in cluster details - if err := pkgutil.CloneThroughJSON(kaniko, &newConfig.Cluster); err != nil { - return errors.Wrap(err, "cloning cluster details") - } - return nil + pkgutil.CloneThroughJSON(kaniko, &newConfig.Cluster) } diff --git a/pkg/skaffold/schema/v1beta7/upgrade.go b/pkg/skaffold/schema/v1beta7/upgrade.go index 9192c27ab2d..930f1ecb731 100644 --- a/pkg/skaffold/schema/v1beta7/upgrade.go +++ b/pkg/skaffold/schema/v1beta7/upgrade.go @@ -31,8 +31,8 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - err := pkgutil.CloneThroughJSON(config, &newConfig) + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version - return &newConfig, err + return &newConfig, nil } diff --git a/pkg/skaffold/schema/v1beta8/upgrade.go b/pkg/skaffold/schema/v1beta8/upgrade.go index 5bb839d16b5..4c30e646c3c 100644 --- a/pkg/skaffold/schema/v1beta8/upgrade.go +++ b/pkg/skaffold/schema/v1beta8/upgrade.go @@ -17,8 +17,6 @@ limitations under the License. package v1beta8 import ( - "github.com/pkg/errors" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" next "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta9" pkgutil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" @@ -33,9 +31,7 @@ import ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - if err := pkgutil.CloneThroughJSON(config, &newConfig); err != nil { - return nil, err - } + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version if err := util.UpgradePipelines(config, &newConfig, upgradeOnePipeline); err != nil { @@ -55,16 +51,14 @@ func upgradeOnePipeline(oldPipeline, newPipeline interface{}) error { } if a.BuilderPlugin.Name == "bazel" { var ba *next.BazelArtifact - if err := pkgutil.CloneThroughYAML(a.BuilderPlugin.Properties, &ba); err != nil { - return errors.Wrap(err, "converting bazel artifact") - } + pkgutil.CloneThroughYAML(a.BuilderPlugin.Properties, &ba) + newBuild.Artifacts[i].BazelArtifact = ba } if a.BuilderPlugin.Name == "docker" { var da *next.DockerArtifact - if err := pkgutil.CloneThroughYAML(a.BuilderPlugin.Properties, &da); err != nil { - return errors.Wrap(err, "converting docker artifact") - } + pkgutil.CloneThroughYAML(a.BuilderPlugin.Properties, &da) + newBuild.Artifacts[i].DockerArtifact = da } } @@ -72,16 +66,14 @@ func upgradeOnePipeline(oldPipeline, newPipeline interface{}) error { if c := oldBuild.ExecutionEnvironment; c != nil { if c.Name == "googleCloudBuild" { var gcb *next.GoogleCloudBuild - if err := pkgutil.CloneThroughYAML(c.Properties, &gcb); err != nil { - return errors.Wrap(err, "converting gcb artifact") - } + pkgutil.CloneThroughYAML(c.Properties, &gcb) + newBuild.GoogleCloudBuild = gcb } if c.Name == "local" { var local *next.LocalBuild - if err := pkgutil.CloneThroughYAML(c.Properties, &local); err != nil { - return errors.Wrap(err, "converting local artifact") - } + pkgutil.CloneThroughYAML(c.Properties, &local) + newBuild.LocalBuild = local } } diff --git a/pkg/skaffold/schema/v1beta9/upgrade.go b/pkg/skaffold/schema/v1beta9/upgrade.go index 5291e4edec7..525560c3dfc 100644 --- a/pkg/skaffold/schema/v1beta9/upgrade.go +++ b/pkg/skaffold/schema/v1beta9/upgrade.go @@ -46,9 +46,7 @@ var ( func (config *SkaffoldConfig) Upgrade() (util.VersionedConfig, error) { var newConfig next.SkaffoldConfig - if err := pkgutil.CloneThroughJSON(config, &newConfig); err != nil { - return nil, err - } + pkgutil.CloneThroughJSON(config, &newConfig) newConfig.APIVersion = next.Version if err := util.UpgradePipelines(config, &newConfig, upgradeOnePipeline); err != nil { diff --git a/pkg/skaffold/schema/validation/validation.go b/pkg/skaffold/schema/validation/validation.go index 91b2a7785a7..b1a477b7cb0 100644 --- a/pkg/skaffold/schema/validation/validation.go +++ b/pkg/skaffold/schema/validation/validation.go @@ -21,6 +21,7 @@ import ( "reflect" "strings" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/yamltags" ) @@ -33,6 +34,7 @@ var ( // Process checks if the Skaffold pipeline is valid and returns all encountered errors as a concatenated string func Process(config *latest.SkaffoldConfig) error { errs := visitStructs(config, validateYamltags) + errs = append(errs, validateImageNames(config.Build.Artifacts)...) errs = append(errs, validateDockerNetworkMode(config.Build.Artifacts)...) errs = append(errs, validateCustomDependencies(config.Build.Artifacts)...) errs = append(errs, validateSyncRules(config.Build.Artifacts)...) @@ -49,6 +51,27 @@ func Process(config *latest.SkaffoldConfig) error { return fmt.Errorf(strings.Join(messages, " | ")) } +// validateImageNames makes sure the artifact image names are valid base names, +// without tags nor digests. +func validateImageNames(artifacts []*latest.Artifact) (errs []error) { + for _, a := range artifacts { + parsed, err := docker.ParseReference(a.ImageName) + if err != nil { + errs = append(errs, fmt.Errorf("invalid imageName '%s': %v", a.ImageName, err)) + continue + } + + if parsed.Tag != "" { + errs = append(errs, fmt.Errorf("invalid imageName '%s': no tag should be specified. Use taggers instead: https://skaffold.dev/docs/how-tos/taggers/", a.ImageName)) + } + + if parsed.Digest != "" { + errs = append(errs, fmt.Errorf("invalid imageName '%s': no digest should be specified. Use taggers instead: https://skaffold.dev/docs/how-tos/taggers/", a.ImageName)) + } + } + return +} + // validateDockerNetworkMode makes sure that networkMode is one of `bridge`, `none`, or `host` if set. func validateDockerNetworkMode(artifacts []*latest.Artifact) (errs []error) { for _, a := range artifacts { diff --git a/pkg/skaffold/schema/validation/validation_test.go b/pkg/skaffold/schema/validation/validation_test.go index 9aecbfc69cc..cc7cd01c834 100644 --- a/pkg/skaffold/schema/validation/validation_test.go +++ b/pkg/skaffold/schema/validation/validation_test.go @@ -377,72 +377,69 @@ func TestValidateSyncRules(t *testing.T) { }, { description: "no sync rules", - artifacts: []*latest.Artifact{ - { - Sync: nil, - }, - }, + artifacts: []*latest.Artifact{{ + ImageName: "img", + Sync: nil, + }}, }, { description: "two good rules", - artifacts: []*latest.Artifact{ - { - Sync: &latest.Sync{Manual: []*latest.SyncRule{ - { - Src: "src/**/*.js", - Dest: ".", - }, - { - Src: "src/**/*.js", - Dest: ".", - Strip: "src/", - }, - }}, - }, - }, + artifacts: []*latest.Artifact{{ + ImageName: "img", + Sync: &latest.Sync{Manual: []*latest.SyncRule{ + { + Src: "src/**/*.js", + Dest: ".", + }, + { + Src: "src/**/*.js", + Dest: ".", + Strip: "src/", + }, + }}, + }}, }, { description: "one good one bad rule", - artifacts: []*latest.Artifact{ - { - Sync: &latest.Sync{Manual: []*latest.SyncRule{ - { - Src: "src/**/*.js", - Dest: ".", - Strip: "/src", - }, - { - Src: "src/**/*.py", - Dest: ".", - Strip: "src/", - }, - }}, - }, - }, + artifacts: []*latest.Artifact{{ + ImageName: "img", + Sync: &latest.Sync{Manual: []*latest.SyncRule{ + { + Src: "src/**/*.js", + Dest: ".", + Strip: "/src", + }, + { + Src: "src/**/*.py", + Dest: ".", + Strip: "src/", + }, + }}, + }}, shouldErr: true, }, { description: "two bad rules", - artifacts: []*latest.Artifact{ - { - Sync: &latest.Sync{Manual: []*latest.SyncRule{ - { - Dest: ".", - Strip: "src", - }, - { - Src: "**/*.js", - Dest: ".", - Strip: "src/", - }, - }}, - }, - }, + artifacts: []*latest.Artifact{{ + ImageName: "img", + Sync: &latest.Sync{Manual: []*latest.SyncRule{ + { + Dest: ".", + Strip: "src", + }, + { + Src: "**/*.js", + Dest: ".", + Strip: "src/", + }, + }}, + }}, shouldErr: true, }, { description: "stripping part of folder name is valid", artifacts: []*latest.Artifact{{ + ImageName: "img", Sync: &latest.Sync{ Manual: []*latest.SyncRule{{ Src: "srcsomeother/**/*.js", @@ -555,3 +552,64 @@ func TestValidatePortForwardResources(t *testing.T) { }) } } + +func TestValidateImageNames(t *testing.T) { + tests := []struct { + description string + artifacts []*latest.Artifact + shouldErr bool + }{ + { + description: "no name", + artifacts: []*latest.Artifact{{ + ImageName: "", + }}, + shouldErr: true, + }, + { + description: "valid", + artifacts: []*latest.Artifact{{ + ImageName: "img", + }}, + shouldErr: false, + }, + { + description: "shouldn't have a tag", + artifacts: []*latest.Artifact{{ + ImageName: "img:tag", + }}, + shouldErr: true, + }, + { + description: "shouldn't have a digest", + artifacts: []*latest.Artifact{{ + ImageName: "img@sha256:77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182", + }}, + shouldErr: true, + }, + { + description: "no tag nor digest", + artifacts: []*latest.Artifact{{ + ImageName: "img:tag@sha256:77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182", + }}, + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + // disable yamltags validation + t.Override(&validateYamltags, func(interface{}) error { return nil }) + + err := Process( + &latest.SkaffoldConfig{ + Pipeline: latest.Pipeline{ + Build: latest.BuildConfig{ + Artifacts: test.artifacts, + }, + }, + }) + + t.CheckError(test.shouldErr, err) + }) + } +} diff --git a/pkg/skaffold/schema/versions.go b/pkg/skaffold/schema/versions.go index ab3f78810df..15031325c60 100644 --- a/pkg/skaffold/schema/versions.go +++ b/pkg/skaffold/schema/versions.go @@ -21,7 +21,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/apiversion" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" @@ -35,6 +35,7 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta10" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta11" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta12" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta13" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta2" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta3" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta4" @@ -68,6 +69,7 @@ var SchemaVersions = Versions{ {v1beta10.Version, v1beta10.NewSkaffoldConfig}, {v1beta11.Version, v1beta11.NewSkaffoldConfig}, {v1beta12.Version, v1beta12.NewSkaffoldConfig}, + {v1beta13.Version, v1beta13.NewSkaffoldConfig}, {latest.Version, latest.NewSkaffoldConfig}, } diff --git a/pkg/skaffold/schema/versions_test.go b/pkg/skaffold/schema/versions_test.go index cf116c5bf7d..66a2a475978 100644 --- a/pkg/skaffold/schema/versions_test.go +++ b/pkg/skaffold/schema/versions_test.go @@ -405,6 +405,12 @@ func withTests(testCases ...*latest.TestCase) func(*latest.SkaffoldConfig) { } } +func withPortForward(portForward ...*latest.PortForwardResource) func(*latest.SkaffoldConfig) { + return func(cfg *latest.SkaffoldConfig) { + cfg.PortForward = portForward + } +} + func withStatusCheckDeadline(deadline int) func(*latest.SkaffoldConfig) { return func(cfg *latest.SkaffoldConfig) { cfg.Deploy.StatusCheckDeadlineSeconds = deadline diff --git a/pkg/skaffold/sources/upload.go b/pkg/skaffold/sources/upload.go index 2c2d44d3738..a4c8bf8b1be 100644 --- a/pkg/skaffold/sources/upload.go +++ b/pkg/skaffold/sources/upload.go @@ -36,13 +36,7 @@ func TarGz(ctx context.Context, w io.Writer, a *latest.Artifact, dependencies [] } // UploadToGCS uploads the artifact's sources to a GCS bucket. -func UploadToGCS(ctx context.Context, a *latest.Artifact, bucket, objectName string, dependencies []string) error { - c, err := cstorage.NewClient(ctx) - if err != nil { - return errors.Wrap(err, "creating GCS client") - } - defer c.Close() - +func UploadToGCS(ctx context.Context, c *cstorage.Client, a *latest.Artifact, bucket, objectName string, dependencies []string) error { w := c.Bucket(bucket).Object(objectName).NewWriter(ctx) if err := TarGz(ctx, w, a, dependencies); err != nil { return errors.Wrap(err, "uploading targz to google storage") diff --git a/pkg/skaffold/util/tar.go b/pkg/skaffold/util/tar.go index c3ad11ad2b5..266ae957129 100644 --- a/pkg/skaffold/util/tar.go +++ b/pkg/skaffold/util/tar.go @@ -22,6 +22,7 @@ import ( "io" "os" "path/filepath" + "runtime" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -102,7 +103,7 @@ func addFileToTar(root string, src string, dst string, tw *tar.Writer) error { } tarHeader.Name = tarPath - if err := tw.WriteHeader(tarHeader); err != nil { + if err := writeHeader(tw, tarHeader); err != nil { return err } case mode.IsRegular(): @@ -112,7 +113,7 @@ func addFileToTar(root string, src string, dst string, tw *tar.Writer) error { } tarHeader.Name = tarPath - if err := tw.WriteHeader(tarHeader); err != nil { + if err := writeHeader(tw, tarHeader); err != nil { return err } @@ -140,7 +141,7 @@ func addFileToTar(root string, src string, dst string, tw *tar.Writer) error { return err } tarHeader.Name = tarPath - if err := tw.WriteHeader(tarHeader); err != nil { + if err := writeHeader(tw, tarHeader); err != nil { return err } default: @@ -150,9 +151,30 @@ func addFileToTar(root string, src string, dst string, tw *tar.Writer) error { if err != nil { return err } - if err := tw.WriteHeader(tarHeader); err != nil { + if err := writeHeader(tw, tarHeader); err != nil { return err } } return nil } + +// Code copied from https://github.com/moby/moby/blob/master/pkg/archive/archive_windows.go +func writeHeader(tw *tar.Writer, tarHeader *tar.Header) error { + if runtime.GOOS == "windows" { + tarHeader.Mode = int64(chmodTarEntry(os.FileMode(tarHeader.Mode))) + } + + return tw.WriteHeader(tarHeader) +} + +// Code copied from https://github.com/moby/moby/blob/master/pkg/archive/archive_windows.go +func chmodTarEntry(perm os.FileMode) os.FileMode { + //perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.) + permPart := perm & os.ModePerm + noPermPart := perm &^ os.ModePerm + // Add the x bit: make everything +x from windows + permPart |= 0111 + permPart &= 0755 + + return noPermPart | permPart +} diff --git a/pkg/skaffold/util/util.go b/pkg/skaffold/util/util.go index b9dcc16873f..ee96cc83374 100644 --- a/pkg/skaffold/util/util.go +++ b/pkg/skaffold/util/util.go @@ -84,22 +84,45 @@ func StrSliceInsert(sl []string, index int, insert []string) []string { return newSlice } +// orderedFileSet holds an ordered set of file paths. +type orderedFileSet struct { + files []string + seen map[string]bool +} + +func (l *orderedFileSet) Add(file string) { + if l.seen[file] { + return + } + + if l.seen == nil { + l.seen = make(map[string]bool) + } + l.seen[file] = true + + l.files = append(l.files, file) +} + +func (l *orderedFileSet) Files() []string { + return l.files +} + // ExpandPathsGlob expands paths according to filepath.Glob patterns // Returns a list of unique files that match the glob patterns passed in. func ExpandPathsGlob(workingDir string, paths []string) ([]string, error) { - expandedPaths := make(map[string]bool) + var set orderedFileSet + for _, p := range paths { if filepath.IsAbs(p) { // This is a absolute file reference - expandedPaths[p] = true + set.Add(p) continue } path := filepath.Join(workingDir, p) - if _, err := os.Stat(path); err == nil { // This is a file reference, so just add it - expandedPaths[path] = true + set.Add(path) continue } @@ -112,25 +135,27 @@ func ExpandPathsGlob(workingDir string, paths []string) ([]string, error) { } for _, f := range files { - err := filepath.Walk(f, func(path string, info os.FileInfo, err error) error { + var filesInDirectory []string + + if err := filepath.Walk(f, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { - expandedPaths[path] = true + filesInDirectory = append(filesInDirectory, path) } return nil - }) - if err != nil { + }); err != nil { return nil, errors.Wrap(err, "filepath walk") } + + // Make sure files inside a directory are listed in a consistent order + sort.Strings(filesInDirectory) + for _, file := range filesInDirectory { + set.Add(file) + } } } - var ret []string - for k := range expandedPaths { - ret = append(ret, k) - } - sort.Strings(ret) - return ret, nil + return set.Files(), nil } // BoolPtr returns a pointer to a bool @@ -234,28 +259,34 @@ func NonEmptyLines(input []byte) []string { return result } -// CloneThroughJSON marshals the old interface into the new one -func CloneThroughJSON(old interface{}, new interface{}) error { +// CloneThroughJSON clones an `old` object into a `new` one +// using json marshalling and unmarshalling. +// Since the object can be marshalled, it's almost sure it can be +// unmarshalled. So we prefer to panic instead of returning an error +// that would create an untestable branch on the call site. +func CloneThroughJSON(old interface{}, new interface{}) { o, err := json.Marshal(old) if err != nil { - return errors.Wrap(err, "marshalling old") + panic(fmt.Sprintf("marshalling old: %v", err)) } - if err := json.Unmarshal(o, &new); err != nil { - return errors.Wrap(err, "unmarshalling new") + if err := json.Unmarshal(o, new); err != nil { + panic(fmt.Sprintf("unmarshalling new: %v", err)) } - return nil } -// CloneThroughYAML marshals the old interface into the new one -func CloneThroughYAML(old interface{}, new interface{}) error { +// CloneThroughYAML clones an `old` object into a `new` one +// using yaml marshalling and unmarshalling. +// Since the object can be marshalled, it's almost sure it can be +// unmarshalled. So we prefer to panic instead of returning an error +// that would create an untestable branch on the call site. +func CloneThroughYAML(old interface{}, new interface{}) { contents, err := yaml.Marshal(old) if err != nil { - return errors.Wrap(err, "unmarshalling properties") + panic(fmt.Sprintf("marshalling old: %v", err)) } if err := yaml.Unmarshal(contents, new); err != nil { - return errors.Wrap(err, "unmarshalling bazel artifact") + panic(fmt.Sprintf("unmarshalling new: %v", err)) } - return nil } // AbsolutePaths prepends each path in paths with workspace if the path isn't absolute diff --git a/pkg/skaffold/util/util_test.go b/pkg/skaffold/util/util_test.go index f2d5f7767cf..eee0db9c30d 100644 --- a/pkg/skaffold/util/util_test.go +++ b/pkg/skaffold/util/util_test.go @@ -78,7 +78,7 @@ func TestExpandPathsGlob(t *testing.T) { out: []string{"dir/sub_dir/file"}, }, { - description: "match top level glob", + description: "top level glob", in: []string{"dir*"}, out: []string{"dir/sub_dir/file", "dir_b/sub_dir_b/file"}, }, @@ -87,6 +87,11 @@ func TestExpandPathsGlob(t *testing.T) { in: []string{"[]"}, shouldErr: true, }, + { + description: "keep top level order", + in: []string{"dir_b/*", "dir/*"}, + out: []string{"dir_b/sub_dir_b/file", "dir/sub_dir/file"}, + }, } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { @@ -220,9 +225,35 @@ func TestCloneThroughJSON(t *testing.T) { } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { - err := CloneThroughJSON(test.old, test.new) + CloneThroughJSON(test.old, test.new) + + t.CheckDeepEqual(test.expected, test.new) + }) + } +} + +func TestCloneThroughYAML(t *testing.T) { + tests := []struct { + description string + old interface{} + new interface{} + expected interface{} + }{ + { + description: "google cloud build", + old: map[string]string{ + "projectId": "unit-test", + }, + new: &latest.GoogleCloudBuild{}, + expected: &latest.GoogleCloudBuild{ + ProjectID: "unit-test", + }, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + CloneThroughYAML(test.old, test.new) - t.CheckNoError(err) t.CheckDeepEqual(test.expected, test.new) }) } diff --git a/pkg/skaffold/yamltags/tags.go b/pkg/skaffold/yamltags/tags.go index f59b31acf1e..b0f926628e1 100644 --- a/pkg/skaffold/yamltags/tags.go +++ b/pkg/skaffold/yamltags/tags.go @@ -46,6 +46,17 @@ func ValidateStruct(s interface{}) error { return nil } +// YamlName returns the YAML name of the given field +func YamlName(field reflect.StructField) string { + if yamltags, ok := field.Tag.Lookup("yaml"); ok { + tags := strings.Split(yamltags, ",") + if len(tags) > 0 && tags[0] != "" { + return tags[0] + } + } + return field.Name +} + func processTags(yamltags string, val reflect.Value, parentStruct reflect.Value, field reflect.StructField) error { tags := strings.Split(yamltags, ",") for _, tag := range tags { diff --git a/pkg/skaffold/yamltags/tags_test.go b/pkg/skaffold/yamltags/tags_test.go index 321f01470b9..dc64eb0f9d1 100644 --- a/pkg/skaffold/yamltags/tags_test.go +++ b/pkg/skaffold/yamltags/tags_test.go @@ -186,3 +186,14 @@ func TestIsZeroValue(t *testing.T) { nonZeroMap := make(map[string]string) testutil.CheckDeepEqual(t, false, isZeroValue(reflect.ValueOf(nonZeroMap))) } + +func TestYamlName(t *testing.T) { + object := struct { + Empty string `yaml:",omitempty"` + Named string `yaml:"named,omitempty"` + Missing string + }{} + testutil.CheckDeepEqual(t, "Empty", YamlName(reflect.TypeOf(object).Field(0))) + testutil.CheckDeepEqual(t, "named", YamlName(reflect.TypeOf(object).Field(1))) + testutil.CheckDeepEqual(t, "Missing", YamlName(reflect.TypeOf(object).Field(2))) +} diff --git a/testutil/util.go b/testutil/util.go index 418df07c89e..2017d10e409 100644 --- a/testutil/util.go +++ b/testutil/util.go @@ -22,6 +22,7 @@ import ( "net/http" "net/http/httptest" "reflect" + "regexp" "strings" "testing" @@ -60,6 +61,13 @@ func (t *T) Override(dest, tmp interface{}) { t.teardownActions = append(t.teardownActions, teardown) } +func (t *T) CheckMatches(pattern, actual string) { + t.T.Helper() + if matches, _ := regexp.MatchString(pattern, actual); !matches { + t.Errorf("expected output %s to match: %s", actual, pattern) + } +} + func (t *T) CheckContains(expected, actual string) { CheckContains(t.T, expected, actual) } diff --git a/vendor/github.com/segmentio/textio/.gitignore b/vendor/github.com/segmentio/textio/.gitignore new file mode 100644 index 00000000000..89b6c8158c5 --- /dev/null +++ b/vendor/github.com/segmentio/textio/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Emacs +*~ diff --git a/vendor/github.com/segmentio/textio/LICENSE b/vendor/github.com/segmentio/textio/LICENSE new file mode 100644 index 00000000000..06d4dea88ae --- /dev/null +++ b/vendor/github.com/segmentio/textio/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Segment + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/segmentio/textio/README.md b/vendor/github.com/segmentio/textio/README.md new file mode 100644 index 00000000000..5bbb588ef18 --- /dev/null +++ b/vendor/github.com/segmentio/textio/README.md @@ -0,0 +1,80 @@ +# textio [![CircleCI](https://circleci.com/gh/segmentio/textio.svg?style=shield)](https://circleci.com/gh/segmentio/textio) [![Go Report Card](https://goreportcard.com/badge/github.com/segmentio/textio)](https://goreportcard.com/report/github.com/segmentio/textio) [![GoDoc](https://godoc.org/github.com/segmentio/textio?status.svg)](https://godoc.org/github.com/segmentio/textio) +Go package providing tools for advanced text manipulations + +## Motivation + +This package aims to provide a sutie of tools to deal with text parsing and +formatting. It is intended to extend what the standard library already offers, +and make it easy to integrate with it. + +## Examples + +This sections presents a couple of examples about how to use this package. + +### Indenting + +Indentation is often a complex problem to solve when dealing with stream of text +that may be composed of multiple lines. To address this problem, this package +provides the `textio.PrefixWriter` type, which implements the `io.Writer` +interface and automatically prepends every line of output with a predefined +prefix. + +Here is an example: +```go +func copyIndent(w io.Writer, r io.Reader) error { + p := textio.NewPrefixWriter(w, "\t") + + // Copy data from an input stream into the PrefixWriter, all lines will + // be prefixed with a '\t' character. + if _, err := io.Copy(p, r); err != nil { + return err + } + + // Flushes any data buffered in the PrefixWriter, this is important in + // case the last line was not terminated by a '\n' character. + return p.Flush() +} +``` + +### Tree Formatting + +A common way to represent tree-like structures is the formatting used by the +`tree(1)` unix command. The `textio.TreeWriter` type is an implementation of +an `io.Writer` which supports this kind of output. It works in a recursive +fashion where nodes created from a parent tree writer are formatted as part +of that tree structure. + +Here is an example: +```go +func ls(w io.Writer, path string) { + tree := NewTreeWriter(w) + tree.WriteString(filepath.Base(path)) + defer tree.Close() + + files, _ := ioutil.ReadDir(path) + + for _, f := range files { + if f.Mode().IsDir() { + ls(tree, filepath.Join(path, f.Name())) + } + } + + for _, f := range files { + if !f.Mode().IsDir() { + io.WriteString(NewTreeWriter(tree), f.Name()) + } + } +} + +... + +ls(os.Stdout, "examples") +``` +Which gives this output: +``` +examples +├── A +│ ├── 1 +│ └── 2 +└── message +``` diff --git a/vendor/github.com/segmentio/textio/go.mod b/vendor/github.com/segmentio/textio/go.mod new file mode 100644 index 00000000000..9a1893c961f --- /dev/null +++ b/vendor/github.com/segmentio/textio/go.mod @@ -0,0 +1,3 @@ +module github.com/segmentio/textio + +go 1.12 diff --git a/vendor/github.com/segmentio/textio/io.go b/vendor/github.com/segmentio/textio/io.go new file mode 100644 index 00000000000..e9f2e2b7a02 --- /dev/null +++ b/vendor/github.com/segmentio/textio/io.go @@ -0,0 +1,63 @@ +package textio + +import "io" + +// Base returns the direct base of w, which may be w itself if it had no base +// writer. +func Base(w io.Writer) io.Writer { + if d, ok := w.(decorator); ok { + return coalesceWriters(d.Base(), w) + } + return w +} + +// Root returns the root writer of w, which is found by going up the list of +// base writers. +// +// The node is usually the writer where the content ends up being written. +func Root(w io.Writer) io.Writer { + switch x := w.(type) { + case tree: + return coalesceWriters(x.Root(), w) + case node: + return coalesceWriters(Root(x.Parent()), w) + case decorator: + return coalesceWriters(Root(x.Base()), w) + default: + return w + } +} + +// Parent returns the parent writer of w, which is usually a writer of a similar +// type on tree-like writer structures. +func Parent(w io.Writer) io.Writer { + switch x := w.(type) { + case node: + return coalesceWriters(x.Parent(), w) + case decorator: + return coalesceWriters(Parent(x.Base()), w) + default: + return x + } +} + +type decorator interface { + Base() io.Writer +} + +type node interface { + Parent() io.Writer +} + +type tree interface { + Root() io.Writer +} + +func coalesceWriters(writers ...io.Writer) io.Writer { + for _, w := range writers { + if w != nil { + return w + } + } + return nil +} diff --git a/vendor/github.com/segmentio/textio/prefix.go b/vendor/github.com/segmentio/textio/prefix.go new file mode 100644 index 00000000000..e76fb2eebe6 --- /dev/null +++ b/vendor/github.com/segmentio/textio/prefix.go @@ -0,0 +1,162 @@ +package textio + +import ( + "bytes" + "fmt" + "io" +) + +// PrefixWriter is an implementation of io.Writer which places a prefix before +// every line. +// +// Instances of PrefixWriter are not safe to use concurrently from multiple +// goroutines. +type PrefixWriter struct { + writer io.Writer + indent []byte + buffer []byte + offset int +} + +// NewPrefixWriter constructs a PrefixWriter which outputs to w and prefixes +// every line with s. +func NewPrefixWriter(w io.Writer, s string) *PrefixWriter { + return &PrefixWriter{ + writer: w, + indent: copyStringToBytes(s), + buffer: make([]byte, 0, 256), + } +} + +// Base returns the underlying writer that w outputs to. +func (w *PrefixWriter) Base() io.Writer { + return w.writer +} + +// Buffered returns a byte slice of the data currently buffered in the writer. +func (w *PrefixWriter) Buffered() []byte { + return w.buffer[w.offset:] +} + +// Write writes b to w, satisfies the io.Writer interface. +func (w *PrefixWriter) Write(b []byte) (int, error) { + var c int + var n int + var err error + + forEachLine(b, func(line []byte) bool { + // Always buffer so the input slice doesn't escape and WriteString won't + // copy the string (it saves a dynamic memory allocation on every call + // to WriteString). + w.buffer = append(w.buffer, line...) + + if chunk := w.Buffered(); isLine(chunk) { + c, err = w.writeLine(chunk) + w.discard(c) + } + + n += len(line) + return err == nil + }) + + return n, err +} + +// WriteString writes s to w. +func (w *PrefixWriter) WriteString(s string) (int, error) { + return w.Write([]byte(s)) +} + +// Flush forces all buffered data to be flushed to the underlying writer. +func (w *PrefixWriter) Flush() error { + n, err := w.write(w.buffer) + w.discard(n) + return err +} + +// Width satisfies the fmt.State interface. +func (w *PrefixWriter) Width() (int, bool) { + f, ok := Base(w).(fmt.State) + if ok { + return f.Width() + } + return 0, false +} + +// Precision satisfies the fmt.State interface. +func (w *PrefixWriter) Precision() (int, bool) { + f, ok := Base(w).(fmt.State) + if ok { + return f.Precision() + } + return 0, false +} + +// Flag satisfies the fmt.State interface. +func (w *PrefixWriter) Flag(c int) bool { + f, ok := Base(w).(fmt.State) + if ok { + return f.Flag(c) + } + return false +} + +func (w *PrefixWriter) writeLine(b []byte) (int, error) { + if _, err := w.write(w.indent); err != nil { + return 0, err + } + return w.write(b) +} + +func (w *PrefixWriter) write(b []byte) (int, error) { + return w.writer.Write(b) +} + +func (w *PrefixWriter) discard(n int) { + if n > 0 { + w.offset += n + + switch { + case w.offset == len(w.buffer): + w.buffer = w.buffer[:0] + w.offset = 0 + + case w.offset > (cap(w.buffer) / 2): + copy(w.buffer, w.buffer[w.offset:]) + w.buffer = w.buffer[:len(w.buffer)-w.offset] + w.offset = 0 + } + } +} + +func copyStringToBytes(s string) []byte { + b := make([]byte, len(s)) + copy(b, s) + return b +} + +func forEachLine(b []byte, do func([]byte) bool) { + for len(b) != 0 { + i := bytes.IndexByte(b, '\n') + + if i < 0 { + i = len(b) + } else { + i++ // include the newline character + } + + if !do(b[:i]) { + break + } + + b = b[i:] + } +} + +func isLine(b []byte) bool { + return len(b) != 0 && b[len(b)-1] == '\n' +} + +var ( + _ fmt.State = (*PrefixWriter)(nil) +) diff --git a/vendor/github.com/segmentio/textio/tree.go b/vendor/github.com/segmentio/textio/tree.go new file mode 100644 index 00000000000..d40ee9f0d43 --- /dev/null +++ b/vendor/github.com/segmentio/textio/tree.go @@ -0,0 +1,271 @@ +package textio + +import ( + "bytes" + "fmt" + "io" + "unicode/utf8" +) + +// TreeWriter is an implementation of an io.Writer which prints a tree-like +// representation of the content. +// +// Instances of TreeWriter are not safe to use concurrently from multiple +// goroutines. +type TreeWriter struct { + writer io.Writer + children []*TreeWriter + content []byte +} + +// NewTreeWriter constructs a new TreeWriter which outputs to w. If w is an +// instance of TreeWriter itself the new writer is added to the list of child +// nodes that will be renderend. +func NewTreeWriter(w io.Writer) *TreeWriter { + node := &TreeWriter{ + writer: w, + content: make([]byte, 0, 64), + } + + if parent, _ := node.Parent().(*TreeWriter); parent != nil { + if parent.children == nil { + parent.children = make([]*TreeWriter, 0, 8) + } + parent.children = append(parent.children, node) + } + + return node +} + +// Root returns the root of w, which is the node on which calling Close will +// cause the tree to be rendered to the underlying writer. +func (w *TreeWriter) Root() io.Writer { + if p, _ := w.Parent().(*TreeWriter); p != nil { + return p.Root() + } + return w +} + +// Parent returns the parent node of w, which its most direct base of type +// *TreeWriter. +func (w *TreeWriter) Parent() io.Writer { + if p, _ := w.writer.(*TreeWriter); p != nil { + return p + } + return Parent(w.writer) +} + +// Base returns the base writer of w. +func (w *TreeWriter) Base() io.Writer { + return w.writer +} + +// Write writes b to w, satisfies the io.Writer interface. +func (w *TreeWriter) Write(b []byte) (int, error) { + if w.writer == nil { + return 0, io.ErrClosedPipe + } + w.content = append(w.content, b...) + return len(b), nil +} + +// WriteString writes s to w. +func (w *TreeWriter) WriteString(s string) (int, error) { + return w.Write([]byte(s)) +} + +// WriteByte writes b to w. +func (w *TreeWriter) WriteByte(b byte) error { + w.content = append(w.content, b) + return nil +} + +// WriteRune writes r to w. +func (w *TreeWriter) WriteRune(r rune) (int, error) { + b := [8]byte{} + n := utf8.EncodeRune(b[:], r) + w.content = append(w.content, b[:n]...) + return n, nil +} + +// Width satisfies the fmt.State interface. +func (w *TreeWriter) Width() (int, bool) { + f, ok := Base(w.Root()).(fmt.State) + if ok { + return f.Width() + } + return 0, false +} + +// Precision satisfies the fmt.State interface. +func (w *TreeWriter) Precision() (int, bool) { + f, ok := Base(w.Root()).(fmt.State) + if ok { + return f.Precision() + } + return 0, false +} + +// Flag satisfies the fmt.State interface. +func (w *TreeWriter) Flag(c int) bool { + f, ok := Base(w.Root()).(fmt.State) + if ok { + return f.Flag(c) + } + return false +} + +// Close closes w, causing all buffered content to be flushed to its underlying +// writer, and future write operations to error with io.ErrClosedPipe. +func (w *TreeWriter) Close() (err error) { + defer func() { + w.writer = nil + switch x := recover().(type) { + case nil: + case error: + err = x + default: + err = fmt.Errorf("%+v", x) + } + }() + + // Technically we could have each child node write its own representation + // to a buffer, then render a tree from those content buffers. However this + // would require a lot more copying because each tree level would be written + // into the buffer of its parent. + // + // Instead the approach we take here only requires 1 level of buffering, no + // matter how complex the tree is. First the data is buffered into each node + // and when the tree is closed the code walks through each node and write + // their content and the leading tree symbols to the underlying writer. + + for _, c := range w.children { + if err = c.Close(); err != nil { + return err + } + } + + switch w.writer.(type) { + case nil: + // Already closed + case *TreeWriter: + // Sub-node, don't write anything + default: + buffer := [10]string{} + writer := treeWriter{writer: w.writer, symbols: buffer[:0]} + writer.writeTree(treeCtx{length: 1}, w) + } + + return +} + +var ( + _ io.Writer = (*TreeWriter)(nil) + _ io.StringWriter = (*TreeWriter)(nil) + _ fmt.State = (*TreeWriter)(nil) +) + +type treeCtx struct { + index int // index of the node + length int // number of nodes + needNewLine bool // whether a new line must be printed +} + +func (ctx *treeCtx) last() bool { + return ctx.index == (ctx.length - 1) +} + +type treeWriter struct { + writer io.Writer + symbols []string +} + +func (w *treeWriter) push(ctx treeCtx) { + w.nextLine(ctx) + w.symbols = append(w.symbols, "") +} + +func (w *treeWriter) pop() { + w.symbols = w.symbols[:w.lastIndex()] +} + +func (w *treeWriter) nextNode(ctx treeCtx) { + if ctx.last() { + w.set("└── ") + } else { + w.set("├── ") + } +} + +func (w *treeWriter) nextLine(ctx treeCtx) { + if ctx.last() { + w.set(" ") + } else { + w.set("│ ") + } +} + +func (w *treeWriter) lastIndex() int { + return len(w.symbols) - 1 +} + +func (w *treeWriter) empty() bool { + return len(w.symbols) == 0 +} + +func (w *treeWriter) set(s string) { + if !w.empty() { + w.symbols[w.lastIndex()] = s + } +} + +func (w *treeWriter) writeTree(ctx treeCtx, node *TreeWriter) { + w.writeNode(ctx, node) + w.push(ctx) + + ctx.length = len(node.children) + ctx.needNewLine = !bytes.HasSuffix(node.content, []byte("\n")) + + for i, child := range node.children { + ctx.index = i + w.writeTree(ctx, child) + } + + w.pop() +} + +func (w *treeWriter) writeNode(ctx treeCtx, node *TreeWriter) { + if ctx.needNewLine { + w.writeString("\n") + w.nextLine(ctx) + } + + w.nextNode(ctx) + i := 0 + + forEachLine(node.content, func(line []byte) bool { + if i != 0 { + w.nextLine(ctx) + } + + for _, symbol := range w.symbols { + w.writeString(symbol) + } + + w.write(line) + i++ + return true + }) +} + +func (w *treeWriter) writeString(s string) { + if _, err := io.WriteString(w.writer, s); err != nil { + panic(err) + } +} + +func (w *treeWriter) write(b []byte) { + if _, err := w.writer.Write(b); err != nil { + panic(err) + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index dbf76c9f642..4f80d2c6740 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -255,6 +255,8 @@ github.com/prometheus/procfs/internal/util github.com/rjeczalik/notify # github.com/russross/blackfriday v1.5.2 github.com/russross/blackfriday +# github.com/segmentio/textio v1.2.0 +github.com/segmentio/textio # github.com/sergi/go-diff v1.0.0 github.com/sergi/go-diff/diffmatchpatch # github.com/shurcooL/sanitized_anchor_name v1.0.0 @@ -320,16 +322,16 @@ golang.org/x/net/http2 golang.org/x/net/trace golang.org/x/net/context/ctxhttp golang.org/x/net/proxy +golang.org/x/net/context golang.org/x/net/http/httpguts golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/internal/timeseries -golang.org/x/net/context golang.org/x/net/internal/socks # golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/oauth2 -golang.org/x/oauth2/internal golang.org/x/oauth2/google +golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt # golang.org/x/sync v0.0.0-20190423024810-112230192c58 @@ -361,16 +363,16 @@ google.golang.org/api/internal google.golang.org/api/googleapi/transport google.golang.org/api/transport/http/internal/propagation # google.golang.org/appengine v1.6.1 +google.golang.org/appengine google.golang.org/appengine/urlfetch google.golang.org/appengine/internal +google.golang.org/appengine/internal/app_identity +google.golang.org/appengine/internal/modules google.golang.org/appengine/internal/urlfetch -google.golang.org/appengine google.golang.org/appengine/internal/base google.golang.org/appengine/internal/datastore google.golang.org/appengine/internal/log google.golang.org/appengine/internal/remote_api -google.golang.org/appengine/internal/app_identity -google.golang.org/appengine/internal/modules # google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610 google.golang.org/genproto/googleapis/api/annotations google.golang.org/genproto/googleapis/iam/v1 @@ -512,6 +514,7 @@ k8s.io/api/storage/v1beta1 # k8s.io/apimachinery v0.0.0-20190620073744-d16981aedf33 k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/apimachinery/pkg/api/resource +k8s.io/apimachinery/pkg/util/wait k8s.io/apimachinery/pkg/api/meta k8s.io/apimachinery/pkg/runtime k8s.io/apimachinery/pkg/runtime/serializer/json @@ -522,7 +525,6 @@ k8s.io/apimachinery/pkg/util/yaml k8s.io/apimachinery/pkg/api/errors k8s.io/apimachinery/pkg/fields k8s.io/apimachinery/pkg/watch -k8s.io/apimachinery/pkg/util/wait k8s.io/apimachinery/pkg/labels k8s.io/apimachinery/pkg/util/intstr k8s.io/apimachinery/pkg/conversion