├── .gitattributes
├── .github
└── workflows
│ ├── build.yml
│ └── release.yaml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── build.gradle.kts
├── connection.template.yml
├── devops-genius.yml
├── docs
├── .gitignore
├── CNAME
├── _config.yml
├── business
│ └── business-review.md
├── ci
│ └── ci.md
├── code-review
│ ├── code-review.md
│ ├── prompt-design.md
│ └── research.md
├── index.md
├── issue
│ └── issue.md
├── logo.svg
└── usage.md
├── fixtures
├── example.json
└── prompt.unit-mesh.yml
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── prompt-test.main.kts
├── settings.gradle.kts
└── src
├── main
├── kotlin
│ └── cc
│ │ └── unitmesh
│ │ └── genius
│ │ ├── CiCdCommand.kt
│ │ ├── CodeReviewCommand.kt
│ │ ├── IssueCommand.kt
│ │ ├── Main.kt
│ │ ├── context
│ │ ├── ActionOption.kt
│ │ └── GeniusAction.kt
│ │ ├── devops
│ │ ├── Issue.kt
│ │ ├── KanbanFactory.kt
│ │ └── kanban
│ │ │ ├── GitHubKanban.kt
│ │ │ ├── GitlabKanban.kt
│ │ │ └── Kanban.kt
│ │ ├── domain
│ │ ├── cicd
│ │ │ ├── CiFileGenerator.kt
│ │ │ └── GitHubActionPromptFactory.kt
│ │ └── review
│ │ │ ├── CodeReviewAction.kt
│ │ │ ├── CodeReviewContext.kt
│ │ │ ├── CodeReviewPromptFactory.kt
│ │ │ └── ReviewOption.kt
│ │ ├── project
│ │ ├── BuildSystemType.java
│ │ ├── BuildSystemTypeDescriptor.kt
│ │ └── GeniusProject.kt
│ │ └── prompt
│ │ ├── PromptBuilder.kt
│ │ ├── PromptFactory.kt
│ │ └── PromptsLoader.kt
└── resources
│ ├── code-review
│ └── simple-review.open-ai.vm
│ ├── container
│ └── docker
│ │ └── docker-file.vm
│ ├── logback.xml
│ └── prompts
│ └── cicd
│ ├── github
│ ├── common
│ │ ├── github_actions_events.prompt
│ │ └── github_actions_publish_docker.prompt
│ ├── gradle
│ │ ├── github_actions_build_gradle.prompt
│ │ └── github_actions_publish_gradle.prompt
│ └── maven
│ │ ├── github_actions_build_maven.prompt
│ │ └── github_actions_publish_maven.prompt
│ └── jenkins
│ └── gradle
│ └── jenkins_build_gradle.prompt
└── test
└── kotlin
└── cc
└── unitmesh
└── genius
├── devops
├── KanbanFactoryTest.kt
└── kanban
│ └── GitHubKanbanTest.kt
├── domain
└── review
│ └── CodeReviewPromptFactoryTest.kt
└── project
└── GeniusProjectTest.kt
/.gitattributes:
--------------------------------------------------------------------------------
1 | #
2 | # https://help.github.com/articles/dealing-with-line-endings/
3 | #
4 | # Linux start script should use lf
5 | /gradlew text eol=lf
6 |
7 | # These are Windows script files and should use crlf
8 | *.bat text eol=crlf
9 |
10 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [ push ]
4 |
5 | jobs:
6 | build:
7 | strategy:
8 | matrix:
9 | os: [ macos-latest, ubuntu-latest, windows-latest ]
10 | runs-on: ${{ matrix.os }}
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 | with:
15 | fetch-depth: 10
16 | - uses: actions/setup-java@v3
17 | with:
18 | distribution: 'zulu'
19 | java-version: '17'
20 |
21 | - name: Setup Gradle
22 | uses: gradle/gradle-build-action@v2.8.0
23 | with:
24 | arguments: build
25 |
26 | - name: Execute Gradle build
27 | run: ./gradlew build
28 |
29 | - name: Execute Gradle Coverage
30 | run: ./gradlew check
31 |
32 | - name: Execute Gradle Coverage
33 | if: runner.os == 'macOS'
34 | run: bash <(curl -s https://codecov.io/bash)
35 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | jobs:
9 | publish:
10 | runs-on: ubuntu-latest
11 | strategy:
12 | matrix:
13 | assets:
14 | - build/libs/devops-genius-*.jar
15 |
16 | permissions:
17 | contents: write
18 | packages: write
19 | steps:
20 | - uses: actions/checkout@v3
21 | - uses: actions/setup-java@v3
22 | with:
23 | distribution: 'zulu'
24 | java-version: '17'
25 | cache: 'gradle'
26 |
27 | - name: Setup Gradle
28 | run: ./gradlew build --no-daemon -x test
29 |
30 | - name: Upload assets to release
31 | uses: svenstaro/upload-release-action@v2
32 | with:
33 | repo_token: ${{ secrets.GITHUB_TOKEN }}
34 | file: ${{ matrix.assets }}
35 | tag: ${{ github.ref }}
36 | overwrite: true
37 | file_glob: true
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | .gradle
3 | build/
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### STS ###
9 | .apt_generated
10 | .classpath
11 | .factorypath
12 | .project
13 | .settings
14 | .springBeans
15 | .sts4-cache
16 | bin/
17 | !**/src/main/**/bin/
18 | !**/src/test/**/bin/
19 |
20 | ### IntelliJ IDEA ###
21 | .idea
22 | *.iws
23 | *.iml
24 | *.ipr
25 | out/
26 | !**/src/main/**/out/
27 | !**/src/test/**/out/
28 |
29 | ### NetBeans ###
30 | /nbproject/private/
31 | /nbbuild/
32 | /dist/
33 | /nbdist/
34 | /.nb-gradle/
35 |
36 | ### VS Code ###
37 | .vscode/
38 | .env
39 | build/
40 | connection.yml
41 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # [](https://github.com/unit-mesh/devops-genius/compare/v0.1.0...v) (2023-10-19)
2 |
3 |
4 |
5 | # [0.1.0](https://github.com/unit-mesh/devops-genius/compare/d088ed8e0172b58594529a4a73ef04f6da5f3e7b...v0.1.0) (2023-10-19)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * **devops:** add more testcases for commit message [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([0f63500](https://github.com/unit-mesh/devops-genius/commit/0f63500e0048203bf155d01dc4ab914dd1b1e831))
11 | * **devops:** fix testing for commit message [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([ed6aad0](https://github.com/unit-mesh/devops-genius/commit/ed6aad04d6c60c474627e7fc839c4c4b08aecd52))
12 | * fix tests ([5ef300b](https://github.com/unit-mesh/devops-genius/commit/5ef300b6bb178dbea7f6a4603e4087e65e43b8d5))
13 | * fix tets ([0a4a7fc](https://github.com/unit-mesh/devops-genius/commit/0a4a7fc093bb2a65e2655fd72dd6da2375060822))
14 | * fix typos ([81ad5bb](https://github.com/unit-mesh/devops-genius/commit/81ad5bb7f7698e50d90971119b56dc26b26f9b09))
15 | * try to handle for Windows ([a3a3e2f](https://github.com/unit-mesh/devops-genius/commit/a3a3e2f5892e9b639509a74b459ade84af20e5f7))
16 |
17 |
18 | ### Features
19 |
20 | * add: for new line end of line handle ([d27187f](https://github.com/unit-mesh/devops-genius/commit/d27187f621e601e57ac715312c87a29338df5c01))
21 | * **devops:** add explain prompt for testing [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([057bc64](https://github.com/unit-mesh/devops-genius/commit/057bc648a36604ffa3dd288642ad8c98753ac3d5))
22 | * **devops:** add filter for patterns [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([5733afe](https://github.com/unit-mesh/devops-genius/commit/5733afeec7042bf1a6f27c0549bde9f69c36055e))
23 | * **devops:** add simple line match for commit [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([b40a354](https://github.com/unit-mesh/devops-genius/commit/b40a354c0fea5c1aa41c0d34e115a0444e91e302))
24 | * **devops:** feat first version git log parser [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([012cc3f](https://github.com/unit-mesh/devops-genius/commit/012cc3f519c09c55676fa3cebe8adeadebdbbb26))
25 | * **devops:** init basic ci/cd scripts ([93c985b](https://github.com/unit-mesh/devops-genius/commit/93c985b27e2a4a723c92a051c1000a7b4ee66758))
26 | * **devops:** init basic for debug [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([3daa9a1](https://github.com/unit-mesh/devops-genius/commit/3daa9a17e0c54f823486f9fd39b1797ddc81edb3))
27 | * **devops:** init basic system build ([a441157](https://github.com/unit-mesh/devops-genius/commit/a44115749485d783891b0443b2b1f724686b9ad1))
28 | * **devops:** init basic workflow [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([38272ba](https://github.com/unit-mesh/devops-genius/commit/38272ba8c5293c7c4507b276702a56a5f049a05e))
29 | * **devops:** init featch issue logic for github [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([78a49be](https://github.com/unit-mesh/devops-genius/commit/78a49be0549b43ea55003ea45b4a655dade4dd48))
30 | * **devops:** init first review command [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([b9f51cc](https://github.com/unit-mesh/devops-genius/commit/b9f51cc02daeaa524f5a15cefc3e4d3e76d004ca))
31 | * **devops:** init for github and gitlab parser [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([3abad42](https://github.com/unit-mesh/devops-genius/commit/3abad429131f2f4fcf4c094b42241d9cb0a4066f))
32 | * **devops:** init issue parser [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([fe8c709](https://github.com/unit-mesh/devops-genius/commit/fe8c709538b0290ff391d54436ec1098e84c9d4d))
33 | * **devops:** init parser for generate patch [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([a31780e](https://github.com/unit-mesh/devops-genius/commit/a31780e7a2da19bbb93fdb4667aff2bf3ebdbde5))
34 | * **devops:** init project config [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([9a2abea](https://github.com/unit-mesh/devops-genius/commit/9a2abea815a3a333c60ad732c9e779c76d7da3ff))
35 | * **devops:** init project config for yaml [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([3ff6e43](https://github.com/unit-mesh/devops-genius/commit/3ff6e4392fdc0ebde3570b6d71b5c8e0417005ab))
36 | * **devops:** init prompt factory [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([bd18659](https://github.com/unit-mesh/devops-genius/commit/bd18659f0814af614228bd161ed70f69a80c0df2))
37 | * **devops:** init prompt testing scripts [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([e55da1e](https://github.com/unit-mesh/devops-genius/commit/e55da1e04ba8dbfb6dd20b0006e536eae68b34ef))
38 | * init basic commands ([be9efde](https://github.com/unit-mesh/devops-genius/commit/be9efde6d944d9fed25643b40cd0091c0b5fb58a))
39 | * init basic genius command ([d088ed8](https://github.com/unit-mesh/devops-genius/commit/d088ed8e0172b58594529a4a73ef04f6da5f3e7b))
40 | * init for docs ([6c1c0ea](https://github.com/unit-mesh/devops-genius/commit/6c1c0ea60c94e2353f4c2ec63abf22741f96fd6b))
41 | * init ignore type [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([5c8981a](https://github.com/unit-mesh/devops-genius/commit/5c8981ad8081d300e383086f673d7364a19fb3e6))
42 | * **review:** add prompt generate for [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([bffb31e](https://github.com/unit-mesh/devops-genius/commit/bffb31ea27d9b38d22f78b9d89ddd3ee98c8f9bb))
43 | * **review:** make it works with llm [#8](https://github.com/unit-mesh/devops-genius/issues/8) ([5fcae4f](https://github.com/unit-mesh/devops-genius/commit/5fcae4faa08147c8813dc381eb3510ae39069cb1))
44 | * update sample for scripts ([c481657](https://github.com/unit-mesh/devops-genius/commit/c481657088a45b5bdd5da6f468b637df7b0da1f4))
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
374 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
DevOps Genius
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | [Read the docs →](https://devops.unitmesh.cc/)
18 |
19 | DevOpsGenius 旨在结合 LLM 重塑软件开发中的 DevOps 实践。将 LLM 视为团队的初级 “打杂工”,为团队提供各类辅助能力,以提高开发流程的效率和质量。
20 |
21 | - **自动 CI/CD 脚本生成**:DevOpsGenius 能够自动分析代码仓库,生成对应的 CI/CD 脚本,以实现自动化的构建、测试和部署流程。
22 | - **自动代码评审**:DevOpsGenius 使用先进的代码分析和静态分析技术,自动检测潜在的问题、错误和不规范的代码风格,并提供有针对性的建议和改进意见。
23 | - **自动需求优化**:DevOpsGenius 能够自动分析需求,识别需求中的问题和不足,并提供有针对性的建议和改进意见。
24 | - **智能拉取请求处理**:DevOpsGenius 能够智能地审查和处理拉取请求。它自动识别代码变更、冲突和合并请求,并以自动化的方式进行验证、测试和部署流程,以确保高质量的代码交付。
25 | - **自动 bug 分析与修复建议**:DevOpsGenius 能够自动分析 bug,识别 bug 中的问题和不足,并提供有针对性的建议和改进意见。
26 | - **智能报告和统计**:DevOpsGenius生成详细的报告和统计数据,展示代码质量、团队绩效和项目进度等关键指标。这些洞察力有助于团队进行数据驱动的决策,优化开发流程和资源分配。
27 | - **SRE 智能化**:DevOpsGenius 能够自动分析系统运行状态,识别系统中的问题和不足,并提供有针对性的建议和改进意见。
28 | - **容器化配置生成**:DevOpsGenius 能够自动分析代码仓库,生成对应的容器化配置文件,以实现自动化的容器化流程。
29 |
30 | ## License
31 |
32 | This code is distributed under the MPL 2.0 license. See `LICENSE` in this directory.
33 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | java
3 | application
4 | alias(libs.plugins.jvm)
5 | alias(libs.plugins.serialization)
6 |
7 | alias(libs.plugins.shadow)
8 | }
9 |
10 | group = "cc.unitmesh"
11 | version = "0.1.1"
12 |
13 | repositories {
14 | mavenCentral()
15 | mavenLocal()
16 | maven {
17 | url = uri("https://repo.spring.io/snapshot")
18 | name = "Spring Snapshots"
19 | }
20 | maven(url = uri("https://packages.jetbrains.team/maven/p/ktls/maven"))
21 | }
22 |
23 | dependencies {
24 | implementation(libs.codedb.checkout)
25 | implementation(libs.archguard.analyser.diffChanges)
26 |
27 | implementation("cc.unitmesh:cocoa-core:0.4.3")
28 | implementation("cc.unitmesh:git-differ:0.4.3")
29 | implementation("cc.unitmesh:code-splitter:0.4.3")
30 | implementation("cc.unitmesh:git-commit-message:0.4.3")
31 |
32 | implementation("cc.unitmesh:connection:0.4.3")
33 | implementation("cc.unitmesh:openai:0.4.3")
34 |
35 | // implementation("cc.unitmesh:sentence-transformers:0.4.3")
36 | // implementation("cc.unitmesh:store-elasticsearch:0.4.3")
37 |
38 | implementation("cc.unitmesh:document:0.4.3")
39 |
40 | implementation(libs.kaml)
41 | implementation(libs.github.api)
42 | implementation(libs.gitlab4j.api)
43 |
44 | implementation(libs.clikt)
45 | implementation(libs.rxjava3)
46 |
47 | implementation(libs.kotlin.stdlib)
48 | implementation(libs.serialization.json)
49 | implementation(libs.logging.slf4j.api)
50 |
51 | testImplementation(libs.bundles.test)
52 | testRuntimeOnly(libs.test.junit.engine)
53 | }
54 |
55 |
56 | application {
57 | mainClass.set("cc.unitmesh.genius.MainKt")
58 | }
59 |
60 | tasks {
61 | shadowJar {
62 | manifest {
63 | attributes(Pair("Main-Class", "cc.unitmesh.genius.MainKt"))
64 | }
65 | }
66 |
67 | withType {
68 | useJUnitPlatform()
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/connection.template.yml:
--------------------------------------------------------------------------------
1 | name: mock_response
2 | type: MockLlm
3 | configs:
4 | api-response: "{\"text\": \"this is a mock resource\"}"
5 |
--------------------------------------------------------------------------------
/devops-genius.yml:
--------------------------------------------------------------------------------
1 | name: "ChocolateFactory"
2 | path: "." # relative to the project root, or GitHub repo, like "unitmesh/chocolate-factory"
3 |
4 | # store the changelog in the repo
5 | store:
6 | indexName: "unitmesh/chocolate-factory" # default to github repo
7 |
8 | kanban:
9 | type: GitHub
10 |
11 | connection: connection.template.yml
12 |
13 | commitLog:
14 | ignoreType: [ "chore", "docs", "style" ]
15 | ignorePatterns:
16 | - "**/*.md"
17 | - "**/*.json"
18 | - "**/*.yml"
19 | - "**/*.yaml"
20 | - "**/*.vm"
21 | - ".gitignore"
22 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 | package.json
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | devops.unitmesh.cc
2 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | remote_theme: pmarsceill/just-the-docs
2 |
3 | title: DevOpsGenius
4 | description: DevOpsGenius 旨在结合 LLM 重塑软件开发中的 DevOps 实践。将 LLM 视为团队的初级 “打杂工”,为团队提供各类辅助能力,以提高开发流程的效率和质量。
5 |
6 | heading_anchors: true
7 |
8 | footer_content: "This code is distributed under the MPL 2.0 license. See `LICENSE` in this directory."
9 |
10 | # Footer last edited timestamp
11 | last_edit_timestamp: true # show or hide edit time - page must have `last_modified_date` defined in the frontmatter
12 | last_edit_time_format: "%b %e %Y at %I:%M %p" # uses ruby's time format: https://ruby-doc.org/stdlib-2.7.0/libdoc/time/rdoc/Time.html
13 |
14 | # Footer "Edit this page on GitHub" link text
15 | gh_edit_link: true # show or hide edit this page link
16 | gh_edit_link_text: "Edit this page on GitHub."
17 | gh_edit_repository: "https://github.com/unit-mesh/devops-genius" # the github URL for your repo
18 | gh_edit_branch: "master" # the branch that your docs are served from
19 | gh_edit_source: docs # the source that your files originate from
20 | gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately
21 |
22 | callouts_level: quiet # or loud
23 | callouts:
24 | highlight:
25 | color: yellow
26 | important:
27 | title: Important
28 | color: blue
29 | new:
30 | title: New
31 | color: green
32 | note:
33 | title: Note
34 | color: purple
35 | warning:
36 | title: Warning
37 | color: red
38 |
39 | # Enable or disable the site search
40 | # Supports true (default) or false
41 | search_enabled: true
42 |
43 | search:
44 | # Split pages into sections that can be searched individually
45 | # Supports 1 - 6, default: 2
46 | heading_level: 4
47 | # Maximum amount of previews per search result
48 | # Default: 3
49 | previews: 3
50 | # Maximum amount of words to display before a matched word in the preview
51 | # Default: 5
52 | preview_words_before: 5
53 | # Maximum amount of words to display after a matched word in the preview
54 | # Default: 10
55 | preview_words_after: 10
56 | # Set the search token separator
57 | # Default: /[\s\-/]+/
58 | # Example: enable support for hyphenated search words
59 | tokenizer_separator: /[\s/]+/
60 | # Display the relative url in search results
61 | # Supports true (default) or false
62 | rel_url: true
63 | # Enable or disable the search button that appears in the bottom right corner of every page
64 | # Supports true or false (default)
65 | button: false
66 |
67 |
68 | # Back to top link
69 | back_to_top: true
70 | back_to_top_text: "Back to top"
71 |
72 | # Google Analytics Tracking (optional)
73 | # e.g, UA-1234567-89
74 | #ga_tracking: G-JR0EZ3NLE1
75 | #ga_tracking_anonymize_ip: true # Use GDPR compliant Google Analytics settings (true by default)
76 |
77 | url: "https://devops.unitmesh.cc" # the base hostname & protocol for your site
78 |
79 | # Aux links for the upper right navigation
80 | aux_links:
81 | "View in on GitHub":
82 | - "//github.com/unit-mesh/devops-genius"
83 |
84 | # Makes Aux links open in a new tab. Default is false
85 | aux_links_new_tab: true
86 |
87 | mermaid:
88 | # Version of mermaid library
89 | # Pick an available version from https://cdn.jsdelivr.net/npm/mermaid/
90 | version: "10.4.0"
91 |
92 |
93 | plugins:
94 | - jekyll-seo-tag
95 | - jekyll-sitemap
96 |
--------------------------------------------------------------------------------
/docs/business/business-review.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Business Review
4 | nav_order: 10
5 | has_children: true
6 | permalink: /business
7 | ---
8 |
9 | 根据用户的问题,分析现在遗留系统中的业务。
10 |
11 | ## 策略
12 |
13 | 分析用户的原始问题,获得 DSL,结合 Semantic Code Search 的方式,给出最后的结果。
14 |
--------------------------------------------------------------------------------
/docs/ci/ci.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: CI/CD
4 | nav_order: 10
5 | has_children: true
6 | permalink: /ci-cd
7 | ---
8 |
9 | ## CI/CD
10 |
11 | 读取和生成项目的构建信息,如 Gradle、Maven、Makefile 等,再结合对应的构建工具,生成对应的 CI/CD 脚本,如 Jenkinsfile、.gitlab-ci.yml、.github/workflows 等。
12 |
13 | Jenkins file: [https://www.jenkins.io/doc/pipeline/examples/](https://www.jenkins.io/doc/pipeline/examples/)
14 |
--------------------------------------------------------------------------------
/docs/code-review/code-review.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Code Review
4 | nav_order: 90
5 | has_children: true
6 | permalink: /code-review
7 | ---
8 |
9 | # CodeReview Design
10 |
11 | ```mermaid
12 | graph TD
13 | A[开始] --> B[获取 commit messages]
14 | B --> C[解析 commit messages]
15 | C --> D[通过 commit type 过滤不需要 review 的 commits]
16 | D --> E[获取 User Stories 标题]
17 | E --> F[生成 patch 文件]
18 | F --> G[过滤不需要 review 的文件]
19 | G --> H[交由 LLM 处理]
20 | ```
21 |
22 | ## Prompt 策略
23 |
24 | 1. 如果变更的代码行数少,则只审核业务含义 —— 根据提交信息,解析对应的 story 名称,然后进行检查。
25 | 2. 根据变更的代码,生成对应的代码信息,作为上下文的一部分。
26 | 3. 如果变更的行数多,则需要进行代码逻辑的检查,以及对应的语法检查。
27 | 4. 如果单次变更的行数过多,则需要进行拆分。
28 |
29 | ### M1:提交格式解析
30 |
31 | 格式:Conventional Commits
32 |
33 | 解析库:[git-commit-message](https://github.com/unit-mesh/chocolate-factory/tree/master/code-modules/git-commit-message) (Chocolate Factory)
34 |
35 | 标准格式:
36 |
37 | ```
38 | [optional scope]:
39 |
40 | [optional description]
41 | [optional footer(s)]
42 | ```
43 |
44 | 示例:
45 |
46 | ```
47 | feat(ng-list): Allow custom separator Closes #123 Closes #25 Fixes #33
48 | ```
49 |
50 | 会生成三个 CommitReference:123,25,33
51 |
52 | ### M1:条件过滤
53 |
54 | 可配置的条件过滤
55 |
56 | 1. 根据提交信息中的 type 过滤,如忽略:docs, chore, style 等。
57 | 2. 根据文件路径过滤,如忽略:.md, .json 等。
58 |
59 | ### M1:基本的 Patch 优化
60 |
61 | 1. 如果变更的代码行数少,则只审核业务含义。
62 | 2. 处理文件目录移动,文件重命名的情况。(即忽略文件的变更)
63 | 3. 使用传统工具,检测语法问题,诸如 pre-commit 的情况。
64 |
65 | ### M2:Patch 优化
66 |
67 | 1. 如果超过 10 个文件,则需要拆分。
68 | - 忽略数据文件。
69 | - 忽略配置文件。
70 | 2. 如果单个行数变更大,则直接 review 原函数。
71 |
72 | ### M2:重写比例
73 |
74 | 1. 如果重写比例过高,则需要进行代码逻辑的检查,结合更多的上下文。(重写比例:重写的代码行数 / 总代码行数,建议小于 0.5,行数大于
75 | 30 / 2 行)
76 | 2. 当出现重大变化时,建议进行人工检查。
77 |
--------------------------------------------------------------------------------
/docs/code-review/prompt-design.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Prompt Sample
4 | parent: Code Review
5 | nav_order: 90
6 | permalink: /code-review/prompt
7 | ---
8 |
9 | You are a senior software developer, who can help me do code review a commit.
10 |
11 | Use the following response format, keeping the section headings as-is, and provide
12 | your feedback. Use bullet points for each response. The provided examples are for
13 | illustration purposes only and should not be repeated.
14 |
15 | **Syntax and logical errors (example)**:
16 | - Incorrect indentation on line 12
17 | - Missing closing parenthesis on line 23
18 |
19 | **Code refactoring and quality (example)**:
20 | - Replace multiple if-else statements with a switch case for readability
21 | - Extract repetitive code into separate functions
22 |
23 | **Performance optimization (example)**:
24 | - Use a more efficient sorting algorithm to reduce time complexity
25 | - Cache results of expensive operations for reuse
26 |
27 | **Security vulnerabilities (example)**:
28 | - Sanitize user input to prevent SQL injection attacks
29 | - Use prepared statements for database queries
30 |
31 | **Best practices (example)**:
32 | - Add meaningful comments and documentation to explain the code
33 | - Follow consistent naming conventions for variables and functions
34 |
35 | Business Context:
36 |
37 | Commit Message: chore: disable some gradle dep for small package size
38 |
39 | Code Changes: index 886725b..af1246e 100644
40 | --- a/build.gradle.kts
41 | +++ b/build.gradle.kts
42 | @@ -8,7 +8,7 @@
43 | }
44 |
45 | group = "cc.unitmesh"
46 | -version = "0.1.0"
47 | +version = "0.1.1"
48 |
49 | repositories {
50 | mavenCentral()
51 |
52 |
53 | 作为您的 Tech Lead,我只关注一些关键的代码审查问题。请为我提供一个关键摘要,按照以下格式:
54 |
55 | 关键摘要: // 你应该使用中文来回答,合并相似的问题
56 | 是否建议立即修改: // 是/否
57 |
58 |
--------------------------------------------------------------------------------
/docs/code-review/research.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Code Review Research
4 | parent: Code Review
5 | nav_order: 90
6 | permalink: /code-review/research
7 | ---
8 |
9 | # Code Review Research
10 |
11 |
12 | ## Article
13 |
14 | [团队的Code Review实践](https://www.thoughtworks.com/zh-cn/insights/blog/agile-engineering-practices/how-to-code-review](https://www.thoughtworks.com/zh-cn/insights/blog/agile-engineering-practices/how-to-code-review)
15 |
16 | - 互相学习,知识共享
17 | - 统一风格,提高代码质量
18 | - 尽早暴露问题,降低修复成本
19 |
20 | 工具:[https://github.com/MTWGA/thoughtworks-code-review-tools](https://github.com/MTWGA/thoughtworks-code-review-tools)
21 |
22 |
23 | ## Paper
24 |
25 | ### Expectations, outcomes, and challenges of modern code review
26 |
27 | 从我们的研究中,我们为开发人员提出以下建议:
28 |
29 | - 质量保证:代码审查的期望与实际结果存在不匹配。根据我们的研究,审查通常不如项目成员期望的那样频繁地发现缺陷,尤其是深层次、微妙或“宏观”层面的问题。以这种方式依赖代码审查来确保质量可能会面临风险。
30 | - 理解:当审阅者在上下文和代码方面具有先验知识时,他们能够更快地完成审查并向作者提供更有价值的反馈。团队应该努力提高开发人员的广泛理解(如果更改的作者是唯一的专家,她就没有潜在的审阅者),在使用审查来发现缺陷时,更改的作者应该尽可能包括代码所有者和其他理解代码的人。开发人员表示,当作者在审查中向他们提供上下文和指导时,他们可以更好、更快地做出反应。
31 | - 超越缺陷:现代代码审查提供了除了发现缺陷以外的好处。代码审查可以用于改善代码风格,寻找替代解决方案,增加学习,分享代码所有权等。这应该指导代码审查政策。
32 | - 沟通:尽管有支持代码审查的工具不断增长,开发人员在审查时仍需要比注释更丰富的沟通方式。团队应该提供面对面或至少同步沟通的机制。
33 |
34 | ### Modern code review: a case study at google
35 |
36 | At Google, over 35% of the changes under consideration modify only a single file and about 90% modify fewer than 10 files.
37 | Over 10% of changes modify only a single line of code, and the median number of lines modified is 24. The median change size
38 | is significantly lower than reported by Rigby and Bird for companies such as AMD (44 lines), Lucent (263 lines),
39 | and Bing, Office and SQL Server at Microsoft (somewhere between those boundaries),
40 | but in line for change sizes in open source projects.
41 |
42 | 在谷歌,有超过35%的正在考虑的更改仅修改一个文件,约90%的更改修改不到10个文件。
43 | 超过10%的更改仅修改一行代码,中位数修改的行数为24。中位数的更改大小明显低于Rigby和Bird为像AMD(44行)、Lucent(263行)以及微软的Bing、
44 | Office和SQL Server(在这些边界之间)等公司报告的更改大小,但与开源项目的更改大小保持一致。
45 |
46 | ### Pre Review
47 |
48 | 简介一下:业务上下文
49 |
50 | # Prompt Demo
51 |
52 | ## JetBrains Explain AI
53 |
54 | You are an senior software developer who can help me understand a commit with business.
55 | Explain this commit.
56 | Do not mention filenames.
57 | Ignore any changes to imports and requires.
58 | Keep the explanation under five sentences. Don't explain changes in test files.
59 |
60 | Message: Use freeCompilerArgs += "-Xjsr305=strict"
61 |
62 | See https://youtrack.jetbrains.com/issue/KT-41985
63 |
64 | Changes:
65 |
66 | Index: README.adoc
67 | ===================================================================
68 | --- a/README.adoc (revision b6ed535e3d4b6734a5695c32cc23ce8d5524b3eb)
69 | +++ b/README.adoc (revision 0906a3d831fea14898e4f0914d6b64531f6c3ade)
70 | @@ -103,7 +103,7 @@
71 | ----
72 | tasks.withType {
73 | kotlinOptions {
74 | - freeCompilerArgs = listOf("-Xjsr305=strict")
75 | + freeCompilerArgs += "-Xjsr305=strict"
76 | }
77 | }
78 | ----
79 | Index: build.gradle.kts
80 | ===================================================================
81 | --- a/build.gradle.kts (revision b6ed535e3d4b6734a5695c32cc23ce8d5524b3eb)
82 | +++ b/build.gradle.kts (revision 0906a3d831fea14898e4f0914d6b64531f6c3ade)
83 | @@ -39,7 +39,7 @@
84 |
85 | tasks.withType {
86 | kotlinOptions {
87 | - freeCompilerArgs = listOf("-Xjsr305=strict")
88 | + freeCompilerArgs += "-Xjsr305=strict"
89 | }
90 | }
91 |
92 |
93 | ## AutoDev
94 |
95 | You are a seasoned software developer, and I'm seeking your expertise to review the following code:
96 |
97 | - Please provide an overview of the business objectives and the context behind this commit. This will ensure that the code aligns with the project's requirements and goals.
98 | - Focus on critical algorithms, logical flow, and design decisions within the code. Discuss how these changes impact the core functionality and the overall structure of the code.
99 | - Identify and highlight any potential issues or risks introduced by these code changes. This will help reviewers pay special attention to areas that may require improvement or further analysis.
100 | - Emphasize the importance of compatibility and consistency with the existing codebase. Ensure that the code adheres to the established standards and practices for code uniformity and long-term maintainability.
101 | - Lastly, provide a concise high-level summary that encapsulates the key aspects of this commit. This summary should enable reviewers to quickly grasp the major changes in this update.
102 |
103 | PS: Your insights and feedback are invaluable in ensuring the quality and reliability of this code. Thank you for your assistance.
104 | Commit Message: feat: update test for samples\n\nCode Changes:\n\nIndex: build.gradle.kts
105 | --- a/build.gradle.kts
106 | +++ b/build.gradle.kts
107 | @@ -6,7 +6,6 @@
108 |
109 | group = "cc.unitmesh.untitled"
110 | version = "0.0.1-SNAPSHOT"
111 | -java.sourceCompatibility = JavaVersion.VERSION_17
112 |
113 | repositories {
114 | mavenCentral()
115 | @@ -17,6 +16,7 @@
116 | implementation("org.springframework.boot:spring-boot-starter-jdbc")
117 | implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
118 | implementation("org.springframework.boot:spring-boot-starter-data-jpa")
119 | + testImplementation("junit:junit:4.13.1")
120 |
121 | developmentOnly("org.springframework.boot:spring-boot-devtools")
122 |
123 | Index: src/main/java/cc/unitmesh/untitled/demo/controller/BlogController.java
124 | --- a/src/main/java/cc/unitmesh/untitled/demo/controller/BlogController.java
125 | +++ b/src/main/java/cc/unitmesh/untitled/demo/controller/BlogController.java
126 | @@ -19,7 +19,12 @@
127 | this.blogService = blogService;
128 | }
129 |
130 | - // create blog
131 | + @ApiOperation(value = "Get Blog by id")
132 | + @GetMapping("/{id}")
133 | + public BlogPost getBlog(@PathVariable Long id) {
134 | + return blogService.getBlogById(id);
135 | + }
136 | +
137 | @ApiOperation(value = "Create a new blog")
138 | @PostMapping("/")
139 | public BlogPost createBlog(@RequestBody CreateBlogRequest request) {
140 | Index: src/main/java/cc/unitmesh/untitled/demo/entity/BlogPost.java
141 | --- a/src/main/java/cc/unitmesh/untitled/demo/entity/BlogPost.java
142 | +++ b/src/main/java/cc/unitmesh/untitled/demo/entity/BlogPost.java
143 | @@ -25,6 +25,10 @@
144 |
145 | }
146 |
147 | + public void setId(Long id) {
148 | + this.id = id;
149 | + }
150 | +
151 | public Long getId() {
152 | return this.id;
153 | }
154 | Index: src/test/java/cc/unitmesh/untitled/demo/controller/BlogControllerTest.java
155 | --- a/src/test/java/cc/unitmesh/untitled/demo/controller/BlogControllerTest.java
156 | +++ b/src/test/java/cc/unitmesh/untitled/demo/controller/BlogControllerTest.java
157 | @@ -1,19 +1,43 @@
158 | package cc.unitmesh.untitled.demo.controller;
159 |
160 | +import cc.unitmesh.untitled.demo.entity.BlogPost;
161 | +import cc.unitmesh.untitled.demo.repository.BlogRepository;
162 | import org.junit.jupiter.api.Test;
163 | +import org.mockito.Mockito;
164 | import org.springframework.beans.factory.annotation.Autowired;
165 | +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
166 | import org.springframework.boot.test.context.SpringBootTest;
167 | +import org.springframework.boot.test.mock.mockito.MockBean;
168 | import org.springframework.test.web.servlet.MockMvc;
169 |
170 | +import java.util.Optional;
171 | +
172 | +import static org.hamcrest.Matchers.containsString;
173 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
174 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
175 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
176 | +
177 | @SpringBootTest
178 | +@AutoConfigureMockMvc
179 | class BlogControllerTest {
180 |
181 | - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
182 | @Autowired
183 | private MockMvc mockMvc;
184 | +
185 | + @MockBean
186 | + private BlogRepository blogRepository;
187 | +
188 | @Test
189 | - void should_get_blog_one_when_has_blog() throws Exception {
190 | + public void should_return_correct_blog_information_when_post_item() throws Exception {
191 | + BlogPost mockBlog = new BlogPost("Test Title", "Test Content", "Test Author");
192 | + mockBlog.setId(1L);
193 |
194 | + Mockito.when(blogRepository.findById(1L)).thenReturn(Optional.of(mockBlog));
195 |
196 | + mockMvc.perform(get("/blog/1"))
197 | + .andExpect(status().isOk())
198 | + .andExpect(content().string(containsString("Test Title")))
199 | + .andExpect(content().string(containsString("Test Content")));
200 | }
201 | -}
202 | \ No newline at end of file
203 | +}
204 | +
205 |
206 |
207 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Home
4 | description: DevOpsGenius 旨在结合 LLM 重塑软件开发中的 DevOps 实践。将 LLM 视为团队的初级 “打杂工”,为团队提供各类辅助能力,以提高开发流程的效率和质量。
5 | nav_order: 1
6 | permalink: /
7 | ---
8 |
9 | DevOps Genius
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | [Read the docs →](https://devops.unitmesh.cc/)
23 |
24 | DevOpsGenius 旨在结合 LLM 重塑软件开发中的 DevOps 实践。将 LLM 视为团队的初级 “打杂工”,为团队提供各类辅助能力,以提高开发流程的效率和质量。
25 |
26 | - **自动 CI/CD 脚本生成**:DevOpsGenius 能够自动分析代码仓库,生成对应的 CI/CD 脚本,以实现自动化的构建、测试和部署流程。
27 | - **自动代码评审**:DevOpsGenius 使用先进的代码分析和静态分析技术,自动检测潜在的问题、错误和不规范的代码风格,并提供有针对性的建议和改进意见。
28 | - **自动需求优化**:DevOpsGenius 能够自动分析需求,识别需求中的问题和不足,并提供有针对性的建议和改进意见。
29 | - **智能拉取请求处理**:DevOpsGenius 能够智能地审查和处理拉取请求。它自动识别代码变更、冲突和合并请求,并以自动化的方式进行验证、测试和部署流程,以确保高质量的代码交付。
30 | - **自动 bug 分析与修复建议**:DevOpsGenius 能够自动分析 bug,识别 bug 中的问题和不足,并提供有针对性的建议和改进意见。
31 | - **智能报告和统计**:DevOpsGenius生成详细的报告和统计数据,展示代码质量、团队绩效和项目进度等关键指标。这些洞察力有助于团队进行数据驱动的决策,优化开发流程和资源分配。
32 |
--------------------------------------------------------------------------------
/docs/issue/issue.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Issue Analysis
4 | nav_order: 30
5 | has_children: true
6 | permalink: /business
7 | ---
8 |
9 | 根据用户的问题,分析现在遗留系统中的业务。
10 |
11 | ## 策略
12 |
13 | 分析用户的原始问题,获得 DSL,结合 Semantic Code Search 的方式,给出最后的结果。
14 |
--------------------------------------------------------------------------------
/docs/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 4
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/usage.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Usage
4 | nav_order: 1
5 | permalink: /usage
6 | ---
7 |
8 | # Usage
9 |
10 | ## QuickStart
11 |
12 | 1. 下载 CLI:https://github.com/unit-mesh/devops-genius/releases
13 | 2. 配置 `devops-genius.yml`,参考 [配置文件](#配置文件)
14 |
15 | ### 配置文件
16 |
17 | ```yaml
18 | name: "ChocolateFactory"
19 | repo: "." # relative to the project root, or GitHub repo, like "unitmesh/chocolate-factory"
20 |
21 | # 配置对应的模型
22 | connection: connection.yml
23 |
24 | # store the changelog in the repo
25 | store:
26 | indexName: "unitmesh/chocolate-factory" # default to github repo
27 |
28 | # 用于获取需求,关联到对应的 issue/用户故事/特征
29 | kanban:
30 | type: GitHub
31 | token: "xxx"
32 |
33 | # 根据 commit message 忽略对应的提交和文件
34 | commitLog:
35 | ignoreType: [ "chore", "docs", "style" ]
36 | ignorePatterns:
37 | - "**/*.md"
38 | - "**/*.json"
39 | - "**/*.yml"
40 | - "**/*.yaml"
41 | - "**/*.vm"
42 | - ".gitignore"
43 | ```
44 |
45 | ### connection.yml 用于配置对应的模型
46 |
47 | 示例:
48 |
49 | ```yaml
50 | name: open_ai_connection
51 | type: OpenAI
52 | configs:
53 | api-host: https://api.aios.chat/ # 如果有的话
54 | secrets:
55 | api-key: "xxx"
56 | ```
57 |
58 | 更详细的模型支持见:[https://framework.unitmesh.cc/prompt-script/connection-config](https://framework.unitmesh.cc/prompt-script/connection-config)
59 |
--------------------------------------------------------------------------------
/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "context": {
3 | "businessContext": "1. 如果变更的代码行数少,则只审核业务含义 —— 根据提交信息,解析对应的 story 名称,然后进行检查。\n2. 根据变更的代码,生成对应的代码信息,作为上下文的一部分。\n3. 如果变更的行数多,则需要进行代码逻辑的检查,以及对应的语法检查。\n4. 如果单次变更的行数过多,则需要进行拆分。\n",
4 | "fullMessage": "feat(differ): add for handle patches match #8",
5 | "changes": "--- /dev/null\n+++ b/code-modules/git-differ/src/main/kotlin/cc/unitmesh/cf/code/ChangedLineCount.kt\n@@ -0,0 +1,9 @@\n+package cc.unitmesh.cf.code\n+\n+import kotlinx.serialization.Serializable\n+\n+@Serializable\n+data class ChangedLineCount(\n+ val added: Int,\n+ val deleted: Int,\n+)\n\nindex 0ea0eb4..efb0fda 100644\n--- a/code-modules/git-differ/src/main/kotlin/cc/unitmesh/cf/code/GitDiffer.kt\n+++ b/code-modules/git-differ/src/main/kotlin/cc/unitmesh/cf/code/GitDiffer.kt\n@@ -39,7 +39,7 @@\n val functionName: String = \"\",\n val code: String = \"\",\n val addedLines: Int = 0,\n- val deletedLines: Int = 0\n+ val deletedLines: Int = 0,\n )\n \n /**\n@@ -108,73 +108,87 @@\n * @param untilRev The revision to end at.\n * @return A map containing the file paths as keys and the corresponding patch text as values.\n */\n- fun patchBetween(sinceRev: String, untilRev: String): Map {\n- git.use {\n- // 获取 sinceRev 和 untilRev 的 ObjectId\n- val sinceObj: ObjectId = repository.resolve(sinceRev)\n- val untilObj: ObjectId = repository.resolve(untilRev)\n+ fun patchBetween(sinceRev: String, untilRev: String): Map {\n+ // 获取 sinceRev 和 untilRev 的 ObjectId\n+ val sinceObj: ObjectId = repository.resolve(sinceRev)\n+ val untilObj: ObjectId = repository.resolve(untilRev)\n \n- // 获取两个提交之间的差异(补丁)\n- val outputStream = ByteArrayOutputStream()\n- val diffFormatter = DiffFormatter(outputStream)\n- diffFormatter.setRepository(repository)\n- diffFormatter.format(sinceObj, untilObj)\n+ // 获取两个提交之间的差异(补丁)\n+ val outputStream = ByteArrayOutputStream()\n+ val diffFormatter = DiffFormatter(outputStream)\n+ diffFormatter.setRepository(repository)\n+ diffFormatter.format(sinceObj, untilObj)\n \n- summaryFileDiff(diffFormatter, sinceObj, untilObj)\n+ val diffs: List = diffFormatter.scan(sinceObj, untilObj)\n+ val patchMap = mutableMapOf()\n \n- // 将补丁转换为 Map\n- val patchMap = mutableMapOf()\n- outputStream.toString().split(\"\nnew file mode 100644\nindex 0000000..d29effd\n--- /dev/null\n+++ b/code-modules/git-differ/src/main/kotlin/cc/unitmesh/cf/code/OptimizePatch.kt\n@@ -0,0 +1,35 @@\n+package cc.unitmesh.cf.code\n+\n+import kotlinx.serialization.Serializable\n+import org.eclipse.jgit.diff.DiffEntry\n+\n+@Serializable\n+data class OptimizePatch(\n+ val changedLineCount: ChangedLineCount,\n+ val changeType: PatchChangeType,\n+ val content: String,\n+ val path: String,\n+)\n+\n+/**\n+ * from [org.eclipse.jgit.diff.DiffEntry.ChangeType]\n+ */\n+enum class PatchChangeType {\n+ ADD,\n+ MODIFY,\n+ DELETE,\n+ RENAME,\n+ COPY;\n+\n+ companion object {\n+ fun from(changeType: DiffEntry.ChangeType): PatchChangeType {\n+ return when (changeType) {\n+ DiffEntry.ChangeType.ADD -> ADD\n+ DiffEntry.ChangeType.MODIFY -> MODIFY\n+ DiffEntry.ChangeType.DELETE -> DELETE\n+ DiffEntry.ChangeType.RENAME -> RENAME\n+ DiffEntry.ChangeType.COPY -> COPY\n+ }\n+ }\n+ }\n+}\n"
6 | }
7 | }
--------------------------------------------------------------------------------
/fixtures/prompt.unit-mesh.yml:
--------------------------------------------------------------------------------
1 | name: "Code Review"
2 | description: "Verify code review template"
3 |
4 | jobs:
5 | prompt-evaluate: # job name should be unique for each job
6 | description: "Evaluate prompt with different parameters"
7 | connection: openai-connection.yml
8 | template: ../src/main/resources/code-review/simple-review.open-ai.vm
9 | template-datasource:
10 | - type: file
11 | value: example.json
12 |
13 | strategy:
14 | - type: connection
15 | value:
16 | - type: range
17 | key: temperature
18 | range: 0.0~0.0
19 | step: 0.1
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # This file was generated by the Gradle 'init' task.
2 | # https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
3 |
4 | org.gradle.parallel=true
5 | org.gradle.caching=true
6 |
7 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | kotlin = "1.9.10"
3 |
4 | kotlinxCoroutines = "1.7.3"
5 | kotlinxSerialization = "1.6.0"
6 |
7 |
8 | junit = "5.9.1"
9 | kotlinTest = "5.5.4"
10 | mockk = "1.13.5"
11 | assertj = "3.22.0"
12 |
13 | logback = "1.4.5"
14 | slf4j = "2.0.5"
15 |
16 | chapi = "2.1.3"
17 | archguard = "2.0.7"
18 | codedb = "0.1.2"
19 |
20 | gson = "2.10.1"
21 | shadowJar = "8.1.1"
22 |
23 |
24 | jgit = "6.7.0.202309050840-r"
25 |
26 | cf = "0.4.0"
27 |
28 | [libraries]
29 | kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
30 | kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
31 |
32 | kotlin-scripting-jvm = { group = "org.jetbrains.kotlin", name = "kotlin-scripting-jvm", version.ref = "kotlin" }
33 | kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
34 | reflections = { group = "org.reflections", name = "reflections", version = "0.10.2" }
35 | kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" }
36 |
37 | dataframe = { group = "org.jetbrains.kotlinx", name = "dataframe", version = "0.11.1" }
38 |
39 | # Kotlinx Serialization
40 | serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
41 |
42 | # Coroutines
43 | coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
44 |
45 |
46 | # Testing
47 | test-junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
48 | test-junit-params = { group = "org.junit.jupiter", name = "junit-jupiter-params", version.ref = "junit" }
49 | test-junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" }
50 | test-kotlintest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotlinTest" }
51 | test-mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
52 | test-assertj = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" }
53 |
54 | # Logging
55 | logging-slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
56 | logging-logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
57 |
58 | # chapi
59 | chapi-domain = { group = "com.phodal.chapi", name = "chapi-domain", version.ref = "chapi" }
60 | chapi-java = { group = "com.phodal.chapi", name = "chapi-ast-java", version.ref = "chapi" }
61 | chapi-kotlin = { group = "com.phodal.chapi", name = "chapi-ast-kotlin", version.ref = "chapi" }
62 |
63 | # archguard
64 | # implementation("org.archguard.aaac:lang:2.0.0-beta.5")
65 | archguard-scanner-core = { group = "org.archguard.scanner", name = "scanner_core", version.ref = "archguard" }
66 | archguard-dsl = { group = "org.archguard.aaac", name = "dsl", version.ref = "archguard" }
67 | archguard-analyser-sca = { group = "org.archguard.scanner", name = "analyser_sca", version.ref = "archguard" }
68 | ## analyser_diff_changes
69 | archguard-analyser-diffChanges = { group = "org.archguard.scanner", name = "analyser_diff_changes", version.ref = "archguard" }
70 | archguard-lang-kotlin = { group = "org.archguard.scanner", name = "lang_kotlin", version.ref = "archguard" }
71 | archguard-lang-java = { group = "org.archguard.scanner", name = "lang_java", version.ref = "archguard" }
72 | archguard-lang-python = { group = "org.archguard.scanner", name = "lang_python", version.ref = "archguard" }
73 | archguard-lang-typescript = { group = "org.archguard.scanner", name = "lang_typescript", version.ref = "archguard" }
74 | archguard-lang-golang = { group = "org.archguard.scanner", name = "lang_golang", version.ref = "archguard" }
75 |
76 | archguard-feat-apicalls = { group = "org.archguard.scanner", name = "feat_apicalls", version.ref = "archguard" }
77 | archguard-feat-datamap = { group = "org.archguard.scanner", name = "feat_datamap", version.ref = "archguard" }
78 | codedb-checkout = { group = "org.archguard.codedb", name = "checkout", version.ref = "codedb" }
79 |
80 | gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
81 |
82 | # llm part
83 | commonmark-core = "org.commonmark:commonmark:0.21.0"
84 | commonmark-gfm-tables = "org.commonmark:commonmark-ext-gfm-tables:0.21.0"
85 | commonmark-heading-anchor = "org.commonmark:commonmark-ext-gfm-tables:0.21.0"
86 |
87 | openai-gpt3 = "com.theokanning.openai-gpt3-java:service:0.14.0"
88 | retrofit2-converter-jackson = "com.squareup.retrofit2:converter-jackson:2.9.0"
89 | azure-openai = "com.azure:azure-ai-openai:1.0.0-beta.3"
90 |
91 | kaml = "com.charleskorn.kaml:kaml:0.55.0"
92 |
93 | github-api = "org.kohsuke:github-api:1.314"
94 | gitlab4j-api = "org.gitlab4j:gitlab4j-api:5.3.0"
95 |
96 | jackson-module-kotlin = "com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2"
97 | jackson-module-jsonSchema = "com.fasterxml.jackson.module:jackson-module-jsonSchema:2.14.2"
98 | jackson-dataformat-yaml = "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.2"
99 | jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.14.2"
100 |
101 |
102 | rxjava3 = "io.reactivex.rxjava3:rxjava:3.1.7"
103 |
104 | kotlinx-datetime = "org.jetbrains.kotlinx:kotlinx-datetime:0.4.1"
105 | clikt = "com.github.ajalt.clikt:clikt:4.2.0"
106 |
107 | jgit = { group = "org.eclipse.jgit", name = "org.eclipse.jgit", version.ref = "jgit" }
108 |
109 | # implementation(libs.cocoaCore)
110 | cf-cocoa-core = { group = "cc.unitmesh", name = "cocoa-core", version.ref = "cf" }
111 | # implementation(libs.codeModules.gitDiffer)
112 | cf-sentence-transformers = { group = "cc.unitmesh", name = "sentence-transformers", version.ref="cf" }
113 | # implementation(libs.codedb.checkout)
114 | # implementation(libs.archguard.analyser.diffChanges)
115 |
116 |
117 |
118 | [plugins]
119 | jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
120 | multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
121 | serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
122 | shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadowJar" }
123 |
124 | [bundles]
125 | test = ["test-junit-params", "kotlin-test", "test-kotlintest-assertions", "test-mockk", "test-assertj"]
126 |
127 | jackson = ["jackson-module-jsonSchema", "jackson-module-kotlin", "jackson-dataformat-yaml"]
128 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/devops-genius/bdcbddd9940844fcca88c5e08c20f1d0994fed9f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | # This is normally unused
84 | # shellcheck disable=SC2034
85 | APP_BASE_NAME=${0##*/}
86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
88 |
89 | # Use the maximum available, or set MAX_FD != -1 to use that value.
90 | MAX_FD=maximum
91 |
92 | warn () {
93 | echo "$*"
94 | } >&2
95 |
96 | die () {
97 | echo
98 | echo "$*"
99 | echo
100 | exit 1
101 | } >&2
102 |
103 | # OS specific support (must be 'true' or 'false').
104 | cygwin=false
105 | msys=false
106 | darwin=false
107 | nonstop=false
108 | case "$( uname )" in #(
109 | CYGWIN* ) cygwin=true ;; #(
110 | Darwin* ) darwin=true ;; #(
111 | MSYS* | MINGW* ) msys=true ;; #(
112 | NONSTOP* ) nonstop=true ;;
113 | esac
114 |
115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
116 |
117 |
118 | # Determine the Java command to use to start the JVM.
119 | if [ -n "$JAVA_HOME" ] ; then
120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
121 | # IBM's JDK on AIX uses strange locations for the executables
122 | JAVACMD=$JAVA_HOME/jre/sh/java
123 | else
124 | JAVACMD=$JAVA_HOME/bin/java
125 | fi
126 | if [ ! -x "$JAVACMD" ] ; then
127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
128 |
129 | Please set the JAVA_HOME variable in your environment to match the
130 | location of your Java installation."
131 | fi
132 | else
133 | JAVACMD=java
134 | if ! command -v java >/dev/null 2>&1
135 | then
136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 | fi
142 |
143 | # Increase the maximum file descriptors if we can.
144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
145 | case $MAX_FD in #(
146 | max*)
147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
148 | # shellcheck disable=SC3045
149 | MAX_FD=$( ulimit -H -n ) ||
150 | warn "Could not query maximum file descriptor limit"
151 | esac
152 | case $MAX_FD in #(
153 | '' | soft) :;; #(
154 | *)
155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
156 | # shellcheck disable=SC3045
157 | ulimit -n "$MAX_FD" ||
158 | warn "Could not set maximum file descriptor limit to $MAX_FD"
159 | esac
160 | fi
161 |
162 | # Collect all arguments for the java command, stacking in reverse order:
163 | # * args from the command line
164 | # * the main class name
165 | # * -classpath
166 | # * -D...appname settings
167 | # * --module-path (only if needed)
168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
169 |
170 | # For Cygwin or MSYS, switch paths to Windows format before running java
171 | if "$cygwin" || "$msys" ; then
172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
174 |
175 | JAVACMD=$( cygpath --unix "$JAVACMD" )
176 |
177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 | for arg do
179 | if
180 | case $arg in #(
181 | -*) false ;; # don't mess with options #(
182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 | [ -e "$t" ] ;; #(
184 | *) false ;;
185 | esac
186 | then
187 | arg=$( cygpath --path --ignore --mixed "$arg" )
188 | fi
189 | # Roll the args list around exactly as many times as the number of
190 | # args, so each arg winds up back in the position where it started, but
191 | # possibly modified.
192 | #
193 | # NB: a `for` loop captures its iteration list before it begins, so
194 | # changing the positional parameters here affects neither the number of
195 | # iterations, nor the values presented in `arg`.
196 | shift # remove old arg
197 | set -- "$@" "$arg" # push replacement arg
198 | done
199 | fi
200 |
201 |
202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204 |
205 | # Collect all arguments for the java command;
206 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
207 | # shell script including quotes and variable substitutions, so put them in
208 | # double quotes to make sure that they get re-expanded; and
209 | # * put everything else in single quotes, so that it's not re-expanded.
210 |
211 | set -- \
212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 | -classpath "$CLASSPATH" \
214 | org.gradle.wrapper.GradleWrapperMain \
215 | "$@"
216 |
217 | # Stop when "xargs" is not available.
218 | if ! command -v xargs >/dev/null 2>&1
219 | then
220 | die "xargs is not available"
221 | fi
222 |
223 | # Use "xargs" to parse quoted args.
224 | #
225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
226 | #
227 | # In Bash we could simply go:
228 | #
229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
230 | # set -- "${ARGS[@]}" "$@"
231 | #
232 | # but POSIX shell has neither arrays nor command substitution, so instead we
233 | # post-process each arg (as a line of input to sed) to backslash-escape any
234 | # character that might be a shell metacharacter, then use eval to reverse
235 | # that process (while maintaining the separation between arguments), and wrap
236 | # the whole thing up as a single "set" statement.
237 | #
238 | # This will of course break if any of these variables contains a newline or
239 | # an unmatched quote.
240 | #
241 |
242 | eval "set -- $(
243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
244 | xargs -n1 |
245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
246 | tr '\n' ' '
247 | )" '"$@"'
248 |
249 | exec "$JAVACMD" "$@"
250 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/prompt-test.main.kts:
--------------------------------------------------------------------------------
1 | @file:DependsOn("cc.unitmesh:prompt-script:0.3.8")
2 |
3 | import cc.unitmesh.prompt.*
4 |
5 | executeScript("config/prompt.unit-mesh.yml")
6 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "devops-genius"
2 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/CiCdCommand.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius
2 |
3 | import com.github.ajalt.clikt.core.CliktCommand
4 |
5 | class CiCdCommand : CliktCommand(help = "Auto create CI/CD script with GenAI") {
6 | override fun run() {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/CodeReviewCommand.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius
2 |
3 | import cc.unitmesh.cf.code.GitCommand
4 | import cc.unitmesh.cf.code.GitDiffer
5 | import cc.unitmesh.genius.domain.review.CodeReviewAction
6 | import cc.unitmesh.genius.domain.review.ReviewOption
7 | import cc.unitmesh.genius.project.GeniusProject
8 | import com.github.ajalt.clikt.core.CliktCommand
9 | import com.github.ajalt.clikt.parameters.options.default
10 | import com.github.ajalt.clikt.parameters.options.flag
11 | import com.github.ajalt.clikt.parameters.options.option
12 | import org.slf4j.LoggerFactory
13 | import org.changelog.CommitParser
14 | import org.changelog.ParserOptions
15 | import com.charleskorn.kaml.PolymorphismStyle
16 | import com.charleskorn.kaml.Yaml
17 | import com.charleskorn.kaml.YamlConfiguration
18 | import kotlinx.serialization.serializer
19 | import java.io.File
20 | import kotlin.io.path.Path
21 | import kotlin.io.path.exists
22 | import kotlin.io.path.readText
23 |
24 | /**
25 | * The `CodeReviewCommand` class is a command-line interface for performing code reviews using AIGC (Artificial Intelligence for Code Review).
26 | * It extends the `CliktCommand` class from the `clikt` library and provides options and functionality for reviewing code in a Git repository.
27 | *
28 | * @property repo The path to the Git repository. It can be a local file path or a Git URL. Default value is "." (current directory).
29 | * @property branch The name of the Git branch to review. Default value is "master".
30 | * @property sinceCommit The revision of the first commit to include in the review. Default value is an empty string, which means the earliest commit in the repository.
31 | * @property untilCommit The revision of the last commit to include in the review. Default value is an empty string, which means the latest commit in the repository.
32 | * @property commitMessageOptionFile The path to the commit message option file. Default value is an empty string, which means no commit message options are used.
33 | * @property verbose A flag indicating whether to enable verbose output. Default value is false.
34 | * @property configFile The path to the configuration file. Default value is "devops-genius.yml".
35 | * @property project The `GeniusProject` instance representing the project being reviewed. It is lazily initialized based on the configuration file or the repository path.
36 | *
37 | * @constructor Creates a new instance of `CodeReviewCommand`.
38 | *
39 | * @see CliktCommand
40 | * @see GeniusProject
41 | */
42 | class CodeReviewCommand : CliktCommand(help = "Code Review with AIGC") {
43 | private val repo by option(help = "Git repository path. Use local file path, or Git Url").default(".")
44 | private val branch by option(help = "Git branch name").default("master")
45 | private val sinceCommit by option(help = "Begin commit revision").default("")
46 | private val untilCommit by option(help = "End commit revision. Aka latest").default("")
47 | private val commitMessageOptionFile by option(help = "commit message option file").default("")
48 | private val verbose by option(help = "verbose").flag(default = false)
49 | private val configFile by option(help = "config file").default("devops-genius.yml")
50 |
51 | private val project: GeniusProject by lazy {
52 | val path = Path(configFile)
53 | if (path.exists()) {
54 | logger.info("load project from config file: ${path.toAbsolutePath()}")
55 | GeniusProject.fromYml(path.readText())
56 | } else {
57 | logger.info("load project from repo: $repo")
58 | GeniusProject(path = repo)
59 | }
60 | }
61 |
62 | override fun run() {
63 | val defaultLatestIds = GitCommand().latestCommitHash(2).stdout.split(System.lineSeparator())
64 | val sinceCommit = sinceCommit.ifEmpty {
65 | defaultLatestIds[defaultLatestIds.lastIndex]
66 | }
67 | val untilCommit = untilCommit.ifEmpty {
68 | defaultLatestIds[0]
69 | }
70 |
71 | val diff = GitDiffer(repo, branch)
72 | val repositoryUrl = diff.gitRepositoryUrl()
73 | logger.info("get repository url from .git/config: $repositoryUrl")
74 | project.repoUrl = repositoryUrl
75 |
76 | val reviewOption = ReviewOption(
77 | path = repo,
78 | repo = repositoryUrl,
79 | branch = branch,
80 | sinceCommit = sinceCommit,
81 | untilCommit = untilCommit,
82 | commitOptionFile = commitMessageOptionFile,
83 | verbose = verbose,
84 | project = project,
85 | )
86 |
87 | val commitParser = createCommitParser()
88 | CodeReviewAction(project, reviewOption, diff, commitParser).execute()
89 | }
90 |
91 | private fun createCommitParser(): CommitParser {
92 | val parserOptions = if (commitMessageOptionFile.isNotEmpty() and Path(commitMessageOptionFile).exists()) {
93 | val commitMsgOptionText = File(commitMessageOptionFile).readText()
94 | ParserOptions.fromString(commitMsgOptionText)
95 | } else {
96 | ParserOptions.defaultOptions()
97 | }
98 |
99 | if (parserOptions == null) {
100 | throw Exception("commit message option file is not valid: $commitMessageOptionFile")
101 | }
102 |
103 | return CommitParser(parserOptions)
104 | }
105 |
106 | companion object {
107 | private val logger = LoggerFactory.getLogger(CodeReviewCommand::class.java)!!
108 | }
109 | }
110 |
111 | private fun ParserOptions.Companion.fromString(content: String): ParserOptions? {
112 | return try {
113 | val conf = YamlConfiguration(polymorphismStyle = PolymorphismStyle.Property)
114 | val userOptions = Yaml(configuration = conf).decodeFromString(serializer(), content)
115 | // merge default options
116 | defaultOptions().copy(
117 | commentChar = userOptions.commentChar ?: defaultOptions().commentChar,
118 | mergePattern = userOptions.mergePattern ?: defaultOptions().mergePattern,
119 | mergeCorrespondence = userOptions.mergeCorrespondence ?: defaultOptions().mergeCorrespondence,
120 | headerPattern = userOptions.headerPattern ?: defaultOptions().headerPattern,
121 | breakingHeaderPattern = userOptions.breakingHeaderPattern
122 | ?: defaultOptions().breakingHeaderPattern,
123 | headerCorrespondence = userOptions.headerCorrespondence ?: defaultOptions().headerCorrespondence,
124 | revertPattern = userOptions.revertPattern ?: defaultOptions().revertPattern,
125 | revertCorrespondence = userOptions.revertCorrespondence ?: defaultOptions().revertCorrespondence,
126 | fieldPattern = userOptions.fieldPattern ?: defaultOptions().fieldPattern,
127 | noteKeywords = userOptions.noteKeywords ?: defaultOptions().noteKeywords,
128 | notesPattern = userOptions.notesPattern ?: defaultOptions().notesPattern,
129 | issuePrefixes = userOptions.issuePrefixes ?: defaultOptions().issuePrefixes,
130 | issuePrefixesCaseSensitive = userOptions.issuePrefixesCaseSensitive
131 | ?: defaultOptions().issuePrefixesCaseSensitive,
132 | referenceActions = userOptions.referenceActions ?: defaultOptions().referenceActions,
133 | )
134 |
135 | } catch (e: Exception) {
136 | e.printStackTrace()
137 | null
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/IssueCommand.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius
2 |
3 | import com.github.ajalt.clikt.core.CliktCommand
4 |
5 | class IssueCommand : CliktCommand(help = "Resolve Issue with GenAI") {
6 | override fun run() {
7 |
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/Main.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius
2 |
3 | import com.github.ajalt.clikt.core.CliktCommand
4 | import com.github.ajalt.clikt.core.subcommands
5 |
6 |
7 | val HELP_TEXT =
8 | """GenAI/AIGC in DevOps practices that improve software development and operations through the integration.""".trimIndent()
9 |
10 | class GeniusCommand : CliktCommand(help = HELP_TEXT) {
11 | override fun run() = Unit
12 | }
13 |
14 | fun main(args: Array) = GeniusCommand().subcommands(
15 | CodeReviewCommand(),
16 | CiCdCommand(),
17 | IssueCommand(),
18 | ).main(args)
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/context/ActionOption.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.context
2 |
3 | interface ActionOption {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/context/GeniusAction.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.context
2 |
3 | interface GeniusAction {
4 | fun execute(): Any
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/devops/Issue.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class Issue(
7 | val id: String,
8 | val title: String,
9 | val body: String,
10 | val url: String = "",
11 | val labels: List = listOf(),
12 | val assignees: List = listOf(),
13 | ) {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/devops/KanbanFactory.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops
2 |
3 | import cc.unitmesh.genius.devops.kanban.GitHubKanban
4 | import cc.unitmesh.genius.devops.kanban.GitlabKanban
5 | import cc.unitmesh.genius.devops.kanban.Kanban
6 | import java.net.URL
7 |
8 | object KanbanFactory {
9 |
10 | /**
11 | * Creates a Kanban object based on the provided repository URL.
12 | *
13 | * @param url the URL of the repository
14 | * @return a Kanban object representing the repository's Kanban board, or null if the URL is invalid or unsupported
15 | */
16 | fun fromRepositoryUrl(url: String, token: String): Kanban? {
17 | return try {
18 | val parsedUrl = URL(url)
19 | val host = parsedUrl.host
20 |
21 | when {
22 | host.contains("github.com") -> GitHubKanban(url, token)
23 | host.contains("gitlab.com") -> GitlabKanban(url, token)
24 | else -> GitlabKanban(url, token)
25 | }
26 | } catch (e: Exception) {
27 | null
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/devops/kanban/GitHubKanban.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops.kanban
2 |
3 | import cc.unitmesh.genius.devops.Issue
4 | import org.kohsuke.github.GitHub
5 | import org.kohsuke.github.GitHubBuilder
6 |
7 | class GitHubKanban(private val repoUrl: String, private val token: String) : Kanban {
8 | private val gitHub: GitHub
9 |
10 | init {
11 | try {
12 | gitHub = GitHubBuilder()
13 | .withOAuthToken(token)
14 | .build()
15 | } catch (e: Exception) {
16 | throw e
17 | }
18 | }
19 |
20 | override fun fetch(id: String): Issue {
21 | val repoUrl = formatUrl(this.repoUrl)
22 | val issue = gitHub.getRepository(repoUrl).getIssue(Integer.parseInt(id))
23 |
24 | return Issue(
25 | issue.number.toString(),
26 | issue.title,
27 | issue.body,
28 | issue.url.toString(),
29 | issue.labels.map { it.name },
30 | issue.assignees.map { it.name }
31 | )
32 | }
33 |
34 | companion object {
35 | /**
36 | * Formats the repository URL to owner/repo format.
37 | *
38 | * The formatUrl method takes the repository URL and formats it to the owner/repo format.
39 | * For example, if the repository URL is "https://github.com/unitmesh/devti",
40 | * the formatted URL will be "unitmesh/devti".
41 | *
42 | * @return The formatted repository URL in the owner/repo format.
43 | */
44 | fun formatUrl(repoUrl: String): String {
45 | var url = repoUrl.split("/").takeLast(2).joinToString("/")
46 | url = if (url.endsWith(".git")) url.substring(0, url.length - 4) else url
47 | return url
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/devops/kanban/GitlabKanban.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops.kanban
2 |
3 | import cc.unitmesh.genius.devops.Issue
4 | import org.gitlab4j.api.GitLabApi
5 |
6 | class GitlabKanban(val repoUrl: String, val token: String) : Kanban {
7 | private var gitLabApi: GitLabApi = GitLabApi(repoUrl, token)
8 | override fun fetch(id: String): Issue {
9 | val issue: org.gitlab4j.api.models.Issue = gitLabApi.issuesApi.getIssue(repoUrl, id.toLong())
10 | return Issue(
11 | issue.iid.toString(),
12 | issue.title,
13 | issue.description,
14 | issue.webUrl,
15 | issue.labels,
16 | issue.assignees.map { it.name }
17 | )
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/devops/kanban/Kanban.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops.kanban
2 |
3 | import cc.unitmesh.genius.devops.Issue
4 |
5 | interface Kanban {
6 | fun fetch(id: String): Issue
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/domain/cicd/CiFileGenerator.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.cicd
2 |
3 | import java.io.File
4 |
5 | abstract class CiFileGenerator {
6 | protected fun rootDir(): File {
7 | return File("").absoluteFile
8 | }
9 |
10 | abstract fun createFile()
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/domain/cicd/GitHubActionPromptFactory.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.cicd
2 |
3 | import cc.unitmesh.genius.prompt.PromptFactory
4 |
5 | class GitHubActionPromptFactory : PromptFactory("prompts/cicd/github-action") {
6 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/domain/review/CodeReviewAction.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.review
2 |
3 | import cc.unitmesh.cf.code.GitDiffer
4 | import cc.unitmesh.genius.context.GeniusAction
5 | import cc.unitmesh.genius.devops.Issue
6 | import cc.unitmesh.genius.project.GeniusProject
7 | import org.changelog.CommitParser
8 | import org.slf4j.LoggerFactory
9 |
10 | class CodeReviewAction(
11 | val project: GeniusProject,
12 | private val option: ReviewOption,
13 | private val diff: GitDiffer,
14 | private val commitParser: CommitParser,
15 | ) : GeniusAction {
16 | private val promptFactory = CodeReviewPromptFactory()
17 | private val context = CodeReviewContext()
18 |
19 | /**
20 | * Executes the full process of reviewing commits.
21 | *
22 | * This method performs the following steps:
23 | * 1. Retrieves the commit messages between the specified `sinceCommit` and `untilCommit`.
24 | * 2. Parses the commit messages to obtain the Commit objects and their references.
25 | * 3. Filters out the commits that do not require review based on the project's configuration.
26 | * 4. Retrieves the titles of the User Stories associated with the referenced issues.
27 | * 5. Generates a patch file to obtain the diff content and filters out files that do not require review.
28 | * 6. Creates a prompt to collect the review results.
29 | * 7. Sends the prompt to the project's connector for completion.
30 | * 8. Prints the completion results.
31 | *
32 | * @return An empty string.
33 | */
34 | override fun execute(): Any {
35 | // 获取 sinceCommit 到 untilCommit 之间的 commit message
36 | val commitMessages = diff.commitMessagesBetween(option.sinceCommit, option.untilCommit)
37 | context.fullMessage = commitMessages.map { it.value }.joinToString(System.lineSeparator())
38 |
39 | // 解析 commit message 为 Commit 对象,以获取其中的 references
40 | val parsedMsgs = commitMessages.map {
41 | commitParser.parse(it.value)
42 | }
43 |
44 | // 从配置文件中读取,并过滤掉不需要 review 的 commit,诸如 chore、ci, docs 等
45 | // 如果没有配置,则全部需要 review
46 | val filterCommits = parsedMsgs.filter {
47 | if (it.meta.containsKey("type")) {
48 | val type = it.meta["type"] as String
49 | project.commitLog?.isIgnoreType(type) ?: true
50 | } else {
51 | true
52 | }
53 | }
54 |
55 | if (option.verbose) {
56 | println("parsedMsgs: $parsedMsgs")
57 | println("filterCommits: $filterCommits")
58 | }
59 |
60 | if (filterCommits.isEmpty()) {
61 | logger.info("commit don't need review")
62 | }
63 |
64 | // 获取所有的 issue id,以获取对应的 User Story 的标题信息,作为业务的上下文使用
65 | val storyIds = parsedMsgs.map { it.references }.flatten()
66 | val stories = storyIds.map {
67 | try {
68 | project.fetchStory(it.issue)
69 | } catch (e: Exception) {
70 | logger.error("fetch story error: $it", e)
71 | null
72 | }
73 | }.filterNotNull()
74 |
75 | context.businessContext = stories.joinToString(System.lineSeparator(), transform = Issue::title)
76 |
77 | // 生成 patch 文件,以获取 diff 的内容,并过滤掉不需要 review 的文件,诸如 .json、.yaml 等
78 | val patch = diff.patchBetween(option.sinceCommit, option.untilCommit)
79 | context.changes = patch.filter {
80 | project.commitLog?.isIgnoreFile(it.key) ?: true
81 | }.map {
82 | it.value.content
83 | }.joinToString(System.lineSeparator())
84 |
85 | // 生成 prompt,以获取 review 的结果
86 | promptFactory.context = context
87 | val messages = promptFactory.createPrompt(project, "")
88 |
89 | logger.info("messages: $messages")
90 |
91 | project.connector().streamCompletion(messages).blockingForEach {
92 | print(it)
93 | }
94 |
95 | return ""
96 | }
97 |
98 | companion object {
99 | val logger = LoggerFactory.getLogger(CodeReviewAction::class.java)
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/domain/review/CodeReviewContext.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.review
2 |
3 | data class CodeReviewContext(
4 | var businessContext: String = "",
5 | var fullMessage: String = "",
6 | var changes: String = "",
7 | )
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/domain/review/CodeReviewPromptFactory.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.review
2 |
3 | import cc.unitmesh.genius.prompt.PromptFactory
4 |
5 | class CodeReviewPromptFactory(public override var context: CodeReviewContext = CodeReviewContext()) :
6 | PromptFactory("code-review") {
7 | override val templatePath = "simple-review.open-ai.vm"
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/domain/review/ReviewOption.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.review
2 |
3 | import cc.unitmesh.genius.context.ActionOption
4 | import cc.unitmesh.genius.project.GeniusProject
5 |
6 | class ReviewOption(
7 | val path: String = "",
8 | val verbose: Boolean,
9 | val repo: String,
10 | val branch: String,
11 | val sinceCommit: String,
12 | val untilCommit: String,
13 | val commitOptionFile: String,
14 | val project: GeniusProject,
15 | ) : ActionOption {
16 |
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/project/BuildSystemType.java:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.project;
2 |
3 | public enum BuildSystemType {
4 | GRADLE,
5 | MAVEN,
6 | YARN,
7 | NPM,
8 | PYTHON,
9 | UNKNOWN;
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/project/BuildSystemTypeDescriptor.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.project
2 |
3 | class BuildSystemTypeDescriptor {
4 | fun getBuildSystemType(project: GeniusProject): BuildSystemType {
5 | TODO()
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/project/GeniusProject.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.project
2 |
3 | import cc.unitmesh.cf.core.llms.LlmProvider
4 | import cc.unitmesh.cf.core.llms.MockLlmProvider
5 | import cc.unitmesh.connection.ConnectionConfig
6 | import cc.unitmesh.connection.MockLlmConnection
7 | import cc.unitmesh.connection.OpenAiConnection
8 | import cc.unitmesh.genius.devops.Issue
9 | import cc.unitmesh.genius.devops.KanbanFactory
10 | import cc.unitmesh.openai.OpenAiProvider
11 | import com.charleskorn.kaml.PolymorphismStyle
12 | import com.charleskorn.kaml.Yaml
13 | import com.charleskorn.kaml.YamlConfiguration
14 | import kotlinx.serialization.Serializable
15 | import kotlinx.serialization.Transient
16 | import kotlinx.serialization.decodeFromString
17 | import java.io.File
18 | import java.nio.file.FileSystems
19 | import java.nio.file.Path
20 |
21 | @Serializable
22 | data class GeniusProject(
23 | val name: String = "",
24 | val path: String = "",
25 | val store: GeniusStore? = null,
26 | val kanban: GeniusKanban? = null,
27 | val commitLog: GeniusCommitLog? = null,
28 | val connection: String = "connection.yml",
29 | ) {
30 | var repoUrl: String = ""
31 |
32 | fun fetchStory(id: String): Issue {
33 | return KanbanFactory.fromRepositoryUrl(repoUrl, kanban!!.token)!!.fetch(id)
34 | }
35 |
36 | fun connector(): LlmProvider {
37 | val text = File(connection).readBytes().toString(Charsets.UTF_8)
38 | val configuration = YamlConfiguration(polymorphismStyle = PolymorphismStyle.Property)
39 | val connection = Yaml(configuration = configuration).decodeFromString(text).convert()
40 |
41 | val llmProvider = when (connection) {
42 | is OpenAiConnection -> OpenAiProvider(connection.apiKey, connection.apiHost)
43 | is MockLlmConnection -> MockLlmProvider(connection.response)
44 | else -> throw Exception("unsupported connection type: ${connection.type}")
45 | }
46 |
47 | return llmProvider
48 | }
49 |
50 |
51 | companion object {
52 | fun fromYml(yaml: String): GeniusProject {
53 | val conf = YamlConfiguration(polymorphismStyle = PolymorphismStyle.Property)
54 | return Yaml(configuration = conf).decodeFromString(serializer(), yaml)
55 | }
56 | }
57 | }
58 |
59 | /**
60 | * Vector store of a project will be used to search project code and documents.
61 | */
62 | @Serializable
63 | data class GeniusStore(
64 | val indexName: String = "",
65 | )
66 |
67 | /**
68 | * Kanban configuration of project, will be used to fetch issues from kanban board.
69 | */
70 | @Serializable
71 | data class GeniusKanban(
72 | val url: String = "",
73 | val token: String = "",
74 | val type: String = "",
75 | )
76 |
77 | @Serializable
78 | data class GeniusCommitLog(
79 | val ignoreType: List,
80 | /**
81 | * Ignore files when generate commit log, which is a list of glob pattern.
82 | */
83 | val ignorePatterns: List,
84 | ) {
85 | @Transient
86 | private val compiledPatterns = ignorePatterns.map {
87 | FileSystems.getDefault().getPathMatcher("glob:$it")
88 | }
89 |
90 | fun isIgnoreType(type: String): Boolean {
91 | return !ignoreType.contains(type)
92 | }
93 |
94 | fun isIgnoreFile(filename: String): Boolean {
95 | return compiledPatterns.none { it.matches(Path.of(filename)) }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/prompt/PromptBuilder.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.prompt
2 |
3 | interface PromptBuilder {
4 |
5 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/prompt/PromptFactory.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.prompt
2 |
3 | import cc.unitmesh.cf.core.llms.LlmMsg
4 | import cc.unitmesh.genius.project.GeniusProject
5 | import cc.unitmesh.template.TemplateRoleSplitter
6 | import cc.unitmesh.template.VelocityCompiler
7 |
8 | abstract class PromptFactory(promptsBasePath: String) {
9 | protected val template = VelocityCompiler()
10 | protected val promptsLoader: PromptsLoader
11 | protected val splitter = TemplateRoleSplitter()
12 | protected open val context: Any = ""
13 |
14 | open val templatePath = ""
15 |
16 | init {
17 | promptsLoader = PromptsLoader(promptsBasePath)
18 | }
19 |
20 | open fun createPrompt(project: GeniusProject, description: String): List {
21 | val prompt = promptsLoader.getTemplate(templatePath)
22 |
23 | val msgs = splitter.split(prompt)
24 | val messages = LlmMsg.fromMap(msgs).toMutableList()
25 |
26 | messages.map {
27 | if (it.role == LlmMsg.ChatRole.User) {
28 | template.append("context", context)
29 | it.content = template.compileToString(it.content)
30 | }
31 | }
32 |
33 | return messages
34 | }
35 | }
--------------------------------------------------------------------------------
/src/main/kotlin/cc/unitmesh/genius/prompt/PromptsLoader.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.prompt
2 |
3 | import java.nio.charset.Charset
4 |
5 | class PromptsLoader(prefix: String) {
6 | private val classLoader: ClassLoader = this.javaClass.classLoader
7 | private val defaultPrefix: String = prefix.trimEnd('/')
8 |
9 | fun getTemplate(path: String): String {
10 | val resourceUrl = classLoader.getResource("$defaultPrefix/$path") ?: throw PromptNotFoundError(path)
11 | val bytes = resourceUrl.readBytes()
12 | return String(bytes, Charset.forName("UTF-8"))
13 | }
14 | }
15 |
16 | class PromptNotFoundError(path: String) : Exception("Prompt not found at path: $path")
17 |
--------------------------------------------------------------------------------
/src/main/resources/code-review/simple-review.open-ai.vm:
--------------------------------------------------------------------------------
1 | ```user```
2 | You are a senior software developer, who can help me do code review a commit.
3 |
4 | Use the following response format, keeping the section headings as-is, and provide
5 | your feedback. Use bullet points for each response. The provided examples are for
6 | illustration purposes only and should not be repeated.
7 |
8 | **Syntax and logical errors (example)**:
9 | - Incorrect indentation on line 12
10 | - Missing closing parenthesis on line 23
11 |
12 | **Code refactoring and quality (example)**:
13 | - Replace multiple if-else statements with a switch case for readability
14 | - Extract repetitive code into separate functions
15 |
16 | **Performance optimization (example)**:
17 | - Use a more efficient sorting algorithm to reduce time complexity
18 | - Cache results of expensive operations for reuse
19 |
20 | **Security vulnerabilities (example)**:
21 | - Sanitize user input to prevent SQL injection attacks
22 | - Use prepared statements for database queries
23 |
24 | **Best practices (example)**:
25 | - Add meaningful comments and documentation to explain the code
26 | - Follow consistent naming conventions for variables and functions
27 |
28 | Business Context: ${context.businessContext}
29 |
30 | Commit Message: ${context.fullMessage}
31 |
32 | Code Changes: ${context.changes}
33 |
34 | 作为您的 Tech Lead,我只关注一些关键的代码审查问题。请为我提供一个关键摘要,按照以下格式:
35 |
36 | 关键摘要: // 你应该使用中文来回答,合并相似的问题
37 | 是否建议立即修改: // 是/否
38 |
--------------------------------------------------------------------------------
/src/main/resources/container/docker/docker-file.vm:
--------------------------------------------------------------------------------
1 | Please write a Dockerfile with minimal steps.
2 |
3 | - I need to build the application with Gradle and run with JDK 11.
4 | - I need the building to be done in separate base image than running the build.
5 | - I need the application port to be 3000.
6 |
7 | Output only the Dockerfile content without any explanation.
8 |
--------------------------------------------------------------------------------
/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UTF-8
5 |
6 | [SCANNER] %logger{36} %msg%n
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/github/common/github_actions_events.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create build.yml YAML file for GitHub Action which triggers on push.
3 | Code:
4 | on:
5 | push
6 | Description:
7 | Create build.yml YAML file for GitHub Action which triggers on push and pull request.
8 | Code:
9 | on:
10 | push:
11 | pull_request:
12 | Description:
13 | Create build.yml YAML file for GitHub Action which triggers on push to branches 'main', all 'releases'.
14 | Code:
15 | on:
16 | push:
17 | branches:
18 | - main
19 | - releases/**
20 | Description:
21 | Create build.yml YAML file for GitHub Action which triggers on opened or closed pull request to branches 'main'.
22 | Code:
23 | on:
24 | pull_request:
25 | branches:
26 | - main
27 | types:
28 | - opened
29 | - closed
30 | Description:
31 | Create build.yml YAML file for GitHub Action which triggers on push to any branch if any kotlin file change.
32 | Code:
33 | on:
34 | push:
35 | paths:
36 | - '**.kt'
37 | Description:
38 | Create build.yml YAML file for GitHub Action which triggers at 8am every day.
39 | Code:
40 | on:
41 | schedule:
42 | - cron: '0 8 * * *'
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/github/common/github_actions_publish_docker.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create build.yml YAML file for GitHub Action.
3 | Define image namespace in variable DOCKER_HUB_NAMESPACE as jetbrains.
4 | Define image repository name in variable DOCKER_HUB_REPOSITORY as hackathon.
5 | Use latest ubuntu version.
6 | Checkout source code.
7 | Log in to Docker Hub using secret DOCKER_USERNAME as username and DOCKER_PASSWORD as password.
8 | Extract metadata for image.
9 | Build and push Docker.
10 | Use docker file from project root.
11 | Use information about tags and labels from docker metadata from previous step.
12 | Code:
13 | env:
14 | DOCKER_HUB_NAMESPACE: jetbrains
15 | DOCKER_HUB_REPOSITORY: hackathon
16 | jobs:
17 | push_to_registry:
18 | name: Push Docker image to Docker Hub
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Check out the repo
22 | uses: actions/checkout@v3
23 |
24 | - name: Log in to Docker Hub
25 | uses: docker/login-action@v2
26 | with:
27 | username: ${{ secrets.DOCKER_USERNAME }}
28 | password: ${{ secrets.DOCKER_PASSWORD }}
29 |
30 | - name: Extract metadata (tags, labels) for Docker
31 | id: meta
32 | uses: docker/metadata-action@v4
33 | with:
34 | images: ${{ env.DOCKER_HUB_NAMESPACE }}/${{ env.DOCKER_HUB_REPOSITORY }}
35 |
36 | - name: Build and push Docker image
37 | uses: docker/build-push-action@v4
38 | with:
39 | context: .
40 | push: true
41 | tags: ${{ steps.meta.outputs.tags }}
42 | labels: ${{ steps.meta.outputs.labels }}
43 | Description:
44 | Create build.yml YAML file for GitHub Action which on latest ubuntu version push Docker image which name as repository has to GitHub Docker Registry using docker file from project root
45 | Code:
46 | env:
47 | REGISTRY: ghcr.io
48 | IMAGE_NAME: ${{ github.repository }}
49 |
50 | jobs:
51 | build-and-push-image:
52 | runs-on: ubuntu-latest
53 | permissions:
54 | contents: read
55 | packages: write
56 |
57 | steps:
58 | - name: Checkout repository
59 | uses: actions/checkout@v3
60 |
61 | - name: Log in to the Container registry
62 | uses: docker/login-action@v2
63 | with:
64 | registry: ${{ env.REGISTRY }}
65 | username: ${{ github.actor }}
66 | password: ${{ secrets.GITHUB_TOKEN }}
67 |
68 | - name: Extract metadata (tags, labels) for Docker
69 | id: meta
70 | uses: docker/metadata-action@v3
71 | with:
72 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
73 |
74 | - name: Build and push Docker image
75 | uses: docker/build-push-action@v4
76 | with:
77 | context: .
78 | push: true
79 | tags: ${{ steps.meta.outputs.tags }}
80 | labels: ${{ steps.meta.outputs.labels }}
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/github/gradle/github_actions_build_gradle.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create build.yml YAML file for GitHub Action for java version 17 gradle project which use latest ubuntu version builds project and runs tests.
3 | Code:
4 | on:
5 | push
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v3
11 | - name: Set up JDK 17
12 | uses: actions/setup-java@v3
13 | with:
14 | java-version: '17'
15 | - name: Validate Gradle wrapper
16 | uses: gradle/wrapper-validation-action@v2
17 | - name: Build with Gradle
18 | uses: gradle/gradle-build-action@v2
19 | with:
20 | arguments: build
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/github/gradle/github_actions_publish_gradle.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create build.yml YAML file for GitHub Action.
3 | Project build system is 'gradle'.
4 | Setup java version '11', distribution 'adopt'
5 | Build project.
6 | Publish package to maven repository.
7 | Take MAVEN_USERNAME env variable from OSSRH_USERNAME secret
8 | Take MAVEN_PASSWORD env variable from OSSRH_TOKEN secret
9 | Code:
10 | jobs:
11 | publish:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Set up Java
16 | uses: actions/setup-java@v3
17 | with:
18 | java-version: '11'
19 | distribution: 'adopt'
20 | - name: Validate Gradle wrapper
21 | uses: gradle/wrapper-validation-action@v1
22 | - name: Publish package
23 | uses: gradle/gradle-build-action@v2
24 | with:
25 | arguments: publish
26 | env:
27 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
28 | MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/github/maven/github_actions_build_maven.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create build.yml YAML file for GitHub Action for java version 17 maven project which on latest ubuntu version builds project and runs tests
3 | Code:
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v3
9 | - name: Set up JDK 17
10 | uses: actions/setup-java@v3
11 | with:
12 | java-version: '17'
13 | - name: Build with Maven
14 | run: mvn --batch-mode --update-snapshots package
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/github/maven/github_actions_publish_maven.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create build.yml YAML file for GitHub Action for java gradle project publish package to maven repository
3 | Code:
4 | jobs:
5 | publish:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v3
9 | - name: Set up Maven Central Repository
10 | uses: actions/setup-java@v3
11 | with:
12 | java-version: '11'
13 | server-id: ossrh
14 | server-username: MAVEN_USERNAME
15 | server-password: MAVEN_PASSWORD
16 | - name: Publish package
17 | run: mvn --batch-mode deploy
18 | env:
19 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
20 | MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
--------------------------------------------------------------------------------
/src/main/resources/prompts/cicd/jenkins/gradle/jenkins_build_gradle.prompt:
--------------------------------------------------------------------------------
1 | Description:
2 | Create Jenkinsfile for Jenkins for java version 17 gradle project which use latest ubuntu version builds project and runs tests.
3 | Code:
4 | node {
5 | agent {
6 | label 'ubuntu'
7 | }
8 |
9 | tools {
10 | jdk 'jdk_17_latest'
11 | }
12 |
13 | stage 'Stage Checkout'
14 |
15 | checkout scm
16 | sh 'git submodule update --init'
17 |
18 | stage 'Stage Build'
19 | sh './gradlew build'
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/kotlin/cc/unitmesh/genius/devops/KanbanFactoryTest.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops;
2 |
3 | import cc.unitmesh.genius.devops.kanban.GitHubKanban
4 | import cc.unitmesh.genius.devops.kanban.GitlabKanban
5 | import io.kotest.matchers.shouldBe
6 | import org.junit.jupiter.api.Test
7 |
8 | class KanbanServiceTest {
9 |
10 | @Test
11 | fun should_return_GitHubKanban_when_given_valid_github_url() {
12 | // given
13 | val url = "https://github.com/example/repository"
14 |
15 | // when
16 | val result = KanbanFactory.fromRepositoryUrl(url, "token")
17 |
18 | // then
19 | result!!.javaClass shouldBe GitHubKanban::class.java
20 | }
21 |
22 | @Test
23 | fun should_return_GitlabKanban_when_given_valid_gitlab_url() {
24 | // given
25 | val url = "https://gitlab.com/example/repository"
26 |
27 | // when
28 | val result = KanbanFactory.fromRepositoryUrl(url, "token")
29 |
30 | // then
31 | result!!.javaClass shouldBe GitlabKanban::class.java
32 | }
33 | }
--------------------------------------------------------------------------------
/src/test/kotlin/cc/unitmesh/genius/devops/kanban/GitHubKanbanTest.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.devops.kanban;
2 |
3 | import org.junit.jupiter.api.Test
4 | import org.junit.jupiter.api.Assertions.assertEquals
5 |
6 | class GitHubKanbanTest {
7 |
8 | @Test
9 | fun should_formatUrl_correctly() {
10 | // given
11 | val repoUrl = "https://github.com/unitmesh/devti"
12 | val expectedFormattedUrl = "unitmesh/devti"
13 |
14 | // when
15 | val formattedUrl = GitHubKanban.formatUrl(repoUrl)
16 |
17 | // then
18 | assertEquals(expectedFormattedUrl, formattedUrl)
19 | }
20 | }
--------------------------------------------------------------------------------
/src/test/kotlin/cc/unitmesh/genius/domain/review/CodeReviewPromptFactoryTest.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.domain.review;
2 |
3 | import cc.unitmesh.genius.project.GeniusProject
4 | import io.kotest.matchers.shouldNotBe
5 | import org.junit.jupiter.api.Test;
6 |
7 | class CodeReviewPromptFactoryTest {
8 | @Test
9 | fun should_success_create_prompt() {
10 | val codeReviewPromptFactory = CodeReviewPromptFactory()
11 | val prompt = codeReviewPromptFactory.createPrompt(GeniusProject(), "test")
12 | prompt shouldNotBe null
13 | }
14 | }
--------------------------------------------------------------------------------
/src/test/kotlin/cc/unitmesh/genius/project/GeniusProjectTest.kt:
--------------------------------------------------------------------------------
1 | package cc.unitmesh.genius.project;
2 |
3 | import io.kotest.matchers.shouldBe
4 | import org.junit.jupiter.api.Test
5 |
6 | class GeniusProjectTest {
7 |
8 | @Test
9 | fun `fromYml should return GeniusProject object`() {
10 | // given
11 | val yaml = """
12 | name: "ChocolateFactory"
13 | path: "." # relative to the project root, or GitHub repo, like "unitmesh/chocolate-factory"
14 |
15 | # store the changelog in the repo
16 | store:
17 | indexName: "unitmesh/chocolate-factory" # default to github repo
18 |
19 | kanban:
20 | type: GitHub
21 | token: "xx"
22 |
23 | commitLog:
24 | ignoreType: [ "chore", "docs", "style" ]
25 | ignorePatterns: ["*.md", "*.json"]
26 | """.trimIndent()
27 |
28 | // when
29 | val geniusProject = GeniusProject.fromYml(yaml)
30 |
31 | // then
32 | geniusProject.name shouldBe "ChocolateFactory"
33 | geniusProject.path shouldBe "."
34 | }
35 | }
--------------------------------------------------------------------------------