How-To's

How We Use Space to Develop Content For the JetBrains Guide

How the developer advocacy team at JetBrains uses Space to develop content for the JetBrains Guide

In this blog post, you’ll see how the developer advocacy team at JetBrains adopted Space to make developing content for the JetBrains Guide easier.

We’ll share a little bit of the history of how the JetBrains Guide was created, and how the team makes use of Space’s end-to-end setup for their development needs:

  • Git repositories hosted in Space (and mirrored to GitHub) to make sure that everyone – even outside of JetBrains – can open pull requests to contribute to the Guide.
  • Code reviews to review and manage merge requests when collaborating on the cross-Guide functionality.
  • Space Automation to make sure everything works correctly before deployment.
  • Space Packages to create public Docker registries so third parties wanting to contribute content can also make use of them.

Ready to dive in? Grab a seat, and follow along!

A little bit of history: The JetBrains Guide

Let’s start with some history. In November 2018, our colleague Paul Everitt started working on the PyCharm Guide, which was officially introduced in 2020. This was a website focused on PyCharm and the related technologies, that collects productivity tips, tutorials, and more together in one place. The content itself can be anything from video or text, to animated gifs, or just a mix of everything.

Other developer advocates saw the value in what Paul was creating, and we all started making the website "multi-tenant", meaning that every advocate could add a new folder to it and build a guide for their product and technology. Today, we have 5 of them:

Some of the content applies to all IDEs, so make sure to have a look through all of them if you want to learn about our IDEs.

The website is built using GatsbyJS, where we’re using React to build common components like layouts and navigation. The content is written in Markdown, and then everything is pushed out as a static website.

Code Reviews and Merge Requests

The source code for all guides is in one public GitHub repository. When Paul started working on the PyCharm Guide, he wanted to make sure the source code was available to everyone on the web, and that everyone — even outside JetBrains — could open pull requests to contribute their own tips, fix typos, and everything in between.

When more guides were added, more features were needed. This meant more discussion and collaboration on this cross-guide functionality. We started doing this on GitHub, using issues and pull requests. Since a lot of our day-to-day communication happens in Space anyway, we thought of using Code Reviews and Merge Requests in Space.

Code reviews in JetBrains Space

Most of us use WebStorm to work on guide content. To work with code reviews, some of us use the Space application, while others have installed the Space plugin. With the plugin, you can work with code reviews directly from the IDE.

All of these features require a Git repository in Space. Rather than switching from GitHub to Space and removing the public repository there, we set up mirroring between GitHub and Space to keep the public GitHub repository in sync with our repository in Space.

A mirrored Git repository in Space is an always-in-sync copy of another Git repository — in our case GitHub and Space. Any changes made to either side are automatically pushed to the other. Using this approach, we could work with all the tools in Space, and still, keep our promise of having the JetBrains Guide repository in the open.

Space Automation for continuous integration

Deployment of the guides is handled by an internal TeamCity server, where our infrastructure team has made several build configurations available to build and deploy to www.jetbrains.com and the staging version of the website.

But before we deploy, we want to make sure everything works correctly. We’re using Space Automation for this. In our repository, we have a .space.kts file that defines our automation jobs. Here’s an example of one of the jobs that we run:

job("Build PyCharm Guide") {
    startOn {
        gitPush {
            pathFilter {
                +"sites/pycharm-guide/**"
                +"packages/**"
                +"package.json"
            }
        }
    }

    container("node:14") {
        resources {
            cpu = 2.cpu
            memory = 4.gb
        }

        env["GATSBY_TELEMETRY_DISABLED"] = "1";

        shellScript {
            content = """
                yarn install
                yarn run pc:build
            """.trimIndent()
        }
    }
}

For every guide, we have one of these jobs defined. Each of them runs with every Git push, on every branch. We added a path filter to make sure a specific job is only executed when the content in that guide changes, or when we make changes to the website template or package.json.

This job has only one step, that runs in a Node container. This container image contains all the tools we need, so we can run yarn install to bring down all dependencies, and then yarn run pc:build to build this specific guide and run automated tests.

Continuous Integration with Space Automation

In the future, we want to add a second step that deploys the generated site to a temporary URL, so we can see the guide in action. We haven’t gotten around to this yet — since we currently deploy to staging on TeamCity, this is not so urgent.

The screenshot shows another automation job: "Docker – Content creators image". Let’s talk about that next.

Docker to simplify content creation

The guide repository contains content for the JetBrains Guide. Since it’s built with GatsbyJS, it has quite a few JavaScript dependencies. We often joke that yarn install (or npm install) downloads the entire Internet! While slightly exaggerated, there are a number of dependencies to be installed, including all of the dependencies from multiple package.json files and Node.js itself.

As a content author, we’d typically run the guide on our machines, and then work on content in various Markdown files, add images, and so on. Changes can sometimes lead to a corrupt cache in Gatsby, so we had to make sure everyone was aware of how to detect and resolve such situations.

The value of the JetBrains Guide is in the tips and tutorials we post, and not in how proficient all of us are with Node.js and GatsbyJS. To make the lives of our colleagues working on content a bit easier, we started thinking about how this experience could be improved.

We came up with an elegant solution — build a custom Docker image with all dependencies embedded. Content creators could then run this Docker image with their local content folder mapped as a directory in the container. In other words, all Markdown files and images would be local on their machine and easy to edit, while Gatsby would run in Docker.

The Dockerfile we created is based on the node image we also use in continuous integration builds. It copies the entire working directory, installs all dependencies, and then runs GatsbyJS in development mode.

We also added a shared run configuration for every guide, that maps the content folder in the container. To create content, all we have to do is make sure Docker is running, and that we are using the correct run configuration.

JetBrains Guide, Docker, and WebStorm

We still run the guides locally if we want to make changes to common components or to update dependencies. For working on content, we now have an easy solution that works based on a pre-built Docker image. I guess you are now wondering where we build this image, and how it is distributed?

Space Packages as a container registry

The content creation Docker image has to be made available to anyone who wants to work on content for the JetBrains Guide. We’re using the Space Packages Container Registry for this.

Space packages lets you create private Docker registries, among other package types such as Maven, NuGet, and npm. We created our Docker registry in Space as a public one, so that third parties wanting to contribute content can also make use of them.

Space Packages - Docker Container Registry

In the screenshot above, you’ll see the "Docker – Content creators image" as the author, which is the Space Automation job that we created to build this container image. Automation and Packages are linked, so we get traceability if we want to see when an image was published.

The Automation job is defined in the .space.kts file again. For content changes, we don’t need to create a new container image — that’s only necessary when components or dependencies are changed. For this reason, we configured the job to require a manual run by disabling the gitPush trigger.

Next, we use the Automation DSL to build an image from the Dockerfile-ContentCreators file, and push it out to the container registry we’re hosting in Space.

job("Docker - Content creators image") {
    startOn {
        gitPush {
            enabled = false // keep as manual build for now
        }
    }

    docker {
        resources {
            cpu = 2.cpu
            memory = 6.gb
        }

        build {
            context = "."
            file = "./Dockerfile-ContentCreators"
            labels["vendor"] = "JetBrains"
        }
        push("registry.jetbrains.team/p/evan/guide-containers/guide-content-creators")
    }
}

Whenever we make changes that apply to all the guides, we trigger this job, which in turn creates the container image the team is using.

Conclusion

In this post, we wanted to show how the developer advocacy team at JetBrains is using Space to build the JetBrains Guide. Thanks to Git repositories, code reviews, Space Automation, and Space Packages, we now have a nice end-to-end setup for our development needs.

If you haven’t already, sign up for a free Space organization, and try it out for yourself!