diff --git a/.github/actions/add-card-to-project/Dockerfile b/.github/actions/add-card-to-project/Dockerfile new file mode 100644 index 0000000000..95c2fe1628 --- /dev/null +++ b/.github/actions/add-card-to-project/Dockerfile @@ -0,0 +1,11 @@ +# Container image that runs your code +FROM alpine:3.10 + +RUN apk add --no-cache --no-progress curl jq + +# Copies your code file from your action repository to the filesystem path `/` of the container +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Code file to execute when the docker container starts up (`entrypoint.sh`) +ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/actions/add-card-to-project/action.yml b/.github/actions/add-card-to-project/action.yml new file mode 100644 index 0000000000..e7fcba44c6 --- /dev/null +++ b/.github/actions/add-card-to-project/action.yml @@ -0,0 +1,23 @@ +name: 'add_card_to_project' +description: 'A GitHub Action to add a card to a project and set the card position' +author: 'Steve Richards' +branding: + icon: 'command' + color: 'blue' +inputs: + project: + description: 'The url of the project to be assigned to.' + required: true + column_name: + description: 'The column name of the project, defaults to "To do" for issues and "In progress" for pull requests.' + required: false + card_position: + description: 'The card position of the card in the column, defaults to "bottom". Valid values are "top", "bottom" and "after:".' + required: false +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.project }} + - ${{ inputs.column_name }} + - ${{ inputs.card_position }} diff --git a/.github/actions/add-card-to-project/entrypoint.sh b/.github/actions/add-card-to-project/entrypoint.sh new file mode 100644 index 0000000000..a67bfb1d96 --- /dev/null +++ b/.github/actions/add-card-to-project/entrypoint.sh @@ -0,0 +1,157 @@ +#!/bin/sh -l + +PROJECT_URL="$INPUT_PROJECT" +if [ -z "$PROJECT_URL" ]; then + echo "PROJECT_URL is not defined." >&2 + exit 1 +fi + +get_project_type() { + _PROJECT_URL="$1" + + case "$_PROJECT_URL" in + https://github.com/orgs/*) + echo "org" + ;; + https://github.com/users/*) + echo "user" + ;; + https://github.com/*/projects/*) + echo "repo" + ;; + *) + echo "Invalid PROJECT_URL: $_PROJECT_URL" >&2 + exit 1 + ;; + esac + + unset _PROJECT_URL +} + +find_project_id() { + _PROJECT_TYPE="$1" + _PROJECT_URL="$2" + + case "$_PROJECT_TYPE" in + org) + _ORG_NAME=$(echo "$_PROJECT_URL" | sed -e 's@https://github.com/orgs/\([^/]\+\)/projects/[0-9]\+@\1@') + _ENDPOINT="https://api.github.com/orgs/$_ORG_NAME/projects" + ;; + user) + _USER_NAME=$(echo "$_PROJECT_URL" | sed -e 's@https://github.com/users/\([^/]\+\)/projects/[0-9]\+@\1@') + _ENDPOINT="https://api.github.com/users/$_USER_NAME/projects" + ;; + repo) + _ENDPOINT="https://api.github.com/repos/$GITHUB_REPOSITORY/projects" + ;; + esac + + _PROJECTS=$(curl -s -X GET -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ + -H 'Accept: application/vnd.github.inertia-preview+json' \ + "$_ENDPOINT") + + _PROJECTID=$(echo "$_PROJECTS" | jq -r ".[] | select(.html_url == \"$_PROJECT_URL\").id") + + if [ "$_PROJECTID" != "" ]; then + echo "$_PROJECTID" + else + echo "No project was found." >&2 + exit 1 + fi + + unset _PROJECT_TYPE _PROJECT_URL _ORG_NAME _USER_NAME _ENDPOINT _PROJECTS _PROJECTID +} + +find_column_id() { + _PROJECT_ID="$1" + _INITIAL_COLUMN_NAME="$2" + + _COLUMNS=$(curl -s -X GET -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ + -H 'Accept: application/vnd.github.inertia-preview+json' \ + "https://api.github.com/projects/$_PROJECT_ID/columns") + + + echo "$_COLUMNS" | jq -r ".[] | select(.name == \"$_INITIAL_COLUMN_NAME\").id" + unset _PROJECT_ID _INITIAL_COLUMN_NAME _COLUMNS +} + +PROJECT_TYPE=$(get_project_type "${PROJECT_URL:? required this environment variable}") + +if [ "$PROJECT_TYPE" = org ] || [ "$PROJECT_TYPE" = user ]; then + if [ -z "$MY_GITHUB_TOKEN" ]; then + echo "MY_GITHUB_TOKEN not defined" >&2 + exit 1 + fi + + TOKEN="$MY_GITHUB_TOKEN" # It's User's personal access token. It should be secret. +else + if [ -z "$GITHUB_TOKEN" ]; then + echo "GITHUB_TOKEN not defined" >&2 + exit 1 + fi + + TOKEN="$GITHUB_TOKEN" # GitHub sets. The scope in only the repository containing the workflow file. +fi + +INITIAL_COLUMN_NAME="$INPUT_COLUMN_NAME" +if [ -z "$INITIAL_COLUMN_NAME" ]; then + # assing the column name by default + INITIAL_COLUMN_NAME='To do' + if [ "$GITHUB_EVENT_NAME" == "pull_request" ] || [ "$GITHUB_EVENT_NAME" == "pull_request_target" ]; then + echo "changing col name for PR event" + INITIAL_COLUMN_NAME='In progress' + fi +fi + + +PROJECT_ID=$(find_project_id "$PROJECT_TYPE" "$PROJECT_URL") +INITIAL_COLUMN_ID=$(find_column_id "$PROJECT_ID" "${INITIAL_COLUMN_NAME:? required this environment variable}") + +if [ -z "$INITIAL_COLUMN_ID" ]; then + echo "INITIAL_COLUMN_ID is not found." >&2 + exit 1 +fi + +case "$GITHUB_EVENT_NAME" in + issues) + ISSUE_ID=$(jq -r '.issue.id' < "$GITHUB_EVENT_PATH") + + # Add this issue to the project column + _CARDS=$(curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ + -H 'Accept: application/vnd.github.inertia-preview+json' \ + -d "{\"content_type\": \"Issue\", \"content_id\": $ISSUE_ID}" \ + "https://api.github.com/projects/columns/$INITIAL_COLUMN_ID/cards") + ;; + pull_request|pull_request_target) + PULL_REQUEST_ID=$(jq -r '.pull_request.id' < "$GITHUB_EVENT_PATH") + + # Add this pull_request to the project column + _CARDS=$(curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ + -H 'Accept: application/vnd.github.inertia-preview+json' \ + -d "{\"content_type\": \"PullRequest\", \"content_id\": $PULL_REQUEST_ID}" \ + "https://api.github.com/projects/columns/$INITIAL_COLUMN_ID/cards") + ;; + *) + echo "Nothing to be done on this action: $GITHUB_EVENT_NAME" >&2 + exit 1 + ;; +esac + +CARDS_ID=$(echo "$_CARDS" | jq -r .id) +unset _CARDS + +if [ -z "$CARDS_ID" ]; then + echo "CARDS_ID is not found." >&2 + exit 1 +fi + +INITIAL_CARD_POSITION="$INPUT_CARD_POSITION" +if [ -z "$INITIAL_CARD_POSITION" ]; then + # assign the card position by default + INITIAL_CARD_POSITION='bottom' +fi + +_CARDS=$(curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ + -H 'Accept: application/vnd.github.inertia-preview+json' \ + -d "{\"position\": \"$INITIAL_CARD_POSITION\"}" \ + "https://api.github.com/projects/columns/cards/$CARDS_ID/moves") diff --git a/.github/workflows/add-to-project-board.yaml b/.github/workflows/add-to-project-board.yaml new file mode 100644 index 0000000000..8f23cd406c --- /dev/null +++ b/.github/workflows/add-to-project-board.yaml @@ -0,0 +1,33 @@ +name: Add Card to Project(s) +on: + issues: + types: [opened] + pull_request_target: + types: [opened] +env: + MY_GITHUB_TOKEN: ${{ secrets.PROJECT_GITHUB_TOKEN }} + EVENT_TYPE: $GITHUB_EVENT_NAME + +jobs: + add_card_to_project: + runs-on: ubuntu-latest + name: Add Card to Project(s) + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Get Event Type + run: echo $GITHUB_EVENT_NAME + - name: Assign NEW issues to project 1 + uses: ./.github/actions/add-card-to-project + if: github.event_name == 'issues' && github.event.action == 'opened' + with: + project: 'https://github.com/orgs/lensapp/projects/1' + column_name: 'Backlog' + card_position: 'bottom' + - name: Assign NEW pull requests to project 1 + uses: ./.github/actions/add-card-to-project + if: github.event_name == 'pull_request_target' && github.event.action == 'opened' + with: + project: 'https://github.com/orgs/lensapp/projects/1' + column_name: 'PRs' + card_position: 'bottom'