{"id":30854428,"url":"https://github.com/sematext/gh-runner","last_synced_at":"2025-09-07T10:40:06.936Z","repository":{"id":297401321,"uuid":"992487491","full_name":"sematext/gh-runner","owner":"sematext","description":"An example of a self-hosted equivalent to a GitHub workflow, designed to avoid excess usage of GitHub Actions minutes","archived":false,"fork":false,"pushed_at":"2025-06-05T09:28:59.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-06-05T09:37:56.012Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://sematext.com/docs/synthetics/ci-cd/overview/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sematext.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-05-29T08:30:07.000Z","updated_at":"2025-06-05T09:29:00.000Z","dependencies_parsed_at":"2025-06-05T09:38:00.130Z","dependency_job_id":"45565811-0d72-4838-b8a4-ac8c9e90186f","html_url":"https://github.com/sematext/gh-runner","commit_stats":null,"previous_names":["sematext/gh-runner"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sematext/gh-runner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sematext%2Fgh-runner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sematext%2Fgh-runner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sematext%2Fgh-runner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sematext%2Fgh-runner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sematext","download_url":"https://codeload.github.com/sematext/gh-runner/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sematext%2Fgh-runner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274026706,"owners_count":25209739,"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","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2025-09-07T10:40:05.475Z","updated_at":"2025-09-07T10:40:06.917Z","avatar_url":"https://github.com/sematext.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Self-hosted GitHub Runner\n\nThis is a working example of a lightweight service that's used as part of Sematext's Synthetics CI/CD. You can use it as an example for how to convert your GitHub workflows to self-hosted applications which you can run on your existing environments and circumvent GitHub Actions Minutes limitations, since it also showcases how to interact with GitHub from external services. \n\nAt Sematext we actually use this internally for reasons described here: https://sematext.com/docs/synthetics/ci-cd/ci-cd-self-hosting/\n\nThis self-hosted Github Runner is designed to run persistently as a server on one of our kubernetes clusters and listen for requests. These requests are sent from ArgoCD when an environment deployment is complete. This service then collects the latest commit hash for the deployed environment from its config on the `deployment` repo so that it can be linked with the appropriate commit on the `sematext-cloud` repo. This information is then sent to the `sematext-cloud` repo as a `repository_dispatch` event.\n\n\n## Running locally\n\nThere are two ways to run the self-hosted runner locally for testing. Running the Go program is easier when making changes to the code, but once those are done you should also run the Dockerized setup to confirm everything works that way, since we'll be using it as a Docker container in production.\n\n\n### Go program\n\n```bash\ngo build main.go\ngo run main.go\n```\n\n\n### Dockerized setup\n\nThe base image we're using is very light, so the building process shouldn't take longer than a couple of seconds.\n\n```bash\ndocker build -t gh-runner .\ndocker run --name gh-runner -p 9555:9555 gh-runner\n```\n\n\n## Authorization for private repositories\n\nA GitHub token with appropriate permissions to access both the `deployment` repo and the `sematext-cloud` repo is required. It will be automatically picked up by the service if it's set as an environment variable called `GITHUB_TOKEN`, but it can also be passed within a request to the `/dispatch` endpoint for testing purposes.\n\n**Note:** We can use the PAT for `build@sematext.com` here, since it has access to both of the repos.\n\n\n\n## Environment variables\n\n| Variable name    | Default value              |\n|------------------|----------------------------|\n| PORT             | `9555`                     |\n| GITHUB_API_URL   | `https://api.github.com`   |\n| TARGET_REPO      | `sematext/sematext-cloud`  |\n| DEPLOYMENT_REPO  | `sematext/deployment`      |\n| GITHUB_TOKEN     | (empty)                    |\n\n\n\n## API specification\n\n### POST `/dispatch`\n\nProcesses deployment notifications and triggers repository dispatch events.\n\n**Request:**\n```json\n{\n  \"application\": \"pr-1234\",\n  \"github_token\": \"ghp_xxxxxxxxxxxx\"\n}\n```\n\n**Request Fields:**\n\n| Field Name | Type | Required | Description |\n|------------|------|----------|-------------|\n| `application` | string | Yes | Application name. Must start with `pr-` to be processed. |\n| `github_token` | string | No | GitHub token for authentication. If not provided, the service will use the `GITHUB_TOKEN` environment variable. |\n\n#### Response Cases\n\n**Success - 200**\n```json\n{\n  \"status\": \"success\",\n  \"commitHash\": \"abc123def456\",\n  \"sourceName\": \"pr-example-app\"\n}\n```\n\n**Skipped (Invalid Application Name) - 200**\n```json\n{\n  \"status\": \"skipped\",\n  \"reason\": \"application name doesn't start with 'pr-'\"\n}\n```\n\n#### Error Responses\n- `400 Bad Request` - Invalid JSON payload or missing GitHub token\n- `404 Not Found` - Could not find `values.yaml` for the specified application\n- `405 Method Not Allowed` - Non-POST request\n- `500 Internal Server Error` - Error extracting deployment tag or sending dispatch\n\n#### Behavior\n1. Validates that the application name starts with `pr-`\n2. Searches for `values.yaml` in `deployment` repository paths:\n   - `configs/pr/light/{application}/values.yaml`\n   - `configs/pr/heavy/{application}/values.yaml`\n3. Extracts the `DEPLOYMENT_TAG` from the `values.yaml` file\n4. Sends a `repository_dispatch` event with type `environment_ready` to the target repository (`sematext-cloud`)\n\n\n### GET `/health`\n\nHealth check endpoint for monitoring service availability.\n\n#### Response Codes\n\n**Success - 200**\n```json\n{\n  \"status\": \"healthy\"\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsematext%2Fgh-runner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsematext%2Fgh-runner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsematext%2Fgh-runner/lists"}