diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000..a4d3e82d --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,67 @@ +name: Backport PR + +on: + pull_request_target: + types: [closed, labeled] + +permissions: + contents: write + pull-requests: write + +jobs: + backport: + name: Backport PR + if: > + github.event.pull_request.merged == true + && contains(join(github.event.pull_request.labels.*.name, ','), 'backport-to-') + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Create backport PRs + uses: korthout/backport-action@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + label_pattern: "^backport-to-(.+)$" + pull_title: "[Backport ${target_branch}] ${pull_title}" + pull_description: | + Backport of #${pull_number} to `${target_branch}`. + + --- + + ${pull_description} + merge_commits: "skip" + copy_requested_reviewers: true + copy_assignees: true + copy_labels_pattern: "^(?!backport-to-)" + auto_merge_enabled: ${{ contains(join(github.event.pull_request.labels.*.name, ','), 'backport-auto-merge') }} + + - name: Report backport status + if: failure() + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const pullNumber = context.payload.pull_request.number; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: pullNumber, + body: [ + "⚠️ **Backport failed!**", + "", + "The automatic backport could not be completed. This might be due to cherry-pick conflicts or a missing target branch.", + "", + "Please manually cherry-pick the commits to the target branch:", + "", + "```bash", + "git checkout ", + `git cherry-pick -x ${context.payload.pull_request.merge_commit_sha}`, + "```", + ].join("\\n"), + }); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..45ac8e06 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,132 @@ +name: CI + +on: + pull_request: + paths-ignore: + - "**.css" + - "**.js" + - "**.md" + - "**.html" + - "**.csv" + workflow_dispatch: + schedule: + - cron: "0 0 * * *" + +permissions: + contents: read + +concurrency: + group: ci-servicems-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + tests: + name: Server Tests + runs-on: ubuntu-latest + timeout-minutes: 45 + + services: + mariadb: + image: mariadb:10.6 + env: + MYSQL_ROOT_PASSWORD: root + ports: + - 3306:3306 + options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=5s --health-timeout=2s --health-retries=3 + + redis-cache: + image: redis:alpine + ports: + - 13000:6379 + + redis-queue: + image: redis:alpine + ports: + - 11000:6379 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Determine Frappe branch + run: | + REF_NAME="${GITHUB_BASE_REF:-${GITHUB_REF_NAME}}" + if [[ "$REF_NAME" =~ ^version-[0-9]+(-hotfix)?$ ]]; then + echo "FRAPPE_BRANCH=$REF_NAME" >> "$GITHUB_ENV" + else + echo "FRAPPE_BRANCH=version-15" >> "$GITHUB_ENV" + fi + + - name: Install MariaDB client + run: sudo apt-get update && sudo apt-get -y install mariadb-client + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + check-latest: true + + - name: Check for valid Python & Merge Conflicts + run: | + python -m compileall -q -f "${GITHUB_WORKSPACE}" + if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"; then + echo "Found merge conflicts" + exit 1 + fi + + - name: Add to Hosts + 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', '**/setup.py', '**/setup.cfg') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> "$GITHUB_OUTPUT" + + - uses: actions/cache@v4 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + ${{ runner.os }}- + + - 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 + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" + + - name: Install Apps + working-directory: /home/runner/frappe-bench + run: | + bench get-app erpnext --branch "$FRAPPE_BRANCH" + bench get-app servicems "$GITHUB_WORKSPACE" + + - name: Setup Test Site + working-directory: /home/runner/frappe-bench + env: + CI: "Yes" + run: | + bench new-site --db-root-password root --admin-password admin test_site + bench --site test_site install-app erpnext + bench --site test_site install-app servicems + bench --site test_site set-config allow_tests true + + - name: Run Tests + working-directory: /home/runner/frappe-bench + run: bench --site test_site run-tests --app servicems diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..36a7c87d --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,26 @@ +name: Pre-commit + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: precommit-servicems-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + pre-commit: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: pip + + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/semantic-commits.yml b/.github/workflows/semantic-commits.yml new file mode 100644 index 00000000..572f78d2 --- /dev/null +++ b/.github/workflows/semantic-commits.yml @@ -0,0 +1,31 @@ +name: Semantic Commits + +on: + pull_request: {} + +permissions: + contents: read + +concurrency: + group: commitcheck-servicems-${{ github.event.number }} + cancel-in-progress: true + +jobs: + commitlint: + name: Check Commit Messages + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 200 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + check-latest: true + + - name: Check commit messages + run: | + npm install @commitlint/cli @commitlint/config-conventional conventional-changelog-conventionalcommits + npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..8d40943f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,59 @@ +exclude: "node_modules|.git|servicems/public/frontend/assets" +default_stages: [pre-commit] +fail_fast: false + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-merge-conflict + - id: check-ast + - id: debug-statements + - id: no-commit-to-branch + args: + - --branch + - main + - --branch + - master + - --branch + - develop + - --branch + - version-15 + - --branch + - version-15-hotfix + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.13.2 + hooks: + - id: ruff + name: "Run ruff linter and apply fixes" + args: ["--fix"] + files: "^servicems/.*\\.py$" + stages: [manual] + - id: ruff-format + name: "Format Python code" + files: "^servicems/.*\\.py$" + stages: [manual] + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.7.1 + hooks: + - id: prettier + types_or: [javascript, vue, css, scss, json] + files: "^(frontend|servicems)/.*" + exclude: | + (?x)^( + frontend/dist/.*| + servicems/public/frontend/assets/.*| + .*node_modules.*| + .*boilerplate.* + )$ + stages: [manual] + +ci: + autoupdate_schedule: weekly + skip: [] + submodules: false diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..26a88cbb --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ["@commitlint/config-conventional"], +};