From 48df76fb8bc10841d4f3c9e85b830fcd46c3cd53 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751NSS@gmail.com> Date: Sun, 31 Mar 2024 12:40:35 +0800 Subject: [PATCH 1/2] docs: update openim images docs deployment aliyun (#2154) --- docs/contrib/images.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/contrib/images.md b/docs/contrib/images.md index d1a83d639..396ffb2e3 100644 --- a/docs/contrib/images.md +++ b/docs/contrib/images.md @@ -96,4 +96,21 @@ When pulling OpenIM's Docker images, you can choose the most suitable source bas 3. Run the `docker images` command to confirm that the image has been successfully pulled. -This concludes OpenIM's image management strategy and the steps for pulling images. If you have any questions, please feel free to ask. +### Accelerating Deployment for Users in China with Aliyun Mirror or Alternative Image Addresses + +For users in China looking to speed up the deployment process of OpenIM, leveraging a mirror image address is a highly recommended practice. After executing the `make init` command, a `.env` file is generated, which you'll need to edit to configure the image registry source. This configuration is crucial for optimizing download speeds and ensuring a smoother setup process. + +Within the generated `.env` file, you'll find a section dedicated to choosing the image address. It includes options for GitHub (`ghcr.io/openimsdk`), Docker Hub (`openim`), and Ali Cloud (`registry.cn-hangzhou.aliyuncs.com/openimsdk`). To achieve the best performance within China, it is advised to use the Aliyun image address. + +To do this, you need to comment out the current `IMAGE_REGISTRY` setting and uncomment the Aliyun option. Here is how you can adjust it for Aliyun: + +```bash +# Choose the image address: GitHub (ghcr.io/openimsdk), Docker Hub (openim), +# or Ali Cloud (registry.cn-hangzhou.aliyuncs.com/openimsdk). +# Uncomment one of the following three options. Aliyun is recommended for users in China. +# IMAGE_REGISTRY="ghcr.io/openimsdk" +# IMAGE_REGISTRY="openim" +IMAGE_REGISTRY="registry.cn-hangzhou.aliyuncs.com/openimsdk" +``` + +This change directs the deployment process to fetch the required images from the Aliyun registry, significantly improving download and installation speeds due to the geographical and network advantages within China. If, for any reason, you prefer not to use Aliyun or encounter issues, consider switching to another mirror address listed in the `.env` file by following the same uncommenting process. This flexibility ensures that users can select the most suitable image source for their specific situation, leading to a more efficient deployment of OpenIM. 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 2/2] 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