diff --git a/README.md b/README.md index 37a2dc4..06bb021 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ GitHub Action for refreshing dummy self hosted runner. - -- Create or refresh dummy runner for target organization. +The action creates or refreshes dummy runner for target organization or target repository. # Background @@ -16,13 +15,13 @@ However, because dummy runner is always in offline status, GitHub sever will rem ## Inputs - Required - - `org-name`: Target organization name. (ex. cycloud-io) + - `org-name` or `repo-name`: Target organization or repository name. + - Either name must be specified. You can't set both. + - `org-name` example: cycloud-io + - `repo-name` example: cycloud-io/my-repo - `github-access-token`: GitHub access token to use. - You must prepare the GitHub access token. The GitHub Actions' **default token `secrets.GITHUB_TOKEN` won't work.** - - Following scope/permission is required depending on solutions you use: - - Personal Access Token: `admin:org` scope is required for the target organization. - - OAuth Apps: `admin:org` scope is required for the target organization. - - GitHub Apps: `organization_self_hosted_runners: write` permission for the target organization. ([REST API Link](https://docs.github.com/en/enterprise-server@3.0/rest/reference/apps#create-an-installation-access-token-for-an-app)) + - Check required scope/permission for the token [here](#required-scopepermission). - Always use secret environment (ex. `${{ secrets.SECRET_NAME }}`). **NEVER SET THIS VALUE AS PLAIN TEXT.** - Optional - `runner-version`: Dummy runner version to use. If not specified, it will copy and use the version of the running runner. @@ -35,10 +34,10 @@ For complete action definition, see [action.yaml](./action.yaml) Following GitHub Actions workflow example shows how to use `refresh-runner-action` in your repository's workflow. -- For the first wokrlfow run, you must prepare your own dummy runner. Without it you can't run the workflow that uses `refresh-runner-action`. -- You must set following field to appropriate values. - - org-name - - github-access-token +- For the first wokrlfow run, you must prepare your own dummy runner. Without it you can't run the workflow that uses `refresh-runner-action`. See [official document](https://docs.github.com/en/enterprise-server@3.0/actions/hosting-your-own-runners/adding-self-hosted-runners) for detail. +- You must set following fields to appropriate values. + - `org-name` or `repo-name` (Do not set both) + - `github-access-token` ```yaml name: refresh-dummy-runner @@ -59,15 +58,33 @@ jobs: - name: Refresh runner uses: cycloud-io/refresh-runner-action@v1 with: - # NOTE: Set to appropriate organization name. + # NOTE: Set either `org-name` or `repo-name`. org-name: cycloud-io + #repo-name: cycloud-io/my-repo + # NOTE: Add `RUNNER_API_ACCESS_TOKEN` secret to the repository. github-access-token: ${{ secrets.RUNNER_API_ACCESS_TOKEN }} ``` -# Future Plan +## Required scope/permission + +Following scope/permission is required for `github-access-token`. + +- Personal Access Token + - For `org-name` - `admin:org` scope is required for target organization. + - For `repo-name` - `repo` scope is required for target repository. + +- OAuth Apps + - Same as Personal Access Token. + +- GitHub Apps + - For `org-name` - `organization_self_hosted_runners: write` permission is required for target organization. + - For `repo-name` - `administration: write` permission is required for target repository. + + +Related Links: -Following features will be added **if there are certain demands.** +- [Self-hosted runner groups](https://docs.github.com/en/enterprise-server@3.0/rest/reference/actions#self-hosted-runner-groups) +- [Create an installation access token for an app](https://docs.github.com/en/enterprise-server@3.0/rest/reference/apps#create-an-installation-access-token-for-an-app) -- Support repository scope runner. diff --git a/action.yaml b/action.yaml index 8d3e1d5..de40cc2 100644 --- a/action.yaml +++ b/action.yaml @@ -4,8 +4,15 @@ description: Creates/Refreshes self hosted runner. inputs: ## Required Parameters org-name: - description: Target organization name. - required: true + description: Target organization name. Either org-name or repo-name must be specified. + default: "" + required: false + repo-name: + description: | + Target repository name. Repository name must include owner: `{owner}/{repo}`. + Either org-name or repo-name must be specified. + default: "" + required: false github-access-token: description: Github access token to use. Token should be personal access token or Github Apps generated token. required: true @@ -13,7 +20,8 @@ inputs: ## Optional Parameters runner-version: description: | - Version of Github Self Hosted Runner. If not specified, it will use the version of the running runner. (NOTE: Architecture is fixed to "linux-x64") + Version of Github Self Hosted Runner. + If not specified, it will use the version of the running runner. (NOTE: Architecture is fixed to "linux-x64") required: false default: '' runner-name: @@ -30,6 +38,15 @@ runs: # Exit on error set -eu + if [ "${{ inputs.org-name }}" != "" ] && [ "${{ inputs.repo-name }}" != "" ]; then + echo "Error: Can't specify both org-name and repo-name." + exit 1 + fi + if [ "${{ inputs.org-name }}" = "" ] && [ "${{ inputs.repo-name }}" = "" ]; then + echo "Error: Required to specify either org-name or repo-name." + exit 1 + fi + # Prepare dummy runner files mkdir actions-runner && cd actions-runner if [ "${{ inputs.runner-version }}" = "" ]; then @@ -48,10 +65,19 @@ runs: echo "Prepared dummy runner version: $(./config.sh --version)" echo "### Configure dummy runner" - RUNNER_TOKEN=$(bash ${{ github.action_path }}/script/get-runner-token.sh ${{ inputs.github-access-token }} ${GITHUB_API_URL} ${{ inputs.org-name }} ) + if [ "${{ inputs.org-name }}" != "" ]; then + echo "target org: ${{ inputs.org-name }}" + RUNNER_TOKEN=$(bash ${{ github.action_path }}/script/get-org-runner-token.sh ${{ inputs.github-access-token }} ${GITHUB_API_URL} ${{ inputs.org-name }} ) + TARGET_NAME=${{ inputs.org-name }} + else + echo "target repository: ${{ inputs.repo-name }}" + RUNNER_TOKEN=$(bash ${{ github.action_path }}/script/get-repo-runner-token.sh ${{ inputs.github-access-token }} ${GITHUB_API_URL} ${{ inputs.repo-name }} ) + TARGET_NAME=${{ inputs.repo-name }} + fi + ./config.sh \ --name ${{ inputs.runner-name }} \ - --url ${GITHUB_SERVER_URL}/${{ inputs.org-name }} \ + --url ${GITHUB_SERVER_URL}/${TARGET_NAME} \ --token ${RUNNER_TOKEN} \ --labels dummy-runner \ --replace \ diff --git a/script/get-runner-token.sh b/script/get-org-runner-token.sh similarity index 70% rename from script/get-runner-token.sh rename to script/get-org-runner-token.sh index 54c827d..90dfb2f 100644 --- a/script/get-runner-token.sh +++ b/script/get-org-runner-token.sh @@ -1,10 +1,11 @@ #!/bin/bash -set -e +set -eu RUNNER_API_ACCESS_TOKEN=$1 API_URL=$2 ORG_NAME=$3 +# API ref: https://docs.github.com/en/enterprise-server@3.0/rest/reference/actions#create-a-registration-token-for-an-organization RUNNER_TOKEN=$(curl -s \ -X POST \ -H "Accept: application/vnd.github.v3+json" \ diff --git a/script/get-repo-runner-token.sh b/script/get-repo-runner-token.sh new file mode 100644 index 0000000..b00fb29 --- /dev/null +++ b/script/get-repo-runner-token.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -eu + +RUNNER_API_ACCESS_TOKEN=$1 +API_URL=$2 +# Expects to be `{owner}/{repo}` +REPO_NAME=$3 + +# API ref: https://docs.github.com/en/enterprise-server@3.0/rest/reference/actions#create-a-registration-token-for-a-repository +RUNNER_TOKEN=$(curl -s \ + -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "authorization: Bearer ${RUNNER_API_ACCESS_TOKEN}" \ + ${API_URL}/repos/${REPO_NAME}/actions/runners/registration-token \ + | jq -r .token +) +echo -n $RUNNER_TOKEN \ No newline at end of file