You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2023/10/13 02:55:14 UTC

[incubator-opendal] branch main updated: refactor: Introduce OpenDAL Workflow Planner (#3258)

This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 147753d80 refactor: Introduce OpenDAL Workflow Planner (#3258)
147753d80 is described below

commit 147753d80a15661711fc796c25928a31be1a427b
Author: Xuanwo <gi...@xuanwo.io>
AuthorDate: Fri Oct 13 10:55:07 2023 +0800

    refactor: Introduce OpenDAL Workflow Planner (#3258)
    
    * Try workflow call
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Add s3 as ignore example
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Remove concurrency
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Use output file
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Let's go
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * wrap
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix typo
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * test
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Polish naming
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * polish naming
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Can we use / ?
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Try
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix build
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * polish matrix
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix not found
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix path
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * FIx path
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * try
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix typo
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * toJson
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix typo
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * polish naming
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * FIx build
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Auto detect task
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * better
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Polish fs
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Add s3
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Make json pretty
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Make sure secrets
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Try passing
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Use from json
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Fix
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Remove migrated tests
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * remove unused functions
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    * Work under push event
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
    
    ---------
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
---
 .github/actions/setup/action.yaml       |  20 +++---
 .github/actions/test-core/action.yaml   |  51 ++++++++++++++
 .github/services/fs/local-fs/action.yml |  28 ++++++++
 .github/services/s3/aws-s3/action.yml   |  39 +++++++++++
 .github/workflows/core_test.yml         |  93 +++++++++++++++++++++++++
 .github/workflows/service_test_fs.yml   |  57 ---------------
 .github/workflows/service_test_s3.yml   |  22 ------
 .github/workflows/test_planner.yml      |  94 +++++++++++++++++++++++++
 scripts/workflow_planner.py             | 120 ++++++++++++++++++++++++++++++++
 9 files changed, 436 insertions(+), 88 deletions(-)

diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml
index 5c5dc5dc8..2adc5d67a 100644
--- a/.github/actions/setup/action.yaml
+++ b/.github/actions/setup/action.yaml
@@ -49,24 +49,26 @@ runs:
       shell: bash
       run: sudo apt-get install libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
 
-    - name: Setup protoc on linux
-      if: inputs.need-protoc == 'true' && runner.os == 'Linux'
-      shell: bash
-      run: sudo apt install -y protobuf-compiler
+    - name: Setup Protoc
+      if: inputs.need-protoc == 'true'
+      uses: arduino/setup-protoc@v2
+      with:
+          version: "23.4"
 
     - name: Cache nextest on linux
       id: cache-nextest
       uses: actions/cache@v3
-      if: inputs.need-nextest == 'true' && runner.os == 'Linux'
+      if: inputs.need-nextest == 'true'
       with:
-        path: ~/.cargo/bin/cargo-nextest
-        # TODO: remove the runner.os while bumping version
-        key: r0-${{runner.os}}-nextest-0.9.53
+        path: |
+          ~/.cargo/bin/cargo-nextest
+          ~/.cargo/bin/cargo-nextest.exe
+        key: r0-${{runner.os}}-nextest-0.9.59
 
     - name: Build nextest if not cached
       if: steps.cache-nextest.outputs.cache-hit != 'true' && inputs.need-nextest == 'true'
       shell: bash
-      run: cargo install cargo-nextest@0.9.53 --locked
+      run: cargo install cargo-nextest@0.9.59 --locked
 
     - name: Setup rust on linux
       if: runner.os == 'Linux' && inputs.need-rocksdb == 'true'
diff --git a/.github/actions/test-core/action.yaml b/.github/actions/test-core/action.yaml
new file mode 100644
index 000000000..da5759fe1
--- /dev/null
+++ b/.github/actions/test-core/action.yaml
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: Test Core
+description: 'Test Core with given setup and service'
+inputs:
+  setup:
+    description: "The setup action for test"
+  service:
+    description: "The service to test"
+  secrets:
+    description: "The secrets for test"
+    default: "{}"
+
+runs:
+  using: "composite"
+  steps:
+      - name: Setup
+        shell: bash
+        run: |
+            mkdir -p ./dynamic_test_core &&
+            cat <<EOF >./dynamic_test_core/action.yml
+            runs:
+              using: composite
+              steps:
+              - name: Setup Test Core
+                uses: ./.github/services/${{ inputs.service }}/${{ inputs.setup }}
+                with:
+                  secrets: ${{ toJson(inputs.secrets) }}
+              - name: Run Test Core
+                shell: bash
+                working-directory: core
+                run: cargo nextest run services_${{ inputs.service }} --archive-file=./core-test.tar.zst
+            EOF
+      - name: Run
+        id: run
+        uses: ./dynamic_test_core
diff --git a/.github/services/fs/local-fs/action.yml b/.github/services/fs/local-fs/action.yml
new file mode 100644
index 000000000..4175de1eb
--- /dev/null
+++ b/.github/services/fs/local-fs/action.yml
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: local_fs
+description: "Setup local fs"
+
+runs:
+    using: "composite"
+    steps:
+        - name: Setup
+          shell: bash
+          run: |
+              echo "OPENDAL_FS_TEST=on" >> $GITHUB_ENV
+              echo "OPENDAL_FS_ROOT=${{ runner.temp }}/" >> $GITHUB_ENV
diff --git a/.github/services/s3/aws-s3/action.yml b/.github/services/s3/aws-s3/action.yml
new file mode 100644
index 000000000..7591937d5
--- /dev/null
+++ b/.github/services/s3/aws-s3/action.yml
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: aws_s3
+description: "Setup AWS S3"
+
+inputs:
+  secrets:
+    description: "The secrets for test"
+    default: "{}"
+
+# TODO: we should migrate to 1password instead.
+runs:
+  using: "composite"
+  steps:
+    - name: Setup
+      shell: bash
+      run: |
+        echo "OPENDAL_S3_TEST=${{ fromJson(inputs.secrets).OPENDAL_S3_TEST }}" >> $GITHUB_ENV
+        echo "OPENDAL_S3_ROOT=${{ fromJson(inputs.secrets).OPENDAL_S3_ROOT }}" >> $GITHUB_ENV
+        echo "OPENDAL_S3_BUCKET=${{ fromJson(inputs.secrets).OPENDAL_S3_BUCKET }}" >> $GITHUB_ENV
+        echo "OPENDAL_S3_ENDPOINT=${{ fromJson(inputs.secrets).OPENDAL_S3_ENDPOINT }}" >> $GITHUB_ENV
+        echo "OPENDAL_S3_ACCESS_KEY_ID=${{ fromJson(inputs.secrets).OPENDAL_S3_ACCESS_KEY_ID }}" >> $GITHUB_ENV
+        echo "OPENDAL_S3_SECRET_ACCESS_KEY=${{ fromJson(inputs.secrets).OPENDAL_S3_SECRET_ACCESS_KEY }}" >> $GITHUB_ENV
+        echo "OPENDAL_S3_REGION=ap-northeast-1" >> $GITHUB_ENV
diff --git a/.github/workflows/core_test.yml b/.github/workflows/core_test.yml
new file mode 100644
index 000000000..a92cadd9a
--- /dev/null
+++ b/.github/workflows/core_test.yml
@@ -0,0 +1,93 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: Core
+
+on:
+  workflow_call:
+    inputs:
+      os:
+        required: true
+        type: string
+      cases:
+        required: true
+        type: string
+      features:
+        required: true
+        type: string
+
+jobs:
+  build:
+    name: build
+    runs-on: ${{ inputs.os }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Setup Rust toolchain
+        uses: ./.github/actions/setup
+        with:
+          need-nextest: true
+          need-protoc: true
+          need-rocksdb: true
+
+      # Required by hdfs
+      - name: Setup java env
+        uses: actions/setup-java@v3
+        with:
+          distribution: temurin
+          java-version: "11"
+
+      - name: Build
+        shell: bash
+        working-directory: core
+        run: |
+          cargo nextest archive --features ${{ inputs.features }} --archive-file ./core-test.tar.zst
+
+      - name: Upload
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ inputs.os }}-core-test
+          path: ./core/core-test.tar.zst
+
+  test:
+    name: ${{ matrix.cases.service }} / ${{ matrix.cases.setup }}
+    needs: [build]
+    runs-on: ${{ inputs.os }}
+    strategy:
+      matrix:
+        cases: ${{ fromJson(inputs.cases) }}
+    steps:
+      - uses: actions/checkout@v4
+      - name: Setup Rust toolchain
+        uses: ./.github/actions/setup
+        with:
+          need-nextest: true
+          need-protoc: true
+          need-rocksdb: true
+
+      - name: Download
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ inputs.os }}-core-test
+          path: ./core
+
+      - name: Test Core
+        uses: ./.github/actions/test-core
+        with:
+            setup: ${{ matrix.cases.setup }}
+            service: ${{ matrix.cases.service }}
+            secrets: ${{ toJson(secrets) }}
diff --git a/.github/workflows/service_test_fs.yml b/.github/workflows/service_test_fs.yml
deleted file mode 100644
index c06b9e81d..000000000
--- a/.github/workflows/service_test_fs.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-name: Service Test Fs
-
-on:
-  push:
-    branches:
-      - main
-  pull_request:
-    branches:
-      - main
-    paths:
-      - "core/src/**"
-      - "core/tests/**"
-      - "!core/src/docs/**"
-      - "!core/src/services/**"
-      - "core/src/services/fs/**"
-      - ".github/workflows/service_test_fs.yml"
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
-  cancel-in-progress: true
-
-jobs:
-  local_fs:
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os:
-          - ubuntu-latest
-          - windows-latest
-    steps:
-      - uses: actions/checkout@v4
-      - name: Setup Rust toolchain
-        uses: ./.github/actions/setup
-      - name: Test
-        shell: bash
-        working-directory: core
-        run: cargo test services_fs
-        env:
-          OPENDAL_FS_TEST: on
-          OPENDAL_FS_ROOT: ${{ runner.temp }}/
diff --git a/.github/workflows/service_test_s3.yml b/.github/workflows/service_test_s3.yml
index 9efd04f60..95f703ab7 100644
--- a/.github/workflows/service_test_s3.yml
+++ b/.github/workflows/service_test_s3.yml
@@ -39,28 +39,6 @@ concurrency:
   cancel-in-progress: true
 
 jobs:
-  aws_s3:
-    runs-on: ubuntu-latest
-    if: github.event_name == 'push' || !github.event.pull_request.head.repo.fork
-    steps:
-      - uses: actions/checkout@v4
-      - name: Setup Rust toolchain
-        uses: ./.github/actions/setup
-        with:
-          need-nextest: true
-      - name: Test
-        shell: bash
-        working-directory: core
-        run: cargo nextest run s3
-        env:
-          OPENDAL_S3_TEST: ${{ secrets.OPENDAL_S3_TEST }}
-          OPENDAL_S3_ROOT: ${{ secrets.OPENDAL_S3_ROOT }}
-          OPENDAL_S3_BUCKET: ${{ secrets.OPENDAL_S3_BUCKET }}
-          OPENDAL_S3_ENDPOINT: ${{ secrets.OPENDAL_S3_ENDPOINT }}
-          OPENDAL_S3_ACCESS_KEY_ID: ${{ secrets.OPENDAL_S3_ACCESS_KEY_ID }}
-          OPENDAL_S3_SECRET_ACCESS_KEY: ${{ secrets.OPENDAL_S3_SECRET_ACCESS_KEY }}
-          OPENDAL_S3_REGION: ap-northeast-1
-
   aws_s3_with_virtual_host:
     runs-on: ubuntu-latest
     if: github.event_name == 'push' || !github.event.pull_request.head.repo.fork
diff --git a/.github/workflows/test_planner.yml b/.github/workflows/test_planner.yml
new file mode 100644
index 000000000..535170d86
--- /dev/null
+++ b/.github/workflows/test_planner.yml
@@ -0,0 +1,94 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: Test
+
+on:
+  push:
+    branches:
+      - main
+  pull_request:
+    branches:
+      - main
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
+  cancel-in-progress: true
+
+jobs:
+  plan:
+    runs-on: ubuntu-latest
+    outputs:
+      plan: ${{ steps.plan.outputs.plan }}
+
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          # fetch depth set to 0 to make sure we have correct diff result.
+          fetch-depth: 0
+
+      - name: Plan
+        id: plan
+        run: |
+          git fetch origin main:main
+
+          event_name="${{ github.event_name }}"
+          repository="${{ github.repository }}"
+          files_changed=""
+          has_secrets="False"
+          is_push="False"
+
+          # Handle event-specific logic
+          if [ "$event_name" == "push" ]; then
+            if [ "$repository" == "apache/incubator-opendal" ]; then
+              is_push="True"
+              has_secrets="True"
+            fi
+          elif [ "$event_name" == "pull_request" ]; then
+            pr_head_repo_fork="${{ github.event.pull_request.head.repo.fork }}"
+            if [ "$pr_head_repo_fork" != "true" ]; then
+              has_secrets="True"
+            fi
+
+            files_changed=$(git diff --name-only main ${{ github.event.pull_request.head.sha }})
+            echo "Files changed:"
+            echo "$FILES_CHANGED"
+          fi
+
+          # Export variables
+          export GITHUB_HAS_SECRETS=$has_secrets
+          export GITHUB_IS_PUSH=$is_push
+
+          # Run the workflow planner script
+          PLAN=$(./scripts/workflow_planner.py $files_changed)
+          echo "Plan:"
+          echo "$PLAN" | jq .
+          echo "plan=$PLAN" >> $GITHUB_OUTPUT
+
+  core_test:
+    name: core / ${{ matrix.os }}
+    needs: [plan]
+    if: fromJson(needs.plan.outputs.plan).components.core
+    secrets: inherit
+    strategy:
+      matrix:
+        include: ${{ fromJson(needs.plan.outputs.plan).core }}
+    uses: ./.github/workflows/core_test.yml
+    with:
+      os: ${{ matrix.os }}
+      cases: ${{ toJson(matrix.cases) }}
+      features: ${{ matrix.features }}
diff --git a/scripts/workflow_planner.py b/scripts/workflow_planner.py
new file mode 100755
index 000000000..7c8d8f9d7
--- /dev/null
+++ b/scripts/workflow_planner.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import sys
+import json
+import os
+from pathlib import Path
+
+
+def get_provided_cases():
+    root_dir = ".github/services"
+
+    cases = [
+        {
+            "service": service,
+            "setup": setup,
+            "content": Path(
+                os.path.join(root_dir, service, setup, "action.yml")
+            ).read_text(),
+        }
+        for service in os.listdir(root_dir)
+        for setup in os.listdir(os.path.join(root_dir, service))
+    ]
+
+    # Check if this workflow needs to read secrets.
+    #
+    # We will check if pattern `secrets.XXX` exist in content.
+    if not bool(os.getenv("GITHUB_HAS_SECRETS")):
+        cases[:] = [v for v in cases if "secrets." not in v["content"]]
+
+    return cases
+
+
+def calculate_core_cases(cases, changed_files):
+    # If any of the core workflow changed, we will run all cases.
+    for p in [
+        ".github/workflows/core_test.yml",
+        ".github/workflows/test_planner.yml",
+        ".github/actions/test-core",
+    ]:
+        if p in changed_files:
+            return cases
+
+    # Always run all tests if it is a push event.
+    if bool(os.getenv("GITHUB_IS_PUSH")):
+        return cases
+
+    # If any of the core files changed, we will run all cases.
+    if any(
+        p.startswith("core/src/") and not p.startswith("core/src/services")
+        for p in changed_files
+    ):
+        return cases
+    if any(p.startswith("core/tests/") for p in changed_files):
+        return cases
+
+    # Filter all cases that not shown un in changed files
+    cases = [v for v in cases if any(v["service"] in p for p in changed_files)]
+    return cases
+
+
+# Context is the github context: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
+def plan(changed_files):
+    # TODO: add bindings/java, bindings/python in the future.
+    components = ["core"]
+    cases = get_provided_cases()
+
+    core_cases = calculate_core_cases(cases, changed_files)
+
+    jobs = {}
+
+    if len(core_cases) > 0:
+        jobs["components"] = {"core": True}
+        jobs["core"] = [
+            {
+                "os": "ubuntu-latest",
+                "features": ",".join(
+                    set([f"services-{v['service']}" for v in core_cases])
+                ),
+                "cases": [
+                    {"setup": v["setup"], "service": v["service"]} for v in core_cases
+                ],
+            },
+        ]
+
+        # fs is the only services need to run upon windows, let's hard code it here.
+        if "fs" in [v["service"] for v in core_cases]:
+            jobs["core"].append(
+                {
+                    "os": "windows-latest",
+                    "features": "services-fs",
+                    "cases": [{"setup": "local-fs", "service": "fs"}],
+                }
+            )
+
+    return json.dumps(jobs)
+
+
+# For quick test:
+#
+# ./scripts/workflow_planner.py PATH
+if __name__ == "__main__":
+    changed_files = sys.argv[1:]
+    result = plan(changed_files)
+    print(result)