Skip to content

Commit

Permalink
Merge pull request #31 from dataquest-dev/devops/finish-actions
Browse files Browse the repository at this point in the history
finishing github actions
  • Loading branch information
MajoBerger authored Apr 7, 2022
2 parents 06f070a + 17e4663 commit cb3d0f6
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 60 deletions.
22 changes: 0 additions & 22 deletions .github/ISSUE_TEMPLATE/bug_report.md

This file was deleted.

20 changes: 0 additions & 20 deletions .github/ISSUE_TEMPLATE/feature_request.md

This file was deleted.

10 changes: 10 additions & 0 deletions .github/actions/project-management-action/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 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 777 /entrypoint.sh
# Code file to execute when the docker container starts up (`entrypoint.sh`)
ENTRYPOINT ["/entrypoint.sh"]
21 changes: 21 additions & 0 deletions .github/actions/project-management-action/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Sergio Pintaldi

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.
132 changes: 132 additions & 0 deletions .github/actions/project-management-action/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# GitHub Action for Assign to One Project

[![Docker Cloud Automated build](https://img.shields.io/docker/cloud/automated/srggrs/assign-one-project-github-action)][docker]
[![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/srggrs/assign-one-project-github-action)][docker]
[![Docker Pulls](https://img.shields.io/docker/pulls/srggrs/assign-one-project-github-action)][docker]
[![GitHub license](https://img.shields.io/github/license/srggrs/assign-one-project-github-action.svg)][license]
![Latest Version](https://img.shields.io/github/v/release/srggrs/assign-one-project-github-action?color=orange&label=latest%20release)

[docker]: https://hub.docker.com/r/srggrs/assign-one-project-github-action
[license]: https://github.com/srggrs/assign-one-project-github-action/blob/master/LICENSE

Automatically add an issue or pull request to specific [GitHub Project](https://help.github.com/articles/about-project-boards/) when you __create__ and/or __label__ them. By default, the issues are assigned to the __`To do`__ column and the pull requests to the __`In progress`__ one, so make sure you have those columns in your project dashboard. But the workflow __allowed you to specify the column name as input__, so you can assign the issues/PRs based on a set of conditions to a specific column of a specific project.

## Latest features:

* included `issue_comment` as trigger for this action.
* added project pagination for searching 100+ GitHub projects.

## Acknowledgment & Motivations

This action has been modified from the original action from [masutaka](https://github.com/masutaka/github-actions-all-in-one-project). I needed to fix it as the original docker container would not build. Also I think the GitHub Action syntax changed a bit.

I would like to thank @SunRunAway for adding the labelling functionality and custom column input.

## Inputs

### `project`

**Required** The url of the project to be assigned to.

### `column_name`

The column name of the project, defaults to `'To do'` for issues and `'In progress'` for pull requests.

## Example usage

Examples of action:

### Repository project

```yaml
name: Auto Assign to Project(s)

on:
issues:
types: [opened, labeled]
pull_request:
types: [opened, labeled]
issue_comment:
types: [created]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
assign_one_project:
runs-on: ubuntu-latest
name: Assign to One Project
steps:
- name: Assign NEW issues and NEW pull requests to project 2
uses: srggrs/[email protected]
if: github.event.action == 'opened'
with:
project: 'https://github.com/srggrs/assign-one-project-github-action/projects/2'

- name: Assign issues and pull requests with `bug` label to project 3
uses: srggrs/[email protected]
if: |
contains(github.event.issue.labels.*.name, 'bug') ||
contains(github.event.pull_request.labels.*.name, 'bug')
with:
project: 'https://github.com/srggrs/assign-one-project-github-action/projects/3'
column_name: 'Labeled'
```
#### __Notes__
Be careful of using the conditions above (opened and labeled issues/PRs) because in such workflow, if the issue/PR is opened and labeled at the same time, it will be assigned to __both__ projects!
You can use any combination of conditions. For example, to assign new issues or issues labeled with 'mylabel' to a project column, use:
```yaml
...

if: |
github.event_name == 'issues' &&
(
github.event.action == 'opened' ||
contains(github.event.issue.labels.*.name, 'mylabel')
)
...
```

### Organisation or User project

Generate a token from the Organisation settings or User Settings and add it as a secret in the repository secrets as `MY_GITHUB_TOKEN`

```yaml
name: Auto Assign to Project(s)

on:
issues:
types: [opened, labeled]
pull_request_target:
types: [opened, labeled]
issue_comment:
types: [created]
env:
MY_GITHUB_TOKEN: ${{ secrets.MY_GITHUB_TOKEN }}

jobs:
assign_one_project:
runs-on: ubuntu-latest
name: Assign to One Project
steps:
- name: Assign NEW issues and NEW pull requests to project 2
uses: srggrs/[email protected]
if: github.event.action == 'opened'
with:
project: 'https://github.com/srggrs/assign-one-project-github-action/projects/2'

- name: Assign issues and pull requests with `bug` label to project 3
uses: srggrs/[email protected]
if: |
contains(github.event.issue.labels.*.name, 'bug') ||
contains(github.event.pull_request.labels.*.name, 'bug')
with:
project: 'https://github.com/srggrs/assign-one-project-github-action/projects/3'
column_name: 'Labeled'
```
## [Change Log](./CHANGELOG.md)
Please refer to the list of changes [here](./CHANGELOG.md)
22 changes: 22 additions & 0 deletions .github/actions/project-management-action/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# action.yml
name: 'Assign to One Project'
description: 'Assign new/labeled Issue or Pull Request to a specific project dashboard column'
author: srggrs
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

runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.project }}
- ${{ inputs.column_name }}

branding:
icon: 'box'
color: 'red'
150 changes: 150 additions & 0 deletions .github/actions/project-management-action/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/bin/sh -l

PROJECT_URL="$INPUT_PROJECT"
if [ -z "$PROJECT_URL" ]; then
echo "Project input variable 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' . Please pass a valid Project URL in the project input variable" >&2
exit 1
;;
esac

unset _PROJECT_URL
}

get_next_url_from_headers() {
_HEADERS_FILE=$1
grep -i '^link' "$_HEADERS_FILE" | tr ',' '\n'| grep \"next\" | sed 's/.*<\(.*\)>.*/\1/'
}

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?per_page=100"
;;
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?per_page=100"
;;
repo)
_ENDPOINT="https://api.github.com/repos/$GITHUB_REPOSITORY/projects?per_page=100"
;;
esac

_NEXT_URL="$_ENDPOINT"

while : ; do

_PROJECTS=$(curl -s -X GET -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \
-H 'Accept: application/vnd.github.inertia-preview+json' \
-D /tmp/headers \
"$_NEXT_URL")

_PROJECTID=$(echo "$_PROJECTS" | jq -r ".[] | select(.html_url == \"$_PROJECT_URL\").id")
_NEXT_URL=$(get_next_url_from_headers '/tmp/headers')

if [ "$_PROJECTID" != "" ]; then
echo "$_PROJECTID"
elif [ "$_NEXT_URL" == "" ]; then
echo "No project was found." >&2
exit 1
fi
done

unset _PROJECT_TYPE _PROJECT_URL _ORG_NAME _USER_NAME _ENDPOINT _PROJECTS _PROJECTID _NEXT_URL
}

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:?<Error> 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 column 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:?<Error> required this environment variable}")

if [ -z "$INITIAL_COLUMN_ID" ]; then
echo "Column name '$INITIAL_COLUMN_ID' is not found." >&2
exit 1
fi

case "$GITHUB_EVENT_NAME" in
issues|issue_comment)
ISSUE_ID=$(jq -r '.issue.id' < "$GITHUB_EVENT_PATH")

# Add this issue to the project column
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
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
Loading

0 comments on commit cb3d0f6

Please sign in to comment.