Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

amplify-preview: custom action to trigger amplify previews #287

Merged
merged 10 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/amplify-preview-cd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: Amplify Preview CD

on:
push:
branches:
- main
paths:
- tools/amplify-preview
tags:
- "tools/amplify-preview/v[0-9]+.[0-9]+.[0-9]+**"
pull_request:
paths:
- tools/amplify-preview/workflows/cd.yaml
- .github/workflows/amplify-preview-cd.yaml
- .github/workflows/reusable-cd.yaml

jobs:
release:
uses: ./.github/workflows/reusable-cd.yaml
permissions:
contents: write
packages: write
with:
tool-directory: ./tools/amplify-preview
14 changes: 14 additions & 0 deletions .github/workflows/amplify-preview-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
name: Amplify Preview CI

on:
pull_request:

jobs:
release:
uses: ./.github/workflows/reusable-ci.yaml
permissions:
contents: write
packages: write
with:
tool-directory: ./tools/amplify-preview
70 changes: 70 additions & 0 deletions libs/github/comment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package github

import (
"context"
"errors"
"strings"

"github.com/google/go-github/v63/github"
)

var (
ErrCommentNotFound = errors.New("comment not found")
)

// IssueIdentifier represents an issue or PR on GitHub
type IssueIdentifier struct {
taraspos marked this conversation as resolved.
Show resolved Hide resolved
Owner string
Repo string
Number int
}

// CommentTraits defines optional traits to filter comments.
// Every trait (if non-empty-string) is matched with an "AND" operator
type CommentTraits struct {
BodyContains string
UserLogin string
}

// FindCommentByTraits searches for a comment in an PR or issue based on specified traits
func (c *Client) FindCommentByTraits(ctx context.Context, issue IssueIdentifier, targetComment CommentTraits) (*github.IssueComment, error) {
comments, _, err := c.client.Issues.ListComments(ctx, issue.Owner, issue.Repo, issue.Number, nil)
if err != nil {
return nil, err
}

for _, c := range comments {
matcher := true
if targetComment.UserLogin != "" {
matcher = matcher && c.User.GetLogin() == targetComment.UserLogin
}

if targetComment.BodyContains != "" {
matcher = matcher && strings.Contains(c.GetBody(), targetComment.BodyContains)
}

if matcher {
return c, nil
}
}
Comment on lines +36 to +49
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proper zero values for CommentTraits means you can remove matcher and the empty string checks. Also, see https://pkg.go.dev/slices#ContainsFunc


return nil, ErrCommentNotFound
}

// CreateComment creates a new comment on an issue or PR
func (c *Client) CreateComment(ctx context.Context, issue IssueIdentifier, commentBody string) error {
_, _, err := c.client.Issues.CreateComment(ctx, issue.Owner, issue.Repo, issue.Number, &github.IssueComment{
Body: &commentBody,
})

return err
}

// UpdateComment updates an existing comment on an issue or PR
func (c *Client) UpdateComment(ctx context.Context, issue IssueIdentifier, commentId int64, commentBody string) error {
_, _, err := c.client.Issues.EditComment(ctx, issue.Owner, issue.Repo, commentId, &github.IssueComment{
Body: &commentBody,
})

return err
}
7 changes: 5 additions & 2 deletions libs/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ module github.com/gravitational/shared-workflows/libs
go 1.22.4

require (
github.com/cli/go-gh/v2 v2.9.0
github.com/cli/go-gh/v2 v2.11.1
github.com/google/go-github/v63 v63.0.0
github.com/gravitational/trace v1.4.0
github.com/stretchr/testify v1.8.3
golang.org/x/oauth2 v0.21.0
)

require (
github.com/cli/safeexec v1.0.0 // indirect
github.com/cli/safeexec v1.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.23.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
9 changes: 5 additions & 4 deletions libs/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,10 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cli/go-gh/v2 v2.9.0 h1:D3lTjEneMYl54M+WjZ+kRPrR5CEJ5BHS05isBPOV3LI=
github.com/cli/go-gh/v2 v2.9.0/go.mod h1:MeRoKzXff3ygHu7zP+NVTT+imcHW6p3tpuxHAzRM2xE=
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/cli/go-gh/v2 v2.11.1 h1:amAyfqMWQTBdue8iTmDUegGZK7c8kk6WCxD9l/wLtGI=
github.com/cli/go-gh/v2 v2.11.1/go.mod h1:MeRoKzXff3ygHu7zP+NVTT+imcHW6p3tpuxHAzRM2xE=
github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00=
github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
Expand Down Expand Up @@ -997,6 +997,7 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down
1 change: 1 addition & 0 deletions tools/amplify-preview/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/*
3 changes: 3 additions & 0 deletions tools/amplify-preview/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TOOL_NAME = amplify-preview

include ../repo-release-tooling/tooling.mk
96 changes: 96 additions & 0 deletions tools/amplify-preview/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# amplify-preview


This gha-tool is basically re-implements what [AWS Amplify's GitHub integration should be doing](https://docs.aws.amazon.com/amplify/latest/userguide/pr-previews.html),
however because of following limitations, we can't really use it for some of the repos:
- [No way to filter for which PRs to generate preview deployments](https://github.com/aws-amplify/amplify-hosting/issues/3960)
- [Hard limit of 50 preview branches per amplify app][https://docs.aws.amazon.com/amplify/latest/userguide/quotas-chapter.html]
- [No way to create PR preview programmatically](https://github.com/aws-amplify/amplify-hosting/issues/3963)

This action accepts of AWS Amplify App IDs, checks if current git branch is connected to the apps and posts deployment status and PR preview in PR comments.

If `--create-branches` is enabled, then it will also connect git branch to one of the AWS Amplify apps (where hard limit of 50 branches hasn't been reached yet) and kick of new build.
If `--wait` is enabled, then it will also wait for deployment to be completed and fail the GHA run if deployment had failed.

## Usage

```shell
usage: amplify-preview --amplify-app-ids=AMPLIFY-APP-IDS --git-branch-name=GIT-BRANCH-NAME [<flags>]

Flags:
--[no-]help Show context-sensitive help (also try --help-long and --help-man).
--amplify-app-ids=AMPLIFY-APP-IDS ...
List of Amplify App IDs ($AMPLIFY_APP_IDS)
--git-branch-name=GIT-BRANCH-NAME
Git branch name ($GIT_BRANCH_NAME)
--[no-]create-branches Defines whether Amplify branches should be created if missing, or just lookup existing ones ($CREATE_BRANCHES)
--[no-]wait Wait for pending/running job to complete ($WAIT)
```

Example GHA workflow:

```yaml
name: Amplify Preview
on:
pull_request:
paths:
- 'docs/**'
workflow_dispatch:

permissions:
# Permissions to write PR comment
pull-requests: write
id-token: write

jobs:
amplify-preview:
name: Get and post Amplify preview URL
runs-on: ubuntu-22.04-2core-arm64
environment: docs-amplify
steps:
- name: Checkout shared-workflow
uses: actions/checkout@v4
with:
repository: gravitational/shared-workflows
sparse-checkout: |
tools

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4
with:
aws-region: us-west-2
role-to-assume: ${{ vars.IAM_ROLE }}

- name: Check Amplify job status test
uses: ./tools/amplify-preview
with:
app_ids: ${{ vars.AMPLIFY_APP_IDS }}
create_branches: "true"
github_token: ${{ secrets.GITHUB_TOKEN }}
wait: "true"
```

## AWS Permissions

For this action to work, AWS role with following IAM permissions is required:
```json
{
"Statement": [
{
"Action": [
"amplify:CreateBranch",
"amplify:GetBranch",
"amplify:ListJobs"
"amplify:StartJob",
],
"Effect": "Allow",
"Resource": [
"arn:aws:amplify:<region>:<account_id>:apps/<app_id>/branches/*"
]
}
],
"Version": "2012-10-17"
}
```

Where `amplify:CreateBranch` and `amplify:StartJob` are needed only when `--create-branches` is enabled.
39 changes: 39 additions & 0 deletions tools/amplify-preview/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Amplify Preview
description: Prepare Amplify Preview URL and post it in PR comments
inputs:
app_ids:
description: "Comma separated list of Amplify App IDs"
required: true
create_branches:
description: 'Create preview branches using this actions instead of "auto-build" feature on AWS Amplify'
required: false
default: "false"
github_token:
required: true
description: "Github token with permissions to read/write comments in pull request"
wait:
default: "false"
description: "If Amplify deployment is pending/running state wait for it's completion"
runs:
using: composite
steps:
- name: Extract branch name
shell: bash
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
id: extract_branch

- uses: actions/setup-go@v5
with:
go-version-file: tools/amplify-preview/go.mod
cache-dependency-path: tools/amplify-preview/go.sum

- name: Amplify Preview
env:
AMPLIFY_APP_IDS: ${{ inputs.app_ids }}
GIT_BRANCH_NAME: ${{ steps.extract_branch.outputs.branch }}
CREATE_BRANCHES: ${{ inputs.create_branches }}
GITHUB_TOKEN: ${{ inputs.github_token }}
WAIT: ${{ inputs.wait }}
shell: bash
run: |
pushd ./tools/amplify-preview/; go run ./; popd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need shell and pushd? go run ./tools/amplify-preview

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed in subsequent release PR once libs package is released and I can remove the replace rule from go.mod:

replace github.com/gravitational/shared-workflows/libs => ../../libs/

Loading
Loading