From 4f40022105bc6d671bb04c4831ceb961c6f02bee Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Tue, 2 Apr 2024 11:31:25 +0800 Subject: [PATCH] feat: Enhancements to OpenIM Engineering Practices with Standardizer and Tool Versioning (#2159) * feat: add standardizer optimize makefile * feat: add standardizer optimize makefile * feat: add openim test docs * feat: add openim kafka docs * feat: add openim kafka docs * feat: add openim kafka docs --- .github/code-language-detector.yml | 1 + .github/release-drafter.yml | 2 +- .github/standardizer.yml | 50 ++++++ .github/workflows/openimci.yml | 3 + Makefile | 1 + README_zh_CN.md | 2 +- docker-compose-1.yml | 2 +- docker-compose.yml | 2 +- docs/contrib/kafka.md | 162 ++++++++++++++++++ docs/contrib/logging.md | 2 +- docs/contrib/test.md | 86 +++++++++- docs/images/Open-IM.png | Bin 17614 -> 0 bytes .../{Architecture.jpg => architecture.jpg} | Bin docs/images/{Wechat.jpg => wechat.jpg} | Bin go.work | 1 - .../{directResolver.go => direct_resolver.go} | 0 scripts/lib/golang.sh | 3 - scripts/lib/release.sh | 2 +- scripts/make-rules/common-versions.mk | 58 +++++++ scripts/make-rules/common.mk | 7 + scripts/make-rules/tools.mk | 110 +++++++----- scripts/verify-standardizer.sh | 33 ++++ .../{sendMessage.json => send-message.json} | 0 tools/formitychecker/README.md | 102 ----------- tools/formitychecker/checker/checker.go | 113 ------------ tools/formitychecker/config/config.go | 41 ----- tools/formitychecker/formitychecker.go | 41 ----- tools/formitychecker/go.mod | 3 - 28 files changed, 472 insertions(+), 355 deletions(-) create mode 100644 .github/standardizer.yml create mode 100644 docs/contrib/kafka.md delete mode 100644 docs/images/Open-IM.png rename docs/images/{Architecture.jpg => architecture.jpg} (100%) rename docs/images/{Wechat.jpg => wechat.jpg} (100%) rename pkg/common/discoveryregister/direct/{directResolver.go => direct_resolver.go} (100%) create mode 100644 scripts/make-rules/common-versions.mk create mode 100755 scripts/verify-standardizer.sh rename test/testdata/requests/{sendMessage.json => send-message.json} (100%) delete mode 100644 tools/formitychecker/README.md delete mode 100644 tools/formitychecker/checker/checker.go delete mode 100644 tools/formitychecker/config/config.go delete mode 100644 tools/formitychecker/formitychecker.go delete mode 100644 tools/formitychecker/go.mod diff --git a/.github/code-language-detector.yml b/.github/code-language-detector.yml index 32a8c1f54..194c2474a 100644 --- a/.github/code-language-detector.yml +++ b/.github/code-language-detector.yml @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +# https://github.com/marketplace/actions/code-language-detector directory: ./ file_types: - .go diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 154386ff5..55ee241d7 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -48,4 +48,4 @@ template: | ## Contributors to this $REPOSITORY release - $CONTRIBUTORS \ No newline at end of file + $CONTRIBUTORS diff --git a/.github/standardizer.yml b/.github/standardizer.yml new file mode 100644 index 000000000..fceb69df1 --- /dev/null +++ b/.github/standardizer.yml @@ -0,0 +1,50 @@ +# https://github.com/marketplace/actions/conformity-checker-for-project +baseConfig: + searchDirectory: "./" + ignoreCase: false + +directoryNaming: + allowHyphens: true + allowUnderscores: false + mustBeLowercase: true + +fileNaming: + allowHyphens: true + allowUnderscores: true + mustBeLowercase: true + +ignoreFormats: + - "\\.log$" + - "\\.env$" + - "README\\.md$" + - "_test\\.go$" + - "\\.md$" + - _test\\.txt$ + - LICENSE + - Dockerfile + - CODEOWNERS + - Makefile + +ignoreDirectories: + - "vendor" + - ".git" + - "deployments" + - "node_modules" + - "logs" + - "CHANGELOG" + - "components" + - "_output" + - "tools/openim-web" + - "CHANGELOG" + - "examples/Test_directory" + - test/testdata + +fileTypeSpecificNaming: + ".yaml": + allowHyphens: true + allowUnderscores: false + mustBeLowercase: true + ".go": + allowHyphens: false + allowUnderscores: true + mustBeLowercase: true \ No newline at end of file diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index 5aeddd09a..f47283997 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -73,6 +73,9 @@ jobs: - name: Code Typecheck Detector uses: kubecub/typecheck@main + - name: Conformity Checker for Project + uses: kubecub/standardizer@main + - name: Module Operations run: | sudo make tidy diff --git a/Makefile b/Makefile index 89b9e4152..818372fb8 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ VERSION_PACKAGE=github.com/openimsdk/open-im-server/v3/pkg/version # Includes include scripts/make-rules/common.mk # make sure include common.mk at the first include line +include scripts/make-rules/common-versions.mk include scripts/make-rules/golang.mk include scripts/make-rules/image.mk include scripts/make-rules/copyright.mk diff --git a/README_zh_CN.md b/README_zh_CN.md index 7eabfa509..f42031165 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -52,7 +52,7 @@

## 🟢 扫描微信进群交流 - + ## Ⓜ️ 关于 OpenIM diff --git a/docker-compose-1.yml b/docker-compose-1.yml index 39fc944ce..ed852fd29 100644 --- a/docker-compose-1.yml +++ b/docker-compose-1.yml @@ -1,4 +1,4 @@ -#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git +#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/openimsdk/open-im-server.git # The command that triggers this file to pull the image is "docker compose up -f" version: '3' diff --git a/docker-compose.yml b/docker-compose.yml index ef0714329..a983acbaf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git +#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/openimsdk/open-im-server.git # The command that triggers this file to pull the image is "docker compose up -d". version: '3' diff --git a/docs/contrib/kafka.md b/docs/contrib/kafka.md new file mode 100644 index 000000000..4547c9480 --- /dev/null +++ b/docs/contrib/kafka.md @@ -0,0 +1,162 @@ +# OpenIM Kafka Guide + +This document aims to provide a set of concise guidelines to help you quickly install and use Kafka through Docker Compose. + +## Installing Kafka + +With the Docker Compose script provided by OpenIM, you can easily install Kafka. Use the following command to start Kafka: + +```bash +docker compose up -d +``` + +After executing this command, Kafka will be installed and started. You can confirm the Kafka container is running with the following command: + +```bash +docker ps | grep kafka +``` + +The output of this command, as shown below, displays the status information of the Kafka container: + +``` +be416b5a0851 bitnami/kafka:3.5.1 "/opt/bitnami/script…" 3 days ago Up 2 days 9092/tcp, 0.0.0.0:19094->9094/tcp, :::19094->9094/tcp kafka +``` + +### References + +- Official Docker installation documentation: [Click here](http://events.jianshu.io/p/b60afa35303a) +- Detailed installation guide: [Tutorial on Towards Data Science](https://towardsdatascience.com/how-to-install-apache-kafka-using-docker-the-easy-way-4ceb00817d8b) + +## Using Kafka + +### Entering the Kafka Container + +To execute Kafka commands, you first need to enter the Kafka container. Use the following command: + +```bash +docker exec -it kafka bash +``` + +### Kafka Command Tools + +Inside the Kafka container, you can use various command-line tools to manage Kafka. These tools include but are not limited to: + +- `kafka-topics.sh`: For creating, deleting, listing, or altering topics. +- `kafka-console-producer.sh`: Allows sending messages to a specified topic from the command line. +- `kafka-console-consumer.sh`: Allows reading messages from the command line, with the ability to specify topics. +- `kafka-consumer-groups.sh`: For managing consumer group information. + +### Kafka Client Tool Installation + +For easier Kafka management, you can install Kafka client tools. If you installed Kafka through OpenIM's Docker Compose, you can install the Kafka client tools with the following command: + +```bash +make install.kafkactl +``` + +### Automatic Topic Creation + +When installing Kafka through OpenIM's Docker Compose method, OpenIM automatically creates the following topics: + +- `latestMsgToRedis` +- `msgToPush` +- `offlineMsgToMongoMysql` + +These topics are created using the `scripts/create-topic.sh` script. The script waits for Kafka to be ready before executing the commands to create topics: + +```bash +# Wait for Kafka to be ready +until /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server localhost:9092; do + echo "Waiting for Kafka to be ready..." + sleep 2 +done + +# Create topics +/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic latestMsgToRedis +/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic msgToPush +/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 8 --topic offlineMsgToMongoMysql + +echo "Topics created." +``` + +The optimized and expanded documentation further details some basic commands for operations inside the Kafka container, as well as basic commands for managing Kafka using `kafkactl`. Here is a more detailed guide. + + +## Basic Commands in the Kafka Container + +### Listing Topics + +To list all existing topics, you can use the following command: + +```bash +kafka-topics.sh --list --bootstrap-server localhost:9092 +``` + +### Creating a New Topic + +When creating a new topic, you can specify the number of partitions and the replication factor. Here is the command to create a new topic: + +```bash +kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic your_topic_name +``` + +### Producing Messages + +To send messages to a specific topic, you can use the producer command. The following command prompts you to enter messages, which are sent to the specified topic with each press of the Enter key: + +```bash +kafka-console-producer.sh --broker-list localhost:9092 --topic your_topic_name +``` + +### Consuming Messages + +To read messages from a specific topic, you can use the consumer command. The following command reads new messages from the specified topic and outputs them on the console: + +```bash +kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic your_topic_name --from-beginning +``` + +The ` + +--from-beginning` parameter reads messages from the beginning of the topic. If this parameter is omitted, only new messages will be read. + + +## Basic Commands Using `kafkactl` + +`kafkactl` is a command-line tool for managing and operating Kafka clusters. It offers a more modern way to interact with Kafka. + +### Listing Topics + +To list all topics, you can use: + +```bash +kafkactl get topics +``` + +### Creating a New Topic + +To create a new topic with `kafkactl`, use: + +```bash +kafkactl create topic your_topic_name --partitions 1 --replication-factor 1 +``` + +### Producing Messages + +To send messages to a topic, you can use: + +```bash +kafkactl produce your_topic_name --value "your message" +``` + +Here, `"your message"` is the content of the message you want to send. + +### Consuming Messages + +To consume messages from a topic, use: + +```bash +kafkactl consume your_topic_name --from-beginning +``` + +Again, the `--from-beginning` parameter will start consuming messages from the beginning of the topic. If you do not wish to start from the beginning, you can omit this parameter. \ No newline at end of file diff --git a/docs/contrib/logging.md b/docs/contrib/logging.md index e4774929c..c44f6f3c7 100644 --- a/docs/contrib/logging.md +++ b/docs/contrib/logging.md @@ -2,7 +2,7 @@ ## Script Logging Documentation Link -If you wish to view the script's logging documentation, you can click on this link: [Logging Documentation](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/contrib/bash-log.md). +If you wish to view the script's logging documentation, you can click on this link: [Logging Documentation](https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/bash-log.md). Below is the documentation for logging and error handling in the OpenIM Go project. diff --git a/docs/contrib/test.md b/docs/contrib/test.md index 37c1792cf..2470a0537 100644 --- a/docs/contrib/test.md +++ b/docs/contrib/test.md @@ -2,14 +2,94 @@ This document serves as a comprehensive guide to understanding and utilizing the `test.sh` script for testing OpenIM RPC services. The `test.sh` script is a collection of bash functions designed to test various aspects of the OpenIM RPC services, ensuring that each part of the API is functioning as expected. -+ Scripts:https://github.com/OpenIMSDK/Open-IM-Server/tree/main/scripts/install/test.sh ++ Scripts:https://github.com/openimsdk/open-im-server/tree/main/scripts/install/test.sh -For some complex, bulky functional tests, performance tests, and various e2e tests, We are all in the current warehouse to https://github.com/OpenIMSDK/Open-IM-Server/tree/main/test or https://github.com/openim-sigs/test-infra directory In the. +For some complex, bulky functional tests, performance tests, and various e2e tests, We are all in the current warehouse to https://github.com/openimsdk/open-im-server/tree/main/test or https://github.com/openim-sigs/test-infra directory In the. + About OpenIM Feature [Test Docs](https://docs.google.com/spreadsheets/d/1zELWkwxgOOZ7u5pmYCqqaFnvZy2SVajv/edit?usp=sharing&ouid=103266350914914783293&rtpof=true&sd=true) +## Util Test -## Usage +Let's restructure and enhance the document under a unified second-level heading, adding clarity and details for better comprehension and visual appeal. + +--- + +## Development Guide + +### Comprehensive Testing Instructions + +#### Running Unit Tests + +- **Command**: To execute unit tests, input the following in your terminal: + ``` + make test + ``` + +#### Evaluating Test Coverage + +- **Overview**: It's crucial to assess how much of your code is covered by tests. +- **Command**: + ```bash + make cover + ``` + This command generates a report detailing the percentage of your code tested, ensuring adherence to quality standards. + +#### Conducting API Tests + +- **Purpose**: API tests validate the interaction and functionality of your application's interfaces. +- **How to Run**: + ``` + make test-api + ``` + Use this to check the integrity and reliability of your API endpoints. + +#### End-to-End (E2E) Testing + +- **Scope**: E2E tests simulate real-user scenarios from start to finish. +- **Execution**: + ``` + make test-e2e + ``` + This comprehensive testing ensures your application performs as expected in real-world situations. + +### Crafting Unit Test Cases + +#### Setup for Test Case Generation + +- **Installation**: Install the `gotests` tool to generate test cases automatically. + ```bash + make install.gotests + ``` + This command installs the `gotests` tool for test case generation. + +- **Environment Preparation**: Define your test template environment variable and generate test cases as shown below: + ```bash + export GOTESTS_TEMPLATE=testify + gotests -i -w -only keyFunc . + ``` + This prepares your environment for test case generation using the `testify` template. + +#### Isolating Function Tests + +- **Single Function Testing**: When you need to focus on testing a single function for detailed examination. +- **Method**: + ```bash + go test -v -run TestKeyFunc + ``` + This command specifically runs tests for `TestKeyFunc`, allowing targeted debugging and validation. + +### Important Note + +- **Quality Assurance**: Throughout your development process, it is imperative to ensure that the unit test coverage meets or surpasses the standards set by OpenIM. +- **Maintaining Standards**: Regularly running your tests with + ```make test``` + supports maintaining high code quality and adherence to OpenIM's rigorous testing benchmarks. + +## E2E Test + +TODO + +## Api Test The `test.sh` script is located within the `./scripts/install/` directory of the OpenIM service's codebase. To use the script, navigate to this directory from your terminal: diff --git a/docs/images/Open-IM.png b/docs/images/Open-IM.png deleted file mode 100644 index b617065505626ea5df9467ca5e945f851258aee6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17614 zcmZU*2RNJU8#Z3r(we3AtWs)Io1nF+)vAas6t!zhtkRa+_1d+HqLmpsu(y6z`JUss)+go)(FjT_{e8Y(Yu+#rPG|Nd}? z2>)rA3sJ)VBJg~vu5_bhfMo;!<(B<3oo6?0l*N(az_;<=@4nSA_PlX}qV3NQL8sgI z*Eepc*l4Oed*x@b6L^sT?1Zdc5yT(*<2!AGR8jR`}UXCH$s|7d79+L>gQxs zYAvx;*00l5$8AByK1!`R_3tw8d?uHC()!>jk@ad?dF>k;!ej=@GVZWj%Vpq9QSS4% z`olABmIE6X8yNF2#-j$q!Ys&|*J*7)U|lvQtET?CckjxTzW(y0p5fk|TZAD`AKa5x z@T2ei!8YtOyhFG8LnC1B>u1LJx+O8HEA}aB??~! z(}q@&vH|~X(4wDBSa{W)yZWJquI2aM{#W(~Jd~!L^|p3u7JjJk-yIhkmq>EkNBq~K zPIgZK{3TqgrRWJgv-JN;&iwR%3(`?K%<%5`kN@jxR!@2Olh`CuU|Q{~rp5o2%+;Q@ zqTfYpHJ)XBs!ki=b^(Ha$LUx4yIMBjBapXUW61meif^(LvS`+9=v)rU2J|%HH^1}W zY)nGn8{qs~iM4^Ecd@vu3wChu<-~&ZUV~@s-l$aX6OmqAB&Jz4V{n$&h{jI!OWm4SKeo1Sa@=_R^E9agY884`jGT^VQss9fwikH zR`$%l*;h)=bB$;7PXE+tbMV6pzrVX$%`OIjo0}mH`y;?rq+7SHdyK9kFAr0$^}N%n z<8R~#F5uR-whgjPfU7)12%nt=L^f{K{N(E5I_Kq#+WeGGdK1U*w{l4O01x-W$>0^{ z1#t7#vD>TuF0mqCW+~VESR2$r@O5YV#5=p5t5u%n#iR)m%ktIc3YZZF`94eVJaTB} zLg~O`VgN(%x3!caS&@z$Ci&rp9SEk-F@bLeXYp};Hi~C0*D=sn3;ug`XMK8Ed9P%i zrzrFXom2z^Yn}7THAjPv@}lyvA?#$hR{AU(8yh3TevKJq@YVB^vbaD=m|5%Y?xU)P zl2^i(fyYmMureB`_N@HRnX<>R$4`j=EULx+PBKau#of=LhIX!&+M)gIkX29T*Q=qM zvVol7gHeNPvHFJky)2#vRnd#F(hkQY;vlEP`#e_`W1lKn0e<4CitUta0S2f6F%omg zeu$n*FRYC{VE?|Vbbl~T{VeLeL-XZMa|ONS?C8^Qm}mral^5Q(JR-5COH`3 zevQjau?Kpp`TBzV#3=Z9VhUCGxhLoFF&XzU*_%B3rLxYZM016|ZFS{+Q+N^pRuG=_ z!I1-R-9KD;4gCFleNA5d6}}!LHSb&(aL5#Y`q*x@*1USVwxE|ddp6_4nfCo&8uWJM1tNBio=fSesyD({*|Az-oiqxUT*T?n@$ zC4WRqo_d^ZdxAy%iQ9Gr&v|)I90#hfm`%!yTT~} zEL<=|Vlt%I7rS4N+w`@b%#<^qvS(x)OB>=b)jMApAGJ! zlG9tsnX9=|ydI4xar_zFkd+N^amC@NBCZWN$&MpvgrnGz0@*~S8`o|BwJ-n87(*;L zv!I~rWm;rvC^t6ziJS}d-OI~#{@z}cxHmA?H|j%cxFVpi9I$Wtej*Bdj4AxN0X7%- zy=cBYWj_uKYyI3!VBnO1syFk0t7;L%(x|x5)`Jv%q42k#K0EW=Fc!21$&l<7(G{

(=B5HMGYis7g@9X2O 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 diff --git a/docs/images/Architecture.jpg b/docs/images/architecture.jpg similarity index 100% rename from docs/images/Architecture.jpg rename to docs/images/architecture.jpg diff --git a/docs/images/Wechat.jpg b/docs/images/wechat.jpg similarity index 100% rename from docs/images/Wechat.jpg rename to docs/images/wechat.jpg diff --git a/go.work b/go.work index 02e4154d3..7cc1b80a1 100644 --- a/go.work +++ b/go.work @@ -4,7 +4,6 @@ use ( . ./tools/changelog ./tools/component - ./tools/formitychecker ./tools/imctl ./tools/infra ./tools/ncpu diff --git a/pkg/common/discoveryregister/direct/directResolver.go b/pkg/common/discoveryregister/direct/direct_resolver.go similarity index 100% rename from pkg/common/discoveryregister/direct/directResolver.go rename to pkg/common/discoveryregister/direct/direct_resolver.go diff --git a/scripts/lib/golang.sh b/scripts/lib/golang.sh index 7b9d7e60c..f9648cbdb 100755 --- a/scripts/lib/golang.sh +++ b/scripts/lib/golang.sh @@ -314,9 +314,6 @@ openim::golang::setup_platforms readonly OPENIM_CLIENT_TARGETS=( changelog component - conversion-msg - conversion-mysql - formitychecker imctl infra ncpu diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh index c1fbd00a1..05e92377d 100755 --- a/scripts/lib/release.sh +++ b/scripts/lib/release.sh @@ -243,7 +243,7 @@ function openim::release::package_client_tarballs() { local client_bins=("${OPENIM_CLIENT_BINARIES[@]}") - # client_bins: changelog component conversion-msg conversion-mysql formitychecker imctl infra ncpu openim-web up35 versionchecker yamlfmt + # client_bins: changelog component imctl infra ncpu openim-web up35 versionchecker yamlfmt # Copy client binclient_bins:aries openim::log::info " Copy client binaries: ${client_bins[@]/#/${LOCAL_OUTPUT_BINTOOLSPATH}/${platform}/}" openim::log::info " Copy client binaries to: ${release_stage}/client/bin" diff --git a/scripts/make-rules/common-versions.mk b/scripts/make-rules/common-versions.mk new file mode 100644 index 000000000..572585fce --- /dev/null +++ b/scripts/make-rules/common-versions.mk @@ -0,0 +1,58 @@ +# Copyright © 2023 OpenIMSDK. +# +# Licensed 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. +# ============================================================================== +# OpenIM Makefile Versions used +# +# Define the latest version for each tool to ensure consistent versioning across installations +GOLANGCI_LINT_VERSION ?= latest +GOIMPORTS_VERSION ?= latest +ADDLICENSE_VERSION ?= latest +DEEPCOPY_GEN_VERSION ?= latest +CONVERSION_GEN_VERSION ?= latest +GINKGO_VERSION ?= v1.16.2 +GO_GITLINT_VERSION ?= latest +GO_JUNIT_REPORT_VERSION ?= latest +GOTESTS_VERSION ?= latest +SWAGGER_VERSION ?= latest +KUBE_SCORE_VERSION ?= latest +KUBECONFORM_VERSION ?= latest +GSEMVER_VERSION ?= latest +GIT_CHGLOG_VERSION ?= latest +KO_VERSION ?= latest +GITHUB_RELEASE_VERSION ?= latest +COSCLI_VERSION ?= v0.19.0-beta +MINIO_VERSION ?= latest +DELVE_VERSION ?= latest +AIR_VERSION ?= latest +GOLINES_VERSION ?= latest +GO_MOD_OUTDATED_VERSION ?= latest +CFSSL_VERSION ?= latest +DEPTH_VERSION ?= latest +GO_CALLVIS_VERSION ?= latest +MISSPELL_VERSION ?= latest +GOTHANKS_VERSION ?= latest +RICHGO_VERSION ?= latest +RTS_VERSION ?= latest +TYPECHECK_VERSION ?= latest +COMMENT_LANG_DETECTOR_VERSION ?= latest +STANDARDIZER_VERSION ?= latest +GO_TESTS_VERSION ?= v1.6.0 +GO_APIDIFF_VERSION ?= v0.8.2 +KAFKACTL_VERSION ?= latest +GOTESTSUM_VERSION ?= latest + +WIRE_VERSION ?= latest +# WIRE_VERSION ?= $(call get_go_version,github.com/google/wire) +MOCKGEN_VERSION ?= $(call get_go_version,github.com/golang/mock) +PROTOC_GEN_GO_VERSION ?= $(call get_go_version,github.com/golang/protobuf/protoc-gen-go) \ No newline at end of file diff --git a/scripts/make-rules/common.mk b/scripts/make-rules/common.mk index f8537b6ca..ffbb69a55 100644 --- a/scripts/make-rules/common.mk +++ b/scripts/make-rules/common.mk @@ -78,6 +78,13 @@ VERSION := $(shell git describe --tags --always --match='v*') # v2.3.3: git tag endif +# Helper function to get dependency version from go.mod +get_gomod_version = $(shell go list -m $1 | awk '{print $$2}') +define go_install +$(info ===========> Installing $(1)@$(2)) +$(GO) install $(1)@$(2) +endef + # Check if the tree is dirty. default to dirty(maybe u should commit?) GIT_TREE_STATE:="dirty" ifeq (, $(shell git status --porcelain 2>/dev/null)) diff --git a/scripts/make-rules/tools.mk b/scripts/make-rules/tools.mk index 917c18cfe..5335d094d 100644 --- a/scripts/make-rules/tools.mk +++ b/scripts/make-rules/tools.mk @@ -64,81 +64,101 @@ tools.verify.%: ## install.golangci-lint: Install golangci-lint .PHONY: install.golangci-lint install.golangci-lint: - @$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + @$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) ## install.goimports: Install goimports, used to format go source files .PHONY: install.goimports install.goimports: - @$(GO) install golang.org/x/tools/cmd/goimports@latest + @$(GO) install golang.org/x/tools/cmd/goimports@$(GOIMPORTS_VERSION) ## install.addlicense: Install addlicense, used to add license header to source files .PHONY: install.addlicense install.addlicense: - @$(GO) install github.com/google/addlicense@latest + @$(GO) install github.com/google/addlicense@$(ADDLICENSE_VERSION) ## install.deepcopy-gen: Install deepcopy-gen, used to generate deep copy functions .PHONY: install.deepcopy-gen install.deepcopy-gen: - @$(GO) install k8s.io/code-generator/cmd/deepcopy-gen@latest + @$(GO) install k8s.io/code-generator/cmd/deepcopy-gen@$(DEEPCOPY_GEN_VERSION) ## install.conversion-gen: Install conversion-gen, used to generate conversion functions .PHONY: install.conversion-gen install.conversion-gen: - @$(GO) install k8s.io/code-generator/cmd/conversion-gen@latest + @$(GO) install k8s.io/code-generator/cmd/conversion-gen@$(CONVERSION_GEN_VERSION) ## install.ginkgo: Install ginkgo to run a single test or set of tests .PHONY: install.ginkgo install.ginkgo: - @$(GO) install github.com/onsi/ginkgo/ginkgo@v1.16.2 + @$(GO) install github.com/onsi/ginkgo/ginkgo@$(GINKGO_VERSION) -## Install go-gitlint: Install go-gitlint, used to check git commit message +## install.go-gitlint: Install go-gitlint, used to check git commit message .PHONY: install.go-gitlint install.go-gitlint: - @$(GO) install github.com/marmotedu/go-gitlint/cmd/go-gitlint@latest + @$(GO) install github.com/marmotedu/go-gitlint/cmd/go-gitlint@$(GO_GITLINT_VERSION) ## install.go-junit-report: Install go-junit-report, used to convert go test output to junit xml .PHONY: install.go-junit-report install.go-junit-report: - @$(GO) install github.com/jstemmer/go-junit-report@latest + @$(GO) install github.com/jstemmer/go-junit-report@$(GO_JUNIT_REPORT_VERSION) ## install.gotests: Install gotests, used to generate go tests +.PHONY: install.gotests +install.gotests: + @$(GO) install github.com/cweill/gotests/gotests@$(GO_TESTS_VERSION) + +## install.kafkactl: Install kafkactl command line tool. +.PHONY: install.kafkactl +install.kafkactl: + @$(GO) install github.com/deviceinsight/kafkactl@$(KAFKACTL_VERSION) + +## install.go-apidiff: Install go-apidiff, used to check api changes +.PHONY: install.go-apidiff +install.go-apidiff: + @$(GO) install github.com/joelanford/go-apidiff@$(GO_APIDIFF_VERSION) + +## install.swagger: Install swagger, used to generate swagger documentation .PHONY: install.swagger install.swagger: - @$(GO) install github.com/go-swagger/go-swagger/cmd/swagger@latest + @$(GO) install github.com/go-swagger/go-swagger/cmd/swagger@$(SWAGGER_VERSION) # ============================================================================== # Tools that might be used include go gvm # +## install.gotestsum: Install gotestsum, used to run go tests +.PHONY: install.gotestsum +install.gotestsum: + @$(GO) install gotest.tools/gotestsum@$(GOTESTSUM_VERSION) + ## install.kube-score: Install kube-score, used to check kubernetes yaml files .PHONY: install.kube-score install.kube-score: - @$(GO) install github.com/zegl/kube-score/cmd/kube-score@latest + @$(GO) install github.com/zegl/kube-score/cmd/kube-score@$(KUBE_SCORE_VERSION) ## install.kubeconform: Install kubeconform, used to check kubernetes yaml files .PHONY: install.kubeconform install.kubeconform: - @$(GO) install github.com/yannh/kubeconform/cmd/kubeconform@latest + @$(GO) install github.com/yannh/kubeconform/cmd/kubeconform@$(KUBECONFORM_VERSION) ## install.gsemver: Install gsemver, used to generate semver .PHONY: install.gsemver install.gsemver: - @$(GO) install github.com/arnaud-deprez/gsemver@latest + @$(GO) install github.com/arnaud-deprez/gsemver@$(GSEMVER_VERSION) ## install.git-chglog: Install git-chglog, used to generate changelog .PHONY: install.git-chglog install.git-chglog: - @$(GO) install github.com/git-chglog/git-chglog/cmd/git-chglog@latest + @$(GO) install github.com/git-chglog/git-chglog/cmd/git-chglog@$(GIT_CHGLOG_VERSION) ## install.ko: Install ko, used to build go program into container images .PHONY: install.ko install.ko: - @$(GO) install github.com/google/ko@latest + @$(GO) install github.com/google/ko@$(KO_VERSION) ## install.github-release: Install github-release, used to create github release .PHONY: install.github-release install.github-release: - @$(GO) install github.com/github-release/github-release@latest + @$(GO) install github.com/github-release/github-release@$(GITHUB_RELEASE_VERSION) ## install.coscli: Install coscli, used to upload files to cos # example: ./coscli cp/sync -r /home/off-line/docker-off-line/ cos://openim-1306374445/openim/image/amd/off-line/off-line/ -e cos.ap-guangzhou.myqcloud.com @@ -146,7 +166,7 @@ install.github-release: # amd64 .PHONY: install.coscli install.coscli: - @wget -q https://github.com/tencentyun/coscli/releases/download/v0.19.0-beta/coscli-linux -O ${TOOLS_DIR}/coscli + @wget -q https://github.com/tencentyun/coscli/releases/download/$(COSCLI_VERSION)/coscli-linux -O ${TOOLS_DIR}/coscli @chmod +x ${TOOLS_DIR}/coscli ## install.coscmd: Install coscmd, used to upload files to cos @@ -157,50 +177,50 @@ install.coscmd: ## install.minio: Install minio, used to upload files to minio .PHONY: install.minio install.minio: - @$(GO) install github.com/minio/minio@latest + @$(GO) install github.com/minio/minio@$(MINIO_VERSION) ## install.delve: Install delve, used to debug go program .PHONY: install.delve install.delve: - @$(GO) install github.com/go-delve/delve/cmd/dlv@latest + @$(GO) install github.com/go-delve/delve/cmd/dlv@$(DELVE_VERSION) ## install.air: Install air, used to hot reload go program .PHONY: install.air install.air: - @$(GO) install github.com/cosmtrek/air@latest + @$(GO) install github.com/cosmtrek/air@$(AIR_VERSION) ## install.gvm: Install gvm, gvm is a Go version manager, built on top of the official go tool. -# github: https://github.com/moovweb/gvm .PHONY: install.gvm install.gvm: - @echo "===========> Installing gvm,The default installation path is ~/.gvm/scripts/gvm" + @echo "===========> Installing gvm, The default installation path is ~/.gvm/scripts/gvm" @bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) - @$(shell source /root/.gvm/scripts/gvm) + @source /root/.gvm/scripts/gvm ## install.golines: Install golines, used to format long lines .PHONY: install.golines install.golines: - @$(GO) install github.com/segmentio/golines@latest + @$(GO) install github.com/segmentio/golines@$(GOLINES_VERSION) ## install.go-mod-outdated: Install go-mod-outdated, used to check outdated dependencies .PHONY: install.go-mod-outdated install.go-mod-outdated: - @$(GO) install github.com/psampaz/go-mod-outdated@latest + @$(GO) install github.com/psampaz/go-mod-outdated@$(GO_MOD_OUTDATED_VERSION) ## install.mockgen: Install mockgen, used to generate mock functions .PHONY: install.mockgen install.mockgen: - @$(GO) install github.com/golang/mock/mockgen@latest + @$(GO) install github.com/golang/mock/mockgen@$(MOCKGEN_VERSION) + +## install.wire: Install wire, used to generate wire files +.PHONY: install.wire +install.wire: + @$(GO) install github.com/google/wire/cmd/wire@$(WIRE_VERSION) -## install.gotests: Install gotests, used to generate test functions -.PHONY: install.gotests -install.gotests: - @$(GO) install github.com/cweill/gotests/gotests@latest ## install.protoc-gen-go: Install protoc-gen-go, used to generate go source files from protobuf files .PHONY: install.protoc-gen-go install.protoc-gen-go: - @$(GO) install github.com/golang/protobuf/protoc-gen-go@latest + @$(GO) install github.com/golang/protobuf/protoc-gen-go@$(PROTOC_GEN_GO_VERSION) ## install.cfssl: Install cfssl, used to generate certificates .PHONY: install.cfssl @@ -210,43 +230,49 @@ install.cfssl: ## install.depth: Install depth, used to check dependency tree .PHONY: install.depth install.depth: - @$(GO) install github.com/KyleBanks/depth/cmd/depth@latest + @$(GO) install github.com/KyleBanks/depth/cmd/depth@$(DEPTH_VERSION) ## install.go-callvis: Install go-callvis, used to visualize call graph .PHONY: install.go-callvis install.go-callvis: - @$(GO) install github.com/ofabry/go-callvis@latest + @$(GO) install github.com/ofabry/go-callvis@$(GO_CALLVIS_VERSION) -## install.misspell +## install.misspell: Install misspell .PHONY: install.misspell install.misspell: - @$(GO) install github.com/client9/misspell/cmd/misspell@latest + @$(GO) install github.com/client9/misspell/cmd/misspell@$(MISSPELL_VERSION) ## install.gothanks: Install gothanks, used to thank go dependencies .PHONY: install.gothanks install.gothanks: - @$(GO) install github.com/psampaz/gothanks@latest + @$(GO) install github.com/psampaz/gothanks@$(GOTHANKS_VERSION) ## install.richgo: Install richgo .PHONY: install.richgo install.richgo: - @$(GO) install github.com/kyoh86/richgo@latest + @$(GO) install github.com/kyoh86/richgo@$(RICHGO_VERSION) ## install.rts: Install rts .PHONY: install.rts install.rts: - @$(GO) install github.com/galeone/rts/cmd/rts@latest + @$(GO) install github.com/galeone/rts/cmd/rts@$(RTS_VERSION) # ================= kubecub openim tools ========================================= -## install.typecheck: install kubecub typecheck check for go code +# https://github.com/kubecub +## install.typecheck: Install kubecub typecheck, checks for go code .PHONY: install.typecheck install.typecheck: - @$(GO) install github.com/kubecub/typecheck@latest + @$(GO) install github.com/kubecub/typecheck@$(TYPECHECK_VERSION) -## install.comment-lang-detector: install kubecub comment-lang-detector check for go code comment language +## install.comment-lang-detector: Install kubecub comment-lang-detector, checks for go code comment language .PHONY: install.comment-lang-detector install.comment-lang-detector: - @$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@latest + @$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@$(COMMENT_LANG_DETECTOR_VERSION) + +## install.standardizer: Install kubecub standardizer, checks for go code standardization +.PHONY: install.standardizer +install.standardizer: + @$(GO) install github.com/kubecub/standardizer@$(STANDARDIZER_VERSION) ## tools.help: Display help information about the tools package .PHONY: tools.help diff --git a/scripts/verify-standardizer.sh b/scripts/verify-standardizer.sh new file mode 100755 index 000000000..08a13b9a2 --- /dev/null +++ b/scripts/verify-standardizer.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Copyright © 2023 OpenIM. All rights reserved. +# +# Licensed 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. + +# This script does a fast type check of script srnetes code for all platforms. +# Usage: `scripts/verify-standardizer.sh`. + +OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. +source "${OPENIM_ROOT}/scripts/lib/init.sh" + +openim::golang::verify_go_version + +cd "${OPENIM_ROOT}" +ret=0 +scripts/run-in-gopath.sh \ +make tools.verify.standardizer +${OPENIM_ROOT}/_output/tools/standardizer || ret=$? +if [[ $ret -ne 0 ]]; then + openim::log::error "Failed to check the directory name or file name. Your name may not meet the specification. Please check the configuration file and the directory or file name." >&2 + openim::log::error "Please see https://github.com/kubecub/standardizer for more information." >&2 + exit 1 +fi diff --git a/test/testdata/requests/sendMessage.json b/test/testdata/requests/send-message.json similarity index 100% rename from test/testdata/requests/sendMessage.json rename to test/testdata/requests/send-message.json diff --git a/tools/formitychecker/README.md b/tools/formitychecker/README.md deleted file mode 100644 index 7cabf8a66..000000000 --- a/tools/formitychecker/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# Development of a Go-Based Conformity Checker for Project File and Directory Naming Standards - -### 1. Project Overview - -#### Project Name - -- `GoConformityChecker` - -#### Functionality Description - -- Checks if the file and subdirectory names in a specified directory adhere to specific naming conventions. -- Supports specific file types (e.g., `.go`, `.yml`, `.yaml`, `.md`, `.sh`, etc.). -- Allows users to specify directories to be checked and directories to be ignored. -- More read https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md - -#### Naming Conventions - -- Go files: Only underscores are allowed. -- YAML, YML, and Markdown files: Only hyphens are allowed. -- Directories: Only underscores are allowed. - -### 2. File Structure - -- `main.go`: Entry point of the program, handles command-line arguments. -- `checker/checker.go`: Contains the core logic. -- `config/config.go`: Parses and stores configuration information. - -### 3. Core Code Design - -#### main.go - -- Parses command-line arguments, including the directory to be checked and directories to be ignored. -- Calls the `checker` module for checking. - -#### config.go - -- Defines a configuration structure, such as directories to check and ignore. - -#### checker.go - -- Iterates through the specified directory. -- Applies different naming rules based on file types and directory names. -- Records files or directories that do not conform to the standards. - -### 4. Pseudocode Example - -#### main.go - -```go -package main - -import ( - "flag" - "fmt" - "GoConformityChecker/checker" -) - -func main() { - // Parse command-line arguments - var targetDir string - var ignoreDirs string - flag.StringVar(&targetDir, "target", ".", "Directory to check") - flag.StringVar(&ignoreDirs, "ignore", "", "Directories to ignore") - flag.Parse() - - // Call the checker - err := checker.CheckDirectory(targetDir, ignoreDirs) - if err != nil { - fmt.Println("Error:", err) - } -} -``` - -#### checker.go - -```go -package checker - -import ( - // Import necessary packages -) - -func CheckDirectory(targetDir, ignoreDirs string) error { - // Iterate through the directory, applying rules to check file and directory names - // Return any found errors or non-conformities - return nil -} -``` - -### 5. Implementation Details - -- **File and Directory Traversal**: Use Go's `path/filepath` package to traverse directories and subdirectories. -- **Naming Rules Checking**: Apply different regex expressions for naming checks based on file extensions. -- **Error Handling and Reporting**: Record files or directories that do not conform and report to the user. - -### 6. Future Development and Extensions - -- Support more file types and naming rules. -- Provide more detailed error reports, such as showing line numbers and specific naming mistakes. -- Add a graphical or web interface for non-command-line users. - -The above is an overview of the entire project's design. Following this design, specific coding implementation can begin. Note that the actual implementation may need adjustments based on real-world conditions. \ No newline at end of file diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go deleted file mode 100644 index b17cc5427..000000000 --- a/tools/formitychecker/checker/checker.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed 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. - -package checker - -import ( - "fmt" - "os" - "path/filepath" - "regexp" - "strings" - - "github.com/OpenIMSDK/tools/errs" - - "github.com/openimsdk/open-im-server/tools/formitychecker/config" -) - -var ( - underscoreRegex = regexp.MustCompile(`^[a-zA-Z0-9_]+\.[a-zA-Z0-9]+$`) - hyphenRegex = regexp.MustCompile(`^[a-zA-Z0-9\-]+\.[a-zA-Z0-9]+$`) -) - -// CheckDirectory initiates the checking process for the specified directories using configuration from config.Config. -func CheckDirectory(cfg *config.Config) error { - ignoreMap := make(map[string]struct{}) - for _, dir := range cfg.IgnoreDirs { - ignoreMap[dir] = struct{}{} - } - - for _, targetDir := range cfg.TargetDirs { - err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return errs.Wrap(err, fmt.Sprintf("error walking directory '%s'", targetDir)) - } - - // Skip if the directory is in the ignore list - dirName := filepath.Base(filepath.Dir(path)) - if _, ok := ignoreMap[dirName]; ok && info.IsDir() { - return filepath.SkipDir - } - - // Check the naming convention - if err := checkNamingConvention(path, info); err != nil { - fmt.Println(err) - } - - return nil - }) - - if err != nil { - return fmt.Errorf("error checking directory '%s': %w", targetDir, err) - } - } - - return nil -} - -// checkNamingConvention checks if the file or directory name conforms to the standard naming conventions. -func checkNamingConvention(path string, info os.FileInfo) error { - fileName := info.Name() - - // Handle special cases for directories like .git - if info.IsDir() && strings.HasPrefix(fileName, ".") { - return nil // Skip special directories - } - - // Extract the main part of the name (without extension for files) - mainName := fileName - if !info.IsDir() { - mainName = strings.TrimSuffix(fileName, filepath.Ext(fileName)) - } - - // Determine the type of file and apply corresponding naming rule - switch { - case info.IsDir(): - if !isValidName(mainName, "_") { // Directory names must only contain underscores - return fmt.Errorf("!!! invalid directory name: %s", path) - } - case strings.HasSuffix(fileName, ".go"): - if !isValidName(mainName, "_") { // Go files must only contain underscores - return fmt.Errorf("!!! invalid Go file name: %s", path) - } - case strings.HasSuffix(fileName, ".yml"), strings.HasSuffix(fileName, ".yaml"), strings.HasSuffix(fileName, ".md"): - if !isValidName(mainName, "-") { // YML, YAML, and Markdown files must only contain hyphens - return fmt.Errorf("!!! invalid file name: %s", path) - } - } - - return nil -} - -// isValidName checks if the file name conforms to the specified rule (underscore or hyphen). -func isValidName(name, charType string) bool { - switch charType { - case "_": - return underscoreRegex.MatchString(name) - case "-": - return hyphenRegex.MatchString(name) - default: - return false - } -} diff --git a/tools/formitychecker/config/config.go b/tools/formitychecker/config/config.go deleted file mode 100644 index 0c4f6a16b..000000000 --- a/tools/formitychecker/config/config.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed 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. - -package config - -import ( - "strings" -) - -// Config holds all the configuration parameters for the checker. -type Config struct { - TargetDirs []string // Directories to check - IgnoreDirs []string // Directories to ignore -} - -// NewConfig creates and returns a new Config instance. -func NewConfig(targetDirs, ignoreDirs string) *Config { - return &Config{ - TargetDirs: parseDirs(targetDirs), - IgnoreDirs: parseDirs(ignoreDirs), - } -} - -// parseDirs splits a comma-separated string into a slice of directory names. -func parseDirs(dirs string) []string { - if dirs == "" { - return nil - } - return strings.Split(dirs, ",") -} diff --git a/tools/formitychecker/formitychecker.go b/tools/formitychecker/formitychecker.go deleted file mode 100644 index 2bedbfb32..000000000 --- a/tools/formitychecker/formitychecker.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed 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. - -package main - -import ( - "flag" - "fmt" - - "github.com/openimsdk/open-im-server/tools/formitychecker/checker" - "github.com/openimsdk/open-im-server/tools/formitychecker/config" -) - -func main() { - defaultTargetDirs := "." - defaultIgnoreDirs := "components,.git" - - var targetDirs string - var ignoreDirs string - flag.StringVar(&targetDirs, "target", defaultTargetDirs, "Directories to check (default: current directory)") - flag.StringVar(&ignoreDirs, "ignore", defaultIgnoreDirs, "Directories to ignore (default: A/, B/)") - flag.Parse() - - conf := config.NewConfig(targetDirs, ignoreDirs) - - err := checker.CheckDirectory(conf) - if err != nil { - fmt.Println("Error:", err) - } -} diff --git a/tools/formitychecker/go.mod b/tools/formitychecker/go.mod deleted file mode 100644 index 698b77647..000000000 --- a/tools/formitychecker/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/openimsdk/open-im-server/tools/formitychecker - -go 1.19