Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Commit d4f0b2f

Browse files
committed
feat(jetbrains): add JetBrains IDE module
- Introduced a new JetBrains module that allows launching JetBrains IDEs with a single click using trh JetBrains Toolbox
1 parent df98cf4 commit d4f0b2f

File tree

4 files changed

+403
-0
lines changed

4 files changed

+403
-0
lines changed

.icons/jetbrains-toolbox.svg

Lines changed: 12 additions & 0 deletions
Loading

jetbrains/README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
display_name: JetBrains
3+
description: Add a one-click button to launch JetBrains IDEs in the dashboard.
4+
icon: ../.icons/jetbrains-toolbox.svg
5+
maintainer_github: coder
6+
partner_github: jetbrains
7+
verified: true
8+
tags: [ide, jetbrains, helper, parameter]
9+
---
10+
11+
# JetBrains
12+
13+
This module adds a JetBrains IDE Button to open any workspace with a single click.
14+
15+
```tf
16+
module "jetbrains" {
17+
count = data.coder_workspace.me.start_count
18+
source = "registry.coder.com/modules/jetbrains/coder"
19+
version = "1.0.0"
20+
agent_id = coder_agent.example.id
21+
folder = "/home/coder/example"
22+
default = "GO"
23+
}
24+
```
25+
26+
> [!WARNING]
27+
> JetBrains recommends a minimum of 4 CPU cores and 8GB of RAM.
28+
> Consult the [JetBrains documentation](https://www.jetbrains.com/help/idea/prerequisites.html#min_requirements) to confirm other system requirements.
29+
30+
![JetBrains IDEs list](../.images/jetbrains-gateway.png)
31+
32+
## Examples
33+
34+
### Use the latest version of each IDE
35+
36+
```tf
37+
module "jetbrains" {
38+
count = data.coder_workspace.me.start_count
39+
source = "registry.coder.com/modules/jetbrains/coder"
40+
version = "1.0.0"
41+
agent_id = coder_agent.example.id
42+
folder = "/home/coder/example"
43+
options = ["IU", "PY"]
44+
default = "IU"
45+
latest = true
46+
}
47+
```
48+
49+
### Use the latest EAP version
50+
51+
```tf
52+
module "jetbrains" {
53+
count = data.coder_workspace.me.start_count
54+
source = "registry.coder.com/modules/jetbrains/coder"
55+
version = "1.0.0"
56+
agent_id = coder_agent.example.id
57+
folder = "/home/coder/example"
58+
options = ["GO", "WS"]
59+
default = "GO"
60+
latest = true
61+
channel = "eap"
62+
}
63+
```
64+
65+
### Custom base link
66+
67+
Due to the highest priority of the `ide_download_link` parameter in the `(jetbrains-gateway://...` within IDEA, the pre-configured download address will be overridden when using [IDEA's offline mode](https://www.jetbrains.com/help/idea/fully-offline-mode.html). Therefore, it is necessary to configure the `download_base_link` parameter for the `jetbrains_gateway` module to change the value of `ide_download_link`.
68+
69+
```tf
70+
module "jetbrains_gateway" {
71+
count = data.coder_workspace.me.start_count
72+
source = "registry.coder.com/modules/jetbrains-gateway/coder"
73+
version = "1.0.0"
74+
agent_id = coder_agent.example.id
75+
folder = "/home/coder/example"
76+
options = ["GO", "WS"]
77+
releases_base_link = "https://releases.internal.site/"
78+
download_base_link = "https://download.internal.site/"
79+
default = "GO"
80+
}
81+
```
82+
83+
## Supported IDEs
84+
85+
JetBrains supports remote development for the following IDEs:
86+
87+
- [GoLand (`GO`)](https://www.jetbrains.com/go/)
88+
- [WebStorm (`WS`)](https://www.jetbrains.com/webstorm/)
89+
- [IntelliJ IDEA Ultimate (`IU`)](https://www.jetbrains.com/idea/)
90+
- [PyCharm Professional (`PY`)](https://www.jetbrains.com/pycharm/)
91+
- [PhpStorm (`PS`)](https://www.jetbrains.com/phpstorm/)
92+
- [CLion (`CL`)](https://www.jetbrains.com/clion/)
93+
- [RubyMine (`RM`)](https://www.jetbrains.com/ruby/)
94+
- [Rider (`RD`)](https://www.jetbrains.com/rider/)
95+
- [RustRover (`RR`)](https://www.jetbrains.com/rust/)

jetbrains/main.test.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { it, expect, describe } from "bun:test";
2+
import {
3+
runTerraformInit,
4+
testRequiredVariables,
5+
runTerraformApply,
6+
} from "../test";
7+
8+
describe("jetbrains", async () => {
9+
await runTerraformInit(import.meta.dir);
10+
11+
await testRequiredVariables(import.meta.dir, {
12+
agent_id: "foo",
13+
folder: "/home/foo",
14+
});
15+
16+
it("should create a link with the default values", async () => {
17+
const state = await runTerraformApply(import.meta.dir, {
18+
// These are all required.
19+
agent_id: "foo",
20+
folder: "/home/coder",
21+
});
22+
23+
// Check that the URL contains the expected components
24+
const url = state.outputs.url.value;
25+
expect(url).toContain("jetbrains://gateway/com.coder.toolbox");
26+
expect(url).toMatch(/workspace=[^&]+/);
27+
expect(url).toContain("owner=default");
28+
expect(url).toContain("project_path=/home/coder");
29+
expect(url).toContain("token=$SESSION_TOKEN");
30+
expect(url).toContain("ide_product_code=CL"); // First option in the default list
31+
32+
const coder_app = state.resources.find(
33+
(res) => res.type === "coder_app" && res.name === "jetbrains",
34+
);
35+
36+
expect(coder_app).not.toBeNull();
37+
expect(coder_app?.instances.length).toBe(1);
38+
expect(coder_app?.instances[0].attributes.order).toBeNull();
39+
});
40+
41+
it("should use the specified default IDE", async () => {
42+
const state = await runTerraformApply(import.meta.dir, {
43+
agent_id: "foo",
44+
folder: "/home/foo",
45+
default: "GO",
46+
});
47+
expect(state.outputs.identifier.value).toBe("GO");
48+
});
49+
50+
it("should use the first IDE from options when no default is specified", async () => {
51+
const state = await runTerraformApply(import.meta.dir, {
52+
agent_id: "foo",
53+
folder: "/home/foo",
54+
options: '["PY", "GO", "IU"]',
55+
});
56+
expect(state.outputs.identifier.value).toBe("PY");
57+
});
58+
59+
it("should set the app order when specified", async () => {
60+
const state = await runTerraformApply(import.meta.dir, {
61+
agent_id: "foo",
62+
folder: "/home/foo",
63+
coder_app_order: 42,
64+
});
65+
66+
const coder_app = state.resources.find(
67+
(res) => res.type === "coder_app" && res.name === "jetbrains",
68+
);
69+
70+
expect(coder_app).not.toBeNull();
71+
expect(coder_app?.instances[0].attributes.order).toBe(42);
72+
});
73+
74+
it("should use the latest build number when latest is true", async () => {
75+
const state = await runTerraformApply(import.meta.dir, {
76+
agent_id: "foo",
77+
folder: "/home/foo",
78+
latest: true,
79+
});
80+
81+
// We can't test the exact build number since it's fetched dynamically,
82+
// but we can check that the URL contains the build number parameter
83+
const url = state.outputs.url.value;
84+
expect(url).toContain("ide_build_number=");
85+
});
86+
});

0 commit comments

Comments
 (0)