Skip to content

Commit 506d2b1

Browse files
Update sourcemaps command to use @highlight-run/sourcemap-uploader npm package
Co-Authored-By: [email protected] <[email protected]>
1 parent 5e52229 commit 506d2b1

File tree

1 file changed

+30
-246
lines changed

1 file changed

+30
-246
lines changed

cmd/sourcemaps/upload.go

Lines changed: 30 additions & 246 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@ package sourcemaps
22

33
import (
44
"bytes"
5-
"encoding/json"
65
"fmt"
7-
"io"
8-
"mime/multipart"
9-
"net/http"
106
"os"
11-
"path/filepath"
7+
"os/exec"
128
"strings"
139

1410
"github.com/spf13/cobra"
@@ -30,17 +26,7 @@ const (
3026
defaultPath = "."
3127
defaultBackendUrl = "https://app.launchdarkly.com"
3228

33-
verifyApiKeyQuery = `
34-
query ApiKeyToOrgID($api_key: String!) {
35-
api_key_to_org_id(api_key: $api_key)
36-
}
37-
`
38-
39-
getSourceMapUrlsQuery = `
40-
query GetSourceMapUploadUrls($api_key: String!, $paths: [String!]!) {
41-
get_source_map_upload_urls(api_key: $api_key, paths: $paths)
42-
}
43-
`
29+
npmPackage = "@highlight-run/sourcemap-uploader"
4430
)
4531

4632
func NewUploadCmd(client resources.Client) *cobra.Command {
@@ -106,261 +92,59 @@ func runE(client resources.Client) func(cmd *cobra.Command, args []string) error
10692
return fmt.Errorf("api key cannot be empty")
10793
}
10894

109-
organizationId, err := verifyApiKey(apiKey, backendUrl)
110-
if err != nil {
111-
return err
95+
if err := checkNodeInstalled(); err != nil {
96+
return fmt.Errorf("Node.js is required to upload sourcemaps: %v", err)
11297
}
11398

114-
fmt.Printf("Starting to upload source maps from %s\n", path)
99+
args := []string{npmPackage, "upload", "--apiKey", apiKey}
115100

116-
fileList, err := getAllSourceMapFiles(path)
117-
if err != nil {
118-
return err
101+
if appVersion != "" {
102+
args = append(args, "--appVersion", appVersion)
119103
}
120104

121-
if len(fileList) == 0 {
122-
return fmt.Errorf("no source maps found in %s, is this the correct path?", path)
105+
if path != defaultPath {
106+
args = append(args, "--path", path)
123107
}
124108

125-
s3Keys := make([]string, len(fileList))
126-
for i, file := range fileList {
127-
s3Keys[i] = getS3Key(organizationId, appVersion, basePath, file.Name)
109+
if basePath != "" {
110+
args = append(args, "--basePath", basePath)
128111
}
129112

130-
uploadUrls, err := getSourceMapUploadUrls(apiKey, s3Keys, backendUrl)
131-
if err != nil {
132-
return err
133-
}
134-
135-
for i, file := range fileList {
136-
err = uploadFile(file.Path, uploadUrls[i], file.Name)
137-
if err != nil {
138-
return err
139-
}
113+
if backendUrl != defaultBackendUrl {
114+
args = append(args, "--backendUrl", backendUrl)
140115
}
141116

142-
fmt.Println("Successfully uploaded all sourcemaps")
143-
return nil
144-
}
145-
}
146-
147-
func verifyApiKey(apiKey, backendUrl string) (string, error) {
148-
variables := map[string]interface{}{
149-
"api_key": apiKey,
150-
}
151-
152-
body, err := json.Marshal(map[string]interface{}{
153-
"query": verifyApiKeyQuery,
154-
"variables": variables,
155-
})
156-
if err != nil {
157-
return "", err
158-
}
159-
160-
req, err := http.NewRequest("POST", backendUrl, bytes.NewBuffer(body))
161-
if err != nil {
162-
return "", err
163-
}
164-
165-
req.Header.Set("Content-Type", "application/json")
166-
req.Header.Set("ApiKey", apiKey)
167-
168-
client := &http.Client{}
169-
resp, err := client.Do(req)
170-
if err != nil {
171-
return "", err
172-
}
173-
defer resp.Body.Close()
174-
175-
respBody, err := io.ReadAll(resp.Body)
176-
if err != nil {
177-
return "", err
178-
}
179-
180-
var result struct {
181-
Data struct {
182-
ApiKeyToOrgID string `json:"api_key_to_org_id"`
183-
} `json:"data"`
184-
}
117+
fmt.Printf("Starting to upload source maps from %s using %s\n", path, npmPackage)
185118

186-
err = json.Unmarshal(respBody, &result)
187-
if err != nil {
188-
return "", err
189-
}
190-
191-
if result.Data.ApiKeyToOrgID == "" || result.Data.ApiKeyToOrgID == "0" {
192-
return "", fmt.Errorf("invalid api key")
193-
}
119+
cmd := exec.Command("npx", args...)
120+
var stdout, stderr bytes.Buffer
121+
cmd.Stdout = &stdout
122+
cmd.Stderr = &stderr
123+
cmd.Env = os.Environ()
194124

195-
return result.Data.ApiKeyToOrgID, nil
196-
}
197-
198-
func getSourceMapUploadUrls(apiKey string, paths []string, backendUrl string) ([]string, error) {
199-
variables := map[string]interface{}{
200-
"api_key": apiKey,
201-
"paths": paths,
202-
}
203-
204-
body, err := json.Marshal(map[string]interface{}{
205-
"query": getSourceMapUrlsQuery,
206-
"variables": variables,
207-
})
208-
if err != nil {
209-
return nil, err
210-
}
211-
212-
req, err := http.NewRequest("POST", backendUrl, bytes.NewBuffer(body))
213-
if err != nil {
214-
return nil, err
215-
}
216-
217-
req.Header.Set("Content-Type", "application/json")
218-
219-
client := &http.Client{}
220-
resp, err := client.Do(req)
221-
if err != nil {
222-
return nil, err
223-
}
224-
defer resp.Body.Close()
225-
226-
respBody, err := io.ReadAll(resp.Body)
227-
if err != nil {
228-
return nil, err
229-
}
230-
231-
var result struct {
232-
Data struct {
233-
GetSourceMapUploadUrls []string `json:"get_source_map_upload_urls"`
234-
} `json:"data"`
235-
}
236-
237-
err = json.Unmarshal(respBody, &result)
238-
if err != nil {
239-
return nil, err
240-
}
241-
242-
if len(result.Data.GetSourceMapUploadUrls) == 0 {
243-
return nil, fmt.Errorf("unable to generate source map upload urls")
244-
}
245-
246-
return result.Data.GetSourceMapUploadUrls, nil
247-
}
248-
249-
type SourceMapFile struct {
250-
Path string
251-
Name string
252-
}
253-
254-
func getAllSourceMapFiles(path string) ([]SourceMapFile, error) {
255-
var fileList []SourceMapFile
256-
257-
absPath, err := filepath.Abs(path)
258-
if err != nil {
259-
return nil, err
260-
}
261-
262-
fileInfo, err := os.Stat(absPath)
263-
if err != nil {
264-
return nil, err
265-
}
266-
267-
if fileInfo.IsDir() {
268-
err = filepath.Walk(absPath, func(path string, info os.FileInfo, err error) error {
269-
if err != nil {
270-
return err
271-
}
272-
273-
if info.IsDir() {
274-
if info.Name() == "node_modules" {
275-
return filepath.SkipDir
276-
}
277-
return nil
278-
}
279-
280-
if strings.HasSuffix(info.Name(), ".js.map") {
281-
relPath, err := filepath.Rel(absPath, path)
282-
if err != nil {
283-
return err
284-
}
285-
286-
fileList = append(fileList, SourceMapFile{
287-
Path: path,
288-
Name: relPath,
289-
})
290-
}
291-
292-
return nil
293-
})
125+
err := cmd.Run()
126+
fmt.Print(stdout.String())
294127

295128
if err != nil {
296-
return nil, err
297-
}
298-
} else {
299-
if strings.HasSuffix(fileInfo.Name(), ".js.map") {
300-
fileList = append(fileList, SourceMapFile{
301-
Path: absPath,
302-
Name: fileInfo.Name(),
303-
})
129+
fmt.Print(stderr.String())
130+
return fmt.Errorf("failed to upload sourcemaps: %v", err)
304131
}
305-
}
306-
307-
return fileList, nil
308-
}
309132

310-
func getS3Key(organizationId, version, basePath, fileName string) string {
311-
if version == "" {
312-
version = "unversioned"
313-
}
314-
315-
if basePath != "" && !strings.HasSuffix(basePath, "/") {
316-
basePath = basePath + "/"
133+
fmt.Println("Successfully uploaded all sourcemaps")
134+
return nil
317135
}
318-
319-
return fmt.Sprintf("%s/%s/%s%s", organizationId, version, basePath, fileName)
320136
}
321137

322-
func uploadFile(filePath, uploadUrl, name string) error {
323-
fileContent, err := os.ReadFile(filePath)
324-
if err != nil {
325-
return err
326-
}
327-
328-
var requestBody bytes.Buffer
329-
writer := multipart.NewWriter(&requestBody)
330-
331-
part, err := writer.CreateFormFile("file", filepath.Base(filePath))
138+
func checkNodeInstalled() error {
139+
_, err := exec.LookPath("node")
332140
if err != nil {
333-
return err
141+
return fmt.Errorf("Node.js is not installed or not in PATH: %v", err)
334142
}
335143

336-
_, err = part.Write(fileContent)
144+
_, err = exec.LookPath("npx")
337145
if err != nil {
338-
return err
339-
}
340-
341-
err = writer.Close()
342-
if err != nil {
343-
return err
344-
}
345-
346-
req, err := http.NewRequest("PUT", uploadUrl, bytes.NewReader(fileContent))
347-
if err != nil {
348-
return err
349-
}
350-
351-
req.Header.Set("Content-Type", "application/octet-stream")
352-
353-
client := &http.Client{}
354-
resp, err := client.Do(req)
355-
if err != nil {
356-
return err
357-
}
358-
defer resp.Body.Close()
359-
360-
if resp.StatusCode >= 400 {
361-
return fmt.Errorf("failed to upload %s: %s", name, resp.Status)
146+
return fmt.Errorf("npx is not installed or not in PATH: %v", err)
362147
}
363148

364-
fmt.Printf("Uploaded %s\n", name)
365149
return nil
366150
}

0 commit comments

Comments
 (0)