[GH-ISSUE #49] Add beta-testers add/remove groups #10

Closed
opened 2026-02-26 21:32:45 +03:00 by kerem · 3 comments
Owner

Originally created by @rudrankriyam on GitHub (Jan 23, 2026).
Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/49

Summary

Add commands to modify a beta tester's group memberships.

API endpoints

CLI

  • asc beta-testers add-groups --id "TESTER_ID" --group "GROUP_ID[,GROUP_ID...]"
  • asc beta-testers remove-groups --id "TESTER_ID" --group "GROUP_ID[,GROUP_ID...]"

Behavior

  • Send relationship payload with data array of beta group IDs.
  • Keep idempotent behavior when group already present/absent.

Output

  • JSON minified default; --output table|markdown; --pretty for JSON.

Tests

  • Relationship POST/DELETE client tests
  • CLI tests for add/remove logic and empty-result validation
Originally created by @rudrankriyam on GitHub (Jan 23, 2026). Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/49 ## Summary Add commands to modify a beta tester's group memberships. ## API endpoints - `POST /v1/betaTesters/{id}/relationships/betaGroups` (add groups) - `DELETE /v1/betaTesters/{id}/relationships/betaGroups` (remove groups) - Relationship docs are under the BetaTester resource: https://developer.apple.com/documentation/appstoreconnectapi/betatester ## CLI - `asc beta-testers add-groups --id "TESTER_ID" --group "GROUP_ID[,GROUP_ID...]"` - `asc beta-testers remove-groups --id "TESTER_ID" --group "GROUP_ID[,GROUP_ID...]"` ## Behavior - Send relationship payload with `data` array of beta group IDs. - Keep idempotent behavior when group already present/absent. ## Output - JSON minified default; `--output table|markdown`; `--pretty` for JSON. ## Tests - Relationship POST/DELETE client tests - CLI tests for add/remove logic and empty-result validation
kerem closed this issue 2026-02-26 21:32:46 +03:00
Author
Owner

@rudrankriyam commented on GitHub (Jan 23, 2026):

@cursor Please implement this issue.

Implementation Guide

1. Add Commands to cmd/beta.go

Add two new subcommands to BetaTestersCommand():

BetaTestersAddGroupsCommand()
BetaTestersRemoveGroupsCommand()

2. Add Client Methods in internal/asc/client.go

// AddBetaTesterToGroups adds a tester to multiple beta groups
// POST /v1/betaTesters/{id}/relationships/betaGroups
func (c *Client) AddBetaTesterToGroups(ctx context.Context, testerID string, groupIDs []string) error {
    url := fmt.Sprintf("%s/betaTesters/%s/relationships/betaGroups", baseURL, testerID)
    payload := RelationshipRequest{
        Data: make([]RelationshipData, len(groupIDs)),
    }
    for i, id := range groupIDs {
        payload.Data[i] = RelationshipData{Type: "betaGroups", ID: id}
    }
    // POST request
}

// RemoveBetaTesterFromGroups removes a tester from multiple beta groups
// DELETE /v1/betaTesters/{id}/relationships/betaGroups
func (c *Client) RemoveBetaTesterFromGroups(ctx context.Context, testerID string, groupIDs []string) error {
    // DELETE with body (same payload structure)
}

3. CLI Flags

For add-groups:

  • --id (required, tester ID)
  • --group (required, comma-separated group IDs)

For remove-groups:

  • --id (required, tester ID)
  • --group (required, comma-separated group IDs)

4. Implementation Pattern

Follow the same pattern as issue #47 (beta-groups add/remove testers), but inverted:

  • Issue #47: Add testers TO a group
  • This issue: Add a tester TO groups
func BetaTestersAddGroupsCommand() *ffcli.Command {
    fs := flag.NewFlagSet("add-groups", flag.ExitOnError)
    id := fs.String("id", "", "Beta tester ID")
    groups := fs.String("group", "", "Comma-separated beta group IDs")
    
    return &ffcli.Command{
        Name:       "add-groups",
        ShortUsage: "asc beta-testers add-groups --id TESTER_ID --group GROUP_ID[,GROUP_ID...]",
        // ...
    }
}

5. Testing

Unit tests in cmd/commands_test.go:

{"beta-testers add-groups missing id", []string{"beta-testers", "add-groups"}, ...}
{"beta-testers add-groups missing group", []string{"beta-testers", "add-groups", "--id", "X"}, ...}
{"beta-testers remove-groups validation", ...}

Client tests in internal/asc/client_http_test.go:

  • Test relationship payload with betaGroups type
  • Test multiple group IDs

Live API test:

# Get tester and group IDs
./asc beta-testers list --app 6747745091 --limit 1
./asc beta-groups list --app 6747745091

# Test
./asc beta-testers add-groups --id "TESTER_ID" --group "GROUP_ID"
./asc beta-testers remove-groups --id "TESTER_ID" --group "GROUP_ID"

# Test multiple groups
./asc beta-testers add-groups --id "TESTER_ID" --group "GROUP1,GROUP2"

6. Success Output

fmt.Fprintf(os.Stderr, "Successfully added tester %s to %d group(s)\n", testerID, len(groupIDs))
fmt.Fprintf(os.Stderr, "Successfully removed tester %s from %d group(s)\n", testerID, len(groupIDs))

7. Code Standards

  • Use strings.TrimSpace() on tester ID and all group IDs
  • Reuse parseCommaSeparatedIDs() helper from issue #47 if available
  • Handle idempotent behavior (adding to group already in is OK)
  • Run make format && make lint && make test before committing
<!-- gh-comment-id:3792265898 --> @rudrankriyam commented on GitHub (Jan 23, 2026): @cursor Please implement this issue. ## Implementation Guide ### 1. Add Commands to `cmd/beta.go` Add two new subcommands to `BetaTestersCommand()`: ```go BetaTestersAddGroupsCommand() BetaTestersRemoveGroupsCommand() ``` ### 2. Add Client Methods in `internal/asc/client.go` ```go // AddBetaTesterToGroups adds a tester to multiple beta groups // POST /v1/betaTesters/{id}/relationships/betaGroups func (c *Client) AddBetaTesterToGroups(ctx context.Context, testerID string, groupIDs []string) error { url := fmt.Sprintf("%s/betaTesters/%s/relationships/betaGroups", baseURL, testerID) payload := RelationshipRequest{ Data: make([]RelationshipData, len(groupIDs)), } for i, id := range groupIDs { payload.Data[i] = RelationshipData{Type: "betaGroups", ID: id} } // POST request } // RemoveBetaTesterFromGroups removes a tester from multiple beta groups // DELETE /v1/betaTesters/{id}/relationships/betaGroups func (c *Client) RemoveBetaTesterFromGroups(ctx context.Context, testerID string, groupIDs []string) error { // DELETE with body (same payload structure) } ``` ### 3. CLI Flags For `add-groups`: - `--id` (required, tester ID) - `--group` (required, comma-separated group IDs) For `remove-groups`: - `--id` (required, tester ID) - `--group` (required, comma-separated group IDs) ### 4. Implementation Pattern Follow the same pattern as issue #47 (beta-groups add/remove testers), but inverted: - Issue #47: Add testers TO a group - This issue: Add a tester TO groups ```go func BetaTestersAddGroupsCommand() *ffcli.Command { fs := flag.NewFlagSet("add-groups", flag.ExitOnError) id := fs.String("id", "", "Beta tester ID") groups := fs.String("group", "", "Comma-separated beta group IDs") return &ffcli.Command{ Name: "add-groups", ShortUsage: "asc beta-testers add-groups --id TESTER_ID --group GROUP_ID[,GROUP_ID...]", // ... } } ``` ### 5. Testing **Unit tests** in `cmd/commands_test.go`: ```go {"beta-testers add-groups missing id", []string{"beta-testers", "add-groups"}, ...} {"beta-testers add-groups missing group", []string{"beta-testers", "add-groups", "--id", "X"}, ...} {"beta-testers remove-groups validation", ...} ``` **Client tests** in `internal/asc/client_http_test.go`: - Test relationship payload with betaGroups type - Test multiple group IDs **Live API test**: ```bash # Get tester and group IDs ./asc beta-testers list --app 6747745091 --limit 1 ./asc beta-groups list --app 6747745091 # Test ./asc beta-testers add-groups --id "TESTER_ID" --group "GROUP_ID" ./asc beta-testers remove-groups --id "TESTER_ID" --group "GROUP_ID" # Test multiple groups ./asc beta-testers add-groups --id "TESTER_ID" --group "GROUP1,GROUP2" ``` ### 6. Success Output ```go fmt.Fprintf(os.Stderr, "Successfully added tester %s to %d group(s)\n", testerID, len(groupIDs)) fmt.Fprintf(os.Stderr, "Successfully removed tester %s from %d group(s)\n", testerID, len(groupIDs)) ``` ### 7. Code Standards - Use `strings.TrimSpace()` on tester ID and all group IDs - Reuse `parseCommaSeparatedIDs()` helper from issue #47 if available - Handle idempotent behavior (adding to group already in is OK) - Run `make format && make lint && make test` before committing
Author
Owner

@cursor[bot] commented on GitHub (Jan 23, 2026):

Summary:

  • Added beta-testers add/remove groups commands with parsed group IDs, success messaging, and JSON/table/markdown output.
  • Added client relationship POST/DELETE helpers for beta group memberships plus output formatting support.
  • Added CLI validation, client HTTP payload, and output tests for the new flow.

Tests:

  • PATH="$(go env GOPATH)/bin:$PATH" make format
  • make lint
  • make test

Notes:

  • Live API tests not run (no credentials in this environment).

View PR
Open in Cursor Open in Web

<!-- gh-comment-id:3792266280 --> @cursor[bot] commented on GitHub (Jan 23, 2026): Summary: - Added beta-testers add/remove groups commands with parsed group IDs, success messaging, and JSON/table/markdown output. - Added client relationship POST/DELETE helpers for beta group memberships plus output formatting support. - Added CLI validation, client HTTP payload, and output tests for the new flow. Tests: - `PATH="$(go env GOPATH)/bin:$PATH" make format` - `make lint` - `make test` Notes: - Live API tests not run (no credentials in this environment). <a href="https://github.com/rudrankriyam/App-Store-Connect-CLI/pull/57"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/view-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/view-pr-light.svg"><img alt="View PR" src="https://cursor.com/view-pr-light.svg"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-a3f92f82-9cc0-4894-8c27-1a841a9c7000"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in Cursor" src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?id=bc-a3f92f82-9cc0-4894-8c27-1a841a9c7000"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/open-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web" src="https://cursor.com/open-in-web.svg"></picture></a>
Author
Owner

@rudrankriyam commented on GitHub (Jan 23, 2026):

Implemented in PR #57 - beta-testers add-groups and remove-groups commands.

<!-- gh-comment-id:3792500217 --> @rudrankriyam commented on GitHub (Jan 23, 2026): Implemented in PR #57 - beta-testers add-groups and remove-groups commands.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/App-Store-Connect-CLI#10
No description provided.