From be2ef5b5672ee5d8b1c035feec4162888d4aa6e4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 6 Oct 2021 18:25:52 +0000 Subject: [PATCH] Implement the action (#1) --- LICENSE | 20 ++++++++++++++++ README.md | 58 +++++++++++++++++++++++++++++++++++++++++++++ action.yaml | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ find-ref.sh | 54 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 action.yaml create mode 100644 find-ref.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..36bdef3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2021, Google LLC + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6007ab3 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +This is a small utility action that clones a repository, using a ref linked from +a pull request if possible. + +For example: + +```yaml +jobs: + sass-spec: + name: Language Tests + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + dart_channel: [stable, dev] + async_label: [synchronous] + async_args: [''] + include: + - dart_channel: stable + async_label: asynchronous + async_args: '--cmd-args --async' + + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + with: {sdk: stable} + - uses: actions/setup-node@v2 + with: {node-version: 16} + - run: dart pub get + + - name: Check out sass-spec + uses: sass/clone-linked-repo@v1 + args: {repo: sass/sass-spec} + - run: npm install + working-directory: sass-spec + - name: Run specs + run: npm run sass-spec -- --dart .. $extra_args + working-directory: sass-spec + env: {extra_args: "${{ matrix.async_args }}"} +``` + +By default, this will clone `sass-spec`'s `main` branch into the `sass-spec` +path. But if a PR contains the text "sass/sass-spec#123" and there's a pull +request with ID 123, it will clone `pull/123/head` instead. + +This action is meant primarily for Sass repositories. Other repositories are +welcome to use it, but please be aware that support will be a very low +priority. + +## Details + +* This will recognize both short references (`sass/sass-spec#123`) and full URLs + (`https://github.com/sass/sass-spec/pulls/123`). + +* This will ignore issue references. + +* If the PR message contains multiple references to a PR from the same + repository, this will use the first one. diff --git a/action.yaml b/action.yaml new file mode 100644 index 0000000..d3142c8 --- /dev/null +++ b/action.yaml @@ -0,0 +1,68 @@ +name: Cloned Linked Repo +description: Clone a repo at a version linked from a PR description. + +inputs: + repo: + description: > + The slug (e.g. "sass/sass") of the repository whose PR links this action + should look for. + required: true + token: + description: > + The GitHub token used to access the pull request's message. + default: ${{ github.token }} + default-ref: + description: > + The default branch to check out when this isn't a PR or doesn't link to a + PR. Note that if the current branch or PR base is of the form "feature.*", + this will always use the same branch name as the default. + default: main + ssh-key: + description: Passed directly to actions/checkout. + ssh-known-hosts: + description: Passed directly to actions/checkout. + ssh-strict: + description: Passed directly to actions/checkout. + persist-credentials: + description: Passed directly to actions/checkout. + path: + description: Passed directly to actions/checkout. + clean: + description: Passed directly to actions/checkout. + fetch-depth: + description: Passed directly to actions/checkout. + lfs: + description: Passed directly to actions/checkout. + submodules: + description: Passed directly to actions/checkout. + +runs: + using: composite + steps: + + - run: "bash $GITHUB_ACTION_PATH/find-ref.sh" + id: find-ref + shell: bash + env: + PR_BRANCH: ${{ github.base_ref }} + CURRENT_REF: ${{ github.ref }} + PR_BODY: ${{ github.event.pull_request.body }} + # Inputs must be repeated due to actions/runner#665 + REPO: ${{ inputs.repo }} + TOKEN: ${{ inputs.token }} + DEFAULT_REF: ${{ inputs.default-ref }} + + - uses: actions/checkout@v2 + with: + repository: ${{ inputs.repo }} + ref: ${{ steps.find-ref.outputs.ref }} + token: ${{ inputs.token }} + ssh-key: ${{ inputs.ssh-key }} + ssh-known-hosts: ${{ inputs.ssh-known-hosts }} + ssh-strict: ${{ inputs.ssh-strict }} + persist-credentials: ${{ inputs.persist-credentials }} + path: ${{ inputs.path }} + clean: ${{ inputs.clean }} + fetch-depth: ${{ inputs.fetch-depth }} + lfs: ${{ inputs.lfs }} + submodules: ${{ inputs.submodules }} diff --git a/find-ref.sh b/find-ref.sh new file mode 100644 index 0000000..6572e79 --- /dev/null +++ b/find-ref.sh @@ -0,0 +1,54 @@ +#!/bin/bash -e +# Copyright 2021 Google Inc. Use of this source code is governed by an MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT. + +# Echoes the sass/sass Git ref that should be checked out for the current GitHub +# Actions run. If we're running specs for a pull request which refers to a +# sass/sass pull request, we'll run against the latter rather than sass/sass +# main. +if [ -z "$PR_BRANCH" ]; then + # Remove the "refs/heads/" prefix + current_branch="${CURRENT_REF/refs\/heads\//}" +else + current_branch="$PR_BRANCH" +fi + +if [[ "$current_branch" == feature.* ]]; then + default="$current_branch" +else + default="$DEFAULT_REF" +fi + +# We don't have a PR_BRANCH so we are not in a pull request, so there's no +# linked PR to find. +if [ -z "$PR_BRANCH" ]; then + echo "::set-output name=ref::$default" + exit 0 +fi + +echo "::group::Pull request body" +echo "$PR_BODY" +echo "::endgroup::" + +echo "::group::Finding pull request reference" +for link in "$(echo "$PR_BODY" | grep -Eo "${REPO}(#|/pull/)[0-9]+")"; do + if [[ "$link" = *#* ]]; then + number="${link#*#}" + else + number="${link#*/pull/}" + fi + + if curl --fail --silent --head --header "Authorization: token $TOKEN" \ + "https://api.github.com/repos/$REPO/pulls/${number}" > /dev/null; then + echo "Linked to pull request $number" + echo "::set-output name=ref::refs/pull/$number/head" + exit 0 + else + echo "$link isn't a pull request." + fi +done + +echo "No linked pull request, using default ref $default" +echo "::set-output name=ref::$default" +echo "::endgroup::"