# `Skipper.Client`
[🔗](https://github.com/get-skipper/skipper-elixir/blob/main/lib/skipper/client.ex#L1)

Reads the spreadsheet: primary sheet plus reference sheets, merged.

# `entry`

```elixir
@type entry() :: %{
  test_id: String.t(),
  disabled_until: DateTime.t() | nil,
  notes: String.t(),
  row: non_neg_integer()
}
```

# `sheet`

```elixir
@type sheet() :: %{
  sheet_name: String.t(),
  sheet_id: integer(),
  header: [String.t()],
  entries: [entry()]
}
```

# `fetch_all`

```elixir
@spec fetch_all(Skipper.SheetsApi.api(), Skipper.Config.t()) ::
  {:ok, %{primary: sheet(), entries: [entry()]}} | {:error, String.t()}
```

Fetch the primary sheet and merge every reference sheet into it (latest date
wins). A failing reference sheet is skipped with a warning.

# `parse_disabled_until`

```elixir
@spec parse_disabled_until(String.t(), non_neg_integer()) ::
  {:ok, DateTime.t() | nil} | {:error, String.t()}
```

Parse a `disabledUntil` cell. Only strict `YYYY-MM-DD` is accepted; the
result is midnight UTC of the *following* day, so the test stays disabled for
the whole calendar day. Empty means no date. `row` (1-based sheet row,
0 = unknown) only appears in the error message.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
