DEV Community

Cover image for Beyond GitHub: Universal Clients, Code Quality, and Bitbucket Traps
Flude team
Flude team

Posted on Originally published at blog.flude.guide

Beyond GitHub: Universal Clients, Code Quality, and Bitbucket Traps

Our core was working perfectly, and the SaaS cloud was ready to accept requests. But for third-party developers to easily start using Flude, they needed convenient entry points—integrations with their CI/CD pipelines.

CI Thin Clients

Initially, we wrote a plugin exclusively for GitHub Actions. However, a huge number of projects and commercial teams prefer GitLab and Bitbucket. It became obvious that we needed to extract the logic into a universal "thin client" that would work equally well on the "big three" platforms.

The Thin Client Philosophy

We moved all the base logic into clean, independent JavaScript files (control-plane-client.js, poll.js, download.js). No heavy builds or node_modules folders.

Our CI client became as dumb as possible: it simply zips the source code, sends it via API to our SaaS cloud, pings the task status at a set interval, and downloads the final ZIP archive with the generated documentation. All the computational magic, parsing, and rendering happen exclusively on the backend.

GitLab and Reporting Architecture (Code Quality)

Ci Thin Clients Gitlab Bitbucket Part 2

Integrating with GitLab brought an interesting architectural challenge.

In GitHub Actions, parser warnings (e.g., about undocumented methods) are easily output to the UI via GITHUB_STEP_SUMMARY and magic strings like ::notice::. GitLab doesn't understand this—it requires providing a special JSON artifact in the CodeClimate format.

An important architectural point: we fundamentally decided not to overload our lightweight client with format conversion logic. All this work is baked into the very heart of the core (engine/ude/reporting.py).

During the build, the engine collects all errors into a unified internal representation (Finding), and then translates it itself into all the necessary external formats: both SARIF (for GitHub) and CodeClimate (for GitLab). The client script in GitLab only has to extract the already generated codequality.json from the downloaded archive and hand it to the runner. Thanks to this, a native, convenient widget "Code Quality scans found N new findings" appears in the Merge Request.

Bitbucket Pipe and the Docker Trap

Integrations in the Bitbucket ecosystem work via so-called "Pipes," which are executed strictly inside isolated Docker containers. To support this platform, we wrapped our JS scripts in a Dockerfile and added a pipe.yml manifest.

And this is exactly where we fell into a classic networking trap. When writing E2E tests locally, our containerized client naturally tried to reach the local mock server at localhost:29418. But we forgot the basics: inside Docker, localhost is the container itself, not the host machine! The requests went into the void, and the tests failed on timeout.

We had to tinker quite a bit with Docker's bridge network settings and port forwarding to make the Pipe see the host machine and successfully pass local testing.

Conclusion

We successfully covered the "big three" CI/CD platforms. The ecosystem closed the loop: C++ code flies from any popular CI runner to our cloud and returns as gold-standard documentation and quality reports.

But having opened the gates to the SaaS for everyone, we faced a new threat. Hung Doxygen and git clone processes began to uncontrollably devour cloud resources. How we built a system of watchdog timers and why the Watchdog itself needed a Watchdog—read about it in the next episode.


Originally published on our blog: https://blog.flude.guide/blog/ci-thin-clients-gitlab-bitbucket

Also read us:

Top comments (0)