{"id":20567775,"url":"https://github.com/isometry/gh-promotion-app","last_synced_at":"2025-08-24T17:10:20.409Z","repository":{"id":246002016,"uuid":"765177215","full_name":"isometry/gh-promotion-app","owner":"isometry","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-07T14:21:57.000Z","size":2226,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-02-07T15:26:42.329Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/isometry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-29T12:31:12.000Z","updated_at":"2025-02-07T14:22:02.000Z","dependencies_parsed_at":"2024-06-25T10:04:19.078Z","dependency_job_id":"123ee39d-6590-48dd-a2d0-b5ea8ea76bd1","html_url":"https://github.com/isometry/gh-promotion-app","commit_stats":null,"previous_names":["isometry/gh-promotion-app"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isometry%2Fgh-promotion-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isometry%2Fgh-promotion-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isometry%2Fgh-promotion-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isometry%2Fgh-promotion-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/isometry","download_url":"https://codeload.github.com/isometry/gh-promotion-app/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242179426,"owners_count":20084947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T04:48:29.552Z","updated_at":"2025-08-24T17:10:20.397Z","avatar_url":"https://github.com/isometry.png","language":"Go","readme":"[![codeql](https://github.com/isometry/gh-promotion-app/actions/workflows/codeql.yaml/badge.svg?branch=main)](https://github.com/isometry/gh-promotion-app/actions/workflows/codeql.yaml)\n[![Go Report](https://goreportcard.com/badge/github.com/isometry/gh-promotion-app)](https://goreportcard.com/report/github.com/isometry/gh-promotion-app)\n\u003cbr\u003e\n[![main](https://github.com/isometry/gh-promotion-app/actions/workflows/main.yaml/badge.svg?branch=main)](https://github.com/isometry/gh-promotion-app/actions/workflows/main.yaml)\n[![publish](https://github.com/isometry/gh-promotion-app/actions/workflows/publish.yaml/badge.svg?branch=main)](https://github.com/isometry/gh-promotion-app/actions/workflows/publish.yaml)\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/isometry/gh-promotion-app/blob/main/docs/images/banner.png?raw=true\" width=\"220\"\n         alt=\"banner\"/\u003e\n    \u003cbr\u003e\n    \u003ci\u003egh-promotion-app\u003c/i\u003e\n    \u003cbr\u003e\n    🔎 \u003ca href=\"#how-it-works\"\u003eHow it works\u003c/a\u003e | 👍 \u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\n    \u003cbr\u003e\u003cbr\u003e\n\u003c/p\u003e\n\n## How it works\n\nThe `gh-promotion-app` is a service that automates the promotion of GitHub branch across environments. It is designed to\noperate as a GitHub App and respond to the webhook events to which its App is subscribed.\nIt currently supports the following event types:\n\n| Event Type            | Description                                                        |\n|-----------------------|--------------------------------------------------------------------|\n| `push`                | Change is **pushed** to a given branch                             |\n| `pull_request`        | Pull request is **opened**, **reopened** or **closed**             |\n| `pull_request_review` | Pull request review is **approved**                                |\n| `check_suite`         | Check suite is **completed**                                       |\n| `deployment_status`   | Deployment status is marked as **success**                         |\n| `status`              | When the status of a Git commit changes to **success**             |\n| `workflow_run`        | Workflow run conclusion is **completed** and status is **success** |\n\n\u003e [!TIP]\n\u003e Check the full docs locally with [pkgsite](https://github.com/golang/pkgsite) by running the following command:\n\u003e ```console\n\u003e go install golang.org/x/pkgsite/cmd/pkgsite@latest \\\n\u003e   \u0026\u0026 pkgsite\n\u003e ```\n\n### Overview\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/isometry/gh-promotion-app/blob/main/docs/images/overview.png?raw=true\" width=\"500\"\n         alt=\"overview\"/\u003e\n\u003c/p\u003e\n\n### Running \u0026 Input\n\nThe `gh-promotion-app` can be run in three modes:\n\n1. **lambda-http**: The application is deployed as an AWS Lambda function and is triggered by an API Gateway endpoint.\n    ```console\n    go run main.go lambda http # or go run main.go --mode=lambda-http\n    ```\n   * `Input`: `HTTP` request containing the GitHub webhook payload w/ Headers.\n2. **lambda-event**: The application is deployed as an AWS Lambda function and is triggered an EventBridge rule.\n    ```console\n    go run main.go lambda event # or go run main.go --mode=lambda-event\n    ```\n    * `Input`: `EventBridge` / `CloudWatch` event which encapsulates the GitHub webhook payload in the `detail` field.\n\n\u003e [!NOTE]\n\u003e The incoming event expected values are as follows:\n\u003e ```json\n\u003e {\n\u003e    \"detail\": \u003coriginal_webhook_payload\u003e,\n\u003e    \"detail-type\": \u003cwebhook_payload_type\u003e, (e.g. pull, pull_request, check_suite, etc.),\n\u003e    \"source\": \u003cyour_custom_event_source\u003e,\n\u003e    ...\n\u003e }\n\u003e ```\n\n3. **service**: The application is deployed as a standalone service and listens for incoming HTTP requests.\n    ```console\n    go run main.go service # or go run main.go --mode=service\n    ```\n    * `Input`: `HTTP` request containing the GitHub webhook payload w/ Headers.\n\n### Feedback\n\n\u003e [!NOTE]\n\u003e Only one feedback mechanism should be enabled at a time to avoid conflicts.\n\n#### Check Run (`default`)\n\nGitHub offers a more detailed check-run feedback mechanism. The initial format is equivalent to the commit status,\nhowever when clicked, it provides a more detailed view of the promotion process.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample...\u003c/summary\u003e\n\n![cr](docs/images/feedback_checkRun.png)\n\n\u003c/details\u003e\n\n#### Commit Status\n\nCommits that are part of a promotion are marked with a status check. The format is as follows:\n\n`{source}→{target} - {status} @ {timestamp}`\n\n\u003cdetails\u003e\n\u003csummary\u003eExample...\u003c/summary\u003e\n\n![cs](docs/images/feedback_commitStatus.png)\n\n\u003c/details\u003e\n\n\n### Configuration\n\nThe application can be configured using environment variables, a YAML configuration file and/or command-line arguments.\nThe location of the configuration file is specified using the `-c, --config` flag, it defaults to `config.yaml`.\n\n\u003cdetails\u003e\n\u003csummary\u003eSample configuration file\u003c/summary\u003e\n\n[config.sample.yaml](config.sample.yaml)\n\n```yaml\n---\nglobal:\n  mode: \u003cstring\u003e            # (defaults to \"lambda\")\n  logging:\n    verbosity: \u003cint\u003e         # 0:WarnLevel 1:InfoLevel 2:DebugLevel (defaults to 0)\n    callerTrace: \u003cbool\u003e      # (defaults to false)\n  s3:\n    upload:\n      enabled: \u003cbool\u003e         # (defaults to false)\n      bucketName: \u003cstring\u003e\n\npromotion:\n  defaultStages: \u003c[]string\u003e # (defaults to [\"main\", \"stating\", \"canary\", \"production\"])\n  dynamicPromotion:\n    enabled: \u003cbool\u003e          # (defaults to true)\n    key: \u003cstring\u003e            # (defaults to \"gitops-promotion-path\")\n  push:\n    createTargetRef: \u003cbool\u003e                    # (defaults to true)\n    createPullRequestInDraftModeKey: \u003cstring\u003e  # (defaults to \"gitops-promotion-draft-pr\")\n  feedback:\n    commitStatus:\n      enabled: \u003cbool\u003e         # (defaults to true)\n      context: \u003cstring\u003e       # (defaults to \"{source}→{target}\")\n    checkRun:\n      enabled: \u003cbool\u003e         # (defaults to true)\n      name: \u003cstring\u003e          # (defaults to \"{source}→{target}\")\n\ngithub:\n  authMode: \u003cstring\u003e        # (defaults to \"ssm\")\n  ssmKey: \u003cstring\u003e\n  webhookSecret: \u003cstring\u003e\n\nservice:\n  path: \u003cstring\u003e            # (defaults to \"/\")\n  addr: \u003cstring\u003e\n  port: \u003cstring\u003e            # (defaults to \"8080\")\n  timeout: \u003cduration\u003e       # (defaults to \"5s\")\n\nlambda:\n  payloadType: \u003cstring\u003e     # (defaults to \"api-gateway-v2\")\n```\n\n\u003c/details\u003e\n\nFor all available configuration options, see the included sample configuration\nfile [config.sample.yaml](config.sample.yaml)\nand refer to the [Usage](#usage) section.\n\n\u003e [!NOTE]\n\u003e When the `github.authMode` key is set to `token`, the `GITHUB_TOKEN` environment variable must be set with a valid\n\u003e GitHub token.\n\u003e If the `promotion.feedback.checkRun.enabled` key is set to `true`, the fetched token value must be spawned from a\n\u003e GitHub app installation.\n\n### Authentication modes\n\nGitHub interactions are handled by:\n* v3 API [go-github](https://github.com/google/go-github)\n* v4 API [graphql](https://github.com/graphql-go/graphql)\n\n#### Token (`GITHUB_TOKEN`)\n\nPersonal access token w/ permissions compatible with the selected configuration.\n\n\u003e [!NOTE]\n\u003e PATs are not allowed to create new check-run(s). You will need to use a [GitHub app](#github-app) installation instead.\n\n#### GitHub App\n\nAt this time, the application requires that the GitHub app installation secrets are stored in AWS SSM.\n\nThe supported format is as follows:\n\n```json\n{\n    \"app_id\": \"\u003cint64\u003e\",\n    \"private_key\": \"\u003cstring\u003e\",\n    \"webhook_secret\": \"\u003cstring\u003e\"\n}\n```\n\nThe above credentials are then used to authenticate to GitHub on behalf of the app.\nFetched secrets are cached in-memory per-GitHub app installation ID as to avoid unnecessary requests.\n\nAWS interactions are handled by the [aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) SDK.\n\n\u003e [!NOTE]\n\u003e The GitHub app permissions must be compatible with the selected configuration.\n\n### Usage\n\n```console\nUsage:\n   [flags]\n   [command]\n\nAvailable Commands:\n  lambda\n  service\n\n  -c, --config string                                  path to the configuration file (default \"config.yaml\")\n      --create-missing-target-branches                 [CREATE_MISSING_TARGET_BRANCHES] Create missing target branches (default true)\n      --feedback-check-run                             [FEEDBACK_CHECK_RUN] Enable check-run feedback (default true)\n      --feedback-check-run-name string                 [FEEDBACK_CHECK_RUN_NAME] The name to use when creating the check run. Supported placeholders: {source}, {target} (default \"{source}→{target}\")\n      --feedback-commit-status                         [FEEDBACK_COMMIT_STATUS] Enable commit status feedback (default true)\n      --feedback-commit-status-context string          [FEEDBACK_COMMIT_STATUS_CONTEXT] The context key to use when pushing the commit status to the repository. Supported placeholders: {source}, {target} (default \"{source}→{target}\")\n      --github-app-ssm-arn string                      [GITHUB_APP_SSM_ARN] The SSM parameter key to use when fetching GitHub App credentials\n  -A, --github-auth-mode string                        [GITHUB_AUTH_MODE] Authentication credentials provider. Supported values are 'token' and 'ssm'. (default \"ssm\")\n      --github-webhook-secret string                   [GITHUB_WEBHOOK_SECRET] The secret to use when validating incoming GitHub webhook payloads. If not specified, no validation is performed\n  -h, --help                                           help for this command\n      --mode string                                    [MODE] The application runtime mode. Possible values are 'lambda-event', 'lambda-http' and 'service' (default \"lambda\")\n      --promotion-default-stages strings               [PROMOTION_DEFAULT_STAGES] The default promotion stages (default [sdasd])\n      --promotion-dynamic                              [PROMOTION_DYNAMIC] Enable dynamic promotion (default true)\n      --promotion-dynamic-custom-property-key string   [DYNAMIC_PROMOTION_KEY] The key to use when fetching the dynamic promoter configuration (default \"gitops-promotion-path\")\n      --promotion-report-s3-upload                     [PROMOTION_REPORT_S3_UPLOAD] Enable S3 upload of promotion reports\n      --promotion-report-s3-upload-bucket string       [PROMOTION_REPORT_S3_BUCKET] The S3 bucket to use when uploading promotion reports\n  -v, --verbose count                                  [VERBOSE] Increase logger verbosity (default WarnLevel)\n  -V, --caller-trace                                   [CALLER_TRACE] Enable caller trace in logs\n```\n\n## Contributing\n\n* Feel free to open an issue describing the problem you are facing or the feature you want to see implemented.\n* If you want to contribute, fork the repository and submit a pull request.\n    * Make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisometry%2Fgh-promotion-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisometry%2Fgh-promotion-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisometry%2Fgh-promotion-app/lists"}