diff --git a/Jenkinsfile b/Jenkinsfile index 688930d227..2ef5929e09 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -75,7 +75,9 @@ node('docker') { integrationTest: { stage('Integration Test') { mvn 'verify -Pit -DskipUnitTests -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true' - junit allowEmptyResults: true, testResults: '**/target/failsafe-reports/TEST-*.xml' + junit allowEmptyResults: true, testResults: '**/target/failsafe-reports/TEST-*.xml,**/target/cypress-reports/TEST-*.xml' + archiveArtifacts allowEmptyArchive: true, artifacts: 'scm-ui/e2e-tests/cypress/videos/*.mp4' + archiveArtifacts allowEmptyArchive: true, artifacts: 'scm-ui/e2e-tests/cypress/screenshots/**/*.png' } } ) @@ -190,7 +192,7 @@ node('docker') { String mainBranch Maven setupMavenBuild() { - MavenWrapperInDocker mvn = new MavenWrapperInDocker(this, "scmmanager/java-build:11.0.7_10") + MavenWrapperInDocker mvn = new MavenWrapperInDocker(this, "scmmanager/java-build:11.0.8_10") mvn.enableDockerHost = true // disable logging durring the build diff --git a/build/Dockerfile b/build/Dockerfile index c9afa6992e..6ef5ff1cfb 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -22,7 +22,7 @@ # SOFTWARE. # -FROM adoptopenjdk/openjdk11:x86_64-debian-jdk-11.0.7_10 +FROM adoptopenjdk/openjdk11:x86_64-debian-jdk-11.0.8_10 ENV DOCKER_VERSION=19.03.8 \ DOCKER_CHANNEL=stable \ @@ -34,11 +34,24 @@ COPY modprobe.sh /usr/local/bin/modprobe # install required packages RUN set -eux; \ apt-get update \ - && apt-get install -y \ + && apt-get install --no-install-recommends -y \ # mercurial is requried for integration tests of the scm-hg-plugin mercurial \ # git is required by yarn install of scm-ui git \ + # the following dependencies are required for cypress tests and are copied from + # https://github.com/cypress-io/cypress-docker-images/blob/master/base/12.18.3/Dockerfile + libgtk2.0-0 \ + libgtk-3-0 \ + libnotify-dev \ + libgconf-2-4 \ + libgbm-dev \ + libnss3 \ + libxss1 \ + libasound2 \ + libxtst6 \ + xauth \ + xvfb \ # download docker && curl -o docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/${DOCKER_CHANNEL}/x86_64/docker-${DOCKER_VERSION}.tgz \ && echo "${DOCKER_CHECKSUM} docker-${DOCKER_VERSION}.tgz" > docker-${DOCKER_VERSION}.sha256sum \ diff --git a/build/Makefile b/build/Makefile index 173df8bcb8..180b0db68d 100644 --- a/build/Makefile +++ b/build/Makefile @@ -1,4 +1,4 @@ -VERSION:=11.0.7_10 +VERSION:=11.0.8_10 .PHONY:build build: diff --git a/package.json b/package.json index 61331899bc..4772263be5 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build": "webpack --mode=production --config=scm-ui/ui-scripts/src/webpack.config.js", "build:dev": "webpack --mode=development --config=scm-ui/ui-scripts/src/webpack.config.js", "test": "lerna run --scope '@scm-manager/ui-*' --scope '@scm-manager/eslint-config' test", + "e2e-tests": "lerna run --scope '@scm-manager/e2e-tests' ci", "typecheck": "lerna run --scope '@scm-manager/ui-*' typecheck", "serve": "NODE_ENV=development webpack-dev-server --hot --mode=development --config=scm-ui/ui-scripts/src/webpack.config.js", "deploy": "ui-scripts publish", diff --git a/scm-it/pom.xml b/scm-it/pom.xml index 44f11f82d2..6911304659 100644 --- a/scm-it/pom.xml +++ b/scm-it/pom.xml @@ -186,6 +186,36 @@ + + com.github.sdorra + buildfrontend-maven-plugin + + ${basedir}/.. + + ${nodejs.version} + + + YARN + ${yarn.version} + + + + true + + + + e2e + integration-test + + run + + + + + org.apache.maven.plugins maven-dependency-plugin @@ -284,7 +314,7 @@ DEVELOPMENT ${project.parent.build.directory}/scm-it - ${project.basedir}/../scm-webapp/src/main/resources/logback.default.xml + ${project.basedir}/../scm-webapp/src/main/resources/logback.ci.xml diff --git a/scm-ui/e2e-tests/cypress.json b/scm-ui/e2e-tests/cypress.json index 03e8546581..128f39dcfb 100644 --- a/scm-ui/e2e-tests/cypress.json +++ b/scm-ui/e2e-tests/cypress.json @@ -1,3 +1,5 @@ { - "baseUrl": "http://localhost:8081/scm" + "baseUrl": "http://localhost:8081/scm", + "videoUploadOnPasses": false, + "videoCompression": false } diff --git a/scm-ui/e2e-tests/cypress/.gitignore b/scm-ui/e2e-tests/cypress/.gitignore new file mode 100644 index 0000000000..adaba54810 --- /dev/null +++ b/scm-ui/e2e-tests/cypress/.gitignore @@ -0,0 +1,2 @@ +videos +screenshots diff --git a/scm-ui/e2e-tests/package.json b/scm-ui/e2e-tests/package.json index 91b2691a7e..d5348843d0 100644 --- a/scm-ui/e2e-tests/package.json +++ b/scm-ui/e2e-tests/package.json @@ -6,8 +6,16 @@ "author": "Eduard Heimbuch ", "license": "MIT", "private": false, - "devDependencies": { + "scripts": { + "headless": "cypress run", + "ci": "node src/index.js" + }, + "dependencies": { + "@ffmpeg-installer/ffmpeg": "^1.0.20", "cypress": "^4.12.0", + "fluent-ffmpeg": "^2.1.2" + }, + "devDependencies": { "eslint-plugin-cypress": "^2.11.1" }, "prettier": "@scm-manager/prettier-config", diff --git a/scm-ui/e2e-tests/src/index.js b/scm-ui/e2e-tests/src/index.js new file mode 100644 index 0000000000..55c08bb312 --- /dev/null +++ b/scm-ui/e2e-tests/src/index.js @@ -0,0 +1,86 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * 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. + */ + +const cypress = require("cypress"); +const fs = require("fs"); +const path = require("path"); +const ffmpegPath = require("@ffmpeg-installer/ffmpeg").path; +const ffmpeg = require("fluent-ffmpeg"); + +ffmpeg.setFfmpegPath(ffmpegPath); + +const options = { + reporter: "junit", + reporterOptions: { + mochaFile: path.join("..", "target", "cypress-reports", "TEST-[hash].xml") + } +}; + +const createOutputFile = test => { + const title = test.title.join(" -- "); + return path.join("cypress", "videos", `${title}.mp4`); +}; + +const cutVideo = (video, test) => { + return new Promise((resolve, reject) => { + const title = createOutputFile(test); + ffmpeg(video) + .setStartTime(test.videoTimestamp / 1000) + .setDuration(test.wallClockDuration / 1000) + .output(title) + .on("end", err => { + if (err) { + reject(err); + } else { + resolve(); + } + }) + .on("error", err => { + reject(err); + }) + .run(); + }); +}; + +cypress + .run(options) + .then(results => { + results.runs.forEach(run => { + // remove videos of successful runs + if (!run.shouldUploadVideo) { + fs.unlinkSync(run.video); + } else { + const cuts = []; + run.tests.forEach(test => { + if (test.state !== "passed") { + cuts.push(cutVideo(run.video, test)); + } + }); + Promise.all(cuts) + .then(() => fs.unlinkSync(run.video)) + .catch(err => console.error("failed to cut video", err)); + } + }); + }) + .catch(err => console.error(err)); diff --git a/scm-ui/ui-components/src/devBuild.test.ts b/scm-ui/ui-components/src/devBuild.test.ts index 8df47ec6ee..5964032f53 100644 --- a/scm-ui/ui-components/src/devBuild.test.ts +++ b/scm-ui/ui-components/src/devBuild.test.ts @@ -25,31 +25,37 @@ import { createAttributesForTesting, isDevBuild } from "./devBuild"; describe("devbuild tests", () => { - let env: string | undefined; + let stage: string | undefined; + + const setStage = (s?: string) => { + // @ts-ignore scmStage is set on the index page + window.scmStage = s; + }; beforeAll(() => { - env = process.env.NODE_ENV; + // @ts-ignore scmStage is set on the index page + stage = window.scmStage; }); afterAll(() => { - process.env.NODE_ENV = env; + setStage(stage); }); describe("isDevBuild tests", () => { it("should return true for development", () => { - process.env.NODE_ENV = "development"; + setStage("development"); expect(isDevBuild()).toBe(true); }); it("should return false for production", () => { - process.env.NODE_ENV = "production"; + setStage("production"); expect(isDevBuild()).toBe(false); }); }); describe("createAttributesForTesting in non development mode", () => { beforeAll(() => { - process.env.NODE_ENV = "production"; + setStage("production"); }); it("should return undefined for non development", () => { @@ -60,7 +66,7 @@ describe("devbuild tests", () => { describe("createAttributesForTesting in development mode", () => { beforeAll(() => { - process.env.NODE_ENV = "development"; + setStage("development"); }); it("should return undefined for non development", () => { diff --git a/scm-ui/ui-components/src/devBuild.ts b/scm-ui/ui-components/src/devBuild.ts index abf1a18dc7..4425f695ab 100644 --- a/scm-ui/ui-components/src/devBuild.ts +++ b/scm-ui/ui-components/src/devBuild.ts @@ -22,7 +22,8 @@ * SOFTWARE. */ -export const isDevBuild = () => process.env.NODE_ENV === "development"; +// @ts-ignore scmStage is set on the index page +export const isDevBuild = () => (window.scmStage || "").toUpperCase() === "DEVELOPMENT"; export const createAttributesForTesting = (testId?: string) => { if (!testId || !isDevBuild()) { diff --git a/scm-ui/ui-scripts/src/webpack.config.js b/scm-ui/ui-scripts/src/webpack.config.js index f25e6c3122..0bc9f93fd7 100644 --- a/scm-ui/ui-scripts/src/webpack.config.js +++ b/scm-ui/ui-scripts/src/webpack.config.js @@ -22,12 +22,13 @@ * SOFTWARE. */ const path = require("path"); -const createIndexMiddleware = require("./middleware/IndexMiddleware"); -const createContextPathMiddleware = require("./middleware/ContextPathMiddleware"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); const WorkerPlugin = require("worker-plugin"); +const createIndexMiddleware = require("./middleware/IndexMiddleware"); +const createContextPathMiddleware = require("./middleware/ContextPathMiddleware"); + const isDevelopment = process.env.NODE_ENV === "development"; const root = path.resolve(process.cwd(), "scm-ui"); @@ -39,6 +40,8 @@ let mode = "production"; if (isDevelopment) { mode = "development"; babelPlugins.push(require.resolve("react-refresh/babel")); + // it is ok to use require here, because we want to load the package conditionally + // eslint-disable-next-line global-require const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); webpackPlugins.push(new ReactRefreshWebpackPlugin()); } @@ -113,13 +116,15 @@ module.exports = [ historyApiFallback: true, overlay: true, port: 3000, - before: function(app) { + before: app => { app.use(createContextPathMiddleware("/scm")); }, - after: function(app) { + after: app => { const templatePath = path.join(root, "ui-webapp", "public", "index.mustache"); + const stage = process.env.NODE_ENV || "DEVELOPMENT"; const renderParams = { - contextPath: "/scm" + contextPath: "/scm", + scmStage: stage.toUpperCase() }; app.use(createIndexMiddleware(templatePath, renderParams)); }, diff --git a/scm-ui/ui-webapp/public/index.mustache b/scm-ui/ui-webapp/public/index.mustache index d94bc552ee..3c0a51713c 100644 --- a/scm-ui/ui-webapp/public/index.mustache +++ b/scm-ui/ui-webapp/public/index.mustache @@ -47,6 +47,7 @@ --> diff --git a/scm-webapp/src/main/java/sonia/scm/TemplatingPushStateDispatcher.java b/scm-webapp/src/main/java/sonia/scm/TemplatingPushStateDispatcher.java index 72f451f614..decc6a09c5 100644 --- a/scm-webapp/src/main/java/sonia/scm/TemplatingPushStateDispatcher.java +++ b/scm-webapp/src/main/java/sonia/scm/TemplatingPushStateDispatcher.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm; import com.google.common.annotations.VisibleForTesting; @@ -46,15 +46,17 @@ public class TemplatingPushStateDispatcher implements PushStateDispatcher { static final String TEMPLATE = "/index.mustache"; private final TemplateEngine templateEngine; + private final SCMContextProvider context; @Inject - public TemplatingPushStateDispatcher(TemplateEngineFactory templateEngineFactory) { - this(templateEngineFactory.getDefaultEngine()); + public TemplatingPushStateDispatcher(TemplateEngineFactory templateEngineFactory, SCMContextProvider context) { + this(templateEngineFactory.getDefaultEngine(), context); } @VisibleForTesting - TemplatingPushStateDispatcher(TemplateEngine templateEngine) { + TemplatingPushStateDispatcher(TemplateEngine templateEngine, SCMContextProvider context) { this.templateEngine = templateEngine; + this.context = context; } @Override @@ -64,7 +66,7 @@ public class TemplatingPushStateDispatcher implements PushStateDispatcher { Template template = templateEngine.getTemplate(TEMPLATE); try (Writer writer = response.getWriter()) { - template.execute(writer, new IndexHtmlModel(request)); + template.execute(writer, new IndexHtmlModel(request, context.getStage())); } } @@ -72,15 +74,21 @@ public class TemplatingPushStateDispatcher implements PushStateDispatcher { static class IndexHtmlModel { private final HttpServletRequest request; + private final Stage scmStage; - private IndexHtmlModel(HttpServletRequest request) { + private IndexHtmlModel(HttpServletRequest request, Stage scmStage) { this.request = request; + this.scmStage = scmStage; } public String getContextPath() { return request.getContextPath(); } + public String getScmStage() { + return scmStage.name(); + } + public String getLiveReloadURL() { return System.getProperty("livereload.url"); } diff --git a/scm-webapp/src/test/java/sonia/scm/PushStateDispatcherProviderTest.java b/scm-webapp/src/test/java/sonia/scm/PushStateDispatcherProviderTest.java index ba3cf66c02..4ad89d1907 100644 --- a/scm-webapp/src/test/java/sonia/scm/PushStateDispatcherProviderTest.java +++ b/scm-webapp/src/test/java/sonia/scm/PushStateDispatcherProviderTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm; import com.google.inject.util.Providers; @@ -39,8 +39,11 @@ public class PushStateDispatcherProviderTest { @Mock private TemplateEngine templateEngine; + @Mock + private SCMContextProvider context; + private PushStateDispatcherProvider provider = new PushStateDispatcherProvider( - Providers.of(new TemplatingPushStateDispatcher(templateEngine)) + Providers.of(new TemplatingPushStateDispatcher(templateEngine, context)) ); @Test diff --git a/scm-webapp/src/test/java/sonia/scm/TemplatingPushStateDispatcherTest.java b/scm-webapp/src/test/java/sonia/scm/TemplatingPushStateDispatcherTest.java index a8dcffc196..b20520ea72 100644 --- a/scm-webapp/src/test/java/sonia/scm/TemplatingPushStateDispatcherTest.java +++ b/scm-webapp/src/test/java/sonia/scm/TemplatingPushStateDispatcherTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm; import org.junit.Before; @@ -61,18 +61,24 @@ public class TemplatingPushStateDispatcherTest { @Mock private Template template; + @Mock + private SCMContextProvider context; + private TemplatingPushStateDispatcher dispatcher; @Before public void setUpMocks() { - dispatcher = new TemplatingPushStateDispatcher(templateEngine); + dispatcher = new TemplatingPushStateDispatcher(templateEngine, context); } @Test public void testDispatch() throws IOException { + when(context.getStage()).thenReturn(Stage.DEVELOPMENT); + TemplatingPushStateDispatcher.IndexHtmlModel model = dispatch(); assertEquals("/scm", model.getContextPath()); assertNull(model.getLiveReloadURL()); + assertEquals("DEVELOPMENT", model.getScmStage()); } @Test diff --git a/yarn.lock b/yarn.lock index 4023bb96a1..46062a1534 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1337,6 +1337,54 @@ unique-filename "^1.1.1" which "^1.3.1" +"@ffmpeg-installer/darwin-x64@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz#48e1706c690e628148482bfb64acb67472089aaa" + integrity sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw== + +"@ffmpeg-installer/ffmpeg@^1.0.20": + version "1.0.20" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.0.20.tgz#d3c9c2bbcd76149468fb0886c2b3fe9e4795490b" + integrity sha512-wbgd//6OdwbFXYgV68ZyKrIcozEQpUKlvV66XHaqO2h3sFbX0jYLzx62Q0v8UcFWN21LoxT98NU2P+K0OWsKNA== + optionalDependencies: + "@ffmpeg-installer/darwin-x64" "4.1.0" + "@ffmpeg-installer/linux-arm" "4.1.3" + "@ffmpeg-installer/linux-arm64" "4.1.4" + "@ffmpeg-installer/linux-ia32" "4.1.0" + "@ffmpeg-installer/linux-x64" "4.1.0" + "@ffmpeg-installer/win32-ia32" "4.1.0" + "@ffmpeg-installer/win32-x64" "4.1.0" + +"@ffmpeg-installer/linux-arm64@4.1.4": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz#7219f3f901bb67f7926cb060b56b6974a6cad29f" + integrity sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg== + +"@ffmpeg-installer/linux-arm@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz#c554f105ed5f10475ec25d7bec94926ce18db4c1" + integrity sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg== + +"@ffmpeg-installer/linux-ia32@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz#adad70b0d0d9d8d813983d6e683c5a338a75e442" + integrity sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ== + +"@ffmpeg-installer/linux-x64@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz#b4a5d89c4e12e6d9306dbcdc573df716ec1c4323" + integrity sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A== + +"@ffmpeg-installer/win32-ia32@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz#6eac4fb691b64c02e7a116c1e2d167f3e9b40638" + integrity sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw== + +"@ffmpeg-installer/win32-x64@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz#17e8699b5798d4c60e36e2d6326a8ebe5e95a2c5" + integrity sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg== + "@fortawesome/fontawesome-free@^5.11.2": version "5.13.0" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz#fcb113d1aca4b471b709e8c9c168674fbd6e06d9" @@ -2482,17 +2530,17 @@ dependencies: "@types/node" ">= 8" -"@pmmmwh/react-refresh-webpack-plugin@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.3.3.tgz#40a3d674f42a011b7f30a9609aa8fb68ec3c39c9" - integrity sha512-uc6FmPEegAZawSHjUMFQwU7EjaDn7zy1iD/KD/wBROL9F4378OES8MKMYHoRAKT61Fk7LxVKZSDR5VespMQiqw== +"@pmmmwh/react-refresh-webpack-plugin@^0.4.0": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.1.tgz#a4db0ed8e58c2f8566161c9a8cdf1d095c9a891b" + integrity sha512-MzM87WdX2r2KRFfhEho7oGyK1XRE/J9WwjB3v6oLQHN0dzBypBZxSWjnoYx+RWneRCsg8Sin1myf+EjX1fqIbQ== dependencies: ansi-html "^0.0.7" error-stack-parser "^2.0.6" html-entities "^1.2.1" - lodash.debounce "^4.0.8" native-url "^0.2.6" schema-utils "^2.6.5" + source-map "^0.7.3" "@reach/router@^1.2.1": version "1.3.3" @@ -4175,6 +4223,11 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== +async@>=0.2.9, async@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" @@ -4182,11 +4235,6 @@ async@^2.6.2: dependencies: lodash "^4.17.14" -async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -4239,11 +4287,6 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@7.0.0-bridge.0: - version "7.0.0-bridge.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" - integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== - babel-eslint@^10.0.3: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" @@ -7743,7 +7786,7 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fault@^1.0.0: +fault@^1.0.0, fault@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== @@ -7978,6 +8021,14 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +fluent-ffmpeg@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" + integrity sha1-yVLeIkD4EuvaCqgAbXd27irPfXQ= + dependencies: + async ">=0.2.9" + which "^1.1.1" + flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -8311,7 +8362,7 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -gitdiff-parser@^0.1.2, "gitdiff-parser@https://github.com/scm-manager/gitdiff-parser#617747460280bf4522bb84d217a9064ac8eb6d3d": +gitdiff-parser@^0.1.2: version "0.1.2" resolved "https://github.com/scm-manager/gitdiff-parser#617747460280bf4522bb84d217a9064ac8eb6d3d" @@ -11299,7 +11350,7 @@ lower-case@^2.0.1: dependencies: tslib "^1.10.0" -lowlight@1.13.1, lowlight@^1.13.0, lowlight@~1.11.0: +lowlight@^1.13.0: version "1.13.1" resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.13.1.tgz#c4f0e03906ebd23fedf2d258f6ab2f6324cf90eb" integrity sha512-kQ71/T6RksEVz9AlPq07/2m+SU/1kGvt9k39UtvHX760u4SaWakaYH7hYgH5n6sTsCWk4MVYzUzLU59aN5CSmQ== @@ -11307,6 +11358,14 @@ lowlight@1.13.1, lowlight@^1.13.0, lowlight@~1.11.0: fault "^1.0.0" highlight.js "~9.16.0" +lowlight@~1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.11.0.tgz#1304d83005126d4e8b1dc0f07981e9b689ec2efc" + integrity sha512-xrGGN6XLL7MbTMdPD6NfWPwY43SNkjf/d0mecSx/CW36fUZTjRHEq0/Cdug3TWKtRXLWi7iMl1eP0olYxj/a4A== + dependencies: + fault "^1.0.2" + highlight.js "~9.13.0" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -17044,7 +17103,7 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==