// PROJECT

Cloud Resource Reporter

Query cloud APIs, aggregate resource data, output formatted reports. Applies Modules 1-5.

Project Goals

Build a CLI tool that queries a cloud API, aggregates resource information, and outputs formatted reports in multiple formats.

Your program should:

  1. Connect to a REST API (we'll use the GitHub API — free, no account needed for public data)
  2. Fetch and paginate through resources
  3. Aggregate data: count by category, compute statistics
  4. Output reports in table, JSON, and CSV formats
  5. Handle errors, rate limiting, and timeouts gracefully

Why This Project

This is the kind of tool every infra team builds internally. Whether it's querying AWS, GCP, or an internal inventory system, the pattern is always: connect → fetch → aggregate → report. This project exercises HTTP clients, JSON handling, pagination, and data aggregation.

Usage

# Report on a GitHub org's repos
cloudreport repos --org kubernetes --format table

# Report with sorting
cloudreport repos --org hashicorp --sort stars --limit 20

# JSON output for piping to jq
cloudreport repos --org prometheus --format json | jq '.repos[].name'

# CSV for spreadsheets
cloudreport repos --org grafana --format csv > repos.csv

Expected Output

Table format (default):
=== Repository Report: kubernetes ===
Total repositories: 20 (showing top 20 by stars)

NAME                     STARS    FORKS    LANG        UPDATED
kubernetes               105841   38420    Go          2024-01-15
minikube                 28102    4891     Go          2024-01-14
ingress-nginx            16421    8102     Go          2024-01-15
dashboard                13542    4021     TypeScript  2024-01-13
kops                     15520    5610     Go          2024-01-12

Summary:
  Total stars: 179,426
  Languages: Go (14), TypeScript (3), Shell (2), Python (1)
  Updated in last 7 days: 18

Requirements

Core

CLI Flags

API Endpoints

GET https://api.github.com/orgs/{org}/repos?per_page=100&page=1&sort=updated

Response headers to check:

Suggested Structure

cloudreport/
├── main.go           ← CLI entry point
├── client.go         ← HTTP client, pagination, rate limit handling
├── client_test.go    ← Tests using httptest.NewServer
├── models.go         ← Repo struct, aggregation types
├── aggregate.go      ← Sorting, grouping, statistics
├── output.go         ← Table, JSON, CSV formatters
└── output_test.go    ← Format output tests

Hints

Suggested approach:

  1. Start by fetching a single page from the GitHub API and parsing the JSON
  2. Add pagination — fetch all pages into a []Repo
  3. Add sorting and limiting
  4. Build the table formatter first (most useful for debugging)
  5. Add JSON and CSV formatters
  6. Add rate limit checking
  7. Add the aggregation summary

Pagination Helper

func (c *Client) fetchAllRepos(org string) ([]Repo, error) {
    var all []Repo
    page := 1
    for {
        repos, hasNext, err := c.fetchReposPage(org, page)
        if err != nil {
            return nil, err
        }
        all = append(all, repos...)
        if !hasNext {
            break
        }
        page++
    }
    return all, nil
}

Table Formatting

// Compute column widths from data, then use fmt.Sprintf with padding
fmt.Sprintf("%-*s  %-*d  %-*d  %-*s", nameWidth, name, 8, stars, 8, forks, langWidth, lang)

Testing

Use httptest.NewServer to mock the GitHub API:

func TestFetchRepos(t *testing.T) {
    server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode([]Repo{
            {Name: "test-repo", Stars: 42, Language: "Go"},
        })
    }))
    defer server.Close()

    client := NewClient(server.URL, 10*time.Second)
    repos, err := client.fetchAllRepos("test-org")
    // assert...
}

Stretch Goals

Skills Used: HTTP clients, JSON parsing, pagination, struct methods, sorting (sort.Slice), string formatting, multiple output formats, CLI flags, error handling, test mocking with httptest.