Skip to content

Commit

Permalink
amplify-preview: custom action to trigger amplify previews (#287)
Browse files Browse the repository at this point in the history
* Initial version of `amplify-preview` action

* Add readme

* Dependency fixes

* Add CICD files

* Address PR feedback

* PR feedback, part 2
  • Loading branch information
taraspos authored Dec 18, 2024
1 parent 0f1f9de commit 606b252
Show file tree
Hide file tree
Showing 16 changed files with 2,478 additions and 6 deletions.
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 {
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
}
}

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
Loading

0 comments on commit 606b252

Please sign in to comment.