Skip to content

Commit 3d88698

Browse files
Initial implementation
1 parent 4a260f6 commit 3d88698

269 files changed

Lines changed: 21589 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 418 additions & 0 deletions
Large diffs are not rendered by default.

.github/dependabot.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version: 2
2+
3+
updates:
4+
- package-ecosystem: "gradle"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
9+
- package-ecosystem: "github-actions"
10+
directory: "/"
11+
schedule:
12+
interval: "weekly"

.github/workflows/ci.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
workflow_dispatch:
6+
push:
7+
release:
8+
types: [ published ]
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
unit-tests:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- uses: actions/setup-java@v5
21+
with:
22+
java-version: 21
23+
distribution: temurin
24+
25+
- uses: gradle/actions/setup-gradle@v5
26+
with:
27+
cache-read-only: false
28+
29+
- run: ./gradlew test
30+
31+
- name: Junit report
32+
uses: mikepenz/action-junit-report@v4
33+
if: success() || failure()
34+
with:
35+
report_paths: '**/test-results/*/*.xml'
36+
37+
publish-to-homebrew:
38+
runs-on: ubuntu-latest
39+
# if: github.event_name == 'release'
40+
steps:
41+
- uses: actions/checkout@v4
42+
43+
- uses: actions/setup-java@v5
44+
with:
45+
java-version: 21
46+
distribution: temurin
47+
48+
- uses: gradle/actions/setup-gradle@v5
49+
with:
50+
cache-read-only: false
51+
52+
# - run: ./gradlew check
53+
54+
- id: publish
55+
run: ./gradlew publish
56+
env:
57+
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
58+
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
59+
JRELEASER_GITHUB_TOKEN: dummy
60+
61+
- id: generate-token
62+
uses: actions/create-github-app-token@v1
63+
with:
64+
app-id: ${{ secrets.ALLEGRO_HOMEBREW_APP_ID }}
65+
private-key: ${{ secrets.ALLEGRO_HOMEBREW_PRIVATE_KEY }}
66+
owner: allegro
67+
repositories: homebrew-tap
68+
69+
- name: Checkout Homebrew repository
70+
uses: actions/checkout@v4
71+
with:
72+
repository: allegro/homebrew-tap
73+
path: homebrew-tap
74+
token: ${{ steps.generate-token.outputs.token }}
75+
76+
- name: Replace file in Homebrew repository
77+
run: |
78+
ls -lah allwrite-runner/build/jreleaser/assemble/allwrite/jlink
79+
cp allwrite-runner/build/jreleaser/package/allwrite/brew/Formula/allwrite.rb homebrew-tap/Formula/allwrite.rb
80+
git add homebrew-tap/Formula/allwrite.rb
81+
82+
- name: Commit changes in Homebrew repository
83+
uses: dsanders11/github-app-commit-action@v2
84+
with:
85+
owner: allegro
86+
repo: homebrew-tap
87+
message: 'Release allwrite ${{ steps.publish.outputs.published-version }}'
88+
token: ${{ steps.generate-token.outputs.token }}
89+
working-directory: ./homebrew-tap

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.gradle
2+
.idea
3+
**/build
4+
**/.kotlin
5+
6+
# OpenCode
7+
.classpath
8+
.project
9+
.factorypath
10+
.settings/
11+
bin/
12+
13+
OPEN_SOURCE_PLAN.md

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# AGENTS.md
2+
3+
You MUST always follow these rules:
4+
* Do not write any comments in the code

CONTRIBUTING.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Contributing guide
2+
3+
## How to write a recipe?
4+
5+
All recipe implementations are kept in the `allwrite-recipes` module.
6+
7+
In general, you should follow the official [Authoring Recipes](https://docs.openrewrite.org/authoring-recipes) docs from OpenRewrite.
8+
9+
However, `allwrite` has some custom features that you can use.
10+
11+
### Visibility
12+
13+
Every recipe within `allwrite-recipes` must provide the `visibility:[internal/public]` tag. Public recipes will be presented to the user via
14+
`allwrite ls` command.
15+
16+
### Friendly names
17+
18+
Every public recipe must provide a friendly name in the form of 2 tags:
19+
* `group:<someGroup>`
20+
* `recipe:<someRecipe>`
21+
22+
For example, the following set of tags [`group:workflows`, `recipe:introduceSetupGradle`] will result in a recipe that can be executed like that:
23+
```
24+
allwrite run workflows/introduceSetupGradle
25+
```
26+
27+
### Convenient base classes
28+
29+
For convenience, you can extend either `AllegroRecipe` or `AllegroScanningRecipe`. It will build all required tags for you:
30+
```kotlin
31+
class SomeRecipe : AllegroRecipe(
32+
displayName = "Some recipe", // optional, defaults to class name
33+
description = "Some description.", // optional, defaults to displayName + '.'
34+
visibility = PUBLIC, // optional, defaults to INTERNAL
35+
group = "some-group", // required if the visibility is PUBLIC
36+
recipe = "some-recipe" // required if the visibility is PUBLIC
37+
) {
38+
// your implementation
39+
}
40+
```
41+
42+
### Limiting which files should be parsed
43+
44+
> [!TIP]
45+
> It may be very useful for improving performance and overcoming OpenRewrite issues with parsing Groovy files
46+
47+
If your recipe is only interested in very specific files (for example it only modifies the `tycho.yaml` file) you can implement the `ParsingAwareRecipe`
48+
interface:
49+
```kotlin
50+
class SomeRecipe : AllegroRecipe(), ParsingAwareRecipe {
51+
52+
override fun selectFilesToParse(inputFiles: List<Path>): List<Path> {
53+
// return the files to be parsed
54+
}
55+
}
56+
```
57+
58+
## Architecture
59+
60+
The `allwrite` is a modular project, utilizing dependency injection capabilities from the [Koin](https://github.com/InsertKoinIO/koin) framework.
61+
62+
It consists of the following Gradle modules (that may contain one or more Koin modules):
63+
* `allwrite-runner` - provides both Application and Infrastructure layers for the CLI app
64+
* `allwrite-runtime` - provides core implementation interacting directly with the OpenRewrite runtime; equivalent of the Domain layer
65+
* `allwrite-recipes` - contains OpenRewrite recipes to be executed by `allwrite-runner`
66+
* `allwrite-completions` - provides annotation processors generating CLI auto-completions
67+
68+
The below diagram shows Koin modules, not Gradle modules. The rule of thumb is: we don't extract Koin module as a separate Gradle module unless required
69+
by the build logic. For example, `allwrite-runtime` must be Gradle module, because it is used by both `allwrite-runner` (at app runtime)
70+
and `allwrite-completions` (at app compile time).
71+
72+
Please keep the diagram up-to-date by editing `architecture.puml` file with the help of [PlantUML IntelliJ Plugin](https://plugins.jetbrains.com/plugin/7017-plantuml-integration) and replacing the rendered PNG.
73+
74+
If you don't like installing IntelliJ plugins, edit `architecture.puml` and execute the following command:
75+
```bash
76+
docker run --rm -v $(pwd):/app -w /app ghcr.io/plantuml/plantuml plantuml docs/architecture.puml
77+
```
78+
79+
![](docs/architecture.png)

Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM eclipse-temurin:21
2+
RUN apt update
3+
RUN apt install -y git
4+
ADD ./allwrite-runner/build/distributions/allwrite.tar /app
5+
RUN ln -s /app/allwrite/bin/allwrite-runner /allwrite
6+
ENTRYPOINT []

LICENSE

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2026 Allegro.pl
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,35 @@
11
allwrite
22
========
3+
4+
A CLI tool and a collection of [OpenRewrite](https://docs.openrewrite.org/) recipes for automated code transformations across YAML, Gradle, Java/Kotlin, and Spring projects.
5+
6+
It wraps OpenRewrite's runtime into a user-friendly CLI that can run recipes by name, integrate with GitHub Actions, and work with Dependabot PRs.
7+
8+
## Usage
9+
10+
Installation:
11+
12+
```bash
13+
brew install allwrite
14+
```
15+
16+
Run a recipe by friendly name:
17+
18+
```bash
19+
allwrite run springBoot/upgrade 3 4
20+
```
21+
22+
Run a recipe by fully-qualified name:
23+
24+
```bash
25+
allwrite run --recipe pl.allegro.tech.allwrite.recipes.SpringBoot4
26+
```
27+
28+
## Recipes
29+
30+
The `allwrite` CLI comes with all the free OpenRewrite migrations bundled (Java/Kotlin refactoring, Spring Boot upgrades, etc.).
31+
32+
In addition, it provides a collection of custom recipes that aim to fill the gaps. See [RECIPES.md](RECIPES.md) for the full list.
33+
34+
If you're a library maintainer and want to automate the migration process for your users (or just have prepared a recipe that may be useful for others),
35+
we would love to see your contribution! ❤️

0 commit comments

Comments
 (0)