Merge remote-tracking branch 'origin/master' into remote-users-not-count-for-license
70
.github/workflows/artifacts.yml
vendored
@ -4,15 +4,12 @@ on:
|
|||||||
workflows: ["Mattermost Build"]
|
workflows: ["Mattermost Build"]
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
upload-s3:
|
upload-s3:
|
||||||
name: cd/Upload artifacts to S3
|
name: cd/Upload artifacts to S3
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
env:
|
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||||
REPO_NAME: ${{ github.event.repository.name }}
|
|
||||||
if: >
|
|
||||||
github.event.workflow_run.event == 'pull_request' &&
|
|
||||||
github.event.workflow_run.conclusion == 'success'
|
|
||||||
steps:
|
steps:
|
||||||
- name: cd/Configure AWS
|
- name: cd/Configure AWS
|
||||||
uses: aws-actions/configure-aws-credentials@07c2f971bac433df982ccc261983ae443861db49 # v1-node16
|
uses: aws-actions/configure-aws-credentials@07c2f971bac433df982ccc261983ae443861db49 # v1-node16
|
||||||
@ -28,23 +25,18 @@ jobs:
|
|||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
name: server-dist-artifact
|
name: server-dist-artifact
|
||||||
path: server/dist
|
path: server/dist
|
||||||
# Get Branch name from calling workflow
|
|
||||||
# Search for the string "pull" and replace it with "PR" in branch-name
|
|
||||||
- name: cd/Get branch name
|
|
||||||
run: echo "BRANCH_NAME=$(echo ${{ github.event.workflow_run.head_branch }} | sed 's/^pull\//PR-/g')" >> $GITHUB_ENV
|
|
||||||
- name: cd/Upload artifacts to S3
|
- name: cd/Upload artifacts to S3
|
||||||
|
env:
|
||||||
|
REPO_NAME: ${{ github.event.repository.name }}
|
||||||
|
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||||
run: |
|
run: |
|
||||||
aws s3 cp server/dist/ s3://pr-builds.mattermost.com/$REPO_NAME/$BRANCH_NAME/ --acl public-read --cache-control "no-cache" --recursive --no-progress
|
aws s3 cp server/dist/ s3://pr-builds.mattermost.com/$REPO_NAME/commit/$COMMIT_SHA/ --acl public-read --cache-control "no-cache" --recursive --no-progress
|
||||||
aws s3 cp server/dist/ s3://pr-builds.mattermost.com/$REPO_NAME/commit/${{ github.sha }}/ --acl public-read --cache-control "no-cache" --recursive --no-progress
|
|
||||||
build-docker:
|
build-docker:
|
||||||
name: cd/Build and push docker image
|
name: cd/Build and push docker image
|
||||||
needs: upload-s3
|
needs: upload-s3
|
||||||
env:
|
|
||||||
REPO_NAME: ${{ github.event.repository.name }}
|
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
if: >
|
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||||
github.event.workflow_run.event == 'pull_request' &&
|
|
||||||
github.event.workflow_run.conclusion == 'success'
|
|
||||||
steps:
|
steps:
|
||||||
- name: cd/Login to Docker Hub
|
- name: cd/Login to Docker Hub
|
||||||
uses: docker/login-action@3da7dc6e2b31f99ef2cb9fb4c50fb0971e0d0139 # v2.1.0
|
uses: docker/login-action@3da7dc6e2b31f99ef2cb9fb4c50fb0971e0d0139 # v2.1.0
|
||||||
@ -64,53 +56,19 @@ jobs:
|
|||||||
- name: cd/Docker build and push
|
- name: cd/Docker build and push
|
||||||
env:
|
env:
|
||||||
DOCKER_CLI_EXPERIMENTAL: enabled
|
DOCKER_CLI_EXPERIMENTAL: enabled
|
||||||
run: |
|
|
||||||
export TAG=$(echo "${{ github.event.pull_request.head.sha || github.sha }}" | cut -c1-7)
|
|
||||||
cd server/build
|
|
||||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
|
||||||
export MM_PACKAGE=https://pr-builds.mattermost.com/$REPO_NAME/commit/${{ github.sha }}/mattermost-team-linux-amd64.tar.gz
|
|
||||||
docker buildx build --push --build-arg MM_PACKAGE=$MM_PACKAGE -t mattermostdevelopment/mm-te-test:${TAG} .
|
|
||||||
# Temporary uploading also to mattermost/mm-te-test:${TAG} except mattermostdevelopment/mm-te-test:${TAG}
|
|
||||||
# Context: https://community.mattermost.com/private-core/pl/3jzzxzfiji8hx833ewyuthzkjh
|
|
||||||
build-docker-temp:
|
|
||||||
name: cd/Build and push docker image
|
|
||||||
needs: upload-s3
|
|
||||||
env:
|
|
||||||
REPO_NAME: ${{ github.event.repository.name }}
|
REPO_NAME: ${{ github.event.repository.name }}
|
||||||
runs-on: ubuntu-22.04
|
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||||
if: >
|
|
||||||
github.event.workflow_run.event == 'pull_request' &&
|
|
||||||
github.event.workflow_run.conclusion == 'success'
|
|
||||||
steps:
|
|
||||||
- name: cd/Login to Docker Hub
|
|
||||||
uses: docker/login-action@3da7dc6e2b31f99ef2cb9fb4c50fb0971e0d0139 # v2.1.0
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: cd/Download artifacts
|
|
||||||
uses: dawidd6/action-download-artifact@0c49384d39ceb023b8040f480a25596fd6cf441b # v2.26.0
|
|
||||||
with:
|
|
||||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
|
||||||
run_id: ${{ github.event.workflow_run.id }}
|
|
||||||
workflow_conclusion: success
|
|
||||||
name: server-build-artifact
|
|
||||||
path: server/build/
|
|
||||||
- name: cd/Setup Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@11e8a2e2910826a92412015c515187a2d6750279 # v2.4
|
|
||||||
- name: cd/Docker build and push
|
|
||||||
env:
|
|
||||||
DOCKER_CLI_EXPERIMENTAL: enabled
|
|
||||||
run: |
|
run: |
|
||||||
export TAG=$(echo "${{ github.event.pull_request.head.sha || github.sha }}" | cut -c1-7)
|
export TAG=$(echo "${{ github.event.pull_request.head.sha || github.event.workflow_run.head_sha }}" | cut -c1-7)
|
||||||
cd server/build
|
cd server/build
|
||||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
export MM_PACKAGE=https://pr-builds.mattermost.com/$REPO_NAME/commit/${{ github.sha }}/mattermost-team-linux-amd64.tar.gz
|
export MM_PACKAGE=https://pr-builds.mattermost.com/$REPO_NAME/commit/$COMMIT_SHA/mattermost-team-linux-amd64.tar.gz
|
||||||
docker buildx build --push --build-arg MM_PACKAGE=$MM_PACKAGE -t mattermost/mm-te-test:${TAG} .
|
docker buildx build --push --build-arg MM_PACKAGE=$MM_PACKAGE -t mattermostdevelopment/mm-te-test:${TAG} .
|
||||||
|
|
||||||
sentry:
|
sentry:
|
||||||
name: Send build info to sentry
|
name: Send build info to sentry
|
||||||
if: >
|
if: >
|
||||||
github.event.workflow_run.event == 'pull_request' &&
|
github.event.workflow_run.event == 'push'
|
||||||
github.event.workflow_run.conclusion == 'success'
|
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
env:
|
env:
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.MM_SERVER_SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.MM_SERVER_SENTRY_AUTH_TOKEN }}
|
||||||
|
12
.github/workflows/channels-ci.yml
vendored
@ -7,7 +7,7 @@ on:
|
|||||||
- mono-repo*
|
- mono-repo*
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: ${{ !contains( github.ref , 'heads/ref/master') }}
|
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -83,6 +83,16 @@ jobs:
|
|||||||
npm run mmjstool -- i18n clean-empty --webapp-dir ./src --mobile-dir /tmp/fake-mobile-dir --check
|
npm run mmjstool -- i18n clean-empty --webapp-dir ./src --mobile-dir /tmp/fake-mobile-dir --check
|
||||||
npm run mmjstool -- i18n check-empty-src --webapp-dir ./src --mobile-dir /tmp/fake-mobile-dir
|
npm run mmjstool -- i18n check-empty-src --webapp-dir ./src --mobile-dir /tmp/fake-mobile-dir
|
||||||
rm -rf tmp
|
rm -rf tmp
|
||||||
|
- name: ci/lint-boards
|
||||||
|
working-directory: webapp/boards
|
||||||
|
run: |
|
||||||
|
npm run i18n-extract
|
||||||
|
git --no-pager diff --exit-code i18n/en.json || (echo "Please run \"cd webapp/boards && npm run i18n-extract\" and commit the changes in webapp/boards/i18n/en.json." && exit 1)
|
||||||
|
- name: ci/lint-playbooks
|
||||||
|
working-directory: webapp/playbooks
|
||||||
|
run: |
|
||||||
|
npm run i18n-extract
|
||||||
|
git --no-pager diff --exit-code i18n/en.json || (echo "Please run \"cd webapp/playbooks && npm run i18n-extract\" and commit the changes in webapp/playbooks/i18n/en.json." && exit 1)
|
||||||
check-types:
|
check-types:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
defaults:
|
defaults:
|
||||||
|
13
.github/workflows/ci.yml
vendored
@ -11,7 +11,7 @@ env:
|
|||||||
go-version: "1.19.5"
|
go-version: "1.19.5"
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: ${{ !contains( github.ref , 'heads/ref/master') }}
|
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||||
jobs:
|
jobs:
|
||||||
check-mocks:
|
check-mocks:
|
||||||
name: Check mocks
|
name: Check mocks
|
||||||
@ -26,6 +26,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Generate mocks
|
- name: Generate mocks
|
||||||
run: make mocks
|
run: make mocks
|
||||||
- name: Check mocks
|
- name: Check mocks
|
||||||
@ -43,6 +44,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Run go mod tidy
|
- name: Run go mod tidy
|
||||||
run: make modules-tidy
|
run: make modules-tidy
|
||||||
- name: Check modules
|
- name: Check modules
|
||||||
@ -60,13 +62,14 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Run make-gen-serialized
|
- name: Run make-gen-serialized
|
||||||
run: make gen-serialized
|
run: make gen-serialized
|
||||||
- name: Check serialized
|
- name: Check serialized
|
||||||
run: if [[ -n $(git status --porcelain) ]]; then echo "Please update the serialized files using 'make gen-serialized'"; exit 1; fi
|
run: if [[ -n $(git status --porcelain) ]]; then echo "Please update the serialized files using 'make gen-serialized'"; exit 1; fi
|
||||||
check-mattermost-vet:
|
check-mattermost-vet:
|
||||||
name: Check style
|
name: Check style
|
||||||
runs-on: ubuntu-latest-8-cores
|
runs-on: ubuntu-22.04
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: server
|
working-directory: server
|
||||||
@ -77,6 +80,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Reset config
|
- name: Reset config
|
||||||
run: make config-reset
|
run: make config-reset
|
||||||
- name: Run plugin-checker
|
- name: Run plugin-checker
|
||||||
@ -106,6 +110,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Checkout mattermost-api-reference
|
- name: Checkout mattermost-api-reference
|
||||||
run: |
|
run: |
|
||||||
cd ..
|
cd ..
|
||||||
@ -128,6 +133,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Generate work templates
|
- name: Generate work templates
|
||||||
run: make generate-worktemplates
|
run: make generate-worktemplates
|
||||||
- name: Check generated work templates
|
- name: Check generated work templates
|
||||||
@ -160,6 +166,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Generate store layers
|
- name: Generate store layers
|
||||||
run: make store-layers
|
run: make store-layers
|
||||||
- name: Check generated code
|
- name: Check generated code
|
||||||
@ -177,6 +184,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Generate app layers
|
- name: Generate app layers
|
||||||
run: make app-layers
|
run: make app-layers
|
||||||
- name: Check generated code
|
- name: Check generated code
|
||||||
@ -216,6 +224,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make config-reset
|
make config-reset
|
||||||
|
2
.github/workflows/codeql-analysis.yml
vendored
@ -2,7 +2,7 @@ name: "CodeQL"
|
|||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: ${{ !contains( github.ref , 'heads/ref/master') }}
|
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
2
.github/workflows/e2e-tests-ci.yml
vendored
@ -7,7 +7,7 @@ on:
|
|||||||
- mono-repo*
|
- mono-repo*
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: ${{ !contains( github.ref , 'heads/ref/master') }}
|
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
159
.github/workflows/esrupgrade-common.yml
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
name: ESR Upgrade
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
db-dump-url:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
initial-version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
final-version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
env:
|
||||||
|
COMPOSE_PROJECT_NAME: ghactions
|
||||||
|
BUILD_IMAGE: mattermost/mattermost-enterprise-edition:${{ inputs.final-version }}
|
||||||
|
MYSQL_CONN_ARGS: -h localhost -P 3306 --protocol=tcp -ummuser -pmostest mattermost_test
|
||||||
|
DUMP_SERVER_NAME: esr.${{ inputs.initial-version }}-${{ inputs.final-version }}.dump.server.sql
|
||||||
|
DUMP_SCRIPT_NAME: esr.${{ inputs.initial-version }}-${{ inputs.final-version }}.dump.script.sql
|
||||||
|
MIGRATION_SCRIPT: esr.${{ inputs.initial-version }}-${{ inputs.final-version }}.mysql.up.sql
|
||||||
|
CLEANUP_SCRIPT: esr.${{ inputs.initial-version }}-${{ inputs.final-version }}.mysql.cleanup.sql
|
||||||
|
PREPROCESS_SCRIPT: esr.common.mysql.preprocess.sql
|
||||||
|
DIFF_NAME: esr.${{ inputs.initial-version }}-${{ inputs.final-version }}.diff
|
||||||
|
jobs:
|
||||||
|
esr-upgrade-server:
|
||||||
|
runs-on: ubuntu-latest-8-cores
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- name: Checkout mattermost-server
|
||||||
|
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||||
|
- name: Run docker compose
|
||||||
|
run: |
|
||||||
|
cd server/build
|
||||||
|
docker-compose --no-ansi run --rm start_dependencies
|
||||||
|
cat ../tests/test-data.ldif | docker-compose --no-ansi exec -T openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest';
|
||||||
|
docker-compose --no-ansi exec -T minio sh -c 'mkdir -p /data/mattermost-test';
|
||||||
|
docker-compose --no-ansi ps
|
||||||
|
- name: Wait for docker compose
|
||||||
|
run: |
|
||||||
|
until docker network inspect ghactions_mm-test; do echo "Waiting for Docker Compose Network..."; sleep 1; done;
|
||||||
|
docker run --net ghactions_mm-test appropriate/curl:latest sh -c "until curl --max-time 5 --output - http://mysql:3306; do echo waiting for mysql; sleep 5; done;"
|
||||||
|
docker run --net ghactions_mm-test appropriate/curl:latest sh -c "until curl --max-time 5 --output - http://elasticsearch:9200; do echo waiting for elasticsearch; sleep 5; done;"
|
||||||
|
- name: Initialize the database with the source DB dump
|
||||||
|
run: |
|
||||||
|
curl ${{ inputs.db-dump-url }} | zcat | docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS
|
||||||
|
- name: Common preprocessing of the DB dump
|
||||||
|
run: |
|
||||||
|
cd server/scripts/esrupgrades
|
||||||
|
docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS < $PREPROCESS_SCRIPT
|
||||||
|
- name: Pull EE image
|
||||||
|
run: |
|
||||||
|
docker pull $BUILD_IMAGE
|
||||||
|
- name: Run migration through server
|
||||||
|
run: |
|
||||||
|
mkdir -p client/plugins
|
||||||
|
cd server/build
|
||||||
|
# Run the server in the background to trigger the migrations
|
||||||
|
docker run --name mmserver \
|
||||||
|
--net ghactions_mm-test \
|
||||||
|
--ulimit nofile=8096:8096 \
|
||||||
|
--env-file=dotenv/test.env \
|
||||||
|
--env MM_SQLSETTINGS_DRIVERNAME="mysql" \
|
||||||
|
--env MM_SQLSETTINGS_DATASOURCE="mmuser:mostest@tcp(mysql:3306)/mattermost_test?charset=utf8mb4,utf8&multiStatements=true" \
|
||||||
|
-v ~/work/mattermost-server:/mattermost-server \
|
||||||
|
-w /mattermost-server/mattermost-server \
|
||||||
|
$BUILD_IMAGE &
|
||||||
|
# In parallel, wait for the migrations to finish.
|
||||||
|
# To verify this, we check that the server has finished the startup job through the log line "Server is listening on"
|
||||||
|
until docker logs mmserver | grep "Server is listening on"; do\
|
||||||
|
echo "Waiting for migrations to finish..."; \
|
||||||
|
sleep 1; \
|
||||||
|
done;
|
||||||
|
# Make sure to stop the server. Also, redirect output to null;
|
||||||
|
# otherwise, the name of the container gets written to the console, which is weird
|
||||||
|
docker stop mmserver > /dev/null
|
||||||
|
- name: Cleanup DB
|
||||||
|
run : |
|
||||||
|
cd server/scripts/esrupgrades
|
||||||
|
docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS < $CLEANUP_SCRIPT
|
||||||
|
- name: Dump upgraded database
|
||||||
|
run: |
|
||||||
|
# Use --skip-opt to have each INSERT into one line.
|
||||||
|
# Use --set-gtid-purged=OFF to suppress GTID-related statements.
|
||||||
|
docker exec -i ghactions_mysql_1 mysqldump \
|
||||||
|
--skip-opt --set-gtid-purged=OFF \
|
||||||
|
$MYSQL_CONN_ARGS > $DUMP_SERVER_NAME
|
||||||
|
- name: Cleanup dump and compress
|
||||||
|
run: |
|
||||||
|
# We skip the very last line, which simply contains the date of the dump
|
||||||
|
head -n -1 ${DUMP_SERVER_NAME} | gzip > ${DUMP_SERVER_NAME}.gz
|
||||||
|
- name: Upload dump
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: upgraded-dump-server
|
||||||
|
path: ${{ env.DUMP_SERVER_NAME }}.gz
|
||||||
|
esr-upgrade-script:
|
||||||
|
runs-on: ubuntu-latest-8-cores
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- name: Checkout mattermost-server
|
||||||
|
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||||
|
- name: Run docker compose
|
||||||
|
run: |
|
||||||
|
cd server/build
|
||||||
|
docker-compose --no-ansi run --rm start_dependencies
|
||||||
|
cat ../tests/test-data.ldif | docker-compose --no-ansi exec -T openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest';
|
||||||
|
docker-compose --no-ansi exec -T minio sh -c 'mkdir -p /data/mattermost-test';
|
||||||
|
docker-compose --no-ansi ps
|
||||||
|
- name: Wait for docker compose
|
||||||
|
run: |
|
||||||
|
until docker network inspect ghactions_mm-test; do echo "Waiting for Docker Compose Network..."; sleep 1; done;
|
||||||
|
docker run --net ghactions_mm-test appropriate/curl:latest sh -c "until curl --max-time 5 --output - http://mysql:3306; do echo waiting for mysql; sleep 5; done;"
|
||||||
|
docker run --net ghactions_mm-test appropriate/curl:latest sh -c "until curl --max-time 5 --output - http://elasticsearch:9200; do echo waiting for elasticsearch; sleep 5; done;"
|
||||||
|
- name: Initialize the database with the source DB dump
|
||||||
|
run: |
|
||||||
|
curl ${{ inputs.db-dump-url }} | zcat | docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS
|
||||||
|
- name: Preprocess the DB dump
|
||||||
|
run: |
|
||||||
|
cd server/scripts/esrupgrades
|
||||||
|
docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS < $PREPROCESS_SCRIPT
|
||||||
|
- name: Run migration through script
|
||||||
|
run : |
|
||||||
|
cd server/scripts/esrupgrades
|
||||||
|
docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS < $MIGRATION_SCRIPT
|
||||||
|
- name: Cleanup DB
|
||||||
|
run : |
|
||||||
|
cd server/scripts/esrupgrades
|
||||||
|
docker exec -i ghactions_mysql_1 mysql -AN $MYSQL_CONN_ARGS < $CLEANUP_SCRIPT
|
||||||
|
- name: Dump upgraded database
|
||||||
|
run: |
|
||||||
|
docker exec -i ghactions_mysql_1 mysqldump --skip-opt --set-gtid-purged=OFF $MYSQL_CONN_ARGS > $DUMP_SCRIPT_NAME
|
||||||
|
- name: Cleanup dump and compress
|
||||||
|
run: |
|
||||||
|
# We skip the very last line, which simply contains the date of the dump
|
||||||
|
head -n -1 ${DUMP_SCRIPT_NAME} | gzip > ${DUMP_SCRIPT_NAME}.gz
|
||||||
|
- name: Upload dump
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: upgraded-dump-script
|
||||||
|
path: ${{ env.DUMP_SCRIPT_NAME }}.gz
|
||||||
|
esr-upgrade-diff:
|
||||||
|
runs-on: ubuntu-latest-8-cores
|
||||||
|
needs:
|
||||||
|
- esr-upgrade-server
|
||||||
|
- esr-upgrade-script
|
||||||
|
steps:
|
||||||
|
- name: Retrieve dumps
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
- name: Diff dumps
|
||||||
|
run: |
|
||||||
|
gzip -d upgraded-dump-server/${DUMP_SERVER_NAME}.gz
|
||||||
|
gzip -d upgraded-dump-script/${DUMP_SCRIPT_NAME}.gz
|
||||||
|
diff upgraded-dump-server/$DUMP_SERVER_NAME upgraded-dump-script/$DUMP_SCRIPT_NAME > $DIFF_NAME
|
||||||
|
- name: Upload diff
|
||||||
|
if: failure() # Upload the diff only if the previous step failed; i.e., if the diff is non-empty
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: dumps-diff
|
||||||
|
path: ${{ env.DIFF_NAME }}
|
33
.github/workflows/esrupgrade.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
name: ESR Upgrade
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'server/scripts/esrupgrades/*'
|
||||||
|
- '.github/workflows/esr*'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- cloud
|
||||||
|
- release-*
|
||||||
|
jobs:
|
||||||
|
esr-upgrade-5_37-7_8:
|
||||||
|
name: Run ESR upgrade script from 5.37 to 7.8
|
||||||
|
uses: ./.github/workflows/esrupgrade-common.yml
|
||||||
|
with:
|
||||||
|
db-dump-url: https://lt-public-data.s3.amazonaws.com/47K_537_mysql_collationfixed.sql.gz
|
||||||
|
initial-version: 5.37
|
||||||
|
final-version: 7.8
|
||||||
|
esr-upgrade-5_37-6_3:
|
||||||
|
name: Run ESR upgrade script from 5.37 to 6.3
|
||||||
|
uses: ./.github/workflows/esrupgrade-common.yml
|
||||||
|
with:
|
||||||
|
db-dump-url: https://lt-public-data.s3.amazonaws.com/47K_537_mysql_collationfixed.sql.gz
|
||||||
|
initial-version: 5.37
|
||||||
|
final-version: 6.3
|
||||||
|
esr-upgrade-6_3-7_8:
|
||||||
|
name: Run ESR upgrade script from 6.3 to 7.8
|
||||||
|
uses: ./.github/workflows/esrupgrade-common.yml
|
||||||
|
with:
|
||||||
|
db-dump-url: https://lt-public-data.s3.amazonaws.com/47K_63_mysql.sql.gz
|
||||||
|
initial-version: 6.3
|
||||||
|
final-version: 7.8
|
2
.github/workflows/scorecards-analysis.yml
vendored
@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: ${{ !contains( github.ref , 'heads/ref/master') }}
|
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||||
|
|
||||||
# Declare default permissions as read only.
|
# Declare default permissions as read only.
|
||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
1
.github/workflows/test.yml
vendored
@ -23,6 +23,7 @@ jobs:
|
|||||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.go-version }}
|
go-version: ${{ env.go-version }}
|
||||||
|
cache-dependency-path: server/go.sum
|
||||||
- name: Run docker compose
|
- name: Run docker compose
|
||||||
run: |
|
run: |
|
||||||
cd server/build
|
cd server/build
|
||||||
|
@ -5,3 +5,6 @@
|
|||||||
/webapp/package-lock.json @mattermost/web-platform
|
/webapp/package-lock.json @mattermost/web-platform
|
||||||
/webapp/platform/*/package.json @mattermost/web-platform
|
/webapp/platform/*/package.json @mattermost/web-platform
|
||||||
/webapp/scripts @mattermost/web-platform
|
/webapp/scripts @mattermost/web-platform
|
||||||
|
/server/channels/db/migrations @mattermost/server-platform
|
||||||
|
/server/boards/services/store/sqlstore/migrations @mattermost/server-platform
|
||||||
|
/server/playbooks/server/sqlstore/migrations @mattermost/server-platform
|
||||||
|
13
e2e-tests/cypress/package-lock.json
generated
@ -12,7 +12,6 @@
|
|||||||
"@babel/eslint-parser": "7.19.1",
|
"@babel/eslint-parser": "7.19.1",
|
||||||
"@babel/eslint-plugin": "7.19.1",
|
"@babel/eslint-plugin": "7.19.1",
|
||||||
"@cypress/request": "2.88.11",
|
"@cypress/request": "2.88.11",
|
||||||
"@cypress/skip-test": "2.6.1",
|
|
||||||
"@mattermost/types": "7.4.0",
|
"@mattermost/types": "7.4.0",
|
||||||
"@testing-library/cypress": "9.0.0",
|
"@testing-library/cypress": "9.0.0",
|
||||||
"@types/async": "3.2.16",
|
"@types/async": "3.2.16",
|
||||||
@ -2250,12 +2249,6 @@
|
|||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cypress/skip-test": {
|
|
||||||
"version": "2.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/skip-test/-/skip-test-2.6.1.tgz",
|
|
||||||
"integrity": "sha512-X+ibefBiuOmC5gKG91wRIT0/OqXeETYvu7zXktjZ3yLeO186Y8ia0K7/gQUpAwuUi28DuqMd1+7tBQVtPkzbPA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@cypress/xvfb": {
|
"node_modules/@cypress/xvfb": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
|
||||||
@ -19062,12 +19055,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@cypress/skip-test": {
|
|
||||||
"version": "2.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/skip-test/-/skip-test-2.6.1.tgz",
|
|
||||||
"integrity": "sha512-X+ibefBiuOmC5gKG91wRIT0/OqXeETYvu7zXktjZ3yLeO186Y8ia0K7/gQUpAwuUi28DuqMd1+7tBQVtPkzbPA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@cypress/xvfb": {
|
"@cypress/xvfb": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"@babel/eslint-parser": "7.19.1",
|
"@babel/eslint-parser": "7.19.1",
|
||||||
"@babel/eslint-plugin": "7.19.1",
|
"@babel/eslint-plugin": "7.19.1",
|
||||||
"@cypress/request": "2.88.11",
|
"@cypress/request": "2.88.11",
|
||||||
"@cypress/skip-test": "2.6.1",
|
|
||||||
"@mattermost/types": "7.4.0",
|
"@mattermost/types": "7.4.0",
|
||||||
"@testing-library/cypress": "9.0.0",
|
"@testing-library/cypress": "9.0.0",
|
||||||
"@types/async": "3.2.16",
|
"@types/async": "3.2.16",
|
||||||
|
@ -98,6 +98,72 @@ describe('Create and delete board / card', () => {
|
|||||||
cy.findByText('for testing purposes only').should('be.visible');
|
cy.findByText('for testing purposes only').should('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('MM-T4276 Set up Board emoji', () => {
|
||||||
|
cy.visit('/boards');
|
||||||
|
|
||||||
|
// # Create an empty board and change tile to Testing
|
||||||
|
cy.findByText('Create an empty board').should('exist').click({force: true});
|
||||||
|
cy.get('.BoardComponent').should('exist');
|
||||||
|
|
||||||
|
// # Change Title
|
||||||
|
cy.findByPlaceholderText('Untitled board').should('be.visible').wait(timeouts.HALF_SEC);
|
||||||
|
|
||||||
|
// * Assert that the title is changed to "testing"
|
||||||
|
cy.findByPlaceholderText('Untitled board').
|
||||||
|
clear().
|
||||||
|
type('Testing').
|
||||||
|
type('{enter}').
|
||||||
|
should('have.value', 'Testing');
|
||||||
|
|
||||||
|
// # "Add icon" and "Show description" options appear
|
||||||
|
cy.findByText('Add icon').should('exist');
|
||||||
|
cy.findByText('show description').should('exist');
|
||||||
|
|
||||||
|
// # Click on "Add icon"
|
||||||
|
cy.findByText('Add icon').should('exist').click({force: true});
|
||||||
|
|
||||||
|
// * Assert that a random emoji is selected and added at the beginning of the board title
|
||||||
|
cy.get('.IconSelector').should('exist');
|
||||||
|
|
||||||
|
// # Click on the emoji next to the board title
|
||||||
|
cy.get('.IconSelector .MenuWrapper').should('exist').click({force: true});
|
||||||
|
|
||||||
|
// * Assert that Dropdown menu with 3 options appears
|
||||||
|
cy.findByText('Random').should('exist');
|
||||||
|
cy.findByText('Pick icon').should('exist');
|
||||||
|
cy.findByText('Remove icon').should('exist');
|
||||||
|
|
||||||
|
// # Hover your mouse over the "Pick Icon" option
|
||||||
|
cy.findByText('Pick icon').trigger('mouseover');
|
||||||
|
|
||||||
|
// * Assert that emoji picker menu appears
|
||||||
|
cy.get('.IconSelector .menu-contents').should('exist');
|
||||||
|
|
||||||
|
// # Click on the emoji from the picker
|
||||||
|
cy.get('.EmojiPicker').should('exist').and('be.visible').within(() => {
|
||||||
|
// # Click on the emoji
|
||||||
|
cy.get("[aria-label='😀, grinning']").should('exist');
|
||||||
|
cy.get("[aria-label='😀, grinning']").eq(0).click({force: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
// * Assert that Selected emoji is now displayed next to the board title
|
||||||
|
cy.get('.IconSelector span').contains('😀');
|
||||||
|
|
||||||
|
// # Click on the emoji next to the board title
|
||||||
|
cy.get('.IconSelector .MenuWrapper').should('exist').click({force: true});
|
||||||
|
|
||||||
|
// * Assert that Dropdown menu with 3 options appears
|
||||||
|
cy.findByText('Random').should('exist');
|
||||||
|
cy.findByText('Pick icon').should('exist');
|
||||||
|
cy.findByText('Remove icon').should('exist');
|
||||||
|
|
||||||
|
// # Click "Remove icon"
|
||||||
|
cy.findByText('Remove icon').click({force: true});
|
||||||
|
|
||||||
|
// * Assert that Icon next to the board title is removed
|
||||||
|
cy.get('.IconSelector').should('not.exist');
|
||||||
|
});
|
||||||
|
|
||||||
it('MM-T5397 Can create and delete a board and a card', () => {
|
it('MM-T5397 Can create and delete a board and a card', () => {
|
||||||
// Visit a page and create new empty board
|
// Visit a page and create new empty board
|
||||||
cy.visit('/boards');
|
cy.visit('/boards');
|
||||||
|
@ -18,7 +18,6 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
let otherUser;
|
let otherUser;
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testChannel;
|
let testChannel;
|
||||||
let emojiPickerEnabled;
|
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||||
@ -33,10 +32,6 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
|
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.apiGetConfig().then(({config}) => {
|
|
||||||
emojiPickerEnabled = config.ServiceSettings.EnableEmojiPicker;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -179,18 +174,11 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.get(`#CENTER_time_${postId}`).should('be.focused');
|
cy.get(`#CENTER_time_${postId}`).should('be.focused');
|
||||||
cy.focused().tab();
|
cy.focused().tab();
|
||||||
|
|
||||||
// eslint-disable-next-line no-negated-condition
|
|
||||||
if (!emojiPickerEnabled) {
|
|
||||||
// * Verify focus is on the actions button
|
|
||||||
cy.get(`#CENTER_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'more');
|
|
||||||
cy.focused().tab();
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
// * Verify focus is on the reactions button
|
// * Verify focus is on the reactions button
|
||||||
cy.get(`#recent_reaction_${i}`).should('have.class', 'emoticon--post-menu').and('have.attr', 'aria-label');
|
cy.get(`#recent_reaction_${i}`).should('have.class', 'emoticon--post-menu').and('have.attr', 'aria-label');
|
||||||
cy.focused().tab();
|
cy.focused().tab();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// * Verify focus is on the reactions button
|
// * Verify focus is on the reactions button
|
||||||
cy.get(`#CENTER_reaction_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'add reaction');
|
cy.get(`#CENTER_reaction_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'add reaction');
|
||||||
@ -200,15 +188,17 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.get(`#CENTER_flagIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'save');
|
cy.get(`#CENTER_flagIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'save');
|
||||||
cy.focused().tab();
|
cy.focused().tab();
|
||||||
|
|
||||||
|
// * Verify focus is on message actions button
|
||||||
|
cy.get(`#CENTER_actions_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'actions');
|
||||||
|
cy.focused().tab();
|
||||||
|
|
||||||
// * Verify focus is on the comment button
|
// * Verify focus is on the comment button
|
||||||
cy.get(`#CENTER_commentIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'reply');
|
cy.get(`#CENTER_commentIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'reply');
|
||||||
cy.focused().tab();
|
cy.focused().tab();
|
||||||
|
|
||||||
if (emojiPickerEnabled) {
|
|
||||||
// * Verify focus is on the more button
|
// * Verify focus is on the more button
|
||||||
cy.get(`#CENTER_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'More');
|
cy.get(`#CENTER_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'more');
|
||||||
cy.focused().tab();
|
cy.focused().tab();
|
||||||
}
|
|
||||||
|
|
||||||
// * Verify focus is on the post text
|
// * Verify focus is on the post text
|
||||||
cy.get(`#postMessageText_${postId}`).should('be.focused').and('have.attr', 'aria-readonly', 'true');
|
cy.get(`#postMessageText_${postId}`).should('be.focused').and('have.attr', 'aria-readonly', 'true');
|
||||||
@ -244,11 +234,13 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.get(`#rhsPostMessageText_${postId}`).should('be.focused').and('have.attr', 'aria-readonly', 'true');
|
cy.get(`#rhsPostMessageText_${postId}`).should('be.focused').and('have.attr', 'aria-readonly', 'true');
|
||||||
cy.focused().tab({shift: true});
|
cy.focused().tab({shift: true});
|
||||||
|
|
||||||
if (emojiPickerEnabled) {
|
// * Verify focus is on the more button
|
||||||
// * Verify focus is on the actions button
|
cy.get(`#RHS_COMMENT_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'more');
|
||||||
cy.get(`#RHS_COMMENT_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'More');
|
cy.focused().tab({shift: true});
|
||||||
|
|
||||||
|
// * Verify focus is on message actions button
|
||||||
|
cy.get(`#RHS_COMMENT_actions_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'actions');
|
||||||
cy.focused().tab({shift: true});
|
cy.focused().tab({shift: true});
|
||||||
}
|
|
||||||
|
|
||||||
// * Verify focus is on the save icon
|
// * Verify focus is on the save icon
|
||||||
cy.get(`#RHS_COMMENT_flagIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'save');
|
cy.get(`#RHS_COMMENT_flagIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'save');
|
||||||
@ -258,15 +250,9 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.get(`#RHS_COMMENT_reaction_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'add reaction');
|
cy.get(`#RHS_COMMENT_reaction_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'add reaction');
|
||||||
cy.focused().tab({shift: true});
|
cy.focused().tab({shift: true});
|
||||||
|
|
||||||
// eslint-disable-next-line no-negated-condition
|
// * Verify focus is on most recent action
|
||||||
if (!emojiPickerEnabled) {
|
|
||||||
// * Verify focus is on the actions button
|
|
||||||
cy.get(`#RHS_COMMENT_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'more');
|
|
||||||
cy.focused().tab({shift: true});
|
|
||||||
} else {
|
|
||||||
cy.get('#recent_reaction_0').should('have.class', 'emoticon--post-menu').and('have.attr', 'aria-label');
|
cy.get('#recent_reaction_0').should('have.class', 'emoticon--post-menu').and('have.attr', 'aria-label');
|
||||||
cy.focused().tab({shift: true});
|
cy.focused().tab({shift: true});
|
||||||
}
|
|
||||||
|
|
||||||
// * Verify focus is on the time
|
// * Verify focus is on the time
|
||||||
cy.get(`#RHS_COMMENT_time_${postId}`).should('be.focused');
|
cy.get(`#RHS_COMMENT_time_${postId}`).should('be.focused');
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
// Group: @channels @bot_accounts
|
// Group: @channels @bot_accounts
|
||||||
|
|
||||||
import {createBotPatch} from '../../../support/api/bots';
|
import {createBotPatch} from '../../../support/api/bots';
|
||||||
|
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('Bot tags', () => {
|
describe('Bot tags', () => {
|
||||||
let me;
|
let me;
|
||||||
@ -48,8 +49,8 @@ describe('Bot tags', () => {
|
|||||||
await client.pinPost(postId);
|
await client.pinPost(postId);
|
||||||
|
|
||||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||||
cy.clickPostDotMenu(postId);
|
cy.get(`#post_${postId}`).trigger('mouseover', {force: true});
|
||||||
cy.get(`#CENTER_flagIcon_${postId}`).click();
|
cy.wait(TIMEOUTS.HALF_SEC).get(`#CENTER_flagIcon_${postId}`).click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -15,7 +15,10 @@ import {getRandomId} from '../../../utils';
|
|||||||
describe('Leave an archived channel', () => {
|
describe('Leave an archived channel', () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let offTopicUrl;
|
let offTopicUrl;
|
||||||
|
const channelType = {
|
||||||
|
public: 'Channel Type: Public',
|
||||||
|
archived: 'Channel Type: Archived',
|
||||||
|
};
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.apiUpdateConfig({
|
cy.apiUpdateConfig({
|
||||||
TeamSettings: {
|
TeamSettings: {
|
||||||
@ -97,7 +100,7 @@ describe('Leave an archived channel', () => {
|
|||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
// # Click on dropdown
|
// # Click on dropdown
|
||||||
cy.findByText('Show: Public Channels').should('be.visible').click();
|
cy.findByText(channelType.public).should('be.visible').click();
|
||||||
|
|
||||||
// # Click archived channels
|
// # Click archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@ -145,7 +148,7 @@ describe('Leave an archived channel', () => {
|
|||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('.more-modal').should('be.visible').within(() => {
|
cy.get('.more-modal').should('be.visible').within(() => {
|
||||||
// # Public channel list opens by default
|
// # Public channel list opens by default
|
||||||
cy.findByText('Show: Public Channels').should('be.visible').click();
|
cy.findByText(channelType.public).should('be.visible').click();
|
||||||
|
|
||||||
// # Click on archived channels
|
// # Click on archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@ -198,7 +201,7 @@ describe('Leave an archived channel', () => {
|
|||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('.more-modal').should('be.visible').within(() => {
|
cy.get('.more-modal').should('be.visible').within(() => {
|
||||||
// # Public channels are shown by default
|
// # Public channels are shown by default
|
||||||
cy.findByText('Show: Public Channels').should('be.visible').click();
|
cy.findByText(channelType.public).should('be.visible').click();
|
||||||
|
|
||||||
// # Go to archived channels
|
// # Go to archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@ -252,7 +255,7 @@ describe('Leave an archived channel', () => {
|
|||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('.more-modal').should('be.visible').within(() => {
|
cy.get('.more-modal').should('be.visible').within(() => {
|
||||||
// # Show public channels is visible by default
|
// # Show public channels is visible by default
|
||||||
cy.findByText('Show: Public Channels').should('be.visible').click();
|
cy.findByText(channelType.public).should('be.visible').click();
|
||||||
|
|
||||||
// # Go to archived channels
|
// # Go to archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@ -286,7 +289,7 @@ describe('Leave an archived channel', () => {
|
|||||||
|
|
||||||
// # More channels modal opens and lands on public channels
|
// # More channels modal opens and lands on public channels
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
cy.findByText('Show: Public Channels').should('be.visible').click();
|
cy.findByText(channelType.public).should('be.visible').click();
|
||||||
|
|
||||||
// # Go to archived channels
|
// # Go to archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
|
@ -14,6 +14,11 @@ import * as TIMEOUTS from '../../../fixtures/timeouts';
|
|||||||
|
|
||||||
import {createPrivateChannel} from '../enterprise/elasticsearch_autocomplete/helpers';
|
import {createPrivateChannel} from '../enterprise/elasticsearch_autocomplete/helpers';
|
||||||
|
|
||||||
|
const channelType = {
|
||||||
|
public: 'Channel Type: Public',
|
||||||
|
archived: 'Channel Type: Archived',
|
||||||
|
};
|
||||||
|
|
||||||
describe('Channels', () => {
|
describe('Channels', () => {
|
||||||
let testUser;
|
let testUser;
|
||||||
let otherUser;
|
let otherUser;
|
||||||
@ -65,7 +70,7 @@ describe('Channels', () => {
|
|||||||
|
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
// * Dropdown should be visible, defaulting to "Public Channels"
|
// * Dropdown should be visible, defaulting to "Public Channels"
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', 'Show: Public Channels').wait(TIMEOUTS.HALF_SEC);
|
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', channelType.public).wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
||||||
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 1).within(() => {
|
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 1).within(() => {
|
||||||
@ -113,7 +118,7 @@ describe('Channels', () => {
|
|||||||
cy.findByText('Archived Channels').should('be.visible').click();
|
cy.findByText('Archived Channels').should('be.visible').click();
|
||||||
|
|
||||||
// * Channel test should be visible as an archived channel in the list
|
// * Channel test should be visible as an archived channel in the list
|
||||||
cy.wrap(el).should('contain', 'Show: Archived Channels');
|
cy.wrap(el).should('contain', channelType.archived);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
||||||
@ -196,7 +201,7 @@ describe('Channels', () => {
|
|||||||
|
|
||||||
// * Dropdown should be visible, defaulting to "Public Channels"
|
// * Dropdown should be visible, defaulting to "Public Channels"
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').within((el) => {
|
cy.get('#channelsMoreDropdown').should('be.visible').within((el) => {
|
||||||
cy.wrap(el).should('contain', 'Show: Public Channels');
|
cy.wrap(el).should('contain', channelType.public);
|
||||||
});
|
});
|
||||||
|
|
||||||
// * Users should be able to type and search
|
// * Users should be able to type and search
|
||||||
@ -207,12 +212,12 @@ describe('Channels', () => {
|
|||||||
|
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
// * Users should be able to switch to "Archived Channels" list
|
// * Users should be able to switch to "Archived Channels" list
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', 'Show: Public Channels').click().within((el) => {
|
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', channelType.public).click().within((el) => {
|
||||||
// # Click on archived channels item
|
// # Click on archived channels item
|
||||||
cy.findByText('Archived Channels').should('be.visible').click();
|
cy.findByText('Archived Channels').should('be.visible').click();
|
||||||
|
|
||||||
// * Modal should show the archived channels list
|
// * Modal should show the archived channels list
|
||||||
cy.wrap(el).should('contain', 'Show: Archived Channels');
|
cy.wrap(el).should('contain', channelType.archived);
|
||||||
}).wait(TIMEOUTS.HALF_SEC);
|
}).wait(TIMEOUTS.HALF_SEC);
|
||||||
cy.get('#searchChannelsTextbox').clear();
|
cy.get('#searchChannelsTextbox').clear();
|
||||||
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 2);
|
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 2);
|
||||||
@ -250,7 +255,7 @@ function verifyMoreChannelsModal(isEnabled) {
|
|||||||
// * Verify that the more channels modal is open and with or without option to view archived channels
|
// * Verify that the more channels modal is open and with or without option to view archived channels
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').and('have.text', 'Show: Public Channels');
|
cy.get('#channelsMoreDropdown').should('be.visible').and('have.text', channelType.public);
|
||||||
} else {
|
} else {
|
||||||
cy.get('#channelsMoreDropdown').should('not.exist');
|
cy.get('#channelsMoreDropdown').should('not.exist');
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ describe('System Console - Subscriptions section', () => {
|
|||||||
cy.get('.RHS').find('button').should('be.enabled');
|
cy.get('.RHS').find('button').should('be.enabled');
|
||||||
|
|
||||||
// # Change the user seats field to a value smaller than the current number of users
|
// # Change the user seats field to a value smaller than the current number of users
|
||||||
const lessThanUserCount = count - 5;
|
const lessThanUserCount = 1;
|
||||||
cy.get('#input_UserSeats').clear().type(lessThanUserCount);
|
cy.get('#input_UserSeats').clear().type(lessThanUserCount);
|
||||||
|
|
||||||
// * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered
|
// * Ensure that the yearly, monthly, and yearly saving prices match the new user seats value entered
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
// ***************************************************************
|
||||||
|
// - [#] indicates a test step (e.g. # Go to a page)
|
||||||
|
// - [*] indicates an assertion (e.g. * Check the title)
|
||||||
|
// - Use element ID when selecting an element. Create one if none.
|
||||||
|
// ***************************************************************
|
||||||
|
// Stage: @prod
|
||||||
|
|
||||||
|
describe('Insights', () => {
|
||||||
|
let teamA;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
cy.shouldHaveFeatureFlag('InsightsEnabled', true);
|
||||||
|
|
||||||
|
cy.apiInitSetup().then(({team}) => {
|
||||||
|
teamA = team;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Check all the cards exist', () => {
|
||||||
|
cy.apiAdminLogin();
|
||||||
|
|
||||||
|
// # Go to the Insights view
|
||||||
|
cy.visit(`/${teamA.name}/activity-and-insights`);
|
||||||
|
|
||||||
|
// * Check top channels exists
|
||||||
|
cy.get('.top-channels-card').should('exist');
|
||||||
|
|
||||||
|
// * Check top threads exists
|
||||||
|
cy.get('.top-threads-card').should('exist');
|
||||||
|
|
||||||
|
// * Check top boards exists because product mode is enabled
|
||||||
|
cy.get('.top-boards-card').should('exist');
|
||||||
|
|
||||||
|
// * Check top reactions exists
|
||||||
|
cy.get('.top-reactions-card').should('exist');
|
||||||
|
|
||||||
|
// * Check top dms exists
|
||||||
|
cy.get('.top-dms-card').should('exist');
|
||||||
|
|
||||||
|
// * Check least active channels exists
|
||||||
|
cy.get('.least-active-channels-card').should('exist');
|
||||||
|
|
||||||
|
// * Check top playbooks exists because product mode is enabled
|
||||||
|
cy.get('.top-playbooks-card').should('exist');
|
||||||
|
});
|
||||||
|
});
|
@ -69,6 +69,12 @@ describe('Incoming webhook', () => {
|
|||||||
|
|
||||||
cy.getLastPost().within(() => {
|
cy.getLastPost().within(() => {
|
||||||
cy.findByRole('link', {name: 'Testing Integration Attachments', hidden: true});
|
cy.findByRole('link', {name: 'Testing Integration Attachments', hidden: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
// # Scroll to the bottom of the posts
|
||||||
|
cy.get('.post-list__dynamic').scrollTo('bottom');
|
||||||
|
|
||||||
|
cy.getLastPost().within(() => {
|
||||||
cy.get('.attachment__image').should('be.visible');
|
cy.get('.attachment__image').should('be.visible');
|
||||||
cy.get(':nth-child(2) > thead > tr > .attachment-field__caption').should('have.text', 'Area');
|
cy.get(':nth-child(2) > thead > tr > .attachment-field__caption').should('have.text', 'Area');
|
||||||
cy.get(':nth-child(3) > thead > tr > :nth-child(1)').should('have.text', 'Iteration');
|
cy.get(':nth-child(3) > thead > tr > :nth-child(1)').should('have.text', 'Iteration');
|
||||||
|
@ -191,7 +191,9 @@ describe('Keyboard shortcut CTRL/CMD+Shift+\\ for adding reaction to last messag
|
|||||||
Cypress._.times(3, () => {
|
Cypress._.times(3, () => {
|
||||||
doReactToLastMessageShortcut('CENTER');
|
doReactToLastMessageShortcut('CENTER');
|
||||||
cy.get('#emojiPicker').should('exist');
|
cy.get('#emojiPicker').should('exist');
|
||||||
cy.get('body').click();
|
|
||||||
|
// # Click anywhere to close emoji picker
|
||||||
|
cy.get('#channelHeaderInfo').click();
|
||||||
cy.get('#emojiPicker').should('not.exist');
|
cy.get('#emojiPicker').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import theme from '../../../fixtures/theme.json';
|
|||||||
|
|
||||||
describe('Status dropdown menu', () => {
|
describe('Status dropdown menu', () => {
|
||||||
const statusTestCases = [
|
const statusTestCases = [
|
||||||
{text: 'Online', className: 'icon-check', profileClassName: 'icon-check-circle'},
|
{text: 'Online', className: 'icon-check-circle', profileClassName: 'icon-check-circle'},
|
||||||
{text: 'Away', className: 'icon-clock'},
|
{text: 'Away', className: 'icon-clock'},
|
||||||
{text: 'Do Not Disturb', className: 'icon-minus-circle'},
|
{text: 'Do Not Disturb', className: 'icon-minus-circle'},
|
||||||
{text: 'Offline', className: 'icon-circle-outline'},
|
{text: 'Offline', className: 'icon-circle-outline'},
|
||||||
|
@ -145,4 +145,42 @@ describe('Edit Message', () => {
|
|||||||
cy.get(postText).should('have.text', `${secondMessage} Another new message Edited`);
|
cy.get(postText).should('have.text', `${secondMessage} Another new message Edited`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('MM-T5416 should discard any changes made after cancelling the edit and opening the edit textbox again should display the original message', () => {
|
||||||
|
const message = 'World!';
|
||||||
|
cy.postMessage(message);
|
||||||
|
|
||||||
|
// * Verify message is sent and not pending
|
||||||
|
cy.getLastPostId().then((postId) => {
|
||||||
|
const postText = `#postMessageText_${postId}`;
|
||||||
|
cy.get(postText).should('have.text', message);
|
||||||
|
|
||||||
|
// # Open edit textbox
|
||||||
|
cy.uiGetPostTextBox().type('{uparrow}');
|
||||||
|
|
||||||
|
// * Edit Post Input should appear, and edit the post
|
||||||
|
cy.get('#edit_textbox').should('be.visible');
|
||||||
|
|
||||||
|
// * Press the escape key to cancel
|
||||||
|
cy.get('#edit_textbox').should('have.text', message).type(' Another new message{esc}');
|
||||||
|
cy.get('#edit_textbox').should('not.exist');
|
||||||
|
|
||||||
|
// * Check that the message wasn't edited
|
||||||
|
cy.get(postText).should('have.text', message);
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.getLastPostId().then((postId) => {
|
||||||
|
const postText = `#postMessageText_${postId}`;
|
||||||
|
cy.get(postText).should('have.text', message);
|
||||||
|
|
||||||
|
// # Open edit textbox again
|
||||||
|
cy.uiGetPostTextBox().type('{uparrow}');
|
||||||
|
|
||||||
|
// * Edit Post Input should appear, and edit the post
|
||||||
|
cy.get('#edit_textbox').should('be.visible');
|
||||||
|
|
||||||
|
// * Opening the edit textbox again after previously cancelling the edit should contain the original message.
|
||||||
|
cy.get('#edit_textbox').should('have.text', message);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -9,71 +9,45 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
import {onlyOn} from '@cypress/skip-test';
|
|
||||||
|
|
||||||
describe('channels > App Bar', {testIsolation: true}, () => {
|
describe('channels > App Bar', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
|
||||||
let appBarEnabled;
|
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.apiInitSetup().then(({team, user}) => {
|
cy.apiInitSetup().then(({team, user}) => {
|
||||||
testTeam = team;
|
testTeam = team;
|
||||||
testUser = user;
|
testUser = user;
|
||||||
|
|
||||||
// # Login as testUser
|
|
||||||
cy.apiLogin(testUser);
|
|
||||||
|
|
||||||
// # Create a playbook
|
|
||||||
cy.apiCreateTestPlaybook({
|
|
||||||
teamId: testTeam.id,
|
|
||||||
title: 'Playbook',
|
|
||||||
userId: testUser.id,
|
|
||||||
}).then((playbook) => {
|
|
||||||
testPlaybook = playbook;
|
|
||||||
|
|
||||||
// # Start a playbook run
|
|
||||||
cy.apiRunPlaybook({
|
|
||||||
teamId: testTeam.id,
|
|
||||||
playbookId: testPlaybook.id,
|
|
||||||
playbookRunName: 'Playbook Run',
|
|
||||||
ownerUserId: testUser.id,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.apiGetConfig(true).then(({config}) => {
|
|
||||||
appBarEnabled = config.EnableAppBar === 'true';
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// # Size the viewport to show the RHS without covering posts.
|
cy.apiAdminLogin();
|
||||||
cy.viewport('macbook-13');
|
|
||||||
|
|
||||||
// # Login as testUser
|
|
||||||
cy.apiLogin(testUser);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('App Bar disabled', () => {
|
describe('App Bar disabled', () => {
|
||||||
it('should not show the Playbook App Bar icon', () => {
|
it('should not show the Playbook App Bar icon', () => {
|
||||||
onlyOn(!appBarEnabled);
|
cy.apiUpdateConfig({ExperimentalSettings: {EnableAppBar: false}});
|
||||||
|
|
||||||
|
// # Login as testUser
|
||||||
|
cy.apiLogin(testUser);
|
||||||
|
|
||||||
// # Navigate directly to a non-playbook run channel
|
// # Navigate directly to a non-playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||||
|
|
||||||
// * Verify App Bar icon is not showing
|
// * Verify App Bar icon is not showing
|
||||||
cy.get('#channel_view').within(() => {
|
cy.get('.app-bar').should('not.exist');
|
||||||
cy.getPlaybooksAppBarIcon().should('not.exist');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('App Bar enabled', () => {
|
describe('App Bar enabled', () => {
|
||||||
it('should show the Playbook App Bar icon', () => {
|
beforeEach(() => {
|
||||||
onlyOn(appBarEnabled);
|
cy.apiUpdateConfig({ExperimentalSettings: {EnableAppBar: true}});
|
||||||
|
|
||||||
|
// # Login as testUser
|
||||||
|
cy.apiLogin(testUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the Playbook App Bar icon', () => {
|
||||||
// # Navigate directly to a non-playbook run channel
|
// # Navigate directly to a non-playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||||
|
|
||||||
@ -82,8 +56,6 @@ describe('channels > App Bar', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show "Playbooks" tooltip for Playbook App Bar icon', () => {
|
it('should show "Playbooks" tooltip for Playbook App Bar icon', () => {
|
||||||
onlyOn(appBarEnabled);
|
|
||||||
|
|
||||||
// # Navigate directly to a non-playbook run channel
|
// # Navigate directly to a non-playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||||
|
|
||||||
|
@ -9,14 +9,11 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
import {onlyOn} from '@cypress/skip-test';
|
|
||||||
|
|
||||||
describe('channels > channel header', {testIsolation: true}, () => {
|
describe('channels > channel header', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
let testPlaybookRun;
|
let testPlaybookRun;
|
||||||
let appBarEnabled;
|
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.apiInitSetup().then(({team, user}) => {
|
cy.apiInitSetup().then(({team, user}) => {
|
||||||
@ -44,24 +41,16 @@ describe('channels > channel header', {testIsolation: true}, () => {
|
|||||||
testPlaybookRun = run;
|
testPlaybookRun = run;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.apiGetConfig(true).then(({config}) => {
|
|
||||||
appBarEnabled = config.EnableAppBar === 'true';
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// # Size the viewport to show the RHS without covering posts.
|
|
||||||
cy.viewport('macbook-13');
|
|
||||||
|
|
||||||
// # Login as testUser
|
|
||||||
cy.apiLogin(testUser);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('App Bar enabled', () => {
|
describe('App Bar enabled', () => {
|
||||||
it('webapp should hide the Playbook channel header button', () => {
|
it('webapp should hide the Playbook channel header button', () => {
|
||||||
onlyOn(appBarEnabled);
|
cy.apiAdminLogin();
|
||||||
|
cy.apiUpdateConfig({ExperimentalSettings: {EnableAppBar: true}});
|
||||||
|
|
||||||
|
// # Login as testUser
|
||||||
|
cy.apiLogin(testUser);
|
||||||
|
|
||||||
// # Navigate directly to a non-playbook run channel
|
// # Navigate directly to a non-playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||||
@ -74,9 +63,15 @@ describe('channels > channel header', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('App Bar disabled', () => {
|
describe('App Bar disabled', () => {
|
||||||
it('webapp should show the Playbook channel header button', () => {
|
beforeEach(() => {
|
||||||
onlyOn(!appBarEnabled);
|
cy.apiAdminLogin();
|
||||||
|
cy.apiUpdateConfig({ExperimentalSettings: {EnableAppBar: false}});
|
||||||
|
|
||||||
|
// # Login as testUser
|
||||||
|
cy.apiLogin(testUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('webapp should show the Playbook channel header button', () => {
|
||||||
// # Navigate directly to a non-playbook run channel
|
// # Navigate directly to a non-playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||||
|
|
||||||
@ -87,8 +82,6 @@ describe('channels > channel header', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('tooltip text should show "Playbooks" for Playbook channel header button', () => {
|
it('tooltip text should show "Playbooks" for Playbook channel header button', () => {
|
||||||
onlyOn(!appBarEnabled);
|
|
||||||
|
|
||||||
// # Navigate directly to a non-playbook run channel
|
// # Navigate directly to a non-playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||||
|
|
||||||
@ -103,6 +96,11 @@ describe('channels > channel header', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('description text', () => {
|
describe('description text', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// # Login as testUser
|
||||||
|
cy.apiLogin(testUser);
|
||||||
|
});
|
||||||
|
|
||||||
it('should contain a link to the playbook', () => {
|
it('should contain a link to the playbook', () => {
|
||||||
// # Navigate directly to a playbook run channel
|
// # Navigate directly to a playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/playbook-run`);
|
cy.visit(`/${testTeam.name}/channels/playbook-run`);
|
||||||
@ -112,6 +110,7 @@ describe('channels > channel header', {testIsolation: true}, () => {
|
|||||||
expect(href).to.equals(`/playbooks/playbooks/${testPlaybook.id}`);
|
expect(href).to.equals(`/playbooks/playbooks/${testPlaybook.id}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain a link to the overview page', () => {
|
it('should contain a link to the overview page', () => {
|
||||||
// # Navigate directly to a playbook run channel
|
// # Navigate directly to a playbook run channel
|
||||||
cy.visit(`/${testTeam.name}/channels/playbook-run`);
|
cy.visit(`/${testTeam.name}/channels/playbook-run`);
|
||||||
|
@ -82,7 +82,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('description link navigates to run overview', () => {
|
it('description link navigates to run overview', () => {
|
||||||
// # Run the `/playbook update` slash command.
|
// # Run the `/playbook update` slash command.
|
||||||
cy.uiPostMessageQuickly('/playbook update');
|
cy.uiPostMessageQuickly('/playbook update');
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ describe('lhs', {testIsolation: true}, () => {
|
|||||||
cy.findByTestId('dropdownmenu').should('be.visible');
|
cy.findByTestId('dropdownmenu').should('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('can copy link', () => {
|
it('can copy link', () => {
|
||||||
// # Visit the playbook run
|
// # Visit the playbook run
|
||||||
cy.visit(`/playbooks/runs/${playbookRun.id}`);
|
cy.visit(`/playbooks/runs/${playbookRun.id}`);
|
||||||
stubClipboard().as('clipboard');
|
stubClipboard().as('clipboard');
|
||||||
@ -295,7 +295,7 @@ describe('lhs', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('leave run, when on rdp of the same run', () => {
|
it('leave run, when on rdp of the same run', () => {
|
||||||
// # Click on leave menu item
|
// # Click on leave menu item
|
||||||
getRunDropdownItemByText('Runs', playbookRun.name, 'Leave and unfollow run').click();
|
getRunDropdownItemByText('Runs', playbookRun.name, 'Leave and unfollow run').click();
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ describe('playbooks > edit_metrics', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('delete metric', () => {
|
describe('delete metric', () => {
|
||||||
it.skip('verifies when clicking delete button; saved metrics have different confirmation text; deleted metrics are deleted', () => {
|
it('verifies when clicking delete button; saved metrics have different confirmation text; deleted metrics are deleted', () => {
|
||||||
// # Visit the selected playbook
|
// # Visit the selected playbook
|
||||||
cy.visit(`/playbooks/playbooks/${testPlaybook.id}`);
|
cy.visit(`/playbooks/playbooks/${testPlaybook.id}`);
|
||||||
|
|
||||||
|
@ -160,9 +160,7 @@ describe('runs > permissions', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('should be visible', () => {
|
describe('should be visible', () => {
|
||||||
// XXX: Skipping this test, since public playbooks currently have no members. This will
|
it('to playbook members', () => {
|
||||||
// likely change in the future, so keeping the skeleton.
|
|
||||||
it.skip('to playbook members', () => {
|
|
||||||
assertRunIsVisible(run, playbookMember);
|
assertRunIsVisible(run, playbookMember);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -242,9 +240,7 @@ describe('runs > permissions', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('should be visible', () => {
|
describe('should be visible', () => {
|
||||||
// XXX: Skipping this test, since public playbooks currently have no members. This will
|
it('to playbook members', () => {
|
||||||
// likely change in the future.
|
|
||||||
it.skip('to playbook members', () => {
|
|
||||||
assertRunIsVisible(run, playbookMember);
|
assertRunIsVisible(run, playbookMember);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -332,10 +328,9 @@ describe('runs > permissions', {testIsolation: true}, () => {
|
|||||||
assertRunIsVisible(run, runParticipant);
|
assertRunIsVisible(run, runParticipant);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Skipping this test, since followers cannot follow a run with a private channel from
|
// Followers cannot follow a run with a private channel from a private playbook
|
||||||
// a private playbook. (But leaving it for clarity in the code.)
|
it('to run followers', () => {
|
||||||
it.skip('to run followers', () => {
|
assertRunIsNotVisible(run, runFollower);
|
||||||
assertRunIsVisible(run, runFollower);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('to admins in the team', () => {
|
it('to admins in the team', () => {
|
||||||
@ -414,10 +409,9 @@ describe('runs > permissions', {testIsolation: true}, () => {
|
|||||||
assertRunIsVisible(run, runParticipant);
|
assertRunIsVisible(run, runParticipant);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Skipping this test, since followers cannot follow a run with a private channel from
|
// Followers cannot follow a run with a private channel from a private playbook
|
||||||
// a private playbook. (But leaving it for clarity in the code.)
|
it('to run followers', () => {
|
||||||
it.skip('to run followers', () => {
|
assertRunIsNotVisible(run, runFollower);
|
||||||
assertRunIsVisible(run, runFollower);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('to admins in the team', () => {
|
it('to admins in the team', () => {
|
||||||
|
@ -692,7 +692,7 @@ describe('runs > run details page > header', {testIsolation: true}, () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.skip('Join action disabled', () => {
|
describe('Join action disabled', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin(testUser);
|
cy.apiLogin(testUser);
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ describe('runs > run details page > status update', {testIsolation: true}, () =>
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('requests an update and confirm', () => {
|
it('requests an update and confirm', () => {
|
||||||
// # Click on request update
|
// # Click on request update
|
||||||
cy.findByTestId('run-statusupdate-section').
|
cy.findByTestId('run-statusupdate-section').
|
||||||
should('be.visible').
|
should('be.visible').
|
||||||
@ -281,11 +281,11 @@ describe('runs > run details page > status update', {testIsolation: true}, () =>
|
|||||||
cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`);
|
cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`);
|
||||||
|
|
||||||
// * Assert that message has been sent
|
// * Assert that message has been sent
|
||||||
cy.getLastPost().contains(`${testUser.username} requested a status update for ${testPublicPlaybook.name}.`);
|
cy.getLastPost().contains(`${testViewerUser.username} requested a status update for ${testRun.name}.`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('requests an update and cancel', () => {
|
it('requests an update and cancel', () => {
|
||||||
// # Click request update
|
// # Click request update
|
||||||
cy.findByTestId('run-statusupdate-section').
|
cy.findByTestId('run-statusupdate-section').
|
||||||
should('be.visible').
|
should('be.visible').
|
||||||
|
@ -2,8 +2,21 @@
|
|||||||
|
|
||||||
#### 1. Start local server in a separate terminal.
|
#### 1. Start local server in a separate terminal.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Typically run the local server with:
|
||||||
|
cd server && make run
|
||||||
|
|
||||||
|
# Or build and distribute webapp including channels, boards and playbooks
|
||||||
|
# so that their product URLs do not rely on Webpack dev server.
|
||||||
|
# Especially important when running test inside the Playwright's docker container.
|
||||||
|
cd webapp && make dist
|
||||||
|
cd server && make run-server
|
||||||
|
```
|
||||||
|
|
||||||
#### 2. Install dependencies and run the test.
|
#### 2. Install dependencies and run the test.
|
||||||
|
|
||||||
|
Note: If you're using Node.js version 18 and above, you may need to set `NODE_OPTIONS='--no-experimental-fetch'`.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Install npm packages
|
# Install npm packages
|
||||||
npm i
|
npm i
|
||||||
@ -32,14 +45,16 @@ npm run test
|
|||||||
Change to root directory, run docker container
|
Change to root directory, run docker container
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.30.0-focal /bin/bash
|
docker run -it --rm -v "$(pwd):/mattermost/" --ipc=host mcr.microsoft.com/playwright:v1.32.0-focal /bin/bash
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2. Inside the docker container
|
#### 2. Inside the docker container
|
||||||
|
|
||||||
```
|
```
|
||||||
|
export NODE_OPTIONS='--no-experimental-fetch'
|
||||||
export PW_BASE_URL=http://host.docker.internal:8065
|
export PW_BASE_URL=http://host.docker.internal:8065
|
||||||
cd mattermost/e2e/playwright
|
export PW_HEADLESS=true
|
||||||
|
cd mattermost/e2e-tests/playwright
|
||||||
|
|
||||||
# Install npm packages. Use "npm ci" to match the automated environment
|
# Install npm packages. Use "npm ci" to match the automated environment
|
||||||
npm ci
|
npm ci
|
||||||
|
1026
e2e-tests/playwright/package-lock.json
generated
@ -1,33 +1,35 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "PW_SNAPSHOT_ENABLE=true playwright test",
|
"test": "cross-env PW_SNAPSHOT_ENABLE=true playwright test",
|
||||||
"percy": "PERCY_TOKEN=$PERCY_TOKEN PW_PERCY_ENABLE=true percy exec -- playwright test --project=chrome --project=iphone --project=ipad",
|
"percy": "cross-env PERCY_TOKEN=$PERCY_TOKEN PW_PERCY_ENABLE=true percy exec -- playwright test --project=chrome --project=iphone --project=ipad",
|
||||||
"tsc": "tsc -b",
|
"tsc": "tsc -b",
|
||||||
"lint": "eslint . --ext .js,.ts",
|
"lint": "eslint . --ext .js,.ts",
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write .",
|
||||||
"check": "npm run tsc && npm run lint && npm run prettier",
|
"check": "npm run tsc && npm run lint && npm run prettier",
|
||||||
"codegen": "playwright codegen $PW_BASE_URL",
|
"codegen": "cross-env playwright codegen $PW_BASE_URL",
|
||||||
"test-slomo": "PW_SNAPSHOT_ENABLE=true PW_HEADLESS=false PW_SLOWMO=1000 playwright test",
|
"playwright-ui": "playwright test --ui",
|
||||||
|
"test-slomo": "cross-env PW_SNAPSHOT_ENABLE=true PW_SLOWMO=1000 playwright test",
|
||||||
"show-report": "npx playwright show-report"
|
"show-report": "npx playwright show-report"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@percy/cli": "1.18.0",
|
"@percy/cli": "1.23.0",
|
||||||
"@percy/playwright": "1.0.4",
|
"@percy/playwright": "1.0.4",
|
||||||
"@playwright/test": "1.30.0",
|
"@playwright/test": "1.32.3",
|
||||||
"async-wait-until": "2.0.12",
|
"async-wait-until": "2.0.12",
|
||||||
"chalk": "4.1.2",
|
"chalk": "4.1.2",
|
||||||
"deepmerge": "4.3.0",
|
"deepmerge": "4.3.1",
|
||||||
"dotenv": "16.0.3",
|
"dotenv": "16.0.3",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"isomorphic-unfetch": "4.0.2",
|
"isomorphic-unfetch": "4.0.2",
|
||||||
"uuid": "9.0.0"
|
"uuid": "9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/uuid": "9.0.0",
|
"@types/uuid": "9.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "5.51.0",
|
"@typescript-eslint/eslint-plugin": "5.59.0",
|
||||||
"@typescript-eslint/parser": "5.51.0",
|
"@typescript-eslint/parser": "5.59.0",
|
||||||
"eslint": "8.34.0",
|
"cross-env": "7.0.3",
|
||||||
"prettier": "2.8.4",
|
"eslint": "8.38.0",
|
||||||
"typescript": "4.9.5"
|
"prettier": "2.8.7",
|
||||||
|
"typescript": "5.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import {defineConfig, devices} from '@playwright/test';
|
|||||||
import {duration} from '@e2e-support/util';
|
import {duration} from '@e2e-support/util';
|
||||||
import testConfig from '@e2e-test.config';
|
import testConfig from '@e2e-test.config';
|
||||||
|
|
||||||
const defaultOutputFolder = 'playwright-report';
|
const defaultOutputFolder = './playwright-report';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
globalSetup: require.resolve('./global_setup'),
|
globalSetup: require.resolve('./global_setup'),
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
# - Default to "false" if not set.
|
# - Default to "false" if not set.
|
||||||
|
|
||||||
# 12. PW_HEADLESS
|
# 12. PW_HEADLESS
|
||||||
# - Default to "true" if not set. Set to false to run test in head mode.
|
# - Default to "false" or headless mode if not set. Set to true to run test in headed mode.
|
||||||
|
|
||||||
# 13. PW_SLOWMO
|
# 13. PW_SLOWMO
|
||||||
# - Default to "0" if not set which means normal test speed run. Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
# - Default to "0" if not set which means normal test speed run. Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||||
|
@ -3,16 +3,18 @@
|
|||||||
|
|
||||||
import {writeFile} from 'node:fs/promises';
|
import {writeFile} from 'node:fs/promises';
|
||||||
|
|
||||||
import {request, Browser} from '@playwright/test';
|
import {request, Browser, BrowserContext} from '@playwright/test';
|
||||||
|
|
||||||
import {UserProfile} from '@mattermost/types/users';
|
import {UserProfile} from '@mattermost/types/users';
|
||||||
import testConfig from '@e2e-test.config';
|
import testConfig from '@e2e-test.config';
|
||||||
|
|
||||||
export class TestBrowser {
|
export class TestBrowser {
|
||||||
readonly browser: Browser;
|
readonly browser: Browser;
|
||||||
|
context: BrowserContext | null;
|
||||||
|
|
||||||
constructor(browser: Browser) {
|
constructor(browser: Browser) {
|
||||||
this.browser = browser;
|
this.browser = browser;
|
||||||
|
this.context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(user: UserProfile | null) {
|
async login(user: UserProfile | null) {
|
||||||
@ -27,8 +29,16 @@ export class TestBrowser {
|
|||||||
const context = await this.browser.newContext(options);
|
const context = await this.browser.newContext(options);
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
return {context, page};
|
return {context, page};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
if (this.context) {
|
||||||
|
await this.context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loginByAPI(loginId: string, password: string, token = '', ldapOnly = false) {
|
export async function loginByAPI(loginId: string, password: string, token = '', ldapOnly = false) {
|
||||||
|
@ -4,25 +4,32 @@
|
|||||||
import {getRandomId} from '@e2e-support/util';
|
import {getRandomId} from '@e2e-support/util';
|
||||||
import {Channel, ChannelType} from '@mattermost/types/channels';
|
import {Channel, ChannelType} from '@mattermost/types/channels';
|
||||||
|
|
||||||
export function createRandomChannel(
|
type ChannelInput = {
|
||||||
teamId: string,
|
teamId: string;
|
||||||
name: string,
|
name: string;
|
||||||
displayName: string,
|
displayName: string;
|
||||||
type: ChannelType = 'O',
|
type?: ChannelType;
|
||||||
purpose = '',
|
purpose?: string;
|
||||||
header = '',
|
header?: string;
|
||||||
unique = true
|
unique?: boolean;
|
||||||
): Channel {
|
};
|
||||||
|
|
||||||
|
export function createRandomChannel(channelInput: ChannelInput): Channel {
|
||||||
|
const channel = {
|
||||||
|
team_id: channelInput.teamId,
|
||||||
|
name: channelInput.name,
|
||||||
|
display_name: channelInput.displayName,
|
||||||
|
type: channelInput.type || 'O',
|
||||||
|
purpose: channelInput.type || '',
|
||||||
|
header: channelInput.type || '',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (channelInput.unique) {
|
||||||
const randomSuffix = getRandomId();
|
const randomSuffix = getRandomId();
|
||||||
|
|
||||||
const channel = {
|
channel.name = `${channelInput.name}-${randomSuffix}`;
|
||||||
team_id: teamId,
|
channel.display_name = `${channelInput.displayName} ${randomSuffix}`;
|
||||||
name: unique ? `${name}-${randomSuffix}` : name,
|
}
|
||||||
display_name: unique ? `${displayName} ${randomSuffix}` : displayName,
|
|
||||||
type,
|
|
||||||
purpose,
|
|
||||||
header,
|
|
||||||
};
|
|
||||||
|
|
||||||
return channel as Channel;
|
return channel as Channel;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
// This is based on "packages/client/src/client4.ts". Modified for node client.
|
// This is based on "webapp/platform/client/src/client4.ts". Modified for node client.
|
||||||
// Update should be made in comparison with the base Client4.
|
// Update should be made in comparison with the base Client4.
|
||||||
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
@ -134,7 +134,7 @@ export default class Client extends Client4 {
|
|||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// Boards client
|
// Boards client
|
||||||
// based on https://github.com/mattermost/focalboard/blob/main/webapp/src/octoClient.ts
|
// based on "webapp/boards/src/octoClient.ts"
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
async patchUserConfig(userID: string, patch: UserConfigPatch): Promise<UserPreference[] | undefined> {
|
async patchUserConfig(userID: string, patch: UserConfigPatch): Promise<UserPreference[] | undefined> {
|
||||||
|
@ -170,7 +170,6 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
EnableCustomGroups: true,
|
EnableCustomGroups: true,
|
||||||
SelfHostedPurchase: true,
|
SelfHostedPurchase: true,
|
||||||
AllowSyncedDrafts: true,
|
AllowSyncedDrafts: true,
|
||||||
SelfHostedExpansion: false,
|
|
||||||
},
|
},
|
||||||
TeamSettings: {
|
TeamSettings: {
|
||||||
SiteName: 'Mattermost',
|
SiteName: 'Mattermost',
|
||||||
@ -319,7 +318,6 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
LoginButtonColor: '#0000',
|
LoginButtonColor: '#0000',
|
||||||
LoginButtonBorderColor: '#2389D7',
|
LoginButtonBorderColor: '#2389D7',
|
||||||
LoginButtonTextColor: '#2389D7',
|
LoginButtonTextColor: '#2389D7',
|
||||||
EnableInactivityEmail: true,
|
|
||||||
},
|
},
|
||||||
RateLimitSettings: {
|
RateLimitSettings: {
|
||||||
Enable: false,
|
Enable: false,
|
||||||
@ -532,7 +530,8 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
EnableSharedChannels: false,
|
EnableSharedChannels: false,
|
||||||
EnableRemoteClusterService: false,
|
EnableRemoteClusterService: false,
|
||||||
EnableAppBar: false,
|
EnableAppBar: false,
|
||||||
PatchPluginsReactDOM: false,
|
DisableRefetchingOnBrowserFocus: false,
|
||||||
|
DelayChannelAutocomplete: false,
|
||||||
},
|
},
|
||||||
AnalyticsSettings: {
|
AnalyticsSettings: {
|
||||||
MaxUsersForStatistics: 2500,
|
MaxUsersForStatistics: 2500,
|
||||||
@ -622,12 +621,6 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
'com.mattermost.nps': {
|
'com.mattermost.nps': {
|
||||||
Enable: true,
|
Enable: true,
|
||||||
},
|
},
|
||||||
focalboard: {
|
|
||||||
Enable: true,
|
|
||||||
},
|
|
||||||
playbooks: {
|
|
||||||
Enable: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
EnableMarketplace: true,
|
EnableMarketplace: true,
|
||||||
EnableRemoteMarketplace: true,
|
EnableRemoteMarketplace: true,
|
||||||
@ -671,13 +664,11 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
BoardsFeatureFlags: '',
|
BoardsFeatureFlags: '',
|
||||||
BoardsDataRetention: false,
|
BoardsDataRetention: false,
|
||||||
NormalizeLdapDNs: false,
|
NormalizeLdapDNs: false,
|
||||||
EnableInactivityCheckJob: true,
|
|
||||||
UseCaseOnboarding: true,
|
|
||||||
GraphQL: false,
|
GraphQL: false,
|
||||||
InsightsEnabled: true,
|
InsightsEnabled: true,
|
||||||
CommandPalette: false,
|
CommandPalette: false,
|
||||||
SendWelcomePost: true,
|
SendWelcomePost: true,
|
||||||
WorkTemplate: false,
|
WorkTemplate: true,
|
||||||
PostPriority: true,
|
PostPriority: true,
|
||||||
WysiwygEditor: false,
|
WysiwygEditor: false,
|
||||||
PeopleProduct: false,
|
PeopleProduct: false,
|
||||||
@ -686,7 +677,9 @@ const defaultServerConfig: AdminConfig = {
|
|||||||
ThreadsEverywhere: false,
|
ThreadsEverywhere: false,
|
||||||
GlobalDrafts: true,
|
GlobalDrafts: true,
|
||||||
OnboardingTourTips: true,
|
OnboardingTourTips: true,
|
||||||
|
DeprecateCloudFree: false,
|
||||||
AppsSidebarCategory: false,
|
AppsSidebarCategory: false,
|
||||||
|
CloudReverseTrial: false,
|
||||||
},
|
},
|
||||||
ImportSettings: {
|
ImportSettings: {
|
||||||
Directory: './import',
|
Directory: './import',
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import {expect} from '@playwright/test';
|
import {expect} from '@playwright/test';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
|
||||||
|
import {ClientError} from '@mattermost/client/client4';
|
||||||
import {PreferenceType} from '@mattermost/types/preferences';
|
import {PreferenceType} from '@mattermost/types/preferences';
|
||||||
import testConfig from '@e2e-test.config';
|
import testConfig from '@e2e-test.config';
|
||||||
|
|
||||||
@ -77,10 +79,21 @@ export async function initSetup({
|
|||||||
offTopicUrl: getUrl(team.name, 'off-topic'),
|
offTopicUrl: getUrl(team.name, 'off-topic'),
|
||||||
townSquareUrl: getUrl(team.name, 'town-square'),
|
townSquareUrl: getUrl(team.name, 'town-square'),
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
// log an error for debugging
|
// log an error for debugging
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(err);
|
const err = error as ClientError;
|
||||||
|
if (err.message === 'Could not parse multipart form.') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(chalk.yellow(`node version: ${process.version}\nNODE_OPTIONS: ${process.env.NODE_OPTIONS}`));
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
chalk.green(
|
||||||
|
`This failed due to the experimental fetch support in Node.js starting v18.0.0.\nYou may set environment variable: "export NODE_OPTIONS='--no-experimental-fetch'", then try again.'`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
expect(err, 'Should not throw an error').toBeFalsy();
|
expect(err, 'Should not throw an error').toBeFalsy();
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {test as base, Browser} from '@playwright/test';
|
import {test as base, Browser, ViewportSize} from '@playwright/test';
|
||||||
|
|
||||||
import {TestBrowser} from './browser_context';
|
import {TestBrowser} from './browser_context';
|
||||||
import {shouldHaveCallsEnabled, shouldHaveFeatureFlag, shouldSkipInSmallScreen, shouldRunInLinux} from './flag';
|
import {shouldHaveCallsEnabled, shouldHaveFeatureFlag, shouldSkipInSmallScreen, shouldRunInLinux} from './flag';
|
||||||
import {initSetup, getAdminClient} from './server';
|
import {initSetup, getAdminClient} from './server';
|
||||||
|
import {isSmallScreen} from './util';
|
||||||
import {hideDynamicChannelsContent, waitForAnimationEnd, waitUntil} from './test_action';
|
import {hideDynamicChannelsContent, waitForAnimationEnd, waitUntil} from './test_action';
|
||||||
import {pages} from './ui/pages';
|
import {pages} from './ui/pages';
|
||||||
import {matchSnapshot} from './visual';
|
import {matchSnapshot} from './visual';
|
||||||
@ -15,9 +16,10 @@ type ExtendedFixtures = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const test = base.extend<ExtendedFixtures>({
|
export const test = base.extend<ExtendedFixtures>({
|
||||||
pw: async ({browser}, use) => {
|
pw: async ({browser, viewport}, use) => {
|
||||||
const pw = new PlaywrightExtended(browser);
|
const pw = new PlaywrightExtended(browser, viewport);
|
||||||
await use(pw);
|
await use(pw);
|
||||||
|
await pw.testBrowser.close();
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line no-empty-pattern
|
// eslint-disable-next-line no-empty-pattern
|
||||||
pages: async ({}, use) => {
|
pages: async ({}, use) => {
|
||||||
@ -47,10 +49,13 @@ class PlaywrightExtended {
|
|||||||
// ./ui/pages
|
// ./ui/pages
|
||||||
readonly pages;
|
readonly pages;
|
||||||
|
|
||||||
|
// ./util
|
||||||
|
readonly isSmallScreen;
|
||||||
|
|
||||||
// ./visual
|
// ./visual
|
||||||
readonly matchSnapshot;
|
readonly matchSnapshot;
|
||||||
|
|
||||||
constructor(browser: Browser) {
|
constructor(browser: Browser, viewport: ViewportSize | null) {
|
||||||
// ./browser_context
|
// ./browser_context
|
||||||
this.testBrowser = new TestBrowser(browser);
|
this.testBrowser = new TestBrowser(browser);
|
||||||
|
|
||||||
@ -72,6 +77,9 @@ class PlaywrightExtended {
|
|||||||
// ./ui/pages
|
// ./ui/pages
|
||||||
this.pages = pages;
|
this.pages = pages;
|
||||||
|
|
||||||
|
// ./util
|
||||||
|
this.isSmallScreen = () => isSmallScreen(viewport);
|
||||||
|
|
||||||
// ./visual
|
// ./visual
|
||||||
this.matchSnapshot = matchSnapshot;
|
this.matchSnapshot = matchSnapshot;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
export default class FindChannelsModal {
|
||||||
|
readonly container: Locator;
|
||||||
|
readonly input;
|
||||||
|
readonly searchList;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
this.input = container.getByRole('textbox', {name: 'quick switch input'});
|
||||||
|
this.searchList = container.locator('.suggestion-list__item');
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {FindChannelsModal};
|
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
export default class ChannelsHeaderMobile {
|
||||||
|
readonly container: Locator;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggleSidebar() {
|
||||||
|
await this.container.getByRole('button', {name: 'Toggle sidebar Menu Icon'}).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {ChannelsHeaderMobile};
|
@ -9,6 +9,7 @@ export default class ChannelsPostCreate {
|
|||||||
readonly input;
|
readonly input;
|
||||||
readonly attachmentButton;
|
readonly attachmentButton;
|
||||||
readonly emojiButton;
|
readonly emojiButton;
|
||||||
|
readonly sendButton: Locator;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
@ -16,12 +17,17 @@ export default class ChannelsPostCreate {
|
|||||||
this.input = container.getByTestId('post_textbox');
|
this.input = container.getByTestId('post_textbox');
|
||||||
this.attachmentButton = container.getByLabel('attachment');
|
this.attachmentButton = container.getByLabel('attachment');
|
||||||
this.emojiButton = container.getByLabel('select an emoji');
|
this.emojiButton = container.getByLabel('select an emoji');
|
||||||
|
this.sendButton = container.getByTestId('SendMessageButton');
|
||||||
}
|
}
|
||||||
|
|
||||||
async postMessage(message: string) {
|
async postMessage(message: string) {
|
||||||
await this.input.fill(message);
|
await this.input.fill(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendMessage() {
|
||||||
|
await this.sendButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
async toBeVisible() {
|
async toBeVisible() {
|
||||||
await expect(this.container).toBeVisible();
|
await expect(this.container).toBeVisible();
|
||||||
await expect(this.input).toBeVisible();
|
await expect(this.input).toBeVisible();
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
export default class ChannelsSidebarLeft {
|
||||||
|
readonly container: Locator;
|
||||||
|
readonly findChannelButton;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
this.findChannelButton = container.getByRole('button', {name: 'Find Channels'});
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {ChannelsSidebarLeft};
|
@ -16,7 +16,7 @@ export default class GlobalHeader {
|
|||||||
|
|
||||||
async switchProduct(name: string) {
|
async switchProduct(name: string) {
|
||||||
await this.productSwitchMenu.click();
|
await this.productSwitchMenu.click();
|
||||||
await this.container.getByRole('link', {name: ` ${name}`}).click();
|
await this.container.getByRole('link', {name}).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
async toBeVisible(name: string) {
|
async toBeVisible(name: string) {
|
||||||
|
@ -3,19 +3,25 @@
|
|||||||
|
|
||||||
import {BoardsSidebar} from './boards/sidebar';
|
import {BoardsSidebar} from './boards/sidebar';
|
||||||
import {ChannelsHeader} from './channels/header';
|
import {ChannelsHeader} from './channels/header';
|
||||||
|
import {ChannelsHeaderMobile} from './channels/header_mobile';
|
||||||
import {ChannelsAppBar} from './channels/app_bar';
|
import {ChannelsAppBar} from './channels/app_bar';
|
||||||
import {ChannelsPostCreate} from './channels/post_create';
|
import {ChannelsPostCreate} from './channels/post_create';
|
||||||
import {ChannelsPost} from './channels/post';
|
import {ChannelsPost} from './channels/post';
|
||||||
|
import {ChannelsSidebarLeft} from './channels/sidebar_left';
|
||||||
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
||||||
|
import {FindChannelsModal} from './channels/find_channels_modal';
|
||||||
import {GlobalHeader} from './global_header';
|
import {GlobalHeader} from './global_header';
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
BoardsSidebar,
|
BoardsSidebar,
|
||||||
ChannelsAppBar,
|
ChannelsAppBar,
|
||||||
ChannelsHeader,
|
ChannelsHeader,
|
||||||
|
ChannelsHeaderMobile,
|
||||||
ChannelsPostCreate,
|
ChannelsPostCreate,
|
||||||
ChannelsPost,
|
ChannelsPost,
|
||||||
|
ChannelsSidebarLeft,
|
||||||
ChannelsSidebarRight,
|
ChannelsSidebarRight,
|
||||||
|
FindChannelsModal,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,8 +30,11 @@ export {
|
|||||||
BoardsSidebar,
|
BoardsSidebar,
|
||||||
ChannelsAppBar,
|
ChannelsAppBar,
|
||||||
ChannelsHeader,
|
ChannelsHeader,
|
||||||
|
ChannelsHeaderMobile,
|
||||||
ChannelsPostCreate,
|
ChannelsPostCreate,
|
||||||
ChannelsPost,
|
ChannelsPost,
|
||||||
|
ChannelsSidebarLeft,
|
||||||
ChannelsSidebarRight,
|
ChannelsSidebarRight,
|
||||||
|
FindChannelsModal,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
};
|
};
|
||||||
|
@ -11,17 +11,23 @@ export default class ChannelsPage {
|
|||||||
readonly channels = 'Channels';
|
readonly channels = 'Channels';
|
||||||
readonly page: Page;
|
readonly page: Page;
|
||||||
readonly postCreate;
|
readonly postCreate;
|
||||||
|
readonly findChannelsModal;
|
||||||
readonly globalHeader;
|
readonly globalHeader;
|
||||||
readonly header;
|
readonly header;
|
||||||
|
readonly headerMobile;
|
||||||
readonly appBar;
|
readonly appBar;
|
||||||
|
readonly sidebarLeft;
|
||||||
readonly sidebarRight;
|
readonly sidebarRight;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
this.postCreate = new components.ChannelsPostCreate(page.locator('#post-create'));
|
this.postCreate = new components.ChannelsPostCreate(page.locator('#post-create'));
|
||||||
|
this.findChannelsModal = new components.FindChannelsModal(page.getByRole('dialog', {name: 'Find Channels'}));
|
||||||
this.globalHeader = new components.GlobalHeader(page.locator('#global-header'));
|
this.globalHeader = new components.GlobalHeader(page.locator('#global-header'));
|
||||||
this.header = new components.ChannelsHeader(page.locator('.channel-header'));
|
this.header = new components.ChannelsHeader(page.locator('.channel-header'));
|
||||||
|
this.headerMobile = new components.ChannelsHeaderMobile(page.locator('.navbar'));
|
||||||
this.appBar = new components.ChannelsAppBar(page.locator('.app-bar'));
|
this.appBar = new components.ChannelsAppBar(page.locator('.app-bar'));
|
||||||
|
this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer'));
|
||||||
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
|
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,6 +55,10 @@ export default class ChannelsPage {
|
|||||||
await this.postCreate.postMessage(message);
|
await this.postCreate.postMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendMessage() {
|
||||||
|
await this.postCreate.sendMessage();
|
||||||
|
}
|
||||||
|
|
||||||
async getFirstPost() {
|
async getFirstPost() {
|
||||||
await this.page.getByTestId('postView').first().waitFor();
|
await this.page.getByTestId('postView').first().waitFor();
|
||||||
const post = await this.page.getByTestId('postView').first();
|
const post = await this.page.getByTestId('postView').first();
|
||||||
|
@ -55,7 +55,7 @@ const config: TestConfig = {
|
|||||||
// CI
|
// CI
|
||||||
isCI: !!process.env.CI,
|
isCI: !!process.env.CI,
|
||||||
// Playwright
|
// Playwright
|
||||||
headless: parseBool(process.env.PW_HEADLESS, false),
|
headless: parseBool(process.env.PW_HEADLESS, true),
|
||||||
slowMo: parseNumber(process.env.PW_SLOWMO, 0),
|
slowMo: parseNumber(process.env.PW_SLOWMO, 0),
|
||||||
workers: parseNumber(process.env.PW_WORKERS, 1),
|
workers: parseNumber(process.env.PW_WORKERS, 1),
|
||||||
// Visual tests
|
// Visual tests
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, test} from '@e2e-support/test_fixture';
|
||||||
|
import {createRandomChannel} from '@e2e-support/server';
|
||||||
|
|
||||||
|
test('MM-T5424 Find channel search returns only 50 results when there are more than 50 channels with similar names', async ({
|
||||||
|
pw,
|
||||||
|
pages,
|
||||||
|
}) => {
|
||||||
|
const {adminClient, user, team} = await pw.initSetup();
|
||||||
|
|
||||||
|
const commonName = 'test_channel';
|
||||||
|
|
||||||
|
// # Create more than 50 channels with similar names
|
||||||
|
const channelsRes = [];
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
let suffix = i.toString();
|
||||||
|
if (i < 10) {
|
||||||
|
suffix = `0${i}`;
|
||||||
|
}
|
||||||
|
const channel = createRandomChannel({
|
||||||
|
teamId: team.id,
|
||||||
|
name: `${commonName}_${suffix}`,
|
||||||
|
displayName: `Test Channel ${suffix}`,
|
||||||
|
});
|
||||||
|
channelsRes.push(adminClient.createChannel(channel));
|
||||||
|
}
|
||||||
|
await Promise.all(channelsRes);
|
||||||
|
|
||||||
|
// # Log in a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit a default channel page
|
||||||
|
const channelsPage = new pages.ChannelsPage(page);
|
||||||
|
await channelsPage.goto();
|
||||||
|
await channelsPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Click on "Find channel" and type "test_channel"
|
||||||
|
if (pw.isSmallScreen()) {
|
||||||
|
await channelsPage.headerMobile.toggleSidebar();
|
||||||
|
}
|
||||||
|
await channelsPage.sidebarLeft.findChannelButton.click();
|
||||||
|
|
||||||
|
await channelsPage.findChannelsModal.toBeVisible();
|
||||||
|
await channelsPage.findChannelsModal.input.fill(commonName);
|
||||||
|
|
||||||
|
const limitCount = 50;
|
||||||
|
|
||||||
|
// # Only 50 results for similar name should be displayed.
|
||||||
|
await expect(channelsPage.findChannelsModal.searchList).toHaveCount(limitCount);
|
||||||
|
|
||||||
|
for (let i = 0; i < limitCount; i++) {
|
||||||
|
let suffix = i.toString();
|
||||||
|
if (i < 10) {
|
||||||
|
suffix = `0${i}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
await expect(channelsPage.findChannelsModal.container.getByTestId(`${commonName}_${suffix}`)).toBeVisible();
|
||||||
|
}
|
||||||
|
});
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 238 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 84 KiB |
@ -2,7 +2,6 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {expect, test} from '@e2e-support/test_fixture';
|
import {expect, test} from '@e2e-support/test_fixture';
|
||||||
import {isSmallScreen} from '@e2e-support/util';
|
|
||||||
|
|
||||||
test('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => {
|
test('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => {
|
||||||
// Create and sign in a new user
|
// Create and sign in a new user
|
||||||
@ -23,7 +22,7 @@ test('Intro to channel as regular user', async ({pw, pages, browserName, viewpor
|
|||||||
// await wait(duration.one_sec);
|
// await wait(duration.one_sec);
|
||||||
|
|
||||||
// Wait for Playbooks icon to be loaded in App bar, except in iphone
|
// Wait for Playbooks icon to be loaded in App bar, except in iphone
|
||||||
if (!isSmallScreen(viewport)) {
|
if (!pw.isSmallScreen()) {
|
||||||
await expect(channelsPage.appBar.playbooksIcon).toBeVisible();
|
await expect(channelsPage.appBar.playbooksIcon).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 213 KiB |
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 270 KiB After Width: | Height: | Size: 271 KiB |
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 312 KiB |
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 241 KiB |
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 277 KiB |
Before Width: | Height: | Size: 297 KiB After Width: | Height: | Size: 297 KiB |
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 230 KiB |
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 296 KiB |
Before Width: | Height: | Size: 368 KiB After Width: | Height: | Size: 411 KiB |
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 355 KiB |
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 291 KiB |
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 393 KiB |
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 266 KiB |
104
server/Makefile
@ -1,4 +1,4 @@
|
|||||||
.PHONY: build package run stop run-client run-server run-haserver stop-haserver stop-client stop-server restart restart-server restart-client restart-haserver start-docker clean-dist clean nuke check-style check-client-style check-server-style check-unit-tests test dist run-client-tests setup-run-client-tests cleanup-run-client-tests test-client build-linux build-osx build-windows package-prep package-linux package-osx package-windows internal-test-web-client vet run-server-for-web-client-tests diff-config prepackaged-plugins prepackaged-binaries test-server test-server-ee test-server-quick test-server-race new-migration migrations-extract
|
.PHONY: build package run stop run-client run-server run-haserver stop-haserver stop-client stop-server restart restart-server restart-client restart-haserver start-docker update-docker clean-dist clean nuke check-style check-client-style check-server-style check-unit-tests test dist run-client-tests setup-run-client-tests cleanup-run-client-tests test-client build-linux build-osx build-windows package-prep package-linux package-osx package-windows internal-test-web-client vet run-server-for-web-client-tests diff-config prepackaged-plugins prepackaged-binaries test-server test-server-ee test-server-quick test-server-race new-migration migrations-extract
|
||||||
|
|
||||||
ROOT := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
ROOT := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
@ -102,11 +102,11 @@ GOFLAGS ?= $(GOFLAGS:)
|
|||||||
export GOBIN ?= $(PWD)/bin
|
export GOBIN ?= $(PWD)/bin
|
||||||
GO=go
|
GO=go
|
||||||
DELVE=dlv
|
DELVE=dlv
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildNumber=$(BUILD_NUMBER)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/server/v8/model.BuildNumber=$(BUILD_NUMBER)"
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUILD_DATE)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/server/v8/model.BuildDate=$(BUILD_DATE)"
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/server/v8/model.BuildHash=$(BUILD_HASH)"
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/server/v8/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)"
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/server/v8/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)"
|
||||||
|
|
||||||
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
|
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
|
||||||
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
|
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
|
||||||
@ -132,21 +132,22 @@ DIST_PATH_WIN=$(DIST_ROOT)/windows/mattermost
|
|||||||
TESTS=.
|
TESTS=.
|
||||||
|
|
||||||
# Packages lists
|
# Packages lists
|
||||||
TE_PACKAGES=$(shell $(GO) list ./... | grep -vE 'v6/server/playbooks|v6/server/boards')
|
TE_PACKAGES=$(shell $(GO) list ./... | grep -vE 'server/v8/playbooks|server/v8/boards')
|
||||||
BOARDS_PACKAGES=$(shell $(GO) list ./... | grep -E 'v6/server/boards')
|
BOARDS_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/boards')
|
||||||
PLAYBOOKS_PACKAGES=$(shell $(GO) list ./... | grep -E 'v6/server/playbooks')
|
PLAYBOOKS_PACKAGES=$(shell $(GO) list ./... | grep -E 'server/v8/playbooks')
|
||||||
|
SUITE_PACKAGES=$(shell $(GO) list ./...)
|
||||||
|
|
||||||
TEMPLATES_DIR=templates
|
TEMPLATES_DIR=templates
|
||||||
|
|
||||||
# Plugins Packages
|
# Plugins Packages
|
||||||
PLUGIN_PACKAGES ?= mattermost-plugin-antivirus-v0.1.2
|
PLUGIN_PACKAGES ?= mattermost-plugin-antivirus-v0.1.2
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-autolink-v1.2.2
|
PLUGIN_PACKAGES += mattermost-plugin-autolink-v1.4.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-aws-SNS-v1.2.0
|
PLUGIN_PACKAGES += mattermost-plugin-aws-SNS-v1.2.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-calls-v0.15.1
|
PLUGIN_PACKAGES += mattermost-plugin-calls-v0.15.1
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-channel-export-v1.0.0
|
PLUGIN_PACKAGES += mattermost-plugin-channel-export-v1.0.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-confluence-v1.3.0
|
PLUGIN_PACKAGES += mattermost-plugin-confluence-v1.3.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-custom-attributes-v1.3.1
|
PLUGIN_PACKAGES += mattermost-plugin-custom-attributes-v1.3.1
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-github-v2.1.4
|
PLUGIN_PACKAGES += mattermost-plugin-github-v2.1.5
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-gitlab-v1.6.0
|
PLUGIN_PACKAGES += mattermost-plugin-gitlab-v1.6.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-jenkins-v1.1.0
|
PLUGIN_PACKAGES += mattermost-plugin-jenkins-v1.1.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-jira-v3.2.2
|
PLUGIN_PACKAGES += mattermost-plugin-jira-v3.2.2
|
||||||
@ -155,7 +156,7 @@ PLUGIN_PACKAGES += mattermost-plugin-nps-v1.3.1
|
|||||||
PLUGIN_PACKAGES += mattermost-plugin-todo-v0.6.1
|
PLUGIN_PACKAGES += mattermost-plugin-todo-v0.6.1
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-welcomebot-v1.2.0
|
PLUGIN_PACKAGES += mattermost-plugin-welcomebot-v1.2.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-zoom-v1.6.0
|
PLUGIN_PACKAGES += mattermost-plugin-zoom-v1.6.0
|
||||||
PLUGIN_PACKAGES += mattermost-plugin-apps-v1.2.0
|
PLUGIN_PACKAGES += mattermost-plugin-apps-v1.2.1
|
||||||
|
|
||||||
# Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target
|
# Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target
|
||||||
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
||||||
@ -189,7 +190,7 @@ endif
|
|||||||
include config.mk
|
include config.mk
|
||||||
include build/*.mk
|
include build/*.mk
|
||||||
|
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.MockCWS=$(MM_ENABLE_CWS_MOCK)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/server/v8/model.MockCWS=$(MM_ENABLE_CWS_MOCK)"
|
||||||
|
|
||||||
RUN_IN_BACKGROUND ?=
|
RUN_IN_BACKGROUND ?=
|
||||||
ifeq ($(RUN_SERVER_IN_BACKGROUND),true)
|
ifeq ($(RUN_SERVER_IN_BACKGROUND),true)
|
||||||
@ -239,6 +240,11 @@ else
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
update-docker: stop-docker ## Updates the docker containers for local development.
|
||||||
|
@echo Updating docker containers
|
||||||
|
|
||||||
|
$(GO) run ./build/docker-compose-generator/main.go $(ENABLED_DOCKER_SERVICES) | docker-compose -f docker-compose.makefile.yml -f /dev/stdin $(DOCKER_COMPOSE_OVERRIDE) up --no-start
|
||||||
|
|
||||||
run-haserver:
|
run-haserver:
|
||||||
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
||||||
@echo Starting mattermost in an HA topology '(3 node cluster)'
|
@echo Starting mattermost in an HA topology '(3 node cluster)'
|
||||||
@ -270,7 +276,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
plugin-checker:
|
plugin-checker:
|
||||||
$(GO) run $(GOFLAGS) ../plugin/checker
|
$(GO) run $(GOFLAGS) ./plugin/checker
|
||||||
|
|
||||||
prepackaged-plugins: ## Populate the prepackaged-plugins directory
|
prepackaged-plugins: ## Populate the prepackaged-plugins directory
|
||||||
@echo Downloading prepackaged plugins
|
@echo Downloading prepackaged plugins
|
||||||
@ -289,7 +295,7 @@ endif
|
|||||||
|
|
||||||
golangci-lint: ## Run golangci-lint on codebase
|
golangci-lint: ## Run golangci-lint on codebase
|
||||||
@# Keep the version in sync with the command in .circleci/config.yml
|
@# Keep the version in sync with the command in .circleci/config.yml
|
||||||
$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1
|
$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.52.2
|
||||||
|
|
||||||
@echo Running golangci-lint
|
@echo Running golangci-lint
|
||||||
$(GOBIN)/golangci-lint run ./...
|
$(GOBIN)/golangci-lint run ./...
|
||||||
@ -349,9 +355,9 @@ ldap-mocks: ## Creates mock files for ldap.
|
|||||||
|
|
||||||
plugin-mocks: ## Creates mock files for plugins.
|
plugin-mocks: ## Creates mock files for plugins.
|
||||||
$(GO) install github.com/vektra/mockery/v2/...@v2.23.2
|
$(GO) install github.com/vektra/mockery/v2/...@v2.23.2
|
||||||
$(GOBIN)/mockery --dir ../plugin --name API --output ../plugin/plugintest --outpkg plugintest --case underscore --note 'Regenerate this file using `make plugin-mocks`.'
|
$(GOBIN)/mockery --dir ./plugin --name API --output ./plugin/plugintest --outpkg plugintest --case underscore --note 'Regenerate this file using `make plugin-mocks`.'
|
||||||
$(GOBIN)/mockery --dir ../plugin --name Hooks --output ../plugin/plugintest --outpkg plugintest --case underscore --note 'Regenerate this file using `make plugin-mocks`.'
|
$(GOBIN)/mockery --dir ./plugin --name Hooks --output ./plugin/plugintest --outpkg plugintest --case underscore --note 'Regenerate this file using `make plugin-mocks`.'
|
||||||
$(GOBIN)/mockery --dir ../plugin --name Driver --output ../plugin/plugintest --outpkg plugintest --case underscore --note 'Regenerate this file using `make plugin-mocks`.'
|
$(GOBIN)/mockery --dir ./plugin --name Driver --output ./plugin/plugintest --outpkg plugintest --case underscore --note 'Regenerate this file using `make plugin-mocks`.'
|
||||||
|
|
||||||
einterfaces-mocks: ## Creates mock files for einterfaces.
|
einterfaces-mocks: ## Creates mock files for einterfaces.
|
||||||
$(GO) install github.com/vektra/mockery/v2/...@v2.23.2
|
$(GO) install github.com/vektra/mockery/v2/...@v2.23.2
|
||||||
@ -380,7 +386,7 @@ platform-mocks: ## Creates mocks for platform interfaces.
|
|||||||
$(GOBIN)/mockery --dir channels/app/platform --name SuiteIFace --output channels/app/platform/mocks --note 'Regenerate this file using `make platform-mocks`.'
|
$(GOBIN)/mockery --dir channels/app/platform --name SuiteIFace --output channels/app/platform/mocks --note 'Regenerate this file using `make platform-mocks`.'
|
||||||
|
|
||||||
pluginapi: ## Generates api and hooks glue code for plugins
|
pluginapi: ## Generates api and hooks glue code for plugins
|
||||||
$(GO) generate $(GOFLAGS) ../plugin
|
$(GO) generate $(GOFLAGS) ./plugin
|
||||||
|
|
||||||
mocks: store-mocks telemetry-mocks filestore-mocks ldap-mocks plugin-mocks einterfaces-mocks searchengine-mocks sharedchannel-mocks misc-mocks email-mocks platform-mocks
|
mocks: store-mocks telemetry-mocks filestore-mocks ldap-mocks plugin-mocks einterfaces-mocks searchengine-mocks sharedchannel-mocks misc-mocks email-mocks platform-mocks
|
||||||
|
|
||||||
@ -412,7 +418,7 @@ go-junit-report:
|
|||||||
test-compile: ## Compile tests.
|
test-compile: ## Compile tests.
|
||||||
@echo COMPILE TESTS
|
@echo COMPILE TESTS
|
||||||
|
|
||||||
for package in $(TE_PACKAGES) $(BOARDS_PACKAGES) $(PLAYBOOKS_PACKAGES) $(EE_PACKAGES); do \
|
for package in $(SUITE_PACKAGES) $(EE_PACKAGES); do \
|
||||||
$(GO) test $(GOFLAGS) -c $$package; \
|
$(GO) test $(GOFLAGS) -c $$package; \
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -450,9 +456,9 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
test-server-race: test-server-pre
|
test-server-race: test-server-pre
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=true ./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(TE_PACKAGES) $(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic"
|
./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(TE_PACKAGES) $(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic"
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=false ./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(BOARDS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic"
|
./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(BOARDS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic"
|
||||||
MM_DISABLE_PLAYBOOKS=false MM_DISABLE_BOARDS=true ./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(PLAYBOOKS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic"
|
./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(PLAYBOOKS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic"
|
||||||
ifneq ($(IS_CI),true)
|
ifneq ($(IS_CI),true)
|
||||||
ifneq ($(MM_NO_DOCKER),true)
|
ifneq ($(MM_NO_DOCKER),true)
|
||||||
ifneq ($(TEMP_DOCKER_SERVICES),)
|
ifneq ($(TEMP_DOCKER_SERVICES),)
|
||||||
@ -463,9 +469,7 @@ ifneq ($(IS_CI),true)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
test-server: test-server-pre
|
test-server: test-server-pre
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=true ./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(TE_PACKAGES) $(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "45m" "count"
|
./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(SUITE_PACKAGES) $(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "count"
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=false ./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(BOARDS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "45m" "count"
|
|
||||||
MM_DISABLE_PLAYBOOKS=false MM_DISABLE_BOARDS=true ./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(PLAYBOOKS_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "45m" "count"
|
|
||||||
ifneq ($(IS_CI),true)
|
ifneq ($(IS_CI),true)
|
||||||
ifneq ($(MM_NO_DOCKER),true)
|
ifneq ($(MM_NO_DOCKER),true)
|
||||||
ifneq ($(TEMP_DOCKER_SERVICES),)
|
ifneq ($(TEMP_DOCKER_SERVICES),)
|
||||||
@ -477,19 +481,15 @@ endif
|
|||||||
|
|
||||||
test-server-ee: check-prereqs-enterprise start-docker go-junit-report do-cover-file ## Runs EE tests.
|
test-server-ee: check-prereqs-enterprise start-docker go-junit-report do-cover-file ## Runs EE tests.
|
||||||
@echo Running only EE tests
|
@echo Running only EE tests
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=true ./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "20m" "count"
|
./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "20m" "count"
|
||||||
|
|
||||||
test-server-quick: check-prereqs-enterprise ## Runs only quick tests.
|
test-server-quick: check-prereqs-enterprise ## Runs only quick tests.
|
||||||
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
||||||
@echo Running all tests
|
@echo Running all tests
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=true $(GO) test $(GOFLAGS) -short $(TE_PACKAGES) $(EE_PACKAGES)
|
$(GO) test $(GOFLAGS) -short $(SUITE_PACKAGES) $(EE_PACKAGES)
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=false $(GO) test $(GOFLAGS) -short $(BOARDS_PACKAGES)
|
|
||||||
MM_DISABLE_PLAYBOOKS=false MM_DISABLE_BOARDS=true $(GO) test $(GOFLAGS) -short $(PLAYBOOKS_PACKAGES)
|
|
||||||
else
|
else
|
||||||
@echo Running only TE tests
|
@echo Running only TE tests
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=true $(GO) test $(GOFLAGS) -short $(TE_PACKAGES)
|
$(GO) test $(GOFLAGS) -short $(SUITE_PACKAGES)
|
||||||
MM_DISABLE_PLAYBOOKS=true MM_DISABLE_BOARDS=false $(GO) test $(GOFLAGS) -short $(BOARDS_PACKAGES)
|
|
||||||
MM_DISABLE_PLAYBOOKS=false MM_DISABLE_BOARDS=true $(GO) test $(GOFLAGS) -short $(PLAYBOOKS_PACKAGES)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
internal-test-web-client: ## Runs web client tests.
|
internal-test-web-client: ## Runs web client tests.
|
||||||
@ -552,20 +552,20 @@ run-server: setup-go-work prepackaged-binaries validate-go-version start-docker
|
|||||||
debug-server: start-docker ## Compile and start server using delve.
|
debug-server: start-docker ## Compile and start server using delve.
|
||||||
mkdir -p $(BUILD_WEBAPP_DIR)/channels/dist/files
|
mkdir -p $(BUILD_WEBAPP_DIR)/channels/dist/files
|
||||||
$(DELVE) debug $(PLATFORM_FILES) --build-flags="-ldflags '\
|
$(DELVE) debug $(PLATFORM_FILES) --build-flags="-ldflags '\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildNumber=$(BUILD_NUMBER)\
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildNumber=$(BUILD_NUMBER)\
|
||||||
-X \"github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUILD_DATE)\"\
|
-X \"github.com/mattermost/mattermost-server/server/v8/model.BuildDate=$(BUILD_DATE)\"\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)\
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildHash=$(BUILD_HASH)\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)\
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)'"
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)'"
|
||||||
|
|
||||||
debug-server-headless: start-docker ## Debug server from within an IDE like VSCode or IntelliJ.
|
debug-server-headless: start-docker ## Debug server from within an IDE like VSCode or IntelliJ.
|
||||||
mkdir -p $(BUILD_WEBAPP_DIR)/channels/dist/files
|
mkdir -p $(BUILD_WEBAPP_DIR)/channels/dist/files
|
||||||
$(DELVE) debug --headless --listen=:2345 --api-version=2 --accept-multiclient $(PLATFORM_FILES) --build-flags="-ldflags '\
|
$(DELVE) debug --headless --listen=:2345 --api-version=2 --accept-multiclient $(PLATFORM_FILES) --build-flags="-ldflags '\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildNumber=$(BUILD_NUMBER)\
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildNumber=$(BUILD_NUMBER)\
|
||||||
-X \"github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUILD_DATE)\"\
|
-X \"github.com/mattermost/mattermost-server/server/v8/model.BuildDate=$(BUILD_DATE)\"\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)\
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildHash=$(BUILD_HASH)\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)\
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)\
|
||||||
-X github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)'"
|
-X github.com/mattermost/mattermost-server/server/v8/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)'"
|
||||||
|
|
||||||
run-cli: start-docker ## Runs CLI.
|
run-cli: start-docker ## Runs CLI.
|
||||||
@echo Running mattermost for development
|
@echo Running mattermost for development
|
||||||
@ -733,18 +733,18 @@ gen-serialized: ## Generates serialization methods for hot structs
|
|||||||
# would be to temporarily move all the structs to the same file,
|
# would be to temporarily move all the structs to the same file,
|
||||||
# but that involves a lot of manual work.
|
# but that involves a lot of manual work.
|
||||||
$(GO) install github.com/tinylib/msgp@v1.1.6
|
$(GO) install github.com/tinylib/msgp@v1.1.6
|
||||||
$(GOBIN)/msgp -file=../model/session.go -tests=false -o=../model/session_serial_gen.go
|
$(GOBIN)/msgp -file=./model/session.go -tests=false -o=./model/session_serial_gen.go
|
||||||
@echo "$$LICENSE_HEADER" > tmp.go
|
@echo "$$LICENSE_HEADER" > tmp.go
|
||||||
@cat ../model/session_serial_gen.go >> tmp.go
|
@cat ./model/session_serial_gen.go >> tmp.go
|
||||||
@mv tmp.go ../model/session_serial_gen.go
|
@mv tmp.go ./model/session_serial_gen.go
|
||||||
$(GOBIN)/msgp -file=../model/user.go -tests=false -o=../model/user_serial_gen.go
|
$(GOBIN)/msgp -file=./model/user.go -tests=false -o=./model/user_serial_gen.go
|
||||||
@echo "$$LICENSE_HEADER" > tmp.go
|
@echo "$$LICENSE_HEADER" > tmp.go
|
||||||
@cat ../model/user_serial_gen.go >> tmp.go
|
@cat ./model/user_serial_gen.go >> tmp.go
|
||||||
@mv tmp.go ../model/user_serial_gen.go
|
@mv tmp.go ./model/user_serial_gen.go
|
||||||
$(GOBIN)/msgp -file=../model/team_member.go -tests=false -o=../model/team_member_serial_gen.go
|
$(GOBIN)/msgp -file=./model/team_member.go -tests=false -o=./model/team_member_serial_gen.go
|
||||||
@echo "$$LICENSE_HEADER" > tmp.go
|
@echo "$$LICENSE_HEADER" > tmp.go
|
||||||
@cat ../model/team_member_serial_gen.go >> tmp.go
|
@cat ./model/team_member_serial_gen.go >> tmp.go
|
||||||
@mv tmp.go ../model/team_member_serial_gen.go
|
@mv tmp.go ./model/team_member_serial_gen.go
|
||||||
|
|
||||||
todo: ## Display TODO and FIXME items in the source code.
|
todo: ## Display TODO and FIXME items in the source code.
|
||||||
@! ag --ignore Makefile --ignore-dir runtime '(TODO|XXX|FIXME|"FIX ME")[: ]+'
|
@! ag --ignore Makefile --ignore-dir runtime '(TODO|XXX|FIXME|"FIX ME")[: ]+'
|
||||||
|
@ -11,10 +11,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AdminSetPasswordData struct {
|
type AdminSetPasswordData struct {
|
||||||
|
@ -12,12 +12,12 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/app"
|
"github.com/mattermost/mattermost-server/server/v8/boards/app"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/permissions"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/permissions"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -13,8 +13,8 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestErrorResponse(t *testing.T) {
|
func TestErrorResponse(t *testing.T) {
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
mm_model "github.com/mattermost/mattermost-server/server/v8/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -6,8 +6,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// makeAuditRecord creates an audit record pre-populated with data from the request.
|
// makeAuditRecord creates an audit record pre-populated with data from the request.
|
||||||
|
@ -13,12 +13,12 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/auth"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/auth"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/utils"
|
"github.com/mattermost/mattermost-server/server/v8/boards/utils"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerAuthRoutes(r *mux.Router) {
|
func (a *API) registerAuthRoutes(r *mux.Router) {
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerBlocksRoutes(r *mux.Router) {
|
func (a *API) registerBlocksRoutes(r *mux.Router) {
|
||||||
@ -72,7 +72,6 @@ func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
parentID := query.Get("parent_id")
|
parentID := query.Get("parent_id")
|
||||||
blockType := query.Get("type")
|
blockType := query.Get("type")
|
||||||
all := query.Get("all")
|
|
||||||
blockID := query.Get("block_id")
|
blockID := query.Get("block_id")
|
||||||
boardID := mux.Vars(r)["boardID"]
|
boardID := mux.Vars(r)["boardID"]
|
||||||
|
|
||||||
@ -122,18 +121,11 @@ func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
auditRec.AddMeta("boardID", boardID)
|
auditRec.AddMeta("boardID", boardID)
|
||||||
auditRec.AddMeta("parentID", parentID)
|
auditRec.AddMeta("parentID", parentID)
|
||||||
auditRec.AddMeta("blockType", blockType)
|
auditRec.AddMeta("blockType", blockType)
|
||||||
auditRec.AddMeta("all", all)
|
|
||||||
auditRec.AddMeta("blockID", blockID)
|
auditRec.AddMeta("blockID", blockID)
|
||||||
|
|
||||||
var blocks []*model.Block
|
var blocks []*model.Block
|
||||||
var block *model.Block
|
var block *model.Block
|
||||||
switch {
|
switch {
|
||||||
case all != "":
|
|
||||||
blocks, err = a.app.GetBlocksForBoard(boardID)
|
|
||||||
if err != nil {
|
|
||||||
a.errorResponse(w, r, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case blockID != "":
|
case blockID != "":
|
||||||
block, err = a.app.GetBlockByID(blockID)
|
block, err = a.app.GetBlockByID(blockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -148,7 +140,12 @@ func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
default:
|
default:
|
||||||
blocks, err = a.app.GetBlocks(boardID, parentID, blockType)
|
opts := model.QueryBlocksOptions{
|
||||||
|
BoardID: boardID,
|
||||||
|
ParentID: parentID,
|
||||||
|
BlockType: model.BlockType(blockType),
|
||||||
|
}
|
||||||
|
blocks, err = a.app.GetBlocks(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.errorResponse(w, r, err)
|
a.errorResponse(w, r, err)
|
||||||
return
|
return
|
||||||
@ -307,7 +304,7 @@ func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
// this query param exists when creating template from board, or board from template
|
// this query param exists when creating template from board, or board from template
|
||||||
sourceBoardID := r.URL.Query().Get("sourceBoardID")
|
sourceBoardID := r.URL.Query().Get("sourceBoardID")
|
||||||
if sourceBoardID != "" {
|
if sourceBoardID != "" {
|
||||||
if updateFileIDsErr := a.app.CopyCardFiles(sourceBoardID, blocks); updateFileIDsErr != nil {
|
if updateFileIDsErr := a.app.CopyAndUpdateCardFiles(sourceBoardID, userID, blocks, false); updateFileIDsErr != nil {
|
||||||
a.errorResponse(w, r, updateFileIDsErr)
|
a.errorResponse(w, r, updateFileIDsErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerBoardsRoutes(r *mux.Router) {
|
func (a *API) registerBoardsRoutes(r *mux.Router) {
|
||||||
|
@ -11,10 +11,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerBoardsAndBlocksRoutes(r *mux.Router) {
|
func (a *API) registerBoardsAndBlocksRoutes(r *mux.Router) {
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerCategoriesRoutes(r *mux.Router) {
|
func (a *API) registerCategoriesRoutes(r *mux.Router) {
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
mm_model "github.com/mattermost/mattermost-server/server/v8/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerChannelsRoutes(r *mux.Router) {
|
func (a *API) registerChannelsRoutes(r *mux.Router) {
|
||||||
|
@ -11,10 +11,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
|
|
||||||
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
mm_model "github.com/mattermost/mattermost-server/server/v8/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerContentBlocksRoutes(r *mux.Router) {
|
func (a *API) registerContentBlocksRoutes(r *mux.Router) {
|
||||||
|
@ -11,17 +11,17 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/app"
|
"github.com/mattermost/mattermost-server/server/v8/boards/app"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
|
|
||||||
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
mm_model "github.com/mattermost/mattermost-server/server/v8/model"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/platform/shared/web"
|
"github.com/mattermost/mattermost-server/server/v8/platform/shared/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileUploadResponse is the response to a file upload
|
// FileUploadResponse is the response to a file upload
|
||||||
@ -312,7 +312,7 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
auditRec.AddMeta("teamID", board.TeamID)
|
auditRec.AddMeta("teamID", board.TeamID)
|
||||||
auditRec.AddMeta("filename", handle.Filename)
|
auditRec.AddMeta("filename", handle.Filename)
|
||||||
|
|
||||||
fileID, err := a.app.SaveFile(file, board.TeamID, boardID, handle.Filename)
|
fileID, err := a.app.SaveFile(file, board.TeamID, boardID, handle.Filename, board.IsTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.errorResponse(w, r, err)
|
a.errorResponse(w, r, err)
|
||||||
return
|
return
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/model"
|
"github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/server/boards/services/audit"
|
"github.com/mattermost/mattermost-server/server/v8/boards/services/audit"
|
||||||
|
|
||||||
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
mm_model "github.com/mattermost/mattermost-server/server/v8/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *API) registerInsightsRoutes(r *mux.Router) {
|
func (a *API) registerInsightsRoutes(r *mux.Router) {
|
||||||
|