snapshot of https://github.com/frappe/crm.git (develop, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
This commit is contained in:
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
43
.github/actions/frontend-tests/action.yml
vendored
Normal file
43
.github/actions/frontend-tests/action.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Run Frontend Tests
|
||||
description: Install frontend dependencies and run Vitest with coverage.
|
||||
inputs:
|
||||
node-version:
|
||||
description: Node.js version to use
|
||||
required: false
|
||||
default: "24"
|
||||
enable-coverage:
|
||||
description: When true, run with coverage collection
|
||||
required: false
|
||||
default: "true"
|
||||
working-directory:
|
||||
description: Path to the frontend directory
|
||||
required: false
|
||||
default: "frontend"
|
||||
outputs:
|
||||
coverage-path:
|
||||
description: Path to the generated lcov coverage file
|
||||
value: ${{ steps.set-output.outputs.coverage-path }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run tests (with coverage)
|
||||
if: inputs.enable-coverage == 'true'
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: yarn test:coverage
|
||||
|
||||
- name: Run tests (without coverage)
|
||||
if: inputs.enable-coverage != 'true'
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: yarn test:run
|
||||
|
||||
- name: Set coverage output path
|
||||
id: set-output
|
||||
shell: bash
|
||||
run: echo "coverage-path=${{ inputs.working-directory }}/coverage/lcov.info" >> "$GITHUB_OUTPUT"
|
||||
28
.github/actions/publish-codecov/action.yml
vendored
Normal file
28
.github/actions/publish-codecov/action.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Publish Coverage to Codecov
|
||||
description: Upload downloaded coverage artifacts to Codecov.
|
||||
inputs:
|
||||
name:
|
||||
description: Coverage upload name in Codecov
|
||||
required: false
|
||||
default: "MariaDB"
|
||||
token:
|
||||
description: Codecov upload token
|
||||
required: true
|
||||
fail-ci-if-error:
|
||||
description: Fail workflow if Codecov upload fails
|
||||
required: false
|
||||
default: "true"
|
||||
verbose:
|
||||
description: Enable verbose Codecov logging
|
||||
required: false
|
||||
default: "true"
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Upload coverage data
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
name: ${{ inputs.name }}
|
||||
token: ${{ inputs.token }}
|
||||
fail_ci_if_error: ${{ inputs.fail-ci-if-error }}
|
||||
verbose: ${{ inputs.verbose }}
|
||||
42
.github/actions/run-server-tests/action.yml
vendored
Normal file
42
.github/actions/run-server-tests/action.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Run CRM Server Tests
|
||||
description: Execute bench tests for the CRM app with optional coverage collection.
|
||||
inputs:
|
||||
bench-path:
|
||||
description: Absolute path to the bench directory
|
||||
required: false
|
||||
default: "/home/runner/frappe-bench"
|
||||
site:
|
||||
description: Bench site on which to run tests
|
||||
required: false
|
||||
default: "test_site"
|
||||
app:
|
||||
description: App to test
|
||||
required: false
|
||||
default: "crm"
|
||||
enable-coverage:
|
||||
description: When true, include coverage flag during test execution
|
||||
required: false
|
||||
default: "true"
|
||||
type:
|
||||
description: Bench command type environment variable
|
||||
required: false
|
||||
default: "server"
|
||||
ci-build-id:
|
||||
description: CI build identifier propagated to bench commands
|
||||
required: false
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Run Tests
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.bench-path }}
|
||||
env:
|
||||
TYPE: ${{ inputs.type }}
|
||||
CI_BUILD_ID: ${{ inputs.ci-build-id }}
|
||||
run: |
|
||||
bench --site "${{ inputs.site }}" set-config allow_tests true
|
||||
if [ "${{ inputs.enable-coverage }}" = "true" ]; then
|
||||
bench --site "${{ inputs.site }}" run-tests --app "${{ inputs.app }}" --coverage
|
||||
else
|
||||
bench --site "${{ inputs.site }}" run-tests --app "${{ inputs.app }}"
|
||||
fi
|
||||
95
.github/actions/setup-server-env/action.yml
vendored
Normal file
95
.github/actions/setup-server-env/action.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
name: Setup Server Environment
|
||||
description: Prepare Python, Node, caching, and bench prerequisites for CRM server tests.
|
||||
inputs:
|
||||
python-version:
|
||||
description: Python version to install
|
||||
required: false
|
||||
default: "3.14"
|
||||
node-version:
|
||||
description: Node version to install
|
||||
required: false
|
||||
default: "24"
|
||||
type:
|
||||
description: Bench install type passed to install script
|
||||
required: false
|
||||
default: "server"
|
||||
install-erpnext:
|
||||
description: When "true", fetch and install erpnext alongside crm
|
||||
required: false
|
||||
default: "false"
|
||||
frappe-branch:
|
||||
description: Frappe (and erpnext) branch to install and test against
|
||||
required: false
|
||||
default: "develop"
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
|
||||
- name: Check for valid Python & merge conflicts
|
||||
shell: bash
|
||||
run: |
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"; then
|
||||
echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
check-latest: true
|
||||
|
||||
- name: Install Yarn
|
||||
shell: bash
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Add to hosts file
|
||||
shell: bash
|
||||
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
shell: bash
|
||||
run: echo "dir=$(yarn cache dir)" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Cache yarn
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install bench dependencies
|
||||
shell: bash
|
||||
env:
|
||||
TYPE: ${{ inputs.type }}
|
||||
INSTALL_ERPNEXT: ${{ inputs.install-erpnext }}
|
||||
FRAPPE_BRANCH: ${{ inputs.frappe-branch }}
|
||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||
18
.github/actions/upload-coverage/action.yml
vendored
Normal file
18
.github/actions/upload-coverage/action.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Upload Coverage Artifact
|
||||
description: Persist coverage artifacts produced during CRM server testing.
|
||||
inputs:
|
||||
artifact-name:
|
||||
description: Name assigned to the uploaded artifact
|
||||
required: false
|
||||
default: "coverage-server"
|
||||
coverage-path:
|
||||
description: Path to the coverage XML or directory to upload
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Upload coverage data
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.artifact-name }}
|
||||
path: ${{ inputs.coverage-path }}
|
||||
63
.github/helper/install.sh
vendored
Normal file
63
.github/helper/install.sh
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd ~ || ex
|
||||
|
||||
sudo apt update
|
||||
sudo apt remove mysql-server mysql-client
|
||||
sudo apt install libcups2-dev redis-server mariadb-client libmariadb-dev
|
||||
|
||||
# Frappe (and erpnext) branch to test against; set by CI matrix, defaults to develop.
|
||||
FRAPPE_BRANCH="${FRAPPE_BRANCH:-develop}"
|
||||
|
||||
pip install frappe-bench
|
||||
git clone "https://github.com/frappe/frappe" --branch "${FRAPPE_BRANCH}" --depth 1
|
||||
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
|
||||
|
||||
mkdir ~/frappe-bench/sites/test_site
|
||||
|
||||
cp -r "${GITHUB_WORKSPACE}/.github/helper/site_config.json" ~/frappe-bench/sites/test_site/site_config.json
|
||||
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE DATABASE test_frappe"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
|
||||
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "FLUSH PRIVILEGES"
|
||||
|
||||
install_whktml() {
|
||||
wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
|
||||
tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
|
||||
sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
|
||||
sudo chmod o+x /usr/local/bin/wkhtmltopdf
|
||||
}
|
||||
install_whktml &
|
||||
|
||||
cd ~/frappe-bench || exit
|
||||
|
||||
sed -i 's/watch:/# watch:/g' Procfile
|
||||
sed -i 's/schedule:/# schedule:/g' Procfile
|
||||
sed -i 's/socketio:/# socketio:/g' Procfile
|
||||
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
||||
|
||||
bench get-app crm "${GITHUB_WORKSPACE}"
|
||||
|
||||
# Only pull erpnext when the integration is under test, to keep other runs fast.
|
||||
if [ "${INSTALL_ERPNEXT}" = "true" ]; then
|
||||
bench get-app erpnext --branch "${FRAPPE_BRANCH}"
|
||||
fi
|
||||
|
||||
bench setup requirements --dev
|
||||
|
||||
bench start &>> ~/frappe-bench/bench_start.log &
|
||||
CI=Yes bench build --app frappe &
|
||||
bench --site test_site reinstall --yes
|
||||
|
||||
if [ "${INSTALL_ERPNEXT}" = "true" ]; then
|
||||
bench --verbose --site test_site install-app erpnext crm
|
||||
else
|
||||
bench --verbose --site test_site install-app crm
|
||||
fi
|
||||
16
.github/helper/site_config.json
vendored
Normal file
16
.github/helper/site_config.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_host": "127.0.0.1",
|
||||
"db_port": 3306,
|
||||
"db_name": "test_frappe",
|
||||
"db_password": "test_frappe",
|
||||
"auto_email_id": "test@example.com",
|
||||
"mail_server": "smtp.example.com",
|
||||
"mail_login": "test@example.com",
|
||||
"mail_password": "test",
|
||||
"admin_password": "admin",
|
||||
"root_login": "root",
|
||||
"root_password": "root",
|
||||
"host_name": "http://test_site:8000",
|
||||
"install_apps": ["crm"],
|
||||
"throttle_user_limit": 100
|
||||
}
|
||||
59
.github/helper/update_pot_file.sh
vendored
Normal file
59
.github/helper/update_pot_file.sh
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd ~ || exit
|
||||
|
||||
echo "Setting Up Bench..."
|
||||
|
||||
pip install frappe-bench
|
||||
bench -v init frappe-bench --skip-assets --skip-redis-config-generation --python "$(which python)" --frappe-branch develop
|
||||
cd ./frappe-bench || exit
|
||||
|
||||
echo "Get FCRM..."
|
||||
bench get-app --skip-assets crm "${GITHUB_WORKSPACE}"
|
||||
|
||||
echo "Generating POT file..."
|
||||
bench generate-pot-file --app crm
|
||||
|
||||
cd ./apps/crm || exit
|
||||
|
||||
echo "Configuring git user..."
|
||||
git config user.email "developers@erpnext.com"
|
||||
git config user.name "frappe-pr-bot"
|
||||
|
||||
echo "Setting the correct git remote..."
|
||||
# Here, the git remote is a local file path by default. Let's change it to the upstream repo.
|
||||
git remote set-url upstream https://github.com/frappe/crm.git
|
||||
|
||||
gh auth setup-git
|
||||
|
||||
# One stable branch, not a dated one. The POT file is fully regenerated every run, so a
|
||||
# fresh dated branch/PR each week just piles up and conflicts once any one is merged. Reusing
|
||||
# a single branch (reset to the base tip, force-pushed) keeps exactly one PR that updates in
|
||||
# place and can never conflict, since it's always rebuilt from the current base.
|
||||
branch_name="pot_${BASE_BRANCH}"
|
||||
|
||||
echo "Resetting ${branch_name} onto ${BASE_BRANCH}..."
|
||||
generated_pot=$(mktemp)
|
||||
cp crm/locale/main.pot "${generated_pot}"
|
||||
git fetch upstream "${BASE_BRANCH}"
|
||||
git checkout -f -B "${branch_name}" "upstream/${BASE_BRANCH}"
|
||||
cp "${generated_pot}" crm/locale/main.pot
|
||||
|
||||
git add crm/locale/main.pot
|
||||
if git diff --cached --quiet; then
|
||||
echo "No POT changes; nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Commiting changes..."
|
||||
git commit -m "chore: update POT file"
|
||||
|
||||
echo "Pushing ${branch_name}..."
|
||||
git push -u upstream "${branch_name}" --force
|
||||
|
||||
if gh pr view "${branch_name}" -R frappe/crm --json state -q '.state' 2>/dev/null | grep -q OPEN; then
|
||||
echo "PR already open for ${branch_name}; force-push updated it."
|
||||
else
|
||||
echo "Creating a PR..."
|
||||
gh pr create --fill --base "${BASE_BRANCH}" --head "${branch_name}" -R frappe/crm
|
||||
fi
|
||||
BIN
.github/logo.png
vendored
Normal file
BIN
.github/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
4
.github/logo.svg
vendored
Normal file
4
.github/logo.svg
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="300" height="300" viewBox="0 0 300 300" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M214.286 0H85.7143C38.3756 0 0 38.3756 0 85.7143V214.286C0 261.624 38.3756 300 85.7143 300H214.286C261.624 300 300 261.624 300 214.286V85.7143C300 38.3756 261.624 0 214.286 0Z" fill="#EF0BF5"/>
|
||||
<path d="M64.2141 90.301V111.862H214.339V140.214L160.187 193.146V208.993L139.705 208.885V193.146L85.6605 140.214H64.2141V149.269L118.259 202.202V230.23L181.634 230.769V202.202L235.786 149.269V90.301H64.2141Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 534 B |
65
.github/workflows/builds.yml
vendored
Normal file
65
.github/workflows/builds.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
name: Build Container Image
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
|
||||
steps:
|
||||
- name: Checkout Entire Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set Branch
|
||||
run: |
|
||||
export APPS_JSON='[{"url": "https://github.com/frappe/crm","branch": "main"}]'
|
||||
echo "APPS_JSON_BASE64=$(echo $APPS_JSON | base64 -w 0)" >> $GITHUB_ENV
|
||||
echo "FRAPPE_BRANCH=version-15" >> $GITHUB_ENV
|
||||
|
||||
- name: Set Image Tag
|
||||
run: |
|
||||
echo "IMAGE_TAG=stable" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: frappe/frappe_docker
|
||||
path: builds
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
context: builds
|
||||
file: builds/images/layered/Containerfile
|
||||
tags: >
|
||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }},
|
||||
ghcr.io/${{ github.repository }}:${{ env.IMAGE_TAG }}
|
||||
build-args: |
|
||||
"FRAPPE_BRANCH=${{ env.FRAPPE_BRANCH }}"
|
||||
"APPS_JSON_BASE64=${{ env.APPS_JSON_BASE64 }}"
|
||||
125
.github/workflows/frontend-tests.yml
vendored
Normal file
125
.github/workflows/frontend-tests.yml
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
name: Frontend
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- "**.py"
|
||||
- "**.txt"
|
||||
- "**.csv"
|
||||
- "**.po"
|
||||
- "**.pot"
|
||||
- ".github/workflows/server-tests.yml"
|
||||
- ".github/workflows/builds.yml"
|
||||
schedule:
|
||||
# Run every day at midnight UTC / 5:30 IST
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: frontend-${{ github.event.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# frontend/package.json links `@framework/ui` to a sibling frappe checkout
|
||||
# (link:../../frappe/ui); without it, anything importing from @framework/ui
|
||||
# fails to resolve. actions/checkout cannot place a repo outside the
|
||||
# workspace, and only the `ui` package is needed.
|
||||
- name: Clone frappe for @framework/ui
|
||||
run: |
|
||||
git clone --depth 1 --branch develop --filter=blob:none --sparse \
|
||||
https://github.com/frappe/frappe "$GITHUB_WORKSPACE/../frappe"
|
||||
git -C "$GITHUB_WORKSPACE/../frappe" sparse-checkout set ui
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: yarn
|
||||
cache-dependency-path: frontend/yarn.lock
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd frontend && yarn install --frozen-lockfile
|
||||
|
||||
- name: ESLint
|
||||
run: cd frontend && npx eslint src --ext .js,.ts,.vue
|
||||
|
||||
- name: Oxlint
|
||||
run: cd frontend && npx oxlint src
|
||||
|
||||
build:
|
||||
name: Production Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# see the lint job: @framework/ui links to a sibling frappe checkout
|
||||
- name: Clone frappe for @framework/ui
|
||||
run: |
|
||||
git clone --depth 1 --branch develop --filter=blob:none --sparse \
|
||||
https://github.com/frappe/frappe "$GITHUB_WORKSPACE/../frappe"
|
||||
git -C "$GITHUB_WORKSPACE/../frappe" sparse-checkout set ui
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: yarn
|
||||
cache-dependency-path: frontend/yarn.lock
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd frontend && yarn install --frozen-lockfile
|
||||
|
||||
- name: Build frontend
|
||||
run: cd frontend && yarn build
|
||||
|
||||
test:
|
||||
name: Unit Tests & Coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: yarn
|
||||
cache-dependency-path: frontend/yarn.lock
|
||||
|
||||
- name: Run frontend tests
|
||||
uses: ./.github/actions/frontend-tests
|
||||
with:
|
||||
node-version: "24"
|
||||
enable-coverage: "true"
|
||||
|
||||
- name: Upload coverage artifact
|
||||
if: github.base_ref == 'develop' || github.ref_name == 'develop'
|
||||
uses: ./.github/actions/upload-coverage
|
||||
with:
|
||||
artifact-name: coverage-frontend
|
||||
coverage-path: frontend/coverage/lcov.info
|
||||
|
||||
coverage:
|
||||
name: Coverage Wrap Up
|
||||
needs: test
|
||||
if: github.base_ref == 'develop' || github.ref_name == 'develop'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Publish coverage to Codecov
|
||||
uses: ./.github/actions/publish-codecov
|
||||
with:
|
||||
name: Frontend
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
40
.github/workflows/generate-pot-file.yml
vendored
Normal file
40
.github/workflows/generate-pot-file.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Regenerate POT file (translatable strings)
|
||||
on:
|
||||
schedule:
|
||||
# 9:30 UTC => 3 PM IST Sunday
|
||||
- cron: "30 9 * * 0"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
regenerate-pot-file:
|
||||
name: Regenerate POT file
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ["develop", "main-hotfix"]
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.branch }}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Run script to update POT file
|
||||
run: |
|
||||
bash ${GITHUB_WORKSPACE}/.github/helper/update_pot_file.sh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
BASE_BRANCH: ${{ matrix.branch }}
|
||||
85
.github/workflows/linters.yml
vendored
Normal file
85
.github/workflows/linters.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: Linters
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
commit-lint:
|
||||
name: Semantic Commits
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 200
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "24"
|
||||
check-latest: true
|
||||
|
||||
- name: Install commitlint
|
||||
run: npm install --no-save @commitlint/cli @commitlint/config-conventional
|
||||
|
||||
- name: Check commit titles
|
||||
run: npx commitlint --verbose --from "${{ github.event.pull_request.base.sha }}" --to "${{ github.event.pull_request.head.sha }}"
|
||||
|
||||
semgrep:
|
||||
name: Semgrep Rules
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
||||
PYTHONDONTWRITEBYTECODE: "1"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
cache: pip
|
||||
|
||||
- name: Install Semgrep
|
||||
run: pip install --upgrade semgrep
|
||||
|
||||
- name: Download Semgrep rules
|
||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||
|
||||
- name: Run Semgrep rules
|
||||
run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness
|
||||
|
||||
pre-commit:
|
||||
name: Pre-commit Checks
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
||||
PYTHONDONTWRITEBYTECODE: "1"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
cache: pip
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: Install frontend dependencies
|
||||
run: cd frontend && yarn install
|
||||
|
||||
- name: Run Pre-commit
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: --all-files
|
||||
107
.github/workflows/migration-test.yml
vendored
Normal file
107
.github/workflows/migration-test.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
name: Migration
|
||||
|
||||
# Verifies that an existing site on the PR's base branch can `bench migrate`
|
||||
# to the PR code. Catches broken patches / schema changes before release.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.css"
|
||||
- "**.js"
|
||||
- "**.md"
|
||||
- "**.html"
|
||||
- "**.csv"
|
||||
- "**.po"
|
||||
- "**.pot"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: migration-${{ github.event.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
migrate:
|
||||
name: Upgrade base branch -> PR
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:10.6
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
env:
|
||||
BASE_BRANCH: ${{ github.base_ref || github.ref_name }}
|
||||
BENCH_PATH: /home/runner/frappe-bench
|
||||
|
||||
steps:
|
||||
- name: Checkout PR code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: pr-crm
|
||||
|
||||
- name: Resolve frappe branch for base
|
||||
id: frappe
|
||||
run: |
|
||||
# Stable lanes run on frappe version-15; develop tracks frappe develop.
|
||||
case "$BASE_BRANCH" in
|
||||
main|main-hotfix) echo "branch=version-15" >> "$GITHUB_OUTPUT" ;;
|
||||
*) echo "branch=develop" >> "$GITHUB_OUTPUT" ;;
|
||||
esac
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libcups2-dev redis-server mariadb-client libmariadb-dev
|
||||
npm install -g yarn
|
||||
|
||||
- name: Configure database
|
||||
run: |
|
||||
echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE DATABASE test_frappe"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "FLUSH PRIVILEGES"
|
||||
|
||||
- name: Init bench with frappe
|
||||
run: |
|
||||
pip install frappe-bench
|
||||
git clone "https://github.com/frappe/frappe" --branch "${{ steps.frappe.outputs.branch }}" --depth 1 ~/frappe
|
||||
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" "$BENCH_PATH"
|
||||
|
||||
- name: Install CRM at base branch
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
mkdir sites/test_site
|
||||
cp "${GITHUB_WORKSPACE}/pr-crm/.github/helper/site_config.json" sites/test_site/site_config.json
|
||||
sed -i 's/watch:/# watch:/g; s/schedule:/# schedule:/g; s/socketio:/# socketio:/g; s/redis_socketio:/# redis_socketio:/g' Procfile
|
||||
bench get-app crm "https://github.com/frappe/crm" --branch "$BASE_BRANCH"
|
||||
bench setup requirements --dev
|
||||
bench start &>> "$BENCH_PATH/bench_start.log" &
|
||||
CI=Yes bench build --app frappe &
|
||||
bench --site test_site reinstall --yes
|
||||
bench --verbose --site test_site install-app crm
|
||||
|
||||
- name: Upgrade CRM to PR code and migrate
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
# Swap the installed (base branch) code for the PR code, keep the git dir.
|
||||
rsync -a --delete --exclude=".git" "${GITHUB_WORKSPACE}/pr-crm/" apps/crm/
|
||||
bench setup requirements --dev
|
||||
bench --site test_site migrate
|
||||
32
.github/workflows/on_release.yml
vendored
Normal file
32
.github/workflows/on_release.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Generate Semantic Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Entire Repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
- name: Setup dependencies
|
||||
run: |
|
||||
npm install @semantic-release/git @semantic-release/exec --no-save
|
||||
- name: Create Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GIT_AUTHOR_NAME: "Frappe PR Bot"
|
||||
GIT_AUTHOR_EMAIL: "developers@frappe.io"
|
||||
GIT_COMMITTER_NAME: "Frappe PR Bot"
|
||||
GIT_COMMITTER_EMAIL: "developers@frappe.io"
|
||||
run: npx semantic-release
|
||||
40
.github/workflows/release_notes.yml
vendored
Normal file
40
.github/workflows/release_notes.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# This action:
|
||||
#
|
||||
# 1. Generates release notes using github API.
|
||||
# 2. Strips unnecessary info like chore/style etc from notes.
|
||||
# 3. Updates release info.
|
||||
|
||||
name: 'Release Notes'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'Tag of release like v1.0.0'
|
||||
required: true
|
||||
type: string
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
regen-notes:
|
||||
name: 'Regenerate release notes'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Update notes
|
||||
run: |
|
||||
NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/crm/releases/generate-notes -f tag_name=$RELEASE_TAG \
|
||||
| jq -r '.body' \
|
||||
| sed -E '/^\* (chore|ci|test|docs|style)/d' \
|
||||
| sed -E 's/by @mergify //'
|
||||
)
|
||||
RELEASE_ID=$(gh api -H "Accept: application/vnd.github+json" /repos/frappe/crm/releases/tags/$RELEASE_TAG | jq -r '.id')
|
||||
gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/frappe/crm/releases/$RELEASE_ID -f body="$NEW_NOTES"
|
||||
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
RELEASE_TAG: ${{ github.event.inputs.tag_name || github.event.release.tag_name }}
|
||||
106
.github/workflows/server-tests.yml
vendored
Normal file
106
.github/workflows/server-tests.yml
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
name: Server
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.css"
|
||||
- "**.js"
|
||||
- "**.md"
|
||||
- "**.html"
|
||||
- "**.csv"
|
||||
- "**.po"
|
||||
- "**.pot"
|
||||
schedule:
|
||||
# Run everday at midnight UTC / 5:30 IST
|
||||
- cron: "0 0 * * *"
|
||||
env:
|
||||
CRM_BRANCH: ${{ github.base_ref || github.ref_name }}
|
||||
|
||||
concurrency:
|
||||
group: develop-crm-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
name: Resolve frappe matrix
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
frappe-branches: ${{ steps.resolve.outputs.branches }}
|
||||
steps:
|
||||
- name: Resolve frappe branches from target branch
|
||||
id: resolve
|
||||
run: |
|
||||
BASE="${{ github.base_ref || github.ref_name }}"
|
||||
# develop tracks frappe develop; the stable lane ships frappe 15 and 16.
|
||||
if [ "$BASE" = "develop" ]; then
|
||||
echo 'branches=["develop"]' >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo 'branches=["version-15","version-16"]' >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
test:
|
||||
name: Tests (frappe ${{ matrix.frappe-branch }})
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
frappe-branch: ${{ fromJson(needs.setup.outputs.frappe-branches) }}
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:10.6
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup environment
|
||||
uses: ./.github/actions/setup-server-env
|
||||
with:
|
||||
python-version: "3.14"
|
||||
node-version: "24"
|
||||
type: "server"
|
||||
# erpnext: stable lane only, never v16 (v16 test bootstrap broken on bare bench)
|
||||
install-erpnext: ${{ (github.base_ref == 'main-hotfix' || github.base_ref == 'main') && matrix.frappe-branch != 'version-16' }}
|
||||
frappe-branch: ${{ matrix.frappe-branch }}
|
||||
|
||||
- name: Run server tests
|
||||
uses: ./.github/actions/run-server-tests
|
||||
with:
|
||||
bench-path: "/home/runner/frappe-bench"
|
||||
site: "test_site"
|
||||
app: "crm"
|
||||
enable-coverage: "true"
|
||||
type: "server"
|
||||
ci-build-id: ${{ github.run_id }}
|
||||
|
||||
- name: Persist coverage artifact
|
||||
if: github.base_ref == 'develop' || github.ref_name == 'develop'
|
||||
uses: ./.github/actions/upload-coverage
|
||||
with:
|
||||
artifact-name: coverage-${{ matrix.frappe-branch }}
|
||||
coverage-path: /home/runner/frappe-bench/sites/coverage.xml
|
||||
|
||||
coverage:
|
||||
name: Coverage Wrap Up
|
||||
needs: test
|
||||
if: github.base_ref == 'develop' || github.ref_name == 'develop'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Publish coverage
|
||||
uses: ./.github/actions/publish-codecov
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
181
.github/workflows/ui-tests.yml
vendored
Normal file
181
.github/workflows/ui-tests.yml
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
name: UI Tests
|
||||
|
||||
# E2E (Playwright) suite. Heavy gate: runs on the main-hotfix staging lane
|
||||
# before promoting to main, plus on demand. Develop stays on the fast lane.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main-hotfix
|
||||
pull_request:
|
||||
branches:
|
||||
- main-hotfix
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ui-tests-crm-${{ github.event.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
FRAPPE_BRANCH: develop
|
||||
|
||||
jobs:
|
||||
ui-tests:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
name: Playwright E2E Tests
|
||||
|
||||
services:
|
||||
redis-cache:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- 13000:6379
|
||||
redis-queue:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- 11000:6379
|
||||
mariadb:
|
||||
image: mariadb:10.6
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mariadb-admin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
check-latest: true
|
||||
|
||||
- name: Add to Hosts
|
||||
run: echo "127.0.0.1 crm.test" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: 'echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT'
|
||||
|
||||
- name: Cache yarn
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('package.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
|
||||
- name: Install MariaDB Client
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install mariadb-client
|
||||
|
||||
- name: Setup Bench
|
||||
run: |
|
||||
pip install frappe-bench
|
||||
bench init --skip-redis-config-generation --skip-assets --frappe-branch "$FRAPPE_BRANCH" --python "$(which python)" ~/frappe-bench
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
- name: Install CRM
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
bench get-app crm $GITHUB_WORKSPACE
|
||||
bench setup requirements --dev
|
||||
bench new-site --db-root-password root --admin-password admin crm.test
|
||||
bench --site crm.test install-app crm
|
||||
bench build --app crm
|
||||
env:
|
||||
CI: "Yes"
|
||||
|
||||
- name: Configure Site for UI Tests
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
bench --site crm.test set-config allow_tests true
|
||||
bench --site crm.test set-config host_name "http://crm.test:8000"
|
||||
# Dummy default-outgoing account so send-email queues without real SMTP.
|
||||
bench --site crm.test console <<'PY'
|
||||
import frappe
|
||||
if not frappe.db.exists("Email Account", {"default_outgoing": 1}):
|
||||
frappe.get_doc({
|
||||
"doctype": "Email Account",
|
||||
"email_account_name": "E2E Outgoing",
|
||||
"email_id": "e2e@example.com",
|
||||
"smtp_server": "localhost",
|
||||
"smtp_port": 25,
|
||||
"enable_outgoing": 1,
|
||||
"default_outgoing": 1,
|
||||
"no_smtp_authentication": 1,
|
||||
}).insert(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
PY
|
||||
|
||||
- name: Start Frappe Server
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
sed -i 's/^watch:/# watch:/g' Procfile
|
||||
sed -i 's/^schedule:/# schedule:/g' Procfile
|
||||
bench start &> bench_start.log &
|
||||
echo "Waiting for Frappe server to start..."
|
||||
timeout 60 bash -c 'until curl -s http://crm.test:8000 > /dev/null; do sleep 2; done'
|
||||
echo "Frappe server is ready!"
|
||||
|
||||
- name: Install Playwright
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
npx playwright install --with-deps chromium
|
||||
|
||||
- name: Run Playwright Tests
|
||||
run: npx playwright test
|
||||
env:
|
||||
BASE_URL: http://crm.test:8000
|
||||
FRAPPE_USER: Administrator
|
||||
FRAPPE_PASSWORD: admin
|
||||
|
||||
- name: Upload Playwright Report
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results/
|
||||
retention-days: 7
|
||||
|
||||
- name: Show Bench Logs on Failure
|
||||
if: failure()
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
echo "=== Bench Start Log ==="
|
||||
cat bench_start.log || true
|
||||
echo ""
|
||||
echo "=== Frappe Logs ==="
|
||||
cat logs/*.log || true
|
||||
Reference in New Issue
Block a user