# Ways to install

A page per operating system, four ways to get the binary running, and what each one is good for.

Source: https://jmrplens.github.io/ghchronicle/install/

One static binary with no runtime dependencies. How it gets onto the machine is
the only decision, and it follows from where you want it to run.

## Your system, from download to service

Releases carry binaries for Linux, macOS and Windows, on amd64 and arm64. The
three pages below are the same walk for each system, taken all the way: which
archive, how to check it, where the binary goes, how to run it once, and how to
keep it running once you are done watching it.

- [Linux](/ghchronicle/install/linux/): A tar.gz, /usr/local/bin, and a hardened systemd unit.

- [macOS](/ghchronicle/install/macos/): The darwin archive, the quarantine attribute, and a launchd agent or daemon.

- [Windows](/ghchronicle/install/windows/): A zip, PowerShell and cmd, a scheduled task, and what is genuinely different there.

## Getting the binary

- **Go**

  ```sh
  go install github.com/jmrplens/ghchronicle/cmd/ghchronicle@latest
  ```

  Needs a Go toolchain, and builds from source at whatever the newest tag is.

- **Release**

  Take the archive for your platform from the
  [releases page](https://github.com/jmrplens/ghchronicle/releases).
  Archives are built for Linux, macOS and Windows, on amd64 and arm64, and
  ship as `tar.gz` (`zip` on Windows).

  ```sh
  tar -xzf ghchronicle_1.0.0_linux_amd64.tar.gz
  sudo install -m 755 ghchronicle /usr/local/bin/
  ```

- **Container**

  ```sh
  docker run -v $PWD/config.yaml:/config.yaml:ro -e GITHUB_TOKEN \
    ghcr.io/jmrplens/ghchronicle -config /config.yaml
  ```

  Distroless, static, and running as uid 65532.

- **Action**

  ```yaml
  - uses: jmrplens/ghchronicle@v1
    with:
      token: ${{ secrets.GHCHRONICLE_TOKEN }}
      mode: once
      config: .github/ghchronicle.yaml
  ```

  A composite Action that downloads a release binary, so the runner needs no
  Go toolchain.

## Choosing where it runs

The collector pushes to every store it supports, so it does not need to be
reachable from anywhere. It needs to reach GitHub and to reach its databases.
That is the only constraint, and it is what makes all four of these viable.
Three of the four want a host you own: systemd, Docker and cron. GitHub Actions
is the one that does not. The system pages above are where the scheduler lives,
one per system: systemd or cron on Linux, launchd on macOS, a scheduled task on
Windows.

- [systemd](/ghchronicle/install/systemd/): A long-running service on a host you own. The default choice: the state file persists, the schedule is the tool's own, and the unit can be locked down hard.

- [Docker](/ghchronicle/install/docker/): The same thing in a container. Mount a writable volume for the state file and any file sink.

- [GitHub Actions](/ghchronicle/install/actions/): No host at all. Good for the card and for a scheduled sweep; the state file does not survive between runs unless you cache it.

- [cron](/ghchronicle/install/systemd/#cron-instead-of-a-service): `-once` runs a single sweep and exits, which is all a scheduler needs. Keep the state file on a persistent path.

## The three run modes

| Command                                     | Does                                                       |
| ------------------------------------------- | ---------------------------------------------------------- |
| `ghchronicle -config config.yaml`           | Runs forever, each family on its own cadence               |
| `ghchronicle -config config.yaml -once`     | One sweep, then exits                                      |
| `ghchronicle -config config.yaml -backfill` | Walks every surface to its end, waiting for the rate limit |

Plus two that write nothing: `-list` prints the repositories in scope, and
`-card ... -card-only` renders the SVG without touching a database.

> **The state file is the one thing that must persist**
>
> Whichever way it runs, keep `state_file` on a path that survives a restart. It
> is what stops the full stargazer walk and the year-by-year contribution
> backfill happening again on every run.
