github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/step_by_step_contribute.md (about) 1 # Step By Step Contribute Example 2 3 This document introduces a step by step example of contriuting to DM. 4 5 Please perform the following steps to create your Pull Request to this repository. If don't like to use command, you can also use [GitHub Desktop](https://desktop.github.com/), which is easier to get started. 6 7 > **Note:** 8 > 9 > This section takes creating a PR to the `master` branch as an example. Steps of creating PRs to other branches are similar. 10 11 ### Step 1: Fork the repository 12 13 1. Visit the project: <https://github.com/pingcap/dm> 14 2. Click the **Fork** button on the top right and wait it to finish. 15 16 ### Step 2: Clone the forked repository to local storage 17 18 ```sh 19 cd $working_dir # Comes to the directory that you want put the fork in, for example, "cd ~/code" 20 git clone git@github.com:$user/dm.git # Replace "$user" with your GitHub ID 21 22 cd $working_dir/dm 23 git remote add upstream git@github.com:pingcap/dm.git # Adds the upstream repo 24 git remote -v # Confirms that your remote makes sense 25 ``` 26 27 ### Step 3: Setting up your development environment 28 29 1. Setting up a Go development environment: [How to Write Go Code](http://golang.org/doc/code.html). 30 31 > **Note:** 32 > 33 > DM uses [`Go Modules`](https://github.com/golang/go/wiki/Modules) to manage dependencies. The version of Go should be **1.16** or above. 34 35 You'll need `GOPATH` defined, and `PATH` modified to access your Go binaries. A 36 common setup is the following but you could always google a setup for your own 37 flavor. 38 39 ```sh 40 export GOPATH=$HOME/go 41 export PATH=$PATH:$GOPATH/bin 42 ``` 43 44 Then you can use `make` command to build DM. 45 46 ```sh 47 make build 48 ``` 49 50 2. Setting up test environment. See [Test Preparations](tests/README.md#Preparations) for more details. 51 52 ### Step 4: Pick up a issue 53 54 You can start by finding an existing issue with the 55 [help wanted](https://github.com/pingcap/dm/labels/help%20wanted) 56 label in the DM repository. These issues are well suited for new contributors. 57 58 > **Note:** 59 > 60 > This section takes issue [UCP: retrieve the configuration of the running task from the DM cluster](https://github.com/pingcap/dm/issues/182) as an example. Steps of pick up other issues are similar. 61 62 ### Step 5: Create a new branch 63 64 1. Get your local master up-to-date with upstream/master. 65 66 ```bash 67 cd $working_dir/dm 68 git fetch upstream 69 git checkout master 70 git rebase upstream/master 71 ``` 72 73 2. Create a new branch based on the master branch. 74 75 ```bash 76 git checkout -b new-branch-name 77 ``` 78 79 ### Step 6: Edit your code 80 81 Edit some code on the `new-branch-name` branch and save your changes to fix the issure. Below is a example to add `get-task-config` command for DM. 82 83 1. Update the [proto code](dm/proto/dmmaster.proto) for grpc 84 85 ```protobuf 86 // GetTaskCfg implements a rpc method to get task config 87 rpc GetTaskCfg(GetTaskCfgRequest) returns(GetTaskCfgResponse) { 88 ... 89 } 90 91 // GetTaskCfgRequest is a rpc request for GetTaskCfg 92 message GetTaskCfgRequest { 93 ... 94 } 95 96 // GetTaskCfgRequest is a rpc response for GetTaskCfg 97 message GetTaskCfgResponse { 98 ... 99 } 100 ``` 101 102 2. Generate proto code 103 104 ```sh 105 make generate_proto 106 ``` 107 108 3. Generate mock code 109 110 ```sh 111 make generate_mock 112 ``` 113 114 4. Add new command for dmctl in [root commnd](dm/ctl/ctl.go) 115 116 ```go 117 master.NewGetTaskCfgCmd() 118 ``` 119 120 5. Implement new command for [dmctl](dm/ctl/master/get_task_config.go) 121 122 ```go 123 // NewGetTaskCfgCmd creates a getTaskCfg command 124 func NewGetTaskCfgCmd() *cobra.Command { 125 ... 126 cmd := &cobra.Command{ 127 Run: getTaskCfgFunc, 128 } 129 return cmd 130 } 131 132 // getTaskCfgFunc does get task's config 133 func getTaskCfgFunc(cmd *cobra.Command, _ []string) { 134 ... 135 cli := common.MasterClient() 136 resp, err := cli.GetTaskCfg(ctx, &pb.GetTaskCfgRequest{ 137 Name: taskName, 138 }) 139 common.PrettyPrintResponse(resp) 140 } 141 ``` 142 143 6. Implement new command for [dm-master](dm/master/server.go) 144 145 ```go 146 // GetTaskCfg implements MasterServer.GetSubTaskCfg 147 func (s *Server) GetTaskCfg(ctx context.Context, req *pb.GetTaskCfgRequest) (*pb.GetTaskCfgResponse, error) { 148 ... 149 cfg := s.scheduler.GetTaskCfg(req.Name) 150 return &pb.GetTaskCfgResponse{ 151 Result: true, 152 Cfg: cfg, 153 }, nil 154 } 155 ``` 156 157 7. Add some error instance for your new command in [error_list](pkg/terror/error_list.go) 158 159 ```go 160 ErrSchedulerTaskNotExist = New(codeSchedulerTaskNotExist, ClassScheduler, ScopeInternal, LevelMedium, "task with name %s not exist", "Please use `query-status` command to see tasks.") 161 ``` 162 163 8. Generate new [errors.toml](errors.toml) 164 165 ```sh 166 make terror_check 167 ``` 168 169 9. Build your code 170 171 ```sh 172 make build 173 ``` 174 175 ### Step 7: Add Unit Test 176 177 1. Add unit test for [dm-master server](dm/master/server_test.go) 178 179 ```go 180 func (t *testMaster) TestGetTaskCfg(c *check.C) { 181 ... 182 } 183 ``` 184 185 186 2. Run unit test 187 188 ```sh 189 make unit_test 190 ``` 191 192 ### Step 8: Add Integration Test 193 194 1. Add integration test for [dmctl command](tests/dmctl_basic/check_list/get_task_config.sh) 195 196 ```sh 197 function get_task_config_to_file() { 198 ... 199 } 200 ``` 201 202 2. Setup two MySQL server with binlog enabled first and set `GITD_MODE=ON` 203 204 ```sh 205 docker run --rm --name mysql-3306 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.22 --log-bin=mysql-bin --port=3306 --bind-address=0.0.0.0 --binlog-format=ROW --server-id=1 --gtid_mode=ON --enforce-gtid-consistency=true > mysql.3306.log 2>&1 & 206 docker run --rm --name mysql-3307 -p 3307:3307 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0.21 --log-bin=mysql-bin --port=3307 --bind-address=0.0.0.0 --binlog-format=ROW --server-id=1 --gtid_mode=ON --enforce-gtid-consistency=true > mysql.3307.log 2>&1 & 207 ``` 208 209 3. Run integration test 210 211 ```sh 212 make integration_test 213 ``` 214 215 ### Step 9: Commit your changes 216 217 ```sh 218 git status # Checks the local status 219 git add <file> ... # Adds the file(s) you want to commit. If you want to commit all changes, you can directly use `git add .` 220 git commit -m "commit-message: update the xx" 221 ``` 222 223 ### Step 10: Keep your branch in sync with upstream/master 224 225 ```sh 226 # While on your new branch 227 git fetch upstream 228 git rebase upstream/master 229 ``` 230 231 ### Step 11: Push your changes to the remote 232 233 ```sh 234 git push -u origin new-branch-name # "-u" is used to track the remote branch from origin 235 ``` 236 237 ### Step 12: Create a pull request 238 239 1. Visit your fork at <https://github.com/$user/dm> (replace `$user` with your GitHub ID) 240 2. Click the `Compare & pull request` button next to your `new-branch-name` branch to create your PR. 241 242 Now, your PR is successfully submitted! After this PR is merged, you will automatically become a contributor to DM. 243 244 > **Note:** 245 > 246 > You can find this contribute example in PR [#798](https://github.com/pingcap/dm/pull/798) 247 248 ## Contact 249 250 Join the Slack channel: [#sig-tools](https://tidbcommunity.slack.com/archives/C013HGZMBAR)