fix(cli): send telemetry synchronously; tag eval-via-picker correctly

Telemetry was fired as a goroutine then the process exited immediately,
killing it before the HTTP request could complete. Now called
synchronously — sendTelemetry already has a 2s internal timeout so
worst-case latency is unchanged for the user.

Also moves the combined picker into run() so eval products selected
interactively are tagged action=eval with the correct eval_slug instead
of action=interactive with no slug.

Adds What's New changelog section to release notes, auto-generated from
commits since the previous tag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Shekhar Vaidya 2026-06-30 07:50:13 +05:30
parent 5fa1b11835
commit bc857c4986
2 changed files with 51 additions and 25 deletions

View file

@ -12,6 +12,8 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
@ -28,6 +30,19 @@ jobs:
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w -X main.Version=${VERSION}" -o ../dist/msdl-darwin-arm64 .
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -X main.Version=${VERSION}" -o ../dist/msdl-windows-amd64.exe .
- name: Generate changelog
id: changelog
run: |
PREV_TAG=$(git tag --sort=-version:refname | grep 'cli/v' | sed -n '2p')
if [ -n "$PREV_TAG" ]; then
CHANGELOG=$(git log --pretty=format:"- %s" "$PREV_TAG".."${{ github.ref_name }}" -- cli/ backend/ frontend/ | grep -v '^- chore(winget)' | head -30)
else
CHANGELOG="- Initial release"
fi
echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
@ -35,6 +50,10 @@ jobs:
name: "msdl CLI ${{ github.ref_name }}"
files: dist/*
body: |
## What's New
${{ steps.changelog.outputs.changelog }}
## Install
**Windows (winget):**
@ -42,6 +61,8 @@ jobs:
winget install starkSV.msdl
```
**Windows (direct download):** Download `msdl-windows-amd64.exe` below, rename to `msdl.exe`, place in a folder on your PATH.
**Linux/macOS:**
```bash
# Linux x86_64
@ -57,14 +78,12 @@ jobs:
chmod +x msdl && sudo mv msdl /usr/local/bin/
```
**Windows (manual):** Download `msdl-windows-amd64.exe`, rename to `msdl.exe`, place in a directory on your PATH.
## Usage
```
msdl # fully interactive
msdl # fully interactive (includes Server/Enterprise)
msdl "windows 11 25h2" # filter products, pick language
msdl --id 3262 --lang "English (United States)" # direct, no prompts
msdl --eval server-2025 # evaluation ISOs
msdl --eval server-2025 # evaluation ISOs directly
msdl --list # list all products
```

View file

@ -202,28 +202,41 @@ More info: https://msdl.tech-latest.com/cli`)
return nil
}
// Determine telemetry fields before running (product_id / eval_slug known at this point)
telAction := "interactive"
telProductID := ""
telEvalSlug := ""
var err error
switch {
case *evalMode:
telAction = "eval"
telEvalSlug = query
err = runEval(query)
case *productID != "":
telAction = "fetch"
telProductID = *productID
}
var err error
if *evalMode {
err = runEval(query)
} else {
err = runConsumer(*productID, query, *langFlag, noContribute)
case query == "" && isTerminal():
// Pure interactive: combined consumer + eval picker
isEval, product, ep, pickErr := pickCombined()
if pickErr != nil {
return pickErr
}
if isEval {
telAction = "eval"
telEvalSlug = ep.Slug
err = runEval(ep.Slug)
} else {
telAction = "fetch"
telProductID = product.ID
err = runConsumer(product.ID, "", *langFlag, noContribute)
}
default:
err = runConsumer(*productID, query, *langFlag, noContribute)
}
if !noTelemetry {
go sendTelemetry(cliTelemetryPayload{
sendTelemetry(cliTelemetryPayload{
Action: telAction,
ProductID: telProductID,
EvalSlug: telEvalSlug,
@ -245,10 +258,13 @@ func runConsumer(productID, query, langName string, noContribute bool) error {
return fmt.Errorf("unknown product ID %q — run msdl --list to see all products", productID)
}
product = p
} else if query != "" {
candidates := searchProducts(query)
if len(candidates) == 0 {
return fmt.Errorf("no products match %q — run msdl --list to see all products", query)
} else {
candidates := consumerProducts
if query != "" {
candidates = searchProducts(query)
if len(candidates) == 0 {
return fmt.Errorf("no products match %q — run msdl --list to see all products", query)
}
}
if len(candidates) == 1 {
product = candidates[0]
@ -260,15 +276,6 @@ func runConsumer(productID, query, langName string, noContribute bool) error {
return err
}
}
} else {
isEval, selected, ep, err := pickCombined()
if err != nil {
return err
}
if isEval {
return runEval(ep.Slug)
}
product = selected
}
fmt.Fprintf(os.Stderr, "Setting up Microsoft session...\n")