Skip to content

Commit

Permalink
feat: setup code generation (#357)
Browse files Browse the repository at this point in the history
* feat: Add and configure swagger_dart_code_generator.

* feat: Add Earthly targets for code generation.

* feat: Restore `catalyst_analysis` package in the pipeline for the code generation.

* docs: Describe code generation process.

* feat: Add generated models.

* chore: Lint README.

* chore: Spell check.

* chore: Rename earthly targets based on CI style guide.

* refactor: Move generated files in catalyst_voices_services.

* refactor: Introduce `save_locally` arg to generate code locally.

* docs: Update code generator documentation.

---------

Co-authored-by: Oleksandr Prokhorenko <[email protected]>
  • Loading branch information
coire1 and minikin authored Mar 30, 2024
1 parent ab6b844 commit 147168e
Show file tree
Hide file tree
Showing 12 changed files with 2,073 additions and 2 deletions.
10 changes: 10 additions & 0 deletions Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,14 @@ repo-config:
WORKDIR /repo
COPY --dir .sqlfluff .

SAVE ARTIFACT /repo repo

# repo-catalyst-voices-packages - Create artifacts of catalyst_voices_packages
# we need to refer to in other earthly targets.
repo-catalyst-voices-packages:
FROM scratch

WORKDIR /repo
COPY --dir catalyst_voices_packages .

SAVE ARTIFACT /repo repo
36 changes: 36 additions & 0 deletions catalyst_voices/Earthfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
VERSION --try --global-cache --arg-scope-and-set 0.7

# If running this target with a local ssh agent active, set the environment
# variable EARTHLY_SSH_AUTH_SOCK='' to make the `+deps` target work. Earthly
# defaults to ssh authentication when it founds an ssh agent active but the
# flutter repo needs to be cloned via https to properly use the `channel`
# subcommand.
deps:
FROM debian:bookworm-slim
RUN apt-get update
Expand All @@ -24,6 +29,37 @@ src:
FROM +deps
COPY --dir pubspec.yaml lib packages web test test_driver integration_test .

# code-generator - Generates flutter code.
# Based on Catalyst Gateway OpenAPI specifications generates models, clients
# and serialization logic.
# It accepts [save_locally] ARG that when true place the artifacts in the
# proper folder of `catalyst_voices_services` local code.
code-generator:
ARG save_locally=false

FROM +deps
COPY --dir pubspec.yaml lib packages web test test_driver integration_test catalyst_voices
COPY ../+repo-catalyst-voices-packages/repo .
WORKDIR /frontend/catalyst_voices/packages/catalyst_voices_services
COPY ../catalyst-gateway+build/doc/cat-gateway-api.json openapi/cat-gateway-api.json
RUN flutter pub get
RUN dart run build_runner build --delete-conflicting-outputs

IF [ $save_locally = true ]
SAVE ARTIFACT lib/generated/catalyst_gateway/* AS LOCAL ./packages/catalyst_voices_services/lib/generated/catalyst_gateway/
ELSE
SAVE ARTIFACT lib/generated/catalyst_gateway
END

# check-flutter-code-generator - Checks that the code generation is consistent
# with the generated code currently in the repo.
check-flutter-code-generator:
FROM +code-generator
# Copy generated files in the local file tree to a temporary folder
COPY packages/catalyst_voices_services/lib/generated/catalyst_gateway /tmp/repo_generated
# Check diff between local code and earthly artifacts
RUN diff /tmp/repo_generated lib/generated/catalyst_gateway

# Build web version of Catalyst Voices
build:
FROM +src
Expand Down
34 changes: 34 additions & 0 deletions catalyst_voices/packages/catalyst_voices_services/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
# Catalyst Voices Services

## Automated Code Generation

This package is used for the code generation from the OpenAPI specifications.
It leverages `swagger_dart_code_generator` library and the artifacts generated
for the documentation of the `catalyst-gateway` backend.
The process consists in 3 simple steps:

1. The OpenAPI specification is picked from the artifact generated in the
`Earthfile` of `catalyst-gateway`.
2. The code is generated and saved as an artifact in the `Earthfile` of
`catalyst_voices`
3. Generated code is placed in the proper location within the `catalyst_voices`
project (`packages/catalyst_voices_services/lib/generated/catalyst_gateway`)
and it's ready for local usage.

This process can be achieved by executing from the `catalyst_voices` root
folder:

```sh
earthly +code-generator --platform=linux/amd64 --save_locally=true
```

The `--platform=linux/amd64` is necessary only when running the command from a
different platform.

In this way it's possible to locally generate the code using the same version of
OpenAPI specs defined in the backend code and developers have full control of
what should be committed.

To ensure the consistency of the generated code (especially when backend changes
occur) an earthly target is automatically executed on PR against main.
This `+check-flutter-code-generator` generates the code on the CI and compares
it with the code currently in repo, failing if there is an inconsistency.
15 changes: 15 additions & 0 deletions catalyst_voices/packages/catalyst_voices_services/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
targets:
$default:
sources:
- lib/**
- openapi/**
- $package$
builders:
chopper_generator:
options:
header: "// Generated code"
swagger_dart_code_generator:
options:
input_folder: "openapi/"
output_folder: "lib/generated/catalyst_gateway"
separate_models: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:collection/collection.dart';

enum Animals {
@JsonValue(null)
swaggerGeneratedUnknown(null),

@JsonValue('Dogs')
dogs('Dogs'),
@JsonValue('Cats')
cats('Cats'),
@JsonValue('Rabbits')
rabbits('Rabbits');

final String? value;

const Animals(this.value);
}

enum Network {
@JsonValue(null)
swaggerGeneratedUnknown(null),

@JsonValue('Mainnet')
mainnet('Mainnet'),
@JsonValue('Testnet')
testnet('Testnet'),
@JsonValue('Preprod')
preprod('Preprod'),
@JsonValue('Preview')
preview('Preview');

final String? value;

const Network(this.value);
}

enum ReasonRejected {
@JsonValue(null)
swaggerGeneratedUnknown(null),

@JsonValue('FragmentAlreadyInLog')
fragmentalreadyinlog('FragmentAlreadyInLog'),
@JsonValue('FragmentInvalid')
fragmentinvalid('FragmentInvalid'),
@JsonValue('PreviousFragmentInvalid')
previousfragmentinvalid('PreviousFragmentInvalid'),
@JsonValue('PoolOverflow')
pooloverflow('PoolOverflow');

final String? value;

const ReasonRejected(this.value);
}

enum VoterGroupId {
@JsonValue(null)
swaggerGeneratedUnknown(null),

@JsonValue('rep')
rep('rep'),
@JsonValue('direct')
direct('direct');

final String? value;

const VoterGroupId(this.value);
}
Loading

0 comments on commit 147168e

Please sign in to comment.