diff --git a/.ci/Dockerfile.cypress b/.ci/Dockerfile.cypress
index e595fcc1ba..02df86f62e 100644
--- a/.ci/Dockerfile.cypress
+++ b/.ci/Dockerfile.cypress
@@ -5,7 +5,8 @@ WORKDIR $APP
COPY package.json yarn.lock .yarnrc $APP/
COPY viz-lib $APP/viz-lib
-RUN npm install yarn@1.22.22 -g && yarn --frozen-lockfile --network-concurrency 1 > /dev/null
+RUN --mount=type=secret,id=npmrc,target=/root/.npmrc,mode=0644 \
+ npm install yarn@1.22.22 -g && yarn --frozen-lockfile --network-concurrency 1 > /dev/null
COPY . $APP
diff --git a/.ci/compose.cypress.yaml b/.ci/compose.cypress.yaml
index 7f769ab3ef..ea65a8cdf5 100644
--- a/.ci/compose.cypress.yaml
+++ b/.ci/compose.cypress.yaml
@@ -4,11 +4,14 @@ x-redash-service: &redash-service
args:
install_groups: "main"
code_coverage: ${CODE_COVERAGE}
+ secrets:
+ - npmrc
x-redash-environment: &redash-environment
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
POSTGRES_PASSWORD: "FmTKs5vX52ufKR1rd8tn4MoSP7zvCJwb"
REDASH_DATABASE_URL: "postgresql://postgres:FmTKs5vX52ufKR1rd8tn4MoSP7zvCJwb@postgres/postgres"
+ ASSETDB_DATABASE_URI: "postgresql://postgres:FmTKs5vX52ufKR1rd8tn4MoSP7zvCJwb@postgres/postgres"
REDASH_RATELIMIT_ENABLED: "false"
REDASH_ENFORCE_CSRF: "true"
REDASH_COOKIE_SECRET: "2H9gNG9obnAQ9qnR9BDTQUph6CbXKCzF"
@@ -44,6 +47,8 @@ services:
build:
context: ../
dockerfile: .ci/Dockerfile.cypress
+ secrets:
+ - npmrc
depends_on:
- server
- worker
@@ -71,3 +76,6 @@ services:
restart: unless-stopped
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
+secrets:
+ npmrc:
+ file: ${HOME}/.npmrc
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f755ff333d..6931f70f7a 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1 +1 @@
-* @stacklet/platform
+* @stacklet/engineering
diff --git a/.github/composites/install/action.yml b/.github/composites/install/action.yml
new file mode 100644
index 0000000000..e741c997b5
--- /dev/null
+++ b/.github/composites/install/action.yml
@@ -0,0 +1,48 @@
+name: Install Dependencies
+description: AWS Auth and Install Dependencies
+inputs:
+ aws-role:
+ description: AWS Credential Access Role
+ required: false
+ aws-region:
+ description: AWS Region
+ default: us-east-1
+ install-yarn-deps:
+ description: Whether to install yarn dependencies
+ default: 'true'
+
+runs:
+ using: composite
+ steps:
+ - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1
+ with:
+ postfix: _TOOL_VERSION
+
+ - uses: extractions/setup-crate@4993624604c307fbca528d28a3c8b60fa5ecc859 # v1.4.0
+ with:
+ repo: casey/just
+ version: ${{ env.JUST_TOOL_VERSION }}
+
+ - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
+ if: inputs.install-yarn-deps == 'true'
+ with:
+ node-version: ${{ env.NODEJS_TOOL_VERSION }}
+ cache: 'yarn'
+
+ - uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
+ if: inputs.install-yarn-deps == 'true'
+ with:
+ role-to-assume: ${{ inputs.aws-role }}
+ aws-region: ${{ inputs.aws-region }}
+
+ - name: Login to AWS CodeArtifact
+ if: inputs.install-yarn-deps == 'true'
+ shell: bash
+ run: just pkg-login
+
+ - name: Install Dependencies
+ if: inputs.install-yarn-deps == 'true'
+ shell: bash
+ run: |
+ npm install --verbose --global --force yarn@${{ env.YARN_TOOL_VERSION }}
+ yarn cache clean && yarn --frozen-lockfile --network-concurrency 1
diff --git a/.github/weekly-digest.yml b/.github/weekly-digest.yml
deleted file mode 100644
index 08cced6393..0000000000
--- a/.github/weekly-digest.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-# Configuration for weekly-digest - https://github.com/apps/weekly-digest
-publishDay: mon
-canPublishIssues: true
-canPublishPullRequests: true
-canPublishContributors: true
-canPublishStargazers: true
-canPublishCommits: true
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1cee14f8ab..d8ff3f8746 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,176 +2,106 @@ name: Tests
on:
push:
branches:
- - master
+ - stacklet/integration
pull_request:
branches:
- - master
-env:
- NODE_VERSION: 18
- YARN_VERSION: 1.22.22
+ - stacklet/integration
+permissions:
+ contents: read
jobs:
backend-lint:
runs-on: ubuntu-22.04
+ permissions:
+ contents: read
steps:
- - if: github.event.pull_request.mergeable == 'false'
- name: Exit if PR is not mergeable
- run: exit 1
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
- fetch-depth: 1
- ref: ${{ github.event.pull_request.head.sha }}
- - uses: actions/setup-python@v5
+ persist-credentials: false
+ - name: Install Dependencies
+ uses: ./.github/composites/install
+ with:
+ install-yarn-deps: 'false'
+ - name: Install and configure Poetry
+ uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a # v1.4.1
+ with:
+ version: ${{ env.POETRY_TOOL_VERSION }}
+ virtualenvs-in-project: true
+ - name: Set up Python ${{ env.PYTHON_TOOL_VERSION }}
+ uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
- python-version: '3.8'
- - run: sudo pip install black==23.1.0 ruff==0.0.287
- - run: ruff check .
- - run: black --check .
+ python-version: ${{ env.PYTHON_TOOL_VERSION }}
+ cache: poetry
+ - name: Cache Poetry dependencies
+ id: cache
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
+ with:
+ path: .venv
+ key: setup-python-${{ runner.os }}-python-${{ env.PYTHON_TOOL_VERSION }}-poetry-v2-${{ hashFiles('**/poetry.lock') }}
+ - run: just backend-install
+ - run: just backend-lint
backend-unit-tests:
runs-on: ubuntu-22.04
needs: backend-lint
- env:
- COMPOSE_FILE: .ci/compose.ci.yaml
- COMPOSE_PROJECT_NAME: redash
- COMPOSE_DOCKER_CLI_BUILD: 1
- DOCKER_BUILDKIT: 1
+ permissions:
+ contents: read
steps:
- - if: github.event.pull_request.mergeable == 'false'
- name: Exit if PR is not mergeable
- run: exit 1
- - uses: actions/checkout@v4
- with:
- fetch-depth: 1
- ref: ${{ github.event.pull_request.head.sha }}
- - name: Build Docker Images
- run: |
- set -x
- docker compose build --build-arg install_groups="main,all_ds,dev" --build-arg skip_frontend_build=true
- docker compose up -d
- sleep 10
- - name: Create Test Database
- run: docker compose -p redash run --rm postgres psql -h postgres -U postgres -c "create database tests;"
- - name: List Enabled Query Runners
- run: docker compose -p redash run --rm redash manage ds list_types
- - name: Run Tests
- run: docker compose -p redash run --name tests redash tests --junitxml=junit.xml --cov-report=xml --cov=redash --cov-config=.coveragerc tests/
- - name: Copy Test Results
- run: |
- mkdir -p /tmp/test-results/unit-tests
- docker cp tests:/app/coverage.xml ./coverage.xml
- docker cp tests:/app/junit.xml /tmp/test-results/unit-tests/results.xml
- # - name: Upload coverage reports to Codecov
- # uses: codecov/codecov-action@v3
- # with:
- # token: ${{ secrets.CODECOV_TOKEN }}
- - name: Store Test Results
- uses: actions/upload-artifact@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
- name: backend-test-results
- path: /tmp/test-results
- - name: Store Coverage Results
- uses: actions/upload-artifact@v4
+ persist-credentials: false
+ - name: Install Dependencies
+ uses: ./.github/composites/install
with:
- name: coverage
- path: coverage.xml
+ install-yarn-deps: 'false'
+ - name: Run Backend Tests
+ run: just backend-test
frontend-lint:
runs-on: ubuntu-22.04
+ permissions:
+ id-token: write
+ contents: read
steps:
- - if: github.event.pull_request.mergeable == 'false'
- name: Exit if PR is not mergeable
- run: exit 1
- - uses: actions/checkout@v4
- with:
- fetch-depth: 1
- ref: ${{ github.event.pull_request.head.sha }}
- - uses: actions/setup-node@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
- node-version: ${{ env.NODE_VERSION }}
- cache: 'yarn'
+ persist-credentials: false
- name: Install Dependencies
- run: |
- npm install --global --force yarn@$YARN_VERSION
- yarn cache clean && yarn --frozen-lockfile --network-concurrency 1
- - name: Run Lint
- run: yarn lint:ci
- - name: Store Test Results
- uses: actions/upload-artifact@v4
+ uses: ./.github/composites/install
with:
- name: frontend-test-results
- path: /tmp/test-results
+ aws-role: arn:aws:iam::653993915282:role/ci-github-actions
+ - name: Run Frontend Lint
+ run: just frontend-lint
frontend-unit-tests:
runs-on: ubuntu-22.04
needs: frontend-lint
+ permissions:
+ id-token: write
+ contents: read
steps:
- - if: github.event.pull_request.mergeable == 'false'
- name: Exit if PR is not mergeable
- run: exit 1
- - uses: actions/checkout@v4
- with:
- fetch-depth: 1
- ref: ${{ github.event.pull_request.head.sha }}
- - uses: actions/setup-node@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
- node-version: ${{ env.NODE_VERSION }}
- cache: 'yarn'
+ persist-credentials: false
- name: Install Dependencies
- run: |
- npm install --global --force yarn@$YARN_VERSION
- yarn cache clean && yarn --frozen-lockfile --network-concurrency 1
- - name: Run App Tests
- run: yarn test
- - name: Run Visualizations Tests
- run: cd viz-lib && yarn test
- - run: yarn lint
+ uses: ./.github/composites/install
+ with:
+ aws-role: arn:aws:iam::653993915282:role/ci-github-actions
+ - name: Run Frontend Tests
+ run: just frontend-test
frontend-e2e-tests:
runs-on: ubuntu-22.04
needs: frontend-lint
- env:
- COMPOSE_FILE: .ci/compose.cypress.yaml
- COMPOSE_PROJECT_NAME: cypress
- CYPRESS_INSTALL_BINARY: 0
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1
- # PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
- # CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
- # CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+ permissions:
+ id-token: write
+ contents: read
steps:
- - if: github.event.pull_request.mergeable == 'false'
- name: Exit if PR is not mergeable
- run: exit 1
- - uses: actions/checkout@v4
- with:
- fetch-depth: 1
- ref: ${{ github.event.pull_request.head.sha }}
- - uses: actions/setup-node@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
- node-version: ${{ env.NODE_VERSION }}
- cache: 'yarn'
- - name: Enable Code Coverage Report For Master Branch
- if: endsWith(github.ref, '/master')
- run: |
- echo "CODE_COVERAGE=true" >> "$GITHUB_ENV"
+ persist-credentials: false
- name: Install Dependencies
- run: |
- npm install --global --force yarn@$YARN_VERSION
- yarn cache clean && yarn --frozen-lockfile --network-concurrency 1
- - name: Setup Redash Server
- run: |
- set -x
- yarn cypress build
- yarn cypress start -- --skip-db-seed
- docker compose run cypress yarn cypress db-seed
- - name: Execute Cypress Tests
- run: yarn cypress run-ci
- - name: "Failure: output container logs to console"
- if: failure()
- run: docker compose logs
- - name: Copy Code Coverage Results
- run: docker cp cypress:/usr/src/app/coverage ./coverage || true
- - name: Store Coverage Results
- uses: actions/upload-artifact@v4
+ uses: ./.github/composites/install
with:
- name: coverage
- path: coverage
+ aws-role: arn:aws:iam::653993915282:role/ci-github-actions
+ - name: Run Frontend E2E Tests
+ run: just frontend-e2e-test
diff --git a/.github/workflows/periodic-snapshot.yml b/.github/workflows/periodic-snapshot.yml
deleted file mode 100644
index cc9f82b855..0000000000
--- a/.github/workflows/periodic-snapshot.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: Periodic Snapshot
-
-on:
- schedule:
- - cron: '10 0 1 * *' # 10 minutes after midnight on the first day of every month
- workflow_dispatch:
- inputs:
- bump:
- description: 'Bump the last digit of the version'
- required: false
- type: boolean
- version:
- description: 'Specific version to set'
- required: false
- default: ''
-
-env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
-permissions:
- actions: write
- contents: write
-
-jobs:
- bump-version-and-tag:
- runs-on: ubuntu-latest
- if: github.ref_name == github.event.repository.default_branch
- steps:
- - uses: actions/checkout@v4
- with:
- ssh-key: ${{ secrets.ACTION_PUSH_KEY }}
-
- - run: |
- git config user.name 'github-actions[bot]'
- git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
-
- # Function to bump the version
- bump_version() {
- local version="$1"
- local IFS=.
- read -r major minor patch <<< "$version"
- patch=$((patch + 1))
- echo "$major.$minor.$patch-dev"
- }
-
- # Determine the new version tag
- if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
- BUMP_INPUT="${{ github.event.inputs.bump }}"
- SPECIFIC_VERSION="${{ github.event.inputs.version }}"
-
- # Check if both bump and specific version are provided
- if [ "$BUMP_INPUT" = "true" ] && [ -n "$SPECIFIC_VERSION" ]; then
- echo "::error::Error: Cannot specify both bump and specific version."
- exit 1
- fi
-
- if [ -n "$SPECIFIC_VERSION" ]; then
- TAG_NAME="$SPECIFIC_VERSION-dev"
- elif [ "$BUMP_INPUT" = "true" ]; then
- CURRENT_VERSION=$(grep '"version":' package.json | awk -F\" '{print $4}')
- TAG_NAME=$(bump_version "$CURRENT_VERSION")
- else
- echo "No version bump or specific version provided for manual dispatch."
- exit 1
- fi
- else
- TAG_NAME="$(date +%y.%m).0-dev"
- fi
-
- echo "New version tag: $TAG_NAME"
-
- # Update version in files
- gawk -i inplace -F: -v q=\" -v tag=${TAG_NAME} '/^ "version": / { print $1 FS, q tag q ","; next} { print }' package.json
- gawk -i inplace -F= -v q=\" -v tag=${TAG_NAME} '/^__version__ =/ { print $1 FS, q tag q; next} { print }' redash/__init__.py
- gawk -i inplace -F= -v q=\" -v tag=${TAG_NAME} '/^version =/ { print $1 FS, q tag q; next} { print }' pyproject.toml
-
- git add package.json redash/__init__.py pyproject.toml
- git commit -m "Snapshot: ${TAG_NAME}"
- git tag ${TAG_NAME}
- git push --atomic origin master refs/tags/${TAG_NAME}
-
- # Run the 'preview-image' workflow if run this workflow manually
- # For more information, please see the: https://docs.github.com/en/actions/security-guides/automatic-token-authentication
- if [ "$BUMP_INPUT" = "true" ] || [ -n "$SPECIFIC_VERSION" ]; then
- gh workflow run preview-image.yml --ref $TAG_NAME
- fi
diff --git a/.github/workflows/preview-image.yml b/.github/workflows/preview-image.yml
deleted file mode 100644
index 029cec854c..0000000000
--- a/.github/workflows/preview-image.yml
+++ /dev/null
@@ -1,185 +0,0 @@
-name: Preview Image
-on:
- push:
- tags:
- - '*-dev'
- workflow_dispatch:
- inputs:
- dockerRepository:
- description: 'Docker repository'
- required: true
- default: 'preview'
- type: choice
- options:
- - preview
- - redash
-
-env:
- NODE_VERSION: 18
-
-jobs:
- build-skip-check:
- runs-on: ubuntu-22.04
- outputs:
- skip: ${{ steps.skip-check.outputs.skip }}
- steps:
- - name: Skip?
- id: skip-check
- run: |
- if [[ "${{ vars.DOCKER_USER }}" == '' ]]; then
- echo 'Docker user is empty. Skipping build+push'
- echo skip=true >> "$GITHUB_OUTPUT"
- elif [[ "${{ secrets.DOCKER_PASS }}" == '' ]]; then
- echo 'Docker password is empty. Skipping build+push'
- echo skip=true >> "$GITHUB_OUTPUT"
- elif [[ "${{ vars.DOCKER_REPOSITORY }}" == '' ]]; then
- echo 'Docker repository is empty. Skipping build+push'
- echo skip=true >> "$GITHUB_OUTPUT"
- else
- echo 'Docker user and password are set and branch is `master`.'
- echo 'Building + pushing `preview` image.'
- echo skip=false >> "$GITHUB_OUTPUT"
- fi
-
- build-docker-image:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- arch:
- - amd64
- - arm64
- include:
- - arch: amd64
- os: ubuntu-22.04
- - arch: arm64
- os: ubuntu-22.04-arm
- outputs:
- VERSION_TAG: ${{ steps.version.outputs.VERSION_TAG }}
- needs:
- - build-skip-check
- if: needs.build-skip-check.outputs.skip == 'false'
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 1
- ref: ${{ github.event.push.after }}
-
- - uses: actions/setup-node@v4
- with:
- node-version: ${{ env.NODE_VERSION }}
- cache: 'yarn'
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Login to DockerHub
- uses: docker/login-action@v3
- with:
- username: ${{ vars.DOCKER_USER }}
- password: ${{ secrets.DOCKER_PASS }}
-
- - name: Install Dependencies
- env:
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- run: |
- npm install --global --force yarn@1.22.22
- yarn cache clean && yarn --frozen-lockfile --network-concurrency 1
-
- - name: Set version
- id: version
- run: |
- set -x
- .ci/update_version
- VERSION_TAG=$(jq -r .version package.json)
- echo "VERSION_TAG=$VERSION_TAG" >> "$GITHUB_OUTPUT"
-
- - name: Build and push preview image to Docker Hub
- id: build-preview
- uses: docker/build-push-action@v4
- if: ${{ github.event.inputs.dockerRepository == 'preview' || !github.event.workflow_run }}
- with:
- tags: |
- ${{ vars.DOCKER_REPOSITORY }}/redash
- ${{ vars.DOCKER_REPOSITORY }}/preview
- context: .
- build-args: |
- test_all_deps=true
- outputs: type=image,push-by-digest=true,push=true
- cache-from: type=gha,scope=${{ matrix.arch }}
- cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
- env:
- DOCKER_CONTENT_TRUST: true
-
- - name: Build and push release image to Docker Hub
- id: build-release
- uses: docker/build-push-action@v4
- if: ${{ github.event.inputs.dockerRepository == 'redash' }}
- with:
- tags: |
- ${{ vars.DOCKER_REPOSITORY }}/redash:${{ steps.version.outputs.VERSION_TAG }}
- context: .
- build-args: |
- test_all_deps=true
- outputs: type=image,push-by-digest=true,push=true
- cache-from: type=gha,scope=${{ matrix.arch }}
- cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
- env:
- DOCKER_CONTENT_TRUST: true
-
- - name: "Failure: output container logs to console"
- if: failure()
- run: docker compose logs
-
- - name: Export digest
- run: |
- mkdir -p ${{ runner.temp }}/digests
- if [[ "${{ github.event.inputs.dockerRepository }}" == 'preview' || !github.event.workflow_run ]]; then
- digest="${{ steps.build-preview.outputs.digest}}"
- else
- digest="${{ steps.build-release.outputs.digest}}"
- fi
- touch "${{ runner.temp }}/digests/${digest#sha256:}"
-
- - name: Upload digest
- uses: actions/upload-artifact@v4
- with:
- name: digests-${{ matrix.arch }}
- path: ${{ runner.temp }}/digests/*
- if-no-files-found: error
-
- merge-docker-image:
- runs-on: ubuntu-22.04
- needs: build-docker-image
- steps:
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Login to DockerHub
- uses: docker/login-action@v3
- with:
- username: ${{ vars.DOCKER_USER }}
- password: ${{ secrets.DOCKER_PASS }}
-
- - name: Download digests
- uses: actions/download-artifact@v4
- with:
- path: ${{ runner.temp }}/digests
- pattern: digests-*
- merge-multiple: true
-
- - name: Create and push manifest for the preview image
- if: ${{ github.event.inputs.dockerRepository == 'preview' || !github.event.workflow_run }}
- working-directory: ${{ runner.temp }}/digests
- run: |
- docker buildx imagetools create -t ${{ vars.DOCKER_REPOSITORY }}/redash:preview \
- $(printf '${{ vars.DOCKER_REPOSITORY }}/redash:preview@sha256:%s ' *)
- docker buildx imagetools create -t ${{ vars.DOCKER_REPOSITORY }}/preview:${{ needs.build-docker-image.outputs.VERSION_TAG }} \
- $(printf '${{ vars.DOCKER_REPOSITORY }}/preview:${{ needs.build-docker-image.outputs.VERSION_TAG }}@sha256:%s ' *)
-
- - name: Create and push manifest for the release image
- if: ${{ github.event.inputs.dockerRepository == 'redash' }}
- working-directory: ${{ runner.temp }}/digests
- run: |
- docker buildx imagetools create -t ${{ vars.DOCKER_REPOSITORY }}/redash:${{ needs.build-docker-image.outputs.VERSION_TAG }} \
- $(printf '${{ vars.DOCKER_REPOSITORY }}/redash:${{ needs.build-docker-image.outputs.VERSION_TAG }}@sha256:%s ' *)
diff --git a/.github/workflows/restyled.yml b/.github/workflows/restyled.yml
deleted file mode 100644
index 3482740947..0000000000
--- a/.github/workflows/restyled.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Restyled
-
-on:
- pull_request:
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-jobs:
- restyled:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
-
- - uses: restyled-io/actions/setup@v4
- - id: restyler
- uses: restyled-io/actions/run@v4
- with:
- fail-on-differences: true
-
- - if: |
- !cancelled() &&
- steps.restyler.outputs.success == 'true' &&
- github.event.pull_request.head.repo.full_name == github.repository
- uses: peter-evans/create-pull-request@v6
- with:
- base: ${{ steps.restyler.outputs.restyled-base }}
- branch: ${{ steps.restyler.outputs.restyled-head }}
- title: ${{ steps.restyler.outputs.restyled-title }}
- body: ${{ steps.restyler.outputs.restyled-body }}
- labels: "restyled"
- reviewers: ${{ github.event.pull_request.user.login }}
- delete-branch: true
diff --git a/.tool-versions b/.tool-versions
index f89d0d48ee..06a4464618 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,2 +1,5 @@
-yarn 1.22.19
-just 1.36.0
+nodejs 18.20.5
+yarn 1.22.22
+just 1.40.0
+poetry 1.8.3
+python 3.10.11
diff --git a/Dockerfile b/Dockerfile
index 850638edd8..49e09b4383 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -23,7 +23,8 @@ ENV BABEL_ENV=${code_coverage:+test}
# Avoid issues caused by lags in disk and network I/O speeds when working on top of QEMU emulation for multi-platform image building.
RUN yarn config set network-timeout 300000
-RUN if [ "x$skip_frontend_build" = "x" ] ; then yarn --frozen-lockfile --network-concurrency 1; fi
+RUN --mount=type=secret,id=npmrc,target=/frontend/.npmrc,mode=0644 \
+ if [ "x$skip_frontend_build" = "x" ] ; then yarn --frozen-lockfile --network-concurrency 1; fi
COPY --chown=redash client /frontend/client
COPY --chown=redash webpack.config.js /frontend/
diff --git a/client/app/components/BeaconConsent.jsx b/client/app/components/BeaconConsent.jsx
index 4da6337de9..fea8d4cce1 100644
--- a/client/app/components/BeaconConsent.jsx
+++ b/client/app/components/BeaconConsent.jsx
@@ -22,7 +22,7 @@ function BeaconConsent() {
setHide(true);
};
- const confirmConsent = (confirm) => {
+ const confirmConsent = confirm => {
let message = "🙏 Thank you.";
if (!confirm) {
@@ -47,8 +47,7 @@ function BeaconConsent() {
>
}
- bordered={false}
- >
+ bordered={false}>
Help Redash improve by automatically sending anonymous usage data:
diff --git a/client/app/components/EditParameterSettingsDialog.jsx b/client/app/components/EditParameterSettingsDialog.jsx
index f182bb9d1e..d620883549 100644
--- a/client/app/components/EditParameterSettingsDialog.jsx
+++ b/client/app/components/EditParameterSettingsDialog.jsx
@@ -27,7 +27,7 @@ function isTypeDateRange(type) {
function joinExampleList(multiValuesOptions) {
const { prefix, suffix } = multiValuesOptions;
- return ["value1", "value2", "value3"].map((value) => `${prefix}${value}${suffix}`).join(",");
+ return ["value1", "value2", "value3"].map(value => `${prefix}${value}${suffix}`).join(",");
}
function NameInput({ name, type, onChange, existingNames, setValidation }) {
@@ -55,7 +55,7 @@ function NameInput({ name, type, onChange, existingNames, setValidation }) {
return (
- onChange(e.target.value)} autoFocus />
+ onChange(e.target.value)} autoFocus />
);
}
@@ -117,7 +117,7 @@ function EditParameterSettingsDialog(props) {
const paramFormId = useUniqueId("paramForm");
- const handleRegexChange = (e) => {
+ const handleRegexChange = e => {
setUserInput(e.target.value);
try {
new RegExp(e.target.value);
@@ -143,17 +143,15 @@ function EditParameterSettingsDialog(props) {
disabled={!isFulfilled()}
type="primary"
form={paramFormId}
- data-test="SaveParameterSettings"
- >
+ data-test="SaveParameterSettings">
{isNew ? "Add Parameter" : "OK"}
,
- ]}
- >
+ ]}>
}
@@ -1938,7 +1938,7 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "1 Day 22:15" Set
data-testid="utc"
>
(
- 22:15
+ 20:15
UTC)
@@ -4251,7 +4251,7 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "2 Weeks 22:15 Tu
data-testid="time"
>
}
transitionName="slide-up"
- value={"1999-12-31T22:15:00.000Z"}
+ value={"2000-01-01T20:15:00.000Z"}
>
}
transitionName="slide-up"
- value={"1999-12-31T22:15:00.000Z"}
+ value={"2000-01-01T20:15:00.000Z"}
>
}
@@ -4891,7 +4891,7 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "2 Weeks 22:15 Tu
}
tabIndex={-1}
transitionName="slide-up"
- value={"1999-12-31T22:15:00.000Z"}
+ value={"2000-01-01T20:15:00.000Z"}
/>
}
@@ -5032,7 +5032,7 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "2 Weeks 22:15 Tu
data-testid="utc"
>
(
- 22:15
+ 20:15
UTC)
diff --git a/client/app/pages/alert/Alert.jsx b/client/app/pages/alert/Alert.jsx
index 877646b611..303d159b5f 100644
--- a/client/app/pages/alert/Alert.jsx
+++ b/client/app/pages/alert/Alert.jsx
@@ -77,7 +77,7 @@ class Alert extends React.Component {
} else {
const { alertId } = this.props;
AlertService.get({ id: alertId })
- .then((alert) => {
+ .then(alert => {
if (this._isMounted) {
const canEdit = currentUser.canEdit(alert);
@@ -95,7 +95,7 @@ class Alert extends React.Component {
this.onQuerySelected(alert.query);
}
})
- .catch((error) => {
+ .catch(error => {
if (this._isMounted) {
this.props.onError(error);
}
@@ -114,7 +114,7 @@ class Alert extends React.Component {
alert.rearm = pendingRearm || null;
return AlertService.save(alert)
- .then((alert) => {
+ .then(alert => {
notification.success("Saved.");
navigateTo(`alerts/${alert.id}`, true);
this.setState({ alert, mode: MODES.VIEW });
@@ -124,7 +124,7 @@ class Alert extends React.Component {
});
};
- onQuerySelected = (query) => {
+ onQuerySelected = query => {
this.setState(({ alert }) => ({
alert: Object.assign(alert, { query }),
queryResult: null,
@@ -132,7 +132,7 @@ class Alert extends React.Component {
if (query) {
// get cached result for column names and values
- new QueryService(query).getQueryResultPromise().then((queryResult) => {
+ new QueryService(query).getQueryResultPromise().then(queryResult => {
if (this._isMounted) {
this.setState({ queryResult });
let { column } = this.state.alert.options;
@@ -148,18 +148,18 @@ class Alert extends React.Component {
}
};
- onNameChange = (name) => {
+ onNameChange = name => {
const { alert } = this.state;
this.setState({
alert: Object.assign(alert, { name }),
});
};
- onRearmChange = (pendingRearm) => {
+ onRearmChange = pendingRearm => {
this.setState({ pendingRearm });
};
- setAlertOptions = (obj) => {
+ setAlertOptions = obj => {
const { alert } = this.state;
const options = { ...alert.options, ...obj };
this.setState({
@@ -278,7 +278,7 @@ routes.register(
routeWithUserSession({
path: "/alerts/new",
title: "New Alert",
- render: (pageProps) => ,
+ render: pageProps => ,
})
);
routes.register(
@@ -286,7 +286,7 @@ routes.register(
routeWithUserSession({
path: "/alerts/:alertId",
title: "Alert",
- render: (pageProps) => ,
+ render: pageProps => ,
})
);
routes.register(
@@ -294,6 +294,6 @@ routes.register(
routeWithUserSession({
path: "/alerts/:alertId/edit",
title: "Alert",
- render: (pageProps) => ,
+ render: pageProps => ,
})
);
diff --git a/client/app/pages/alert/components/Criteria.jsx b/client/app/pages/alert/components/Criteria.jsx
index 73230a6457..fd0afdfea3 100644
--- a/client/app/pages/alert/components/Criteria.jsx
+++ b/client/app/pages/alert/components/Criteria.jsx
@@ -68,7 +68,7 @@ export default function Criteria({ columnNames, resultValues, alertOptions, onCh
Max column value is{" "}
{toString(
- Math.max(...resultValues.map((o) => Number(o[alertOptions.column])).filter((value) => !isNaN(value)))
+ Math.max(...resultValues.map(o => Number(o[alertOptions.column])).filter(value => !isNaN(value)))
) || "unknown"}
@@ -79,7 +79,7 @@ export default function Criteria({ columnNames, resultValues, alertOptions, onCh
Min column value is{" "}
{toString(
- Math.min(...resultValues.map((o) => Number(o[alertOptions.column])).filter((value) => !isNaN(value)))
+ Math.min(...resultValues.map(o => Number(o[alertOptions.column])).filter(value => !isNaN(value)))
) || "unknown"}
@@ -93,11 +93,10 @@ export default function Criteria({ columnNames, resultValues, alertOptions, onCh
{editMode ? (