]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Merge branch 'release/4.0.0' into develop
authorChocobozzz <me@florianbigard.com>
Fri, 3 Dec 2021 13:40:52 +0000 (14:40 +0100)
committerChocobozzz <me@florianbigard.com>
Fri, 3 Dec 2021 13:40:52 +0000 (14:40 +0100)
35 files changed:
.github/actions/reusable-deploy/action.yml [new file with mode: 0644]
.github/actions/reusable-prepare-peertube-build/action.yml [new file with mode: 0644]
.github/actions/reusable-prepare-peertube-run/action.yml [new file with mode: 0644]
.github/workflows/benchmark.yml
.github/workflows/codeql.yml [new file with mode: 0644]
.github/workflows/codeql/codeql-config.yml [new file with mode: 0644]
.github/workflows/docker.yml [new file with mode: 0644]
.github/workflows/nightly.yml [new file with mode: 0644]
.github/workflows/stats.yml
.github/workflows/test.yml
.gitlab-ci.yml [deleted file]
client/src/app/+about/about-instance/about-instance.component.html
client/src/app/+about/about.component.html
client/src/app/+login/login.component.html
client/src/app/menu/menu.component.html
client/src/assets/player/p2p-media-loader/hls-plugin.ts
config/test.yaml
package.json
server/controllers/api/plugins.ts
server/controllers/api/videos/upload.ts
server/helpers/decache.ts [new file with mode: 0644]
server/initializers/config.ts
server/initializers/constants.ts
server/lib/client-html.ts
server/lib/plugins/plugin-manager.ts
server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.ts
server/lib/uploadx.ts [new file with mode: 0644]
server/middlewares/validators/plugins.ts
server/tests/cli/peertube.ts
server/tools/peertube-plugins.ts
shared/extra-utils/server/plugins-command.ts
shared/models/plugins/client/plugin-selector-id.type.ts
shared/models/plugins/server/api/install-plugin.model.ts
support/doc/development/ci.md [new file with mode: 0644]
yarn.lock

diff --git a/.github/actions/reusable-deploy/action.yml b/.github/actions/reusable-deploy/action.yml
new file mode 100644 (file)
index 0000000..bc69a2e
--- /dev/null
@@ -0,0 +1,46 @@
+name: "Reusable deploy on builds.joinpeertube.org"
+
+description: "Reusable deploy on builds.joinpeertube.org"
+
+inputs:
+  source:
+    required: true
+    description: "Source file/files/directory/directories to deploy"
+  destination:
+    required: true
+    description: "Destination directory on builds.joinpeertube.org"
+  knownHosts:
+    required: true
+    description: "Known hosts"
+  deployKey:
+    required: true
+    description: "Deploy key"
+  deployUser:
+    required: true
+    description: "Deploy user"
+  deployHost:
+    required: true
+    description: "Deploy host"
+
+
+runs:
+  using: "composite"
+
+  steps:
+    - name: "Deploy"
+      shell: bash
+      run: |
+        mkdir -p ~/.ssh
+        chmod 700  ~/.ssh
+
+        echo "Adding ssh key to known hosts"
+        echo -e "${{ inputs.knownHosts }}" > ~/.ssh/known_hosts;
+
+        eval `ssh-agent -s`
+
+        echo "Adding ssh deploy key"
+        ssh-add <(echo "${{ inputs.deployKey }}");
+
+        echo "Uploading files"
+
+        scp ${{ inputs.source }} ${{ inputs.deployUser }}@${{ inputs.deployHost }}:../../web/${{ inputs.destination }};
diff --git a/.github/actions/reusable-prepare-peertube-build/action.yml b/.github/actions/reusable-prepare-peertube-build/action.yml
new file mode 100644 (file)
index 0000000..41ebf71
--- /dev/null
@@ -0,0 +1,31 @@
+name: "Reusable prepare PeerTube build"
+
+description: "Reusable prepare PeerTube build"
+
+inputs:
+  node-version:
+    required: true
+    description: 'NodeJS version'
+
+runs:
+  using: "composite"
+
+  steps:
+    - name: Use Node.js
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ inputs.node-version }}
+
+    - name: Cache Node.js modules
+      uses: actions/cache@v2
+      with:
+        path: |
+          **/node_modules
+        key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
+        restore-keys: |
+          ${{ runner.OS }}-node-
+          ${{ runner.OS }}-
+
+    - name: Install dependencies
+      shell: bash
+      run: yarn install --frozen-lockfile
diff --git a/.github/actions/reusable-prepare-peertube-run/action.yml b/.github/actions/reusable-prepare-peertube-run/action.yml
new file mode 100644 (file)
index 0000000..1a6cd2c
--- /dev/null
@@ -0,0 +1,16 @@
+name: "Reusable prepare PeerTube run"
+description: "Reusable prepare PeerTube run"
+
+runs:
+  using: "composite"
+
+  steps:
+    - name: Setup system dependencies
+      shell: bash
+      run: |
+        sudo apt-get install postgresql-client-common redis-tools parallel
+        wget --quiet --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.3.1-64bit-static.tar.xz"
+        tar xf ffmpeg-release-4.3.1-64bit-static.tar.xz
+        mkdir -p $HOME/bin
+        cp ffmpeg-*/{ffmpeg,ffprobe} $HOME/bin
+        echo "$HOME/bin" >> $GITHUB_PATH
index 86f675432df916da36c82ac5376fb6043fd11d7a..7e8259d27931dc898ce031f49aae911f4fa44257 100644 (file)
@@ -29,48 +29,15 @@ jobs:
     env:
       PGUSER: peertube
       PGHOST: localhost
-      NODE_PENDING_JOB_WAIT: 500
 
     steps:
       - uses: actions/checkout@v2
 
-      - name: Use Node.js
-        uses: actions/setup-node@v1
+      - uses: './.github/actions/reusable-prepare-peertube-build'
         with:
           node-version: '12.x'
 
-      - name: Setup system dependencies
-        run: |
-          sudo apt-get install postgresql-client-common redis-tools parallel
-          wget --quiet --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.3.1-64bit-static.tar.xz"
-          tar xf ffmpeg-release-4.3.1-64bit-static.tar.xz
-          mkdir -p $HOME/bin
-          cp ffmpeg-*/{ffmpeg,ffprobe} $HOME/bin
-          echo "$HOME/bin" >> $GITHUB_PATH
-
-      - name: Cache Node.js modules
-        uses: actions/cache@v2
-        with:
-          path: |
-            **/node_modules
-          key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.OS }}-node-
-            ${{ runner.OS }}-
-
-      - name: Cache fixtures
-        uses: actions/cache@v2
-        with:
-          path: |
-            fixtures
-          key: ${{ runner.OS }}-fixtures-${{ matrix.test_suite }}-${{ hashFiles('fixtures/*') }}
-          restore-keys: |
-            ${{ runner.OS }}-fixtures-${{ matrix.test_suite }}-
-            ${{ runner.OS }}-fixtures-
-            ${{ runner.OS }}-
-
-      - name: Install dependencies
-        run: yarn install --frozen-lockfile
+      - uses: './.github/actions/reusable-prepare-peertube-run'
 
       - name: Build
         run: |
@@ -111,27 +78,11 @@ jobs:
           cat benchmark.json build-time.json startup-time.json
 
       - name: Upload benchmark result
-        env:
-          STATS_DEPLOYEMENT_KNOWN_HOSTS: ${{ secrets.STATS_DEPLOYEMENT_KNOWN_HOSTS }}
-          STATS_DEPLOYEMENT_KEY: ${{ secrets.STATS_DEPLOYEMENT_KEY }}
-          STATS_DEPLOYEMENT_USER: ${{ secrets.STATS_DEPLOYEMENT_USER }}
-          STATS_DEPLOYEMENT_HOST: ${{ secrets.STATS_DEPLOYEMENT_HOST }}
-        run: |
-          mkdir -p ~/.ssh
-          chmod 700  ~/.ssh
-          if [ ! -z ${STATS_DEPLOYEMENT_KNOWN_HOSTS+x} ]; then
-            echo "Adding ssh key to known hosts"
-            echo -e "${STATS_DEPLOYEMENT_KNOWN_HOSTS}" > ~/.ssh/known_hosts;
-          fi
-
-          eval `ssh-agent -s`
-
-          if [ ! -z ${STATS_DEPLOYEMENT_KEY+x} ]; then
-            echo "Adding ssh reployement key"
-            ssh-add <(echo "${STATS_DEPLOYEMENT_KEY}");
-          fi
-
-          if [ ! -z ${STATS_DEPLOYEMENT_KEY+x} ]; then
-            echo "Uploading files"
-            scp benchmark.json build-time.json startup-time.json ${STATS_DEPLOYEMENT_USER}@${STATS_DEPLOYEMENT_HOST}:../../web/peertube-stats;
-          fi
+        uses: './.github/actions/reusable-deploy'
+        with:
+          source: benchmark.json build-time.json startup-time.json
+          destination: peertube-stats
+          knownHosts: ${{ secrets.STATS_DEPLOYEMENT_KNOWN_HOSTS }}
+          deployKey: ${{ secrets.STATS_DEPLOYEMENT_KEY }}
+          deployUser: ${{ secrets.STATS_DEPLOYEMENT_USER }}
+          deployHost: ${{ secrets.STATS_DEPLOYEMENT_HOST }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644 (file)
index 0000000..8764cdd
--- /dev/null
@@ -0,0 +1,68 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ develop, next ]
+  schedule:
+    - cron: '36 9 * * 5'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'javascript' ]
+        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+        # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v2
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v1
+      with:
+        languages: ${{ matrix.language }}
+        config-file: ./.github/workflows/codeql/codeql-config.yml
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file.
+        # Prefix the list here with "+" to use these queries and those in the config file.
+        # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v1
+
+    # ℹ️ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/codeql/codeql-config.yml b/.github/workflows/codeql/codeql-config.yml
new file mode 100644 (file)
index 0000000..8b771ae
--- /dev/null
@@ -0,0 +1,4 @@
+name: "PeerTube CodeQL config"
+
+paths-ignore:
+ - server/tests
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
new file mode 100644 (file)
index 0000000..7afe641
--- /dev/null
@@ -0,0 +1,70 @@
+name: Docker
+
+on:
+  push:
+    branches:
+      - 'master'
+  schedule:
+    - cron: '0 3 * * *'
+
+jobs:
+  generate-matrix:
+    name: Generate matrix for Docker build
+    runs-on: ubuntu-latest
+    outputs:
+      matrix: ${{ steps.set-matrix.outputs.matrix }}
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          ref: master
+      - name: Set matrix for build
+        id: set-matrix
+        run: |
+          # FIXME: https://github.com/actions/checkout/issues/290
+          git fetch --force --tags
+
+          one="{ \"file\": \"./support/docker/production/Dockerfile.bullseye\", \"ref\": \"develop\", \"tags\": \"chocobozzz/peertube:develop-bullseye\" }"
+          two="{ \"file\": \"./support/docker/production/Dockerfile.buster\", \"ref\": \"master\", \"tags\": \"chocobozzz/peertube:production-buster,chocobozzz/peertube:$(git describe --abbrev=0)-buster\" }"
+          three="{ \"file\": \"./support/docker/production/Dockerfile.nginx\", \"ref\": \"master\", \"tags\": \"chocobozzz/peertube-webserver:latest\" }"
+
+          matrix="[$one,$two,$three]"
+          echo ::set-output name=matrix::{\"include\":$(echo $matrix)}
+
+  docker:
+    runs-on: ubuntu-latest
+
+    needs: generate-matrix
+
+    strategy:
+      matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
+      fail-fast: false
+
+    steps:
+      -
+        name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
+      -
+        name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v1
+      -
+        name: Login to DockerHub
+        uses: docker/login-action@v1
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+      -
+        name: Checkout develop
+        uses: actions/checkout@v2
+        with:
+          ref: ${{ matrix.ref }}
+      -
+        name: Docker build
+        uses: docker/build-push-action@v2
+        with:
+          context: '.'
+          platforms: linux/amd64,linux/arm64
+          push: true
+          file: ${{ matrix.file }}
+          tags: ${{ matrix.tags }}
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644 (file)
index 0000000..23898b7
--- /dev/null
@@ -0,0 +1,33 @@
+name: Nightly
+
+on:
+  schedule:
+    - cron: '0 3 * * *'
+
+jobs:
+
+  nightly:
+    runs-on: ubuntu-latest
+
+    steps:
+      -
+        name: Checkout develop
+        uses: actions/checkout@v2
+        with:
+          ref: develop
+
+      - uses: './.github/actions/reusable-prepare-peertube-build'
+        with:
+          node-version: '14.x'
+
+      - name: Build
+        run: npm run nightly
+
+      - uses: './.github/actions/reusable-deploy'
+        with:
+          source: ./peertube-nightly-*
+          destination: nightly
+          knownHosts: ${{ secrets.STATS_DEPLOYEMENT_KNOWN_HOSTS }}
+          deployKey: ${{ secrets.STATS_DEPLOYEMENT_KEY }}
+          deployUser: ${{ secrets.STATS_DEPLOYEMENT_USER }}
+          deployHost: ${{ secrets.STATS_DEPLOYEMENT_HOST }}
index e211f6a3b05cf54b869a83ed177982a147d15524..c87e6fb7759b8532a44f8506616d34fec4982b25 100644 (file)
@@ -1,4 +1,4 @@
-name: "Stats"
+name: Stats
 
 on:
   push:
@@ -20,24 +20,10 @@ jobs:
     steps:
       - uses: actions/checkout@v2
 
-      - name: Use Node.js
-        uses: actions/setup-node@v1
+      - uses: './.github/actions/reusable-prepare-peertube-build'
         with:
           node-version: '14.x'
 
-      - name: Cache Node.js modules
-        uses: actions/cache@v2
-        with:
-          path: |
-            **/node_modules
-          key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.OS }}-node-
-            ${{ runner.OS }}-
-
-      - name: Install dependencies
-        run: yarn install --frozen-lockfile
-
       - name: Angular bundlewatch
         uses: jackyef/bundlewatch-gh-action@master
         with:
@@ -73,27 +59,11 @@ jobs:
 
       - name: Upload stats
         if: github.event_name != 'pull_request'
-        env:
-          STATS_DEPLOYEMENT_KNOWN_HOSTS: ${{ secrets.STATS_DEPLOYEMENT_KNOWN_HOSTS }}
-          STATS_DEPLOYEMENT_KEY: ${{ secrets.STATS_DEPLOYEMENT_KEY }}
-          STATS_DEPLOYEMENT_USER: ${{ secrets.STATS_DEPLOYEMENT_USER }}
-          STATS_DEPLOYEMENT_HOST: ${{ secrets.STATS_DEPLOYEMENT_HOST }}
-        run: |
-          mkdir -p ~/.ssh
-          chmod 700  ~/.ssh
-          if [ ! -z ${STATS_DEPLOYEMENT_KNOWN_HOSTS+x} ]; then
-            echo "Adding ssh key to known hosts"
-            echo -e "${STATS_DEPLOYEMENT_KNOWN_HOSTS}" > ~/.ssh/known_hosts;
-          fi
-
-          eval `ssh-agent -s`
-
-          if [ ! -z ${STATS_DEPLOYEMENT_KEY+x} ]; then
-            echo "Adding ssh reployement key"
-            ssh-add <(echo "${STATS_DEPLOYEMENT_KEY}");
-          fi
-
-          if [ ! -z ${STATS_DEPLOYEMENT_KEY+x} ]; then
-            echo "Uploading files"
-            scp lighthouse.json client-build-stats.json scc.json ${STATS_DEPLOYEMENT_USER}@${STATS_DEPLOYEMENT_HOST}:../../web/peertube-stats;
-          fi
+        uses: './.github/actions/reusable-deploy'
+        with:
+          source: lighthouse.json client-build-stats.json scc.json
+          destination: peertube-stats
+          knownHosts: ${{ secrets.STATS_DEPLOYEMENT_KNOWN_HOSTS }}
+          deployKey: ${{ secrets.STATS_DEPLOYEMENT_KEY }}
+          deployUser: ${{ secrets.STATS_DEPLOYEMENT_USER }}
+          deployHost: ${{ secrets.STATS_DEPLOYEMENT_HOST }}
index 78a9a28c03e7b098e3c4196f092265864d1886b9..030ec37908216b1c8287eb35b79e5625f402c3ee 100644 (file)
@@ -1,4 +1,4 @@
-name: Test Suite
+name: Test
 
 on:
   push:
@@ -50,29 +50,11 @@ jobs:
     steps:
       - uses: actions/checkout@v2
 
-      - name: Use Node.js
-        uses: actions/setup-node@v1
+      - uses: './.github/actions/reusable-prepare-peertube-build'
         with:
           node-version: '12.x'
 
-      - name: Setup system dependencies
-        run: |
-          sudo apt-get install postgresql-client-common redis-tools parallel
-          wget --quiet --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.3.1-64bit-static.tar.xz"
-          tar xf ffmpeg-release-4.3.1-64bit-static.tar.xz
-          mkdir -p $HOME/bin
-          cp ffmpeg-*/{ffmpeg,ffprobe} $HOME/bin
-          echo "$HOME/bin" >> $GITHUB_PATH
-
-      - name: Cache Node.js modules
-        uses: actions/cache@v2
-        with:
-          path: |
-            **/node_modules
-          key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.OS }}-node-
-            ${{ runner.OS }}-
+      - uses: './.github/actions/reusable-prepare-peertube-run'
 
       - name: Cache fixtures
         uses: actions/cache@v2
@@ -85,9 +67,6 @@ jobs:
             ${{ runner.OS }}-fixtures-
             ${{ runner.OS }}-
 
-      - name: Install dependencies
-        run: yarn install --frozen-lockfile
-
       - name: Set env test variable (schedule)
         if: github.event_name != 'schedule'
         run: |
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644 (file)
index ad94c8c..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-image: chocobozzz/peertube-ci:14
-
-stages:
-  - clients
-  - docker-nightly
-
-cache:
-  key: yarn
-  paths:
-    - .yarn-cache
-    - cached-fixtures
-
-# build-openapi-clients:
-#   stage: clients
-#   only:
-#     refs:
-#       - master
-#       - schedules
-#     changes:
-#       - support/doc/api/openapi.yaml
-#   script:
-#     - apt-get update -qq
-#     - apt-get -yqqq install openjdk-8-jre
-#     - yarn install --pure-lockfile
-#     - scripts/openapi-peertube-version.sh
-#     - scripts/openapi-clients.sh
-
-build-nightly:
-  stage: docker-nightly
-  only:
-    - schedules
-  script:
-    - yarn install --pure-lockfile --cache-folder .yarn-cache
-    - npm run nightly
-    - mkdir "${HOME}/.ssh"
-    - chmod 700 "${HOME}/.ssh"
-    - if [ ! -z ${DEPLOYEMENT_KNOWN_HOSTS+x} ]; then echo -e "${DEPLOYEMENT_KNOWN_HOSTS}" > ${HOME}/.ssh/known_hosts; fi
-    - eval `ssh-agent -s`
-    - if [ ! -z ${DEPLOYEMENT_KEY+x} ]; then ssh-add <(echo "${DEPLOYEMENT_KEY}"); fi
-    - if [ ! -z ${DEPLOYEMENT_KEY+x} ]; then scp ./peertube-nightly-* ${DEPLOYEMENT_USER}@${DEPLOYEMENT_HOST}:../../web/nightly; fi
-
-.docker: &docker
-  stage: docker-nightly
-  cache: {}
-  image:
-    name: gcr.io/kaniko-project/executor:debug
-    entrypoint: [""]
-  before_script:
-    - mkdir -p /kaniko/.docker
-    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$CI_REGISTRY_AUTH\",\"email\":\"$CI_REGISTRY_EMAIL\"}}}" > /kaniko/.docker/config.json
-  script:
-    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $DOCKERFILE --destination $DOCKER_IMAGE_NAME
-
-build-docker-develop:
-  <<: *docker
-  only:
-    - schedules
-  variables:
-    DOCKER_IMAGE_NAME: chocobozzz/peertube:develop-bullseye
-    DOCKERFILE: $CI_PROJECT_DIR/support/docker/production/Dockerfile.bullseye
-
-build-docker-webserver:
-  <<: *docker
-  only:
-    - schedules
-  variables:
-    DOCKER_IMAGE_NAME: chocobozzz/peertube-webserver
-    DOCKERFILE: $CI_PROJECT_DIR/support/docker/production/Dockerfile.nginx
-
-build-docker-tag:
-  <<: *docker
-  only:
-    - tags
-  variables:
-    DOCKER_IMAGE_NAME: chocobozzz/peertube:$CI_COMMIT_TAG-bullseye
-    DOCKERFILE: $CI_PROJECT_DIR/support/docker/production/Dockerfile.bullseye
-
-build-docker-master:
-  <<: *docker
-  only:
-    - master
-  variables:
-    DOCKER_IMAGE_NAME: chocobozzz/peertube:production-bullseye
-    DOCKERFILE: $CI_PROJECT_DIR/support/docker/production/Dockerfile.bullseye
index 1026c4e0da506df49292def0cde68cec724e028c..7f2a6aa772eccb56f65b5efee8d2583179a77aa0 100644 (file)
       <my-custom-markup-container [content]="descriptionContent"></my-custom-markup-container>
     </div>
 
-    <div class="anchor" id="moderation"></div>
-    <a
-      *ngIf="html.moderationInformation || html.codeOfConduct || html.terms"
-      class="anchor-link"
-      routerLink="/about/instance"
-      fragment="moderation"
-      #anchorLink
-      (click)="onClickCopyLink(anchorLink)">
-      <h2 i18n class="middle-title">
-        MODERATION
-      </h2>
-    </a>
-
-    <div class="block moderation-information" *ngIf="html.moderationInformation">
-      <div class="anchor" id="moderation-information"></div>
+    <div myPluginSelector pluginSelectorId="about-instance-moderation">
+      <div class="anchor" id="moderation"></div>
       <a
+        *ngIf="html.moderationInformation || html.codeOfConduct || html.terms"
         class="anchor-link"
         routerLink="/about/instance"
-        fragment="moderation-information"
+        fragment="moderation"
         #anchorLink
         (click)="onClickCopyLink(anchorLink)">
-        <h3 i18n class="section-title">Moderation information</h3>
+        <h2 i18n class="middle-title">
+          MODERATION
+        </h2>
       </a>
 
-      <div [innerHTML]="html.moderationInformation"></div>
-    </div>
+      <div class="block moderation-information" *ngIf="html.moderationInformation">
+        <div class="anchor" id="moderation-information"></div>
+        <a
+          class="anchor-link"
+          routerLink="/about/instance"
+          fragment="moderation-information"
+          #anchorLink
+          (click)="onClickCopyLink(anchorLink)">
+          <h3 i18n class="section-title">Moderation information</h3>
+        </a>
 
-    <div class="block code-of-conduct" *ngIf="html.codeOfConduct">
-      <div class="anchor" id="code-of-conduct"></div>
-      <a
-        class="anchor-link"
-        routerLink="/about/instance"
-        fragment="code-of-conduct"
-        #anchorLink
-        (click)="onClickCopyLink(anchorLink)">
-        <h3 i18n class="section-title">Code of conduct</h3>
-      </a>
+        <div [innerHTML]="html.moderationInformation"></div>
+      </div>
 
-      <div [innerHTML]="html.codeOfConduct"></div>
-    </div>
+      <div class="block code-of-conduct" *ngIf="html.codeOfConduct">
+        <div class="anchor" id="code-of-conduct"></div>
+        <a
+          class="anchor-link"
+          routerLink="/about/instance"
+          fragment="code-of-conduct"
+          #anchorLink
+          (click)="onClickCopyLink(anchorLink)">
+          <h3 i18n class="section-title">Code of conduct</h3>
+        </a>
 
-    <div class="block terms">
-      <div class="anchor" id="terms"></div>
-      <a
-        class="anchor-link"
-        routerLink="/about/instance"
-        fragment="terms"
-        #anchorLink
-        (click)="onClickCopyLink(anchorLink)">
-        <h3 i18n class="section-title">Terms</h3>
-      </a>
+        <div [innerHTML]="html.codeOfConduct"></div>
+      </div>
 
-      <div [innerHTML]="html.terms"></div>
-    </div>
+      <div class="block terms">
+        <div class="anchor" id="terms"></div>
+        <a
+          class="anchor-link"
+          routerLink="/about/instance"
+          fragment="terms"
+          #anchorLink
+          (click)="onClickCopyLink(anchorLink)">
+          <h3 i18n class="section-title">Terms</h3>
+        </a>
 
-    <div class="anchor" id="other-information"></div>
-    <a
-      *ngIf="html.hardwareInformation"
-      class="anchor-link"
-      routerLink="/about/instance"
-      fragment="other-information"
-      #anchorLink
-      (click)="onClickCopyLink(anchorLink)">
-      <h2 i18n class="middle-title">
-        OTHER INFORMATION
-      </h2>
-    </a>
+        <div [innerHTML]="html.terms"></div>
+      </div>
+    </div>
 
-    <div class="block hardware-information" *ngIf="html.hardwareInformation">
-      <div class="anchor" id="hardware-information"></div>
+    <div myPluginSelector pluginSelectorId="about-instance-other-information">
+      <div class="anchor" id="other-information"></div>
       <a
+        *ngIf="html.hardwareInformation"
         class="anchor-link"
         routerLink="/about/instance"
-        fragment="hardware-information"
+        fragment="other-information"
         #anchorLink
         (click)="onClickCopyLink(anchorLink)">
-        <h3 i18n class="section-title">Hardware information</h3>
+        <h2 i18n class="middle-title">
+          OTHER INFORMATION
+        </h2>
       </a>
 
-      <div [innerHTML]="html.hardwareInformation"></div>
+      <div class="block hardware-information" *ngIf="html.hardwareInformation">
+        <div class="anchor" id="hardware-information"></div>
+        <a
+          class="anchor-link"
+          routerLink="/about/instance"
+          fragment="hardware-information"
+          #anchorLink
+          (click)="onClickCopyLink(anchorLink)">
+          <h3 i18n class="section-title">Hardware information</h3>
+        </a>
+
+        <div [innerHTML]="html.hardwareInformation"></div>
+      </div>
     </div>
   </div>
 
-  <div class="col-md-12 col-xl-6">
+  <div class="col-md-12 col-xl-6" myPluginSelector pluginSelectorId="about-instance-features">
     <h2 class="sr-only" i18n>FEATURES</h2>
     <my-instance-features-table></my-instance-features-table>
   </div>
 
-  <div class="col">
+  <div class="col" myPluginSelector pluginSelectorId="about-instance-statistics">
     <div class="anchor" id="statistics"></div>
     <a
       class="anchor-link"
index 1ab00c5df4f72db0d40395a75ce2fd0736426ad2..63d429ebfb5be2d220013ec6353e86d50f6680e1 100644 (file)
@@ -2,11 +2,11 @@
   <div class="sub-menu" [ngClass]="{ 'sub-menu-fixed': !isBroadcastMessageDisplayed }">
 
     <div class="links">
-      <a i18n routerLink="instance" routerLinkActive="active" class="title-page title-page-about">Instance</a>
+      <a myPluginSelector pluginSelectorId="about-menu-instance" i18n routerLink="instance" routerLinkActive="active" class="title-page title-page-about">Instance</a>
 
-      <a i18n routerLink="peertube" routerLinkActive="active" class="title-page title-page-about">PeerTube</a>
+      <a myPluginSelector pluginSelectorId="about-menu-peertube" i18n routerLink="peertube" routerLinkActive="active" class="title-page title-page-about">PeerTube</a>
 
-      <a i18n routerLink="follows" routerLinkActive="active" class="title-page title-page-about">Network</a>
+      <a myPluginSelector pluginSelectorId="about-menu-network" i18n routerLink="follows" routerLinkActive="active" class="title-page title-page-about">Network</a>
     </div>
   </div>
 
index 90eea1505e4959a7a0d1c6c8752bb9c3a423ba21..531b06dc9216b4fe0c08a98efbbfb5dc7e987491 100644 (file)
@@ -48,7 +48,8 @@
           <input type="submit" class="peertube-button orange-button" i18n-value value="Login" [disabled]="!form.valid">
 
           <div class="additionnal-links">
-            <a i18n class="forgot-password-button" (click)="openForgotPasswordModal()" i18n-title title="Click here to reset your password">I forgot my password</a>
+            <a i18n role="button" class="forgot-password-button" (click)="openForgotPasswordModal()" i18n-title title="Click here to reset your password">I forgot my password</a>
+
             <div *ngIf="signupAllowed" class="signup-link">
               <span>·</span>
               <a i18n routerLink="/signup" class="create-an-account">Create an account</a>
index 46dd807ec5b171eba79a819907e42e4b401a6971..55fc27b5f410b239ef6bbdcae5f29d4a2f14563a 100644 (file)
 
               <div class="dropdown-divider"></div>
 
-              <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" (click)="openLanguageChooser()">
+              <a
+                myPluginSelector pluginSelectorId="menu-user-dropdown-language-item"
+                ngbDropdownItem ngbDropdownToggle class="dropdown-item" (click)="openLanguageChooser()"
+              >
                 <my-global-icon iconName="language" aria-hidden="true"></my-global-icon>
                 <span i18n>Interface:</span>
                 <span class="ml-auto text-muted">{{ currentInterfaceLanguage }}</span>
index 71c31696a3e5f70b4f896dc9f3b23cc7d9583010..2aa691f05fa05361a4908d5e188908d25d921f4d 100644 (file)
@@ -146,7 +146,9 @@ class Html5Hlsjs {
   }
 
   duration () {
-    return this._duration || this.videoElement.duration || 0
+    if (!isNaN(this.videoElement.duration)) return this.videoElement.duration
+
+    return this._duration || 0
   }
 
   seekable () {
@@ -366,6 +368,7 @@ class Html5Hlsjs {
 
       this.isLive = data.details.live
       this.dvrDuration = data.details.totalduration
+
       this._duration = this.isLive ? Infinity : data.details.totalduration
     })
 
index 2e7f982d3ca01204da1cd58a3ab73b21174cff2c..461e1b4ba637e88b28a3330d396f088aed9ff647 100644 (file)
@@ -155,6 +155,7 @@ search:
 federation:
   videos:
     federate_unlisted: true
+    cleanup_remote_interactions: false
 
 views:
   videos:
index 6cc00d1ae34e6b702428b821c78f78eadec6cdc4..b03f5dcdb01b1702891caa2f2d3283ad39b0505c 100644 (file)
@@ -90,7 +90,6 @@
     "cookie-parser": "^1.4.3",
     "cors": "^2.8.1",
     "create-torrent": "^5.0.0",
-    "decache": "^4.6.0",
     "deep-object-diff": "^1.1.0",
     "email-templates": "^8.0.3",
     "execa": "^5.1.1",
index 2de7fe41f48e826cea5e9a8d729021a45faee500..de9e055dc0fe4b9bf7db4b7c0a5484237a44ebc9 100644 (file)
@@ -144,8 +144,13 @@ async function installPlugin (req: express.Request, res: express.Response) {
 
   const fromDisk = !!body.path
   const toInstall = body.npmName || body.path
+
+  const pluginVersion = body.pluginVersion && body.npmName
+    ? body.pluginVersion
+    : undefined
+
   try {
-    const plugin = await PluginManager.Instance.install(toInstall, undefined, fromDisk)
+    const plugin = await PluginManager.Instance.install(toInstall, pluginVersion, fromDisk)
 
     return res.json(plugin.toFormattedJSON())
   } catch (err) {
index 6773b500f4e0981ddc56a74cf9ea1d497a79ed39..c827f6bf0d161bc0a693d032d1acc5068bce4182 100644 (file)
@@ -8,6 +8,7 @@ import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
 import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
 import { generateWebTorrentVideoFilename } from '@server/lib/paths'
 import { Redis } from '@server/lib/redis'
+import { uploadx } from '@server/lib/uploadx'
 import {
   addMoveToObjectStorageJob,
   addOptimizeOrMergeAudioJob,
@@ -19,7 +20,6 @@ import { VideoPathManager } from '@server/lib/video-path-manager'
 import { buildNextVideoState } from '@server/lib/video-state'
 import { openapiOperationDoc } from '@server/middlewares/doc'
 import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models'
-import { Uploadx } from '@uploadx/core'
 import { VideoCreate, VideoState } from '../../../../shared'
 import { HttpStatusCode } from '../../../../shared/models'
 import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger'
@@ -41,8 +41,8 @@ import {
   authenticate,
   videosAddLegacyValidator,
   videosAddResumableInitValidator,
-  videosResumableUploadIdValidator,
-  videosAddResumableValidator
+  videosAddResumableValidator,
+  videosResumableUploadIdValidator
 } from '../../../middlewares'
 import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
 import { VideoModel } from '../../../models/video/video'
@@ -52,9 +52,6 @@ const lTags = loggerTagsFactory('api', 'video')
 const auditLogger = auditLoggerFactory('videos')
 const uploadRouter = express.Router()
 
-const uploadx = new Uploadx({ directory: getResumableUploadPath() })
-uploadx.getUserId = (_, res: express.Response) => res.locals.oauth?.token.user.id
-
 const reqVideoFileAdd = createReqFiles(
   [ 'videofile', 'thumbnailfile', 'previewfile' ],
   Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT),
diff --git a/server/helpers/decache.ts b/server/helpers/decache.ts
new file mode 100644 (file)
index 0000000..e31973b
--- /dev/null
@@ -0,0 +1,78 @@
+// Thanks: https://github.com/dwyl/decache
+// We reuse this file to also uncache plugin base path
+
+import { extname } from 'path'
+
+function decachePlugin (pluginPath: string, libraryPath: string) {
+  const moduleName = find(libraryPath)
+
+  if (!moduleName) return
+
+  searchCache(moduleName, function (mod) {
+    delete require.cache[mod.id]
+  })
+
+  removeCachedPath(pluginPath)
+}
+
+function decacheModule (name: string) {
+  const moduleName = find(name)
+
+  if (!moduleName) return
+
+  searchCache(moduleName, function (mod) {
+    delete require.cache[mod.id]
+  })
+
+  removeCachedPath(moduleName)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  decacheModule,
+  decachePlugin
+}
+
+// ---------------------------------------------------------------------------
+
+function find (moduleName: string) {
+  try {
+    return require.resolve(moduleName)
+  } catch {
+    return ''
+  }
+}
+
+function searchCache (moduleName: string, callback: (current: NodeModule) => void) {
+  const resolvedModule = require.resolve(moduleName)
+  let mod: NodeModule
+  const visited = {}
+
+  if (resolvedModule && ((mod = require.cache[resolvedModule]) !== undefined)) {
+    // Recursively go over the results
+    (function run (current) {
+      visited[current.id] = true
+
+      current.children.forEach(function (child) {
+        if (extname(child.filename) !== '.node' && !visited[child.id]) {
+          run(child)
+        }
+      })
+
+      // Call the specified callback providing the
+      // found module
+      callback(current)
+    })(mod)
+  }
+};
+
+function removeCachedPath (pluginPath: string) {
+  const pathCache = (module.constructor as any)._pathCache
+
+  Object.keys(pathCache).forEach(function (cacheKey) {
+    if (cacheKey.includes(pluginPath)) {
+      delete pathCache[cacheKey]
+    }
+  })
+}
index dadda2a774d52e3dc3bf2d312cda612b118517fa..f3a7c6b6b42b9b8d6eb17f96f33ba5df3883e1be 100644 (file)
@@ -1,7 +1,7 @@
 import bytes from 'bytes'
 import { IConfig } from 'config'
-import decache from 'decache'
 import { dirname, join } from 'path'
+import { decacheModule } from '@server/helpers/decache'
 import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type'
 import { BroadcastMessageLevel } from '@shared/models/server'
 import { VideosRedundancyStrategy } from '../../shared/models'
@@ -497,7 +497,7 @@ export function reloadConfig () {
       delete require.cache[fileName]
     }
 
-    decache('config')
+    decacheModule('config')
   }
 
   purge()
index b8633e83e1bddcadad24f71a685f9159f9fae980..c61c01d62e8e3b59ac3d1a17c3dcb5fa0b6bf859 100644 (file)
@@ -223,7 +223,7 @@ const SCHEDULER_INTERVALS_MS = {
   REMOVE_OLD_VIEWS: 60000 * 60 * 24, // 1 day
   REMOVE_OLD_HISTORY: 60000 * 60 * 24, // 1 day
   UPDATE_INBOX_STATS: 1000 * 60, // 1 minute
-  REMOVE_DANGLING_RESUMABLE_UPLOADS: 60000 * 60 * 16 // 16 hours
+  REMOVE_DANGLING_RESUMABLE_UPLOADS: 60000 * 60 // 1 hour
 }
 
 // ---------------------------------------------------------------------------
index 360b4667f586bf36e9955ec184da60788b0199ca..adc3d712e98eda336e10e5f81a4b7cfbac98a9c4 100644 (file)
@@ -350,10 +350,6 @@ class ClientHtml {
     return join(__dirname, '../../../client/dist/standalone/videos/embed.html')
   }
 
-  private static addHtmlLang (htmlStringPage: string, paramLang: string) {
-    return htmlStringPage.replace('<html>', `<html lang="${paramLang}">`)
-  }
-
   private static addManifestContentHash (htmlStringPage: string) {
     return htmlStringPage.replace('[manifestContentHash]', FILES_CONTENT_HASH.MANIFEST)
   }
index d4d2a7edc31cf9f4610912a5089295c7eb7e929c..6c2f4764e4169f28e826ca970e22bdc75c6131a1 100644 (file)
@@ -1,8 +1,8 @@
-import decache from 'decache'
 import express from 'express'
 import { createReadStream, createWriteStream } from 'fs'
 import { ensureDir, outputFile, readJSON } from 'fs-extra'
 import { basename, join } from 'path'
+import { decachePlugin } from '@server/helpers/decache'
 import { MOAuthTokenUser, MUser } from '@server/types/models'
 import { getCompleteLocale } from '@shared/core-utils'
 import { ClientScript, PluginPackageJson, PluginTranslation, PluginTranslationPaths, RegisterServerHookOptions } from '@shared/models'
@@ -420,7 +420,7 @@ export class PluginManager implements ServerHook {
 
     // Delete cache if needed
     const modulePath = join(pluginPath, packageJSON.library)
-    decache(modulePath)
+    decachePlugin(pluginPath, modulePath)
     const library: PluginLibrary = require(modulePath)
 
     if (!isLibraryCodeValid(library)) {
index d6e561cadffa54ec70e7835e00a5b377c9092064..61e93eafa89402d6508b3da15956ce7f2d210da4 100644 (file)
@@ -1,9 +1,7 @@
-import { map } from 'bluebird'
-import { readdir, remove, stat } from 'fs-extra'
+
 import { logger, loggerTagsFactory } from '@server/helpers/logger'
-import { getResumableUploadPath } from '@server/helpers/upload'
 import { SCHEDULER_INTERVALS_MS } from '@server/initializers/constants'
-import { METAFILE_EXTNAME } from '@uploadx/core'
+import { uploadx } from '../uploadx'
 import { AbstractScheduler } from './abstract-scheduler'
 
 const lTags = loggerTagsFactory('scheduler', 'resumable-upload', 'cleaner')
@@ -22,36 +20,17 @@ export class RemoveDanglingResumableUploadsScheduler extends AbstractScheduler {
   }
 
   protected async internalExecute () {
-    const path = getResumableUploadPath()
-    const files = await readdir(path)
-
-    const metafiles = files.filter(f => f.endsWith(METAFILE_EXTNAME))
+    logger.debug('Removing dangling resumable uploads', lTags())
 
-    if (metafiles.length === 0) return
-
-    logger.debug('Reading resumable video upload folder %s with %d files', path, metafiles.length, lTags())
+    const now = new Date().getTime()
 
     try {
-      await map(metafiles, metafile => {
-        return this.deleteIfOlderThan(metafile, this.lastExecutionTimeMs)
-      }, { concurrency: 5 })
+      // Remove files that were not updated since the last execution
+      await uploadx.storage.purge(now - this.lastExecutionTimeMs)
     } catch (error) {
       logger.error('Failed to handle file during resumable video upload folder cleanup', { error, ...lTags() })
     } finally {
-      this.lastExecutionTimeMs = new Date().getTime()
-    }
-  }
-
-  private async deleteIfOlderThan (metafile: string, olderThan: number) {
-    const metafilePath = getResumableUploadPath(metafile)
-    const statResult = await stat(metafilePath)
-
-    // Delete uploads that started since a long time
-    if (statResult.ctimeMs < olderThan) {
-      await remove(metafilePath)
-
-      const datafile = metafilePath.replace(new RegExp(`${METAFILE_EXTNAME}$`), '')
-      await remove(datafile)
+      this.lastExecutionTimeMs = now
     }
   }
 
diff --git a/server/lib/uploadx.ts b/server/lib/uploadx.ts
new file mode 100644 (file)
index 0000000..11b1044
--- /dev/null
@@ -0,0 +1,10 @@
+import express from 'express'
+import { getResumableUploadPath } from '@server/helpers/upload'
+import { Uploadx } from '@uploadx/core'
+
+const uploadx = new Uploadx({ directory: getResumableUploadPath() })
+uploadx.getUserId = (_, res: express.Response) => res.locals.oauth?.token.user.id
+
+export {
+  uploadx
+}
index 21171af236e36cc2152a83b51f76cd7ec8c9f0d0..c1e9ebefbb25f8aa2af3a9d6bf642426ab2d24a1 100644 (file)
@@ -116,6 +116,9 @@ const installOrUpdatePluginValidator = [
   body('npmName')
     .optional()
     .custom(isNpmPluginNameValid).withMessage('Should have a valid npm name'),
+  body('pluginVersion')
+    .optional()
+    .custom(isPluginVersionValid).withMessage('Should have a valid plugin version'),
   body('path')
     .optional()
     .custom(isSafePath).withMessage('Should have a valid safe path'),
@@ -129,6 +132,9 @@ const installOrUpdatePluginValidator = [
     if (!body.path && !body.npmName) {
       return res.fail({ message: 'Should have either a npmName or a path' })
     }
+    if (body.pluginVersion && !body.npmName) {
+      return res.fail({ message: 'Should have a npmName when specifying a pluginVersion' })
+    }
 
     return next()
   }
index f2a9849628547a11b853a35b05e13c96297a9f68..3ac440f841aea58c7bde291c121a7ead926fed45 100644 (file)
@@ -207,6 +207,25 @@ describe('Test CLI wrapper', function () {
 
       expect(res).to.not.contain('peertube-plugin-hello-world')
     })
+
+    it('Should install a plugin in requested version', async function () {
+      this.timeout(60000)
+
+      await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world --plugin-version 0.0.17`)
+    })
+
+    it('Should list installed plugins, in correct version', async function () {
+      const res = await cliCommand.execWithEnv(`${cmd} plugins list`)
+
+      expect(res).to.contain('peertube-plugin-hello-world')
+      expect(res).to.contain('0.0.17')
+    })
+
+    it('Should uninstall the plugin again', async function () {
+      const res = await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`)
+
+      expect(res).to.not.contain('peertube-plugin-hello-world')
+    })
   })
 
   describe('Manage video redundancies', function () {
index ae625114d2012d7597deed308f7610e0e63d9746..9dd3f08c90095a2d20bf3670a3553c2394c7ffd6 100644 (file)
@@ -31,6 +31,7 @@ program
   .option('-p, --password <token>', 'Password')
   .option('-P --path <path>', 'Install from a path')
   .option('-n, --npm-name <npmName>', 'Install from npm')
+  .option('--plugin-version <pluginVersion>', 'Specify the plugin version to install (only available when installing from npm)')
   .action((options, command) => installPluginCLI(command, options))
 
 program
@@ -109,7 +110,7 @@ async function installPluginCLI (command: Command, options: OptionValues) {
   await assignToken(server, username, password)
 
   try {
-    await server.plugins.install({ npmName: options.npmName, path: options.path })
+    await server.plugins.install({ npmName: options.npmName, path: options.path, pluginVersion: options.pluginVersion })
   } catch (err) {
     console.error('Cannot install plugin.', err)
     process.exit(-1)
index b944475a264647e83bcff2023844752c7cbae68d..9bf24afffc3aab16a98b92e6ce99ec0700123d00 100644 (file)
@@ -158,15 +158,16 @@ export class PluginsCommand extends AbstractCommand {
   install (options: OverrideCommandOptions & {
     path?: string
     npmName?: string
+    pluginVersion?: string
   }) {
-    const { npmName, path } = options
+    const { npmName, path, pluginVersion } = options
     const apiPath = '/api/v1/plugins/install'
 
     return this.postBodyRequest({
       ...options,
 
       path: apiPath,
-      fields: { npmName, path },
+      fields: { npmName, path, pluginVersion },
       implicitToken: true,
       defaultExpectedStatus: HttpStatusCode.OK_200
     })
index b74dffbef71b19f3cf56276a0bdc60799bc7a4dd..8d23314b5ad98f18bcbc8c571a6b17342446df74 100644 (file)
@@ -1 +1,10 @@
-export type PluginSelectorId = 'login-form'
+export type PluginSelectorId =
+  'login-form' |
+  'menu-user-dropdown-language-item' |
+  'about-instance-features' |
+  'about-instance-statistics' |
+  'about-instance-moderation' |
+  'about-menu-instance' |
+  'about-menu-peertube' |
+  'about-menu-network' |
+  'about-instance-other-information'
index 5a268ebe18b436d852d1eb07c6f90451133c01c0..a1d009a00e1f7a7ccabe93fa59caf7f3d4068ee4 100644 (file)
@@ -1,4 +1,5 @@
 export interface InstallOrUpdatePlugin {
   npmName?: string
+  pluginVersion?: string
   path?: string
 }
diff --git a/support/doc/development/ci.md b/support/doc/development/ci.md
new file mode 100644 (file)
index 0000000..7d6eef1
--- /dev/null
@@ -0,0 +1,40 @@
+# Continuous integration
+
+PeerTube uses Github Actions as a CI platform.
+CI tasks are described in `.github/workflows`.
+
+## benchmark.yml
+
+*Scheduled*
+
+Run various benchmarks (build, API etc) and upload results on https://builds.joinpeertube.org/peertube-stats/ to be publicly consumed.
+
+## codeql.yml
+
+*Scheduled, on push on develop and on pull request*
+
+Run CodeQL task to throw code security issues in Github. https://lgtm.com/projects/g/Chocobozzz/PeerTube can also be used.
+
+## docker.yml
+
+*Scheduled and on push on master*
+
+Build `chocobozzz/peertube-webserver:latest`, `chocobozzz/peertube:production-...`, `chocobozzz/peertube:v-...` (only latest PeerTube tag) and `chocobozzz/peertube:develop-...` Docker images. Scheduled to automatically upgrade image software (Debian security issues etc).
+
+## nightly.yml
+
+*Scheduled*
+
+Build PeerTube nightly build (`develop` branch) and upload the release on https://builds.joinpeertube.org/nightly.
+
+## stats.yml
+
+*On push on develop*
+
+Create various PeerTube stats (line of codes, build size, lighthouse report) and upload results on https://builds.joinpeertube.org/peertube-stats/ to be publicly consumed.
+
+## test.yml
+
+*Scheduled, on push and pull request*
+
+Run PeerTube lint and tests.
index ee35c5c7e4bca6ecf64efcb45491170ee9b76373..62c95cfff0a329072462c8ae6500b2268b4d312c 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -2613,11 +2613,6 @@ call-me-maybe@^1.0.1:
   resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
   integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
 
-callsite@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
-  integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
-
 callsites@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -3229,13 +3224,6 @@ debuglog@^1.0.0:
   resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
   integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
 
-decache@^4.6.0:
-  version "4.6.0"
-  resolved "https://registry.yarnpkg.com/decache/-/decache-4.6.0.tgz#87026bc6e696759e82d57a3841c4e251a30356e8"
-  integrity sha512-PppOuLiz+DFeaUvFXEYZjLxAkKiMYH/do/b/MxpDe/8AgKBi5GhZxridoVIbBq72GDbL36e4p0Ce2jTGUwwU+w==
-  dependencies:
-    callsite "^1.0.0"
-
 decamelize@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"