Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: setup Dockerfile & Docker Compose for project-wide testing #1465

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

nightknighto
Copy link
Contributor

@nightknighto nightknighto commented Apr 2, 2025

Description

This PR improves the Dockerized testing workflow by simplifying the command and making use of caching.

  • Reduce the command needed to test to a simple docker compose up.
  • Make use of caching mechanisms in Dockerfile, ensures the npm modules are not re-installed unless required, saving significant time when re-testing.
  • Allowing the dockerized testing workflow to be more maintainable and easy to extend or configure.

Related issue(s)

Fixes #1423

Screenshots

  1. Running the docker compose

image
...
image

  1. Demonstrate caching. Changed various js and md files then re-tested.
    image
    Notice: RUN npm ci is cached, while changed files were only reflected in the next line.

Design Choices

Writing the dockerfile in a correct way to cache npm modules was the most difficult part of the PR, due to the monorepo structure. Some possible ways were:

1- Manually copying each package.json file from the project. Ex:

COPY package*.json ./
COPY apps/generator/package*.json ./apps/generator/
...
COPY packages\templates\clients\js\websocket\package.json packages\templates\clients\js\websocket\package.json
...

Problem: While manually copying package.json of each package could be ok, the folder structure of the package.json must be written manually and would need manual edit if changed. This problem is very apparent in the js websocket client, which has a deeply nested package.json. Refused this approach.

2- Using turbo prune command. Turborepo CLI has a command that can prune a project out of modules and divide it into a folder of package.json with respecting the nested structure, and a folder of source code. The first folder will be used to install npm modules, and the second will be to add source code.

RUN turbo prune @asyncapi/generator @asyncapi/template-js-websocket-client @asyncapi/generator-components --docker --out-dir /out

A small problem is that the command requires a scope (a package to prune as a target), and there is no all option, so we have to specify all package names. Some packages include other packages as dependencies so some names can be skipped. I've opened an issue anyways in their github: vercel/turborepo#10267

This approach gave great results, and is the chosen one.

Summary by CodeRabbit

  • Chores
    • Added a .dockerignore file to exclude unnecessary files from container builds, enhancing efficiency.
  • Documentation
    • Simplified testing instructions for a clean, container-based environment.
  • New Features
    • Introduced a multi-stage build process for the application.
    • Added a dedicated testing service in the Docker Compose configuration, streamlining development workflows.

Copy link

changeset-bot bot commented Apr 2, 2025

⚠️ No Changeset found

Latest commit: dc83bca

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

coderabbitai bot commented Apr 2, 2025

Walkthrough

This pull request introduces new Docker configuration files to streamline testing. A .dockerignore file is added to exclude unnecessary files from Docker builds. A multi-stage Dockerfile is created to optimize dependency installation and execution of tests. The docker-compose.yaml file now includes a service named test that runs npm test. Additionally, Development.md has been updated to simplify the command from docker run to docker compose up, ensuring a cleaner and more maintainable test environment.

Changes

Files Change Summary
.dockerignore, Dockerfile, docker-compose.yaml Added new Docker configuration files: a .dockerignore to skip unnecessary files, a multi-stage Dockerfile for dependency caching and test execution, and a docker-compose.yaml with a new test service running npm test.
Development.md Updated testing instructions to use docker compose up instead of the previous docker run command, simplifying the process for isolated Docker testing.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant DC as Docker Compose
  participant Container as Docker Container

  Dev->>DC: Run 'docker compose up'
  DC->>Container: Build image using Dockerfile
  Container->>Container: Execute npm ci & npm test
  Container-->>DC: Return test results
  DC-->>Dev: Display test results
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement Docker Compose-based isolated testing environment using a Dockerfile, docker-compose configuration, and .dockerignore (#1423)

Suggested labels

ready-to-merge

Suggested reviewers

  • Florence-Njeri
  • asyncapi-bot-eve
  • magicmatatjahu
  • derberg

Poem

Oh, I’m a rabbit with a joyful hop,
Docker files in line, I just can’t stop!
Ignoring noise with my .dockerignore so neat,
Building and testing with a rhythmic beat.
With every command, my hops do sing,
A code kingdom where new features bring.
Hoppy days ahead — let the changes ring!


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
docker-compose.yaml (1)

1-7: Docker Compose Service Configuration
The test service is clearly defined and aligns with the new Dockerized testing workflow. A couple of suggestions:

  • Verify Compatibility: Ensure that the pull_policy: build setting is supported by the specific Docker Compose version you are using. In some contexts, this might need to be defined within a build block or adapted to the expected schema.
  • Context Clarity: Since both image and build are provided, double-check that the intended build process is triggered as expected and that there’s no ambiguity in which definition takes precedence.
Development.md (1)

53-53: Clarification Note for Docker Testing
The additional note on line 53 clearly explains that tests run in a clean environment with freshly installed dependencies. This is useful for user understanding. Consider adding an optional troubleshooting tip or reference link for users who might not be familiar with Docker environments.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae29b46 and af4e539.

📒 Files selected for processing (4)
  • .dockerignore (1 hunks)
  • Development.md (2 hunks)
  • Dockerfile (1 hunks)
  • docker-compose.yaml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test generator as dependency with Node 18
  • GitHub Check: Test generator as dependency with Node 20
🔇 Additional comments (4)
.dockerignore (1)

1-38: .dockerignore File Review
The patterns in the .dockerignore file are comprehensive, covering common Node.js artifacts (like node_modules, log files, and environment files), build artifacts, Git files, IDE configurations, OS-generated files, and test outputs. This will help keep the Docker build context lean and efficient.

Dockerfile (1)

1-39: Multi-Stage Dockerfile for Optimized Testing

  • The multi-stage build is well-structured: the installer stage uses turbo prune to extract only the necessary package files and source code, which is a smart technique for reducing build context size and enhancing caching.
  • Using npm ci in the final stage ensures a clean, reproducible installation of dependencies based solely on the pruned files.
  • The final command, CMD ["npm", "test"], aligns perfectly with the intended testing workflow.
    Overall, this Dockerfile is well-designed to balance build efficiency with the need for a consistent testing environment.
Development.md (2)

50-51: Simplified Docker Compose Command Update
The change to use docker compose up simplifies the testing process and leverages the new service configurations. This reduces complexity for users who previously had to deal with more cumbersome docker run commands.


180-180: Additional Debugging Guidance
Encouraging users to open an issue if persistent problems arise is a good proactive step to support troubleshooting and community engagement. Ensure that your issue template is prepared to capture the necessary details for Docker-related problems.

@nightknighto nightknighto changed the title feat: Setup Dockerfile & Docker Compose for project-wide testing feat: setup Dockerfile & Docker Compose for project-wide testing Apr 2, 2025
@nightknighto
Copy link
Contributor Author

Regarding SonarCube notes, I believe the notes aren't significant due to this Docker workflow being used only for testing, and not production.

@nightknighto
Copy link
Contributor Author

@derberg What do you think about the new dev workflow?

@derberg
Copy link
Member

derberg commented Apr 8, 2025

the problem is that SonarCloud report is red and blocking merging

and actually, Dockerfile is not only used by us for testing, it is also used by people that still use ag CLI

@derberg
Copy link
Member

derberg commented Apr 8, 2025

nevermind about my comment about Dockerfile, now I get you don't want to use https://github.com/asyncapi/generator/blob/master/apps/generator/Dockerfile but have one for entire monorepo for dev purpose only

@derberg derberg changed the title feat: setup Dockerfile & Docker Compose for project-wide testing chore: setup Dockerfile & Docker Compose for project-wide testing Apr 8, 2025
@nightknighto nightknighto requested a review from derberg April 8, 2025 19:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
Dockerfile (2)

7-10: Installer Stage – Copying Project Files
The installer stage copies the entire project into the container via COPY . ., preparing for subsequent pruning. Make sure your .dockerignore is correctly configured (e.g., to exclude node_modules and other non-essential files) so that the build context stays lean.


12-19: Turbo Prune Optimization
The command

RUN npx [email protected] prune @asyncapi/generator @asyncapi/template-js-websocket-client @asyncapi/generator-components --docker --out-dir /out

effectively reduces the project to just the needed package.json files and related artifacts. It would be beneficial to document (perhaps via an inline comment or in project documentation) why using npx here is sufficient—clarifying that it auto-installs the required version when missing—and to ensure that the pinned version remains compatible with future changes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af4e539 and 0deebb0.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Test generator as dependency with Node 18
  • GitHub Check: Test generator as dependency with Node 20
  • GitHub Check: Test NodeJS PR - macos-13
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (5)
Dockerfile (5)

1-3: Base Image and Working Directory Setup
The Dockerfile uses node:18-alpine as a slim base image and sets the working directory to /app, which is clear and follows best practices.


23-30: Dependency Installation and Caching Strategy
The second stage copies over the pruned package.json and package-lock.json files, then runs npm ci --ignore-scripts. This approach leverages Docker caching to ensure faster dependency installation while maintaining consistency via the lock file.


32-34: Copying the Remaining Source Code
Copying the full source from /out/full/ ensures that only the essential files—filtered through the prune process—are included in the final image. This helps in keeping the image size minimal and aligns well with the caching strategy.


35-36: Setting Correct File Permissions
Changing the ownership of /app to the node user via RUN chown -R node:node /app is a solid security practice, ensuring that the application does not run as root.


38-41: Non-Root Execution and Default Command Configuration
Switching to the non-root node user and setting the default command to npm test are both in line with the PR objectives. These steps simplify the testing workflow while enhancing container security.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0deebb0 and 75d7aa0.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Hadolint (2.12.0)
Dockerfile

[error] 10-10: COPY with more than 2 arguments requires the last argument to end with /

(DL3021)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test generator as dependency with Node 20
  • GitHub Check: Test generator as dependency with Node 18
🔇 Additional comments (8)
Dockerfile (8)

1-4: Base Stage Initialization:
The base image is properly set to Node 18 on Alpine, and the working directory is configured as /app. This establishes a solid foundation for the multi-stage build.


12-20: Turbo Prune Command Execution:
The RUN npx [email protected] prune ... command efficiently prunes the project down to only the necessary package.json files and source code, optimizing the Docker caching mechanism. Just ensure that the package names and the turbo version remain up to date as the project evolves.


21-28: Dependency Setup in the Final Stage:
Copying the pruned package.json files and package-lock.json from the installer stage is correctly implemented. This approach leverages Docker caching effectively and minimizes reinstallation overhead during dependency installation.


29-31: Optimized Dependency Installation:
Using npm ci --ignore-scripts ensures a clean and reproducible installation of dependencies from the copied package files. This not only speeds up builds but also adds a layer of security by ignoring unwanted scripts during installation.


32-34: Copying Full Source Code:
The command COPY --from=installer /out/full/ . successfully brings over the full source code after dependencies are installed. This separation of concerns aids in efficient caching and clear organization of the build process.


35-37: File Ownership Adjustment:
The RUN chown -R node:node /app command correctly changes the ownership of the /app directory to the node user, ensuring appropriate file permissions when running the container as a non-root user.


38-39: Non-Root User Execution:
The directive USER node is an excellent security best practice, enforcing that the container runs with non-root privileges.


41-42: Default Command Configuration:
Setting CMD ["npm", "test"] as the default command aligns perfectly with the project’s testing objectives. This ensures that tests are run by default, which is key to the streamlined Dockerized testing workflow.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
Dockerfile (1)

9-11: Enhance COPY Command with Inline NOSONAR and Trailing Slash
The COPY command is currently split from its NOSONAR directive and lacks a trailing slash on the destination directory. To satisfy Hadolint rule DL3021 and ensure Sonar warnings are properly suppressed, consider combining them as follows:

-# NOSONAR
-COPY . .
+COPY . ./ // NOSONAR

This update explicitly attaches the NOSONAR directive to the command and clarifies the destination directory structure.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75d7aa0 and 99ba9c4.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Test generator as dependency with Node 18
  • GitHub Check: Test generator as dependency with Node 20
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (4)
Dockerfile (4)

1-3: Base Image and Working Directory Setup
The Dockerfile correctly starts with a lightweight Node.js 18 Alpine base image and properly sets the working directory to /app. This provides a solid base for subsequent build stages.


20-20: Prune Command with NPX for Package Optimization
Using npx [email protected] prune ... effectively prunes the project to the minimal required files for dependency management. NPX will automatically handle the installation if the specified version isn’t already available. Just ensure that the fixed version remains in line with project standards over time.


26-31: Optimized Dependency Installation for Caching
By copying only the pruned package.json files (and the corresponding package-lock.json) before running npm ci --ignore-scripts, the Dockerfile smartly leverages caching to avoid redundant installations. This approach improves build speed and consistency.


33-42: Ensuring Secure and Consistent Final Image
The final build stage is well-structured: it copies the complete source code, adjusts the ownership to the non-root node user, and sets the default command to run npm test. Running the container as a non-root user enhances security, and coupling this with the testing command aligns with the Dockerized testing workflow goals.

Copy link

sonarqubecloud bot commented Apr 9, 2025

Quality Gate Passed Quality Gate passed

Issues
1 New issue
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
Dockerfile (3)

1-3: Solid Base Image and Workdir Setup.
Lines 1–3 correctly use a lightweight node:18-alpine image and set the working directory to /app. This establishes a proper base for subsequent stages. Optional: Consider setting an environment variable (for example, ENV NODE_ENV test) if tests need to run under a specific environment.


15-22: Effective Use of Turbo Prune for Monorepo Organization.
Lines 15–22 use the RUN npx [email protected] prune ... command to slim down the project to only the necessary package-related files. This is a smart approach to leverage caching by isolating the dependency files. Remember that the list of package names is hardcoded; ensure you update these as your monorepo evolves.


41-44: Adherence to Security Best Practices with Non-root User and Clear Default Command.
Lines 41–44 switch the running user to node (ensuring the container does not run as root) and set the default command to run tests via CMD ["npm", "test"]. This matches the PR’s testing focus. Optionally, setting an explicit environment variable (such as ENV NODE_ENV test) here could further clarify the container’s role.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db2443c and dc83bca.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
Dockerfile (1)
Learnt from: nightknighto
PR: asyncapi/generator#1465
File: Dockerfile:0-0
Timestamp: 2025-04-09T14:19:06.716Z
Learning: In Dockerfiles, comments must begin with the `#` character and must be on their own line. Inline comments (like `// NOSONAR`) are not supported in Dockerfile syntax and will be interpreted as part of the command. SonarQube suppressions in Dockerfiles should be done using a separate comment line with the `#` prefix.
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Test generator as dependency with Node 20
  • GitHub Check: Test generator as dependency with Node 18
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (3)
Dockerfile (3)

5-13: Clear and Commented Installer Stage Initialization.
Lines 5–13 articulate the intent behind the installer stage. The comments explain why the entire project is copied (i.e. for the subsequent turbo prune process) and underscore that this is primarily for local development and testing. Just ensure that a corresponding .dockerignore file is in place to exclude unnecessary files (such as node_modules) and speed up the build.


24-31: Optimized Dependency Extraction in Final Stage – Part 1.
Lines 24–31 transition into the final build stage. Copying the pruned package.json files and package-lock.json before running npm ci --ignore-scripts is an effective use of caching that minimizes unnecessary reinstallation of dependencies when unrelated source files change.


32-39: Efficient Final Stage Execution and Security Enhancements.
Lines 32–39 execute the dependency installation and then copy over the remaining source code. Running npm ci --ignore-scripts guarantees a clean, reproducible dependency tree, and copying the rest of the source afterward leverages cache layers effectively. The chown -R node:node /app command on line 39 is a good security practice to ensure proper file ownership.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE] Use Docker Compose for Docker isolated testing
3 participants