> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Go SDK: GitHub deploys

> Deploy from GitHub with c.Apps.Deploys: set a webhook, link a repository through the Square Cloud GitHub App, and read the deploy history.

`c.Apps.Deploys` connects an app to GitHub so a push deploys it. There are two ways to do it: a **webhook** that you add to the repository, or the **Square Cloud GitHub App**.

Each snippet below runs on its own inside this program: paste one at a time into `main` and run `goimports` (see [Running the examples](/en/sdks/go/client#running-the-examples)).

```go theme={"system"}
package main

import (
	"context"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

var (
	ctx   = context.Background()
	c     = squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
	appID = "abc123def456abc123def456"
)

func main() {
	// Paste one snippet here, then run goimports.
}
```

## Webhook

`Deploys.SetWebhook(ctx, appID, accessToken)` configures GitHub webhook deploys with a GitHub access token (`ghp_...` or `github_pat_...`) and returns the webhook URL to add to your repository.

```go theme={"system"}
url, err := c.Apps.Deploys.SetWebhook(ctx, appID, os.Getenv("GITHUB_TOKEN"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(url) // add it as a webhook in the repository settings
```

Pass `"@"` as the token to remove the webhook. The method then returns `""`.

```go theme={"system"}
if _, err := c.Apps.Deploys.SetWebhook(ctx, appID, "@"); err != nil {
	log.Fatal(err)
}
```

An invalid token is 400 `INVALID_ACCESS_TOKEN`.

## GitHub App

`Deploys.LinkGithubApp(ctx, appID, repository, branch)` links a repository installed through the Square Cloud GitHub App. It needs the `apps:deploy` scope.

```go theme={"system"}
repo, err := c.Apps.Deploys.LinkGithubApp(ctx, appID, "octocat/hello-world", "main")
if err != nil {
	log.Fatal(err)
}

fmt.Println(repo.ID, repo.FullName, repo.Branch)
```

`Deploys.UnlinkGithubApp(ctx, appID)` removes the link. To link another repository or branch, unlink first.

```go theme={"system"}
if err := c.Apps.Deploys.UnlinkGithubApp(ctx, appID); err != nil {
	log.Fatal(err)
}
```

Link and unlink share a limit of **3 calls per 60 seconds**.

| Status | Code | When |
| - | - | - |
| 400 | `GIT_ALREADY_CONFIGURED` | The app already has a linked repository: unlink it first |
| 400 | `GIT_NOT_CONFIGURED` | `UnlinkGithubApp` with nothing linked |
| 400 | `BRANCH_NOT_FOUND`, `INVALID_BRANCH_LENGTH` | The branch does not exist, or its name is over 256 characters |
| 403 | `GITHUB_NOT_CONNECTED` | Your account has no GitHub App installation |
| 403 | `REPOSITORY_NOT_AVAILABLE` | The GitHub App is not installed on the repository through your GitHub account |
| 403 | `REPOSITORY_PERMISSION_REQUIRED` | Your GitHub account has no write access to the repository |
| 404 | `REPOSITORY_NOT_FOUND` | The repository does not exist or is not visible |
| 409 | `REPOSITORY_BRANCH_ALREADY_CONFIGURED` | Another app, of any account, already links this repository and branch. Its id is in `Message` only when that app is yours |
| 502 | `FAILED_TO_FETCH` | GitHub did not confirm the branch: safe to retry |

## Current configuration

`Deploys.Current(ctx, appID)` returns what is configured: `App` for the GitHub App link, `Webhook` for the webhook URL. When nothing is set, it returns the zero value (`App` is `nil` and `Webhook` is `""`). The fields of `App` are pointers, since the API may send them as `null`.

```go theme={"system"}
current, err := c.Apps.Deploys.Current(ctx, appID)
if err != nil {
	log.Fatal(err)
}

if app := current.App; app != nil && app.Name != nil && app.Branch != nil {
	fmt.Println(*app.Name, *app.Branch) // e.g. "octocat/hello-world" "main"
}
if current.Webhook != "" {
	fmt.Println(current.Webhook)
}
```

## Deploy history

`Deploys.List(ctx, appID)` returns one **timeline per deploy** (a `[][]DeployEvent`), each a slice of events, oldest event first. Only Git deploys (webhook and GitHub App pushes) are recorded.

```go theme={"system"}
timelines, err := c.Apps.Deploys.List(ctx, appID)
if err != nil {
	log.Fatal(err)
}
for _, timeline := range timelines {
	if len(timeline) == 0 {
		continue
	}
	last := timeline[len(timeline)-1]
	fmt.Println(last.ID, last.State, last.Date)

	if last.State == squarecloud.DeployError {
		fmt.Println(last.Code, last.Message)
	}
}
```

| Field | Description |
| - | - |
| `ID` (`id`) | The commit SHA |
| `State` (`state`) | `pending`, `clone`, `commit`, `restarting`, `success` or `error` (constants `DeployPending`, `DeployClone`, `DeployCommit`, `DeployRestarting`, `DeploySuccess`, `DeployError`) |
| `Date` (`date`) | When the event happened (`time.Time`) |
| `Source` (`source`) | Always `"git"` |
| `Branch` (`branch`) | On `clone` events |
| `Files` (`files`) | On `commit` events: a `*DeployFiles` with `Added`, `Removed` and `Modified`; `nil` otherwise |
| `Code` / `Message` (`code` / `message`) | On `error` events: why the deploy failed (for example `CLONE_FAILED`) |

## Next steps

<CardGroup cols={3}>
  <Card title="Network" icon="globe" href="/en/sdks/go/network">
    Analytics, DNS, custom domains and cache.
  </Card>

  <Card title="Deploy API reference" icon="code" href="/en/api-reference/endpoint/apps/deploy/list">
    The REST endpoints behind these methods.
  </Card>

  <Card title="GitHub deploys from the CLI" icon="terminal" href="/en/cli-reference/github-deploys">
    The same actions from the terminal.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.