1
+ terraform {
2
+ required_version = " >= 1.0"
3
+
4
+ required_providers {
5
+ coder = {
6
+ source = " coder/coder"
7
+ version = " >= 0.17"
8
+ }
9
+ http = {
10
+ source = " hashicorp/http"
11
+ version = " >= 3.0"
12
+ }
13
+ }
14
+ }
15
+
16
+ variable "agent_id" {
17
+ type = string
18
+ description = " The ID of a Coder agent."
19
+ }
20
+
21
+ variable "slug" {
22
+ type = string
23
+ description = " The slug for the coder_app. Allows resuing the module with the same template."
24
+ default = " gateway"
25
+ }
26
+
27
+ variable "agent_name" {
28
+ type = string
29
+ description = " Agent name. (unused). Will be removed in a future version"
30
+
31
+ default = " "
32
+ }
33
+
34
+ variable "folder" {
35
+ type = string
36
+ description = " The directory to open in the IDE. e.g. /home/coder/project"
37
+ validation {
38
+ condition = can (regex (" ^(?:/[^/]+)+$" , var. folder ))
39
+ error_message = " The folder must be a full path and must not start with a ~."
40
+ }
41
+ }
42
+
43
+ variable "default" {
44
+ default = " "
45
+ type = string
46
+ description = " Default IDE"
47
+ }
48
+
49
+ variable "order" {
50
+ type = number
51
+ description = " The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
52
+ default = null
53
+ }
54
+
55
+ variable "coder_parameter_order" {
56
+ type = number
57
+ description = " The order determines the position of a template parameter in the UI/CLI presentation. The lowest order is shown first and parameters with equal order are sorted by name (ascending order)."
58
+ default = null
59
+ }
60
+
61
+ variable "latest" {
62
+ type = bool
63
+ description = " Whether to fetch the latest version of the IDE."
64
+ default = false
65
+ }
66
+
67
+ variable "channel" {
68
+ type = string
69
+ description = " JetBrains IDE release channel. Valid values are release and eap."
70
+ default = " release"
71
+ validation {
72
+ condition = can (regex (" ^(release|eap)$" , var. channel ))
73
+ error_message = " The channel must be either release or eap."
74
+ }
75
+ }
76
+
77
+ variable "jetbrains_ide_versions" {
78
+ type = map (object ({
79
+ build_number = string
80
+ version = string
81
+ }))
82
+ description = " The set of versions for each jetbrains IDE"
83
+ default = {
84
+ " IU" = {
85
+ build_number = " 243.21565.193"
86
+ version = " 2024.3"
87
+ }
88
+ " PS" = {
89
+ build_number = " 243.21565.202"
90
+ version = " 2024.3"
91
+ }
92
+ " WS" = {
93
+ build_number = " 243.21565.180"
94
+ version = " 2024.3"
95
+ }
96
+ " PY" = {
97
+ build_number = " 243.21565.199"
98
+ version = " 2024.3"
99
+ }
100
+ " CL" = {
101
+ build_number = " 243.21565.238"
102
+ version = " 2024.1"
103
+ }
104
+ " GO" = {
105
+ build_number = " 243.21565.208"
106
+ version = " 2024.3"
107
+ }
108
+ " RM" = {
109
+ build_number = " 243.21565.197"
110
+ version = " 2024.3"
111
+ }
112
+ " RD" = {
113
+ build_number = " 243.21565.191"
114
+ version = " 2024.3"
115
+ }
116
+ " RR" = {
117
+ build_number = " 243.22562.230"
118
+ version = " 2024.3"
119
+ }
120
+ }
121
+ validation {
122
+ condition = (
123
+ alltrue ([
124
+ for code in keys (var. jetbrains_ide_versions ) : contains ([" IU" , " PS" , " WS" , " PY" , " CL" , " GO" , " RM" , " RD" , " RR" ], code)
125
+ ])
126
+ )
127
+ error_message = " The jetbrains_ide_versions must contain a map of valid product codes. Valid product codes are ${ join (" ," , [" IU" , " PS" , " WS" , " PY" , " CL" , " GO" , " RM" , " RD" , " RR" ])} ."
128
+ }
129
+ }
130
+
131
+ variable "jetbrains_ides" {
132
+ type = list (string )
133
+ description = " The list of IDE product codes."
134
+ default = [" IU" , " PS" , " WS" , " PY" , " CL" , " GO" , " RM" , " RD" , " RR" ]
135
+ validation {
136
+ condition = (
137
+ alltrue ([
138
+ for code in var . jetbrains_ides : contains ([" IU" , " PS" , " WS" , " PY" , " CL" , " GO" , " RM" , " RD" , " RR" ], code)
139
+ ])
140
+ )
141
+ error_message = " The jetbrains_ides must be a list of valid product codes. Valid product codes are ${ join (" ," , [" IU" , " PS" , " WS" , " PY" , " CL" , " GO" , " RM" , " RD" , " RR" ])} ."
142
+ }
143
+ # check if the list is empty
144
+ validation {
145
+ condition = length (var. jetbrains_ides ) > 0
146
+ error_message = " The jetbrains_ides must not be empty."
147
+ }
148
+ # check if the list contains duplicates
149
+ validation {
150
+ condition = length (var. jetbrains_ides ) == length (toset (var. jetbrains_ides ))
151
+ error_message = " The jetbrains_ides must not contain duplicates."
152
+ }
153
+ }
154
+
155
+ variable "releases_base_link" {
156
+ type = string
157
+ description = " "
158
+ default = " https://data.services.jetbrains.com"
159
+ validation {
160
+ condition = can (regex (" ^https?://.+$" , var. releases_base_link ))
161
+ error_message = " The releases_base_link must be a valid HTTP/S address."
162
+ }
163
+ }
164
+
165
+ variable "download_base_link" {
166
+ type = string
167
+ description = " "
168
+ default = " https://download.jetbrains.com"
169
+ validation {
170
+ condition = can (regex (" ^https?://.+$" , var. download_base_link ))
171
+ error_message = " The download_base_link must be a valid HTTP/S address."
172
+ }
173
+ }
174
+
175
+ data "http" "jetbrains_ide_versions" {
176
+ for_each = var. latest ? toset (var. jetbrains_ides ) : toset ([])
177
+ url = " ${ var . releases_base_link } /products/releases?code=${ each . key } &latest=true&type=${ var . channel } "
178
+ }
179
+
180
+ locals {
181
+ jetbrains_ides = {
182
+ " GO" = {
183
+ icon = " /icon/goland.svg" ,
184
+ name = " GoLand" ,
185
+ identifier = " GO" ,
186
+ build_number = var.jetbrains_ide_versions[" GO" ].build_number,
187
+ download_link = " ${ var . download_base_link } /go/goland-${ var . jetbrains_ide_versions [" GO" ]. version } .tar.gz"
188
+ version = var.jetbrains_ide_versions[" GO" ].version
189
+ },
190
+ " WS" = {
191
+ icon = " /icon/webstorm.svg" ,
192
+ name = " WebStorm" ,
193
+ identifier = " WS" ,
194
+ build_number = var.jetbrains_ide_versions[" WS" ].build_number,
195
+ download_link = " ${ var . download_base_link } /webstorm/WebStorm-${ var . jetbrains_ide_versions [" WS" ]. version } .tar.gz"
196
+ version = var.jetbrains_ide_versions[" WS" ].version
197
+ },
198
+ " IU" = {
199
+ icon = " /icon/intellij.svg" ,
200
+ name = " IntelliJ IDEA Ultimate" ,
201
+ identifier = " IU" ,
202
+ build_number = var.jetbrains_ide_versions[" IU" ].build_number,
203
+ download_link = " ${ var . download_base_link } /idea/ideaIU-${ var . jetbrains_ide_versions [" IU" ]. version } .tar.gz"
204
+ version = var.jetbrains_ide_versions[" IU" ].version
205
+ },
206
+ " PY" = {
207
+ icon = " /icon/pycharm.svg" ,
208
+ name = " PyCharm Professional" ,
209
+ identifier = " PY" ,
210
+ build_number = var.jetbrains_ide_versions[" PY" ].build_number,
211
+ download_link = " ${ var . download_base_link } /python/pycharm-professional-${ var . jetbrains_ide_versions [" PY" ]. version } .tar.gz"
212
+ version = var.jetbrains_ide_versions[" PY" ].version
213
+ },
214
+ " CL" = {
215
+ icon = " /icon/clion.svg" ,
216
+ name = " CLion" ,
217
+ identifier = " CL" ,
218
+ build_number = var.jetbrains_ide_versions[" CL" ].build_number,
219
+ download_link = " ${ var . download_base_link } /cpp/CLion-${ var . jetbrains_ide_versions [" CL" ]. version } .tar.gz"
220
+ version = var.jetbrains_ide_versions[" CL" ].version
221
+ },
222
+ " PS" = {
223
+ icon = " /icon/phpstorm.svg" ,
224
+ name = " PhpStorm" ,
225
+ identifier = " PS" ,
226
+ build_number = var.jetbrains_ide_versions[" PS" ].build_number,
227
+ download_link = " ${ var . download_base_link } /webide/PhpStorm-${ var . jetbrains_ide_versions [" PS" ]. version } .tar.gz"
228
+ version = var.jetbrains_ide_versions[" PS" ].version
229
+ },
230
+ " RM" = {
231
+ icon = " /icon/rubymine.svg" ,
232
+ name = " RubyMine" ,
233
+ identifier = " RM" ,
234
+ build_number = var.jetbrains_ide_versions[" RM" ].build_number,
235
+ download_link = " ${ var . download_base_link } /ruby/RubyMine-${ var . jetbrains_ide_versions [" RM" ]. version } .tar.gz"
236
+ version = var.jetbrains_ide_versions[" RM" ].version
237
+ },
238
+ " RD" = {
239
+ icon = " /icon/rider.svg" ,
240
+ name = " Rider" ,
241
+ identifier = " RD" ,
242
+ build_number = var.jetbrains_ide_versions[" RD" ].build_number,
243
+ download_link = " ${ var . download_base_link } /rider/JetBrains.Rider-${ var . jetbrains_ide_versions [" RD" ]. version } .tar.gz"
244
+ version = var.jetbrains_ide_versions[" RD" ].version
245
+ },
246
+ " RR" = {
247
+ icon = " /icon/rustrover.svg" ,
248
+ name = " RustRover" ,
249
+ identifier = " RR" ,
250
+ build_number = var.jetbrains_ide_versions[" RR" ].build_number,
251
+ download_link = " ${ var . download_base_link } /rustrover/RustRover-${ var . jetbrains_ide_versions [" RR" ]. version } .tar.gz"
252
+ version = var.jetbrains_ide_versions[" RR" ].version
253
+ }
254
+ }
255
+
256
+ icon = local. jetbrains_ides [data . coder_parameter . jetbrains_ide . value ]. icon
257
+ json_data = var. latest ? jsondecode (data. http . jetbrains_ide_versions [data . coder_parameter . jetbrains_ide . value ]. response_body ) : {}
258
+ key = var. latest ? keys (local. json_data )[0 ] : " "
259
+ display_name = local. jetbrains_ides [data . coder_parameter . jetbrains_ide . value ]. name
260
+ identifier = data. coder_parameter . jetbrains_ide . value
261
+ download_link = var. latest ? local. json_data [local . key ][0 ]. downloads . linux . link : local. jetbrains_ides [data . coder_parameter . jetbrains_ide . value ]. download_link
262
+ build_number = var. latest ? local. json_data [local . key ][0 ]. build : local. jetbrains_ides [data . coder_parameter . jetbrains_ide . value ]. build_number
263
+ version = var. latest ? local. json_data [local . key ][0 ]. version : var. jetbrains_ide_versions [data . coder_parameter . jetbrains_ide . value ]. version
264
+ }
265
+
266
+ data "coder_parameter" "jetbrains_ide" {
267
+ type = " list(string)"
268
+ form_type = " multi-select"
269
+ name = " jetbrains_ide"
270
+ display_name = " JetBrains IDE"
271
+ icon = " /icon/gateway.svg"
272
+ mutable = true
273
+ default = jsonencode ([var . default == " " ? var . jetbrains_ides [0 ] : var . default ])
274
+ order = var. coder_parameter_order
275
+
276
+ dynamic "option" {
277
+ for_each = var. jetbrains_ides
278
+ content {
279
+ icon = local. jetbrains_ides [option . value ]. icon
280
+ name = local. jetbrains_ides [option . value ]. name
281
+ value = option. value
282
+ }
283
+ }
284
+ }
285
+
286
+ data "coder_workspace" "me" {}
287
+ data "coder_workspace_owner" "me" {}
288
+
289
+ resource "coder_app" "gateway" {
290
+ agent_id = var. agent_id
291
+ slug = var. slug
292
+ display_name = local. display_name
293
+ icon = local. icon
294
+ external = true
295
+ order = var. order
296
+ url = join (" " , [
297
+ " jetbrains-gateway://connect#type=coder&workspace=" ,
298
+ data . coder_workspace . me . name ,
299
+ " &owner=" ,
300
+ data . coder_workspace_owner . me . name ,
301
+ " &folder=" ,
302
+ var . folder ,
303
+ " &url=" ,
304
+ data . coder_workspace . me . access_url ,
305
+ " &token=" ,
306
+ " $SESSION_TOKEN" ,
307
+ " &ide_product_code=" ,
308
+ data . coder_parameter . jetbrains_ide . value ,
309
+ " &ide_build_number=" ,
310
+ local . build_number ,
311
+ " &ide_download_link=" ,
312
+ local . download_link ,
313
+ ])
314
+ }
315
+
316
+ output "identifier" {
317
+ value = local. identifier
318
+ }
319
+
320
+ output "display_name" {
321
+ value = local. display_name
322
+ }
323
+
324
+ output "icon" {
325
+ value = local. icon
326
+ }
327
+
328
+ output "download_link" {
329
+ value = local. download_link
330
+ }
331
+
332
+ output "build_number" {
333
+ value = local. build_number
334
+ }
335
+
336
+ output "version" {
337
+ value = local. version
338
+ }
339
+
340
+ output "url" {
341
+ value = coder_app. gateway . url
342
+ }
0 commit comments