Skip to content

Commit

Permalink
Create Project Automation Shared Workflows (#168)
Browse files Browse the repository at this point in the history
  • Loading branch information
jarmak-nv authored Jan 22, 2024
1 parent 8e2d7dd commit adaaacd
Show file tree
Hide file tree
Showing 5 changed files with 593 additions and 0 deletions.
79 changes: 79 additions & 0 deletions .github/workflows/project-get-item-id.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Project - Get Item ID Within the Project
# This workflow gets the project-specific ID for an item within a project
# All downstream queries and mutations of fields within the project require this ID

on:
workflow_call:
inputs:
PROJECT_ID:
description: "The Project's graphQL node ID"
type: string
required: true

ITEM_NODE_ID:
description: "The issue or PR's graphQL node ID"
type: string
required: true

secrets:
PROJECT_MANAGEMENT_SECRET:
description: "Project Access Token"
required: true

outputs:
ITEM_PROJECT_ID:
description: "The item's project-specific ID"
value: ${{ jobs.get_items_project_id.outputs.ITEM_PROJECT_ID }}

jobs:
get_items_project_id:
runs-on: ubuntu-latest
outputs:
ITEM_PROJECT_ID: ${{ steps.get_item_id.outputs.ITEM_PROJECT_ID }}

steps:
- name: Sleep 1s
id: sleep_1s
run: |
sleep 1 # Ensure the PR is added to the project before we query its ID
- name: Get Item Project ID
id: get_item_id
env:
GH_TOKEN: ${{ secrets.PROJECT_MANAGEMENT_SECRET }}
run: |
# Query up to 10 projects for the PR
# There's no graphQL filter configured to query by a specific project
# So we need to query all projects and filter the result ourselves
gh api graphql -f query='
query {
node(id: "${{ inputs.ITEM_NODE_ID }}") {
... on PullRequest {
projectItems(first: 10) {
nodes {
id
project {
id
}
}
}
}
... on Issue {
projectItems(first: 10) {
nodes {
id
project {
id
}
}
}
}
}
}' > project_data.json
# Use jq to do the actual filtering
item_project_id=$(jq -r '.data.node.projectItems.nodes[] |
select(.project.id == "${{ inputs.PROJECT_ID }}") |
.id' project_data.json)
echo "ITEM_PROJECT_ID=$item_project_id" >> $GITHUB_OUTPUT
continue-on-error: true
132 changes: 132 additions & 0 deletions .github/workflows/project-get-set-iteration-field.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: Project - Get Item ID Within the Project
# This workflow gets the project-specific ID for an item within a project
# All downstream queries and mutations of fields within the project require this ID

on:
workflow_call:
inputs:
PROJECT_ID:
description: "The Project's graphQL node ID"
type: string
required: true

ITERATION_FIELD_NAME:
description: "The name of the iteration field"
type: string
required: true

ITERATION_FIELD_ID:
description: "The graphQL node ID of the iteration field"
type: string
required: true

ITEM_PROJECT_ID:
description: "The issue or PR's graphQL project-specific ID"
type: string
required: true

UPDATE_ITEM:
description: "Whether to update the item's iteration field"
default: false
type: boolean

# Optional fields, used if UPDATE_ITEM is set to true
ITEM_NODE_ID:
description: "The issue or PR's graphQL node ID, only needed if updating linked issues"
default: null
type: string

UPDATE_LINKED_ISSUES:
description: "Whether to update the linked issues' iteration fields"
default: false
type: boolean

secrets:
PROJECT_MANAGEMENT_SECRET:
description: "Project Access Token"
required: true

outputs:
ITERATION_OPTION_ID:
value: ${{ jobs.get_set_iteration_option_id.outputs.ITERATION_OPTION_ID }}
description: "The iteration option ID"

jobs:
get_set_iteration_option_id:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
ITERATION_OPTION_ID: ${{ steps.get_iteration_option_id.outputs.ITERATION_OPTION_ID }}

steps:
- name: Get Iteration Option ID
id: get_iteration_option_id
env:
GH_TOKEN: ${{ secrets.PROJECT_MANAGEMENT_SECRET }}
run: |
# Get current iteration iteration id
# The current iteration is always the first element in the returned list
gh api graphql -f query='
query {
node(id: "${{ inputs.PROJECT_ID }}") {
... on ProjectV2 {
id
field(name: "${{ inputs.ITERATION_FIELD_NAME }}") {
... on ProjectV2IterationField {
id
name
configuration {
iterations {
id
}
}
}
}
}
}
}' > iteration_option_data.json
current_iteration_option_id=$(jq -r '.data.node.field.configuration.iterations[0].id' iteration_option_data.json)
echo "ITERATION_OPTION_ID=$current_iteration_option_id" >> "$GITHUB_OUTPUT"
- name: Update item iteration field
id: update_item_iteration_field
if: ${{ inputs.UPDATE_ITEM == true }}
env:
GH_TOKEN: ${{ secrets.PROJECT_MANAGEMENT_SECRET }}
run: |
# Set the iteration based on the query above
# This overwrites whatever was in it before, we may want to make an "OVERWRITE" option
gh api graphql -f query='
mutation {
updateProjectV2ItemFieldValue(
input: {
projectId: "${{ inputs.PROJECT_ID }}"
itemId: "${{ inputs.ITEM_PROJECT_ID }}"
fieldId: "${{ inputs.ITERATION_FIELD_ID }}"
value: {
iterationId: "${{ steps.get_iteration_option_id.outputs.ITERATION_OPTION_ID }}"
}
}
) {
projectV2Item {
id
}
}
}'
continue-on-error: true

update_linked_issues:
if: ${{ inputs.UPDATE_LINKED_ISSUES == true }}
permissions:
contents: read
uses: ./.github/workflows/project-update-linked-issues.yaml
needs: get_set_iteration_option_id
with:
PROJECT_ID: ${{ inputs.PROJECT_ID }}
PR_PROJECT_ID: ${{ inputs.ITEM_PROJECT_ID }}
PR_NODE_ID: ${{ inputs.ITEM_NODE_ID }}
UPDATE_FIELD_TYPE: "iteration"
UPDATE_FIELD_ID: ${{ inputs.ITERATION_FIELD_ID }}
UPDATE_FIELD_VALUE: ${{ needs.get_set_iteration_option_id.outputs.ITERATION_OPTION_ID }}
secrets: inherit
131 changes: 131 additions & 0 deletions .github/workflows/project-get-set-single-select-field.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Project - Get Item ID Within the Project
# This workflow gets the project-specific ID for an item within a project
# All downstream queries and mutations of fields within the project require this ID

on:
workflow_call:
inputs:
PROJECT_ID:
description: "The Project's graphQL node ID"
type: string
required: true

SINGLE_SELECT_FIELD_NAME:
description: "The name of the single-select field"
type: string
required: true

SINGLE_SELECT_OPTION_VALUE:
description: "The value of the option we'd like to get/set"
type: string
required: true

SINGLE_SELECT_FIELD_ID:
description: "The graphQL node ID of the single-select field"
type: string
required: true

ITEM_PROJECT_ID:
description: "The issue or PR's graphQL project-specific ID"
type: string
required: true

UPDATE_ITEM:
description: "Whether to update the item's single-select field"
default: false
type: boolean

# Optional fields, used if UPDATE_ITEM is set to true
ITEM_NODE_ID:
description: "The issue or PR's graphQL node ID, only needed if updating linked issues"
default: null
type: string

UPDATE_LINKED_ISSUES:
description: "Whether to update the linked issues' single_select fields"
default: false
type: boolean

secrets:
PROJECT_MANAGEMENT_SECRET:
description: "Project Access Token"
required: true

outputs:
SINGLE_SELECT_OPTION_ID:
value: ${{ jobs.get_set_single_select_option_id.outputs.SINGLE_SELECT_OPTION_ID }}
description: "The single_select option ID"

jobs:
get_set_single_select_option_id:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
SINGLE_SELECT_OPTION_ID: ${{ steps.get_single_select_option_id.outputs.SINGLE_SELECT_OPTION_ID }}

steps:
- name: Get single_select Option ID
id: get_single_select_option_id
env:
GH_TOKEN: ${{ secrets.PROJECT_MANAGEMENT_SECRET }}
run: |
# Get single_select option id
gh api graphql -f query='
query {
node(id: "${{ inputs.PROJECT_ID }}") {
... on ProjectV2 {
id
field(name: "${{ inputs.SINGLE_SELECT_FIELD_NAME }}") {
... on ProjectV2SingleSelectField {
id
options(names: "${{ inputs.SINGLE_SELECT_OPTION_VALUE }}") {id}
}
}
}
}
}' > single_select_option_data.json
current_single_select_option_id=$(jq -r '.data.node.field.options[0].id' single_select_option_data.json)
echo "SINGLE_SELECT_OPTION_ID=$current_single_select_option_id" >> "$GITHUB_OUTPUT"
- name: Update item single_select field
id: update_item_single_select_field
if: ${{ inputs.UPDATE_ITEM == true }}
env:
GH_TOKEN: ${{ secrets.PROJECT_MANAGEMENT_SECRET }}
run: |
# Set the single_select based on the query above
# This overwrites whatever was in it before, we may want to make an "OVERWRITE" option
gh api graphql -f query='
mutation {
updateProjectV2ItemFieldValue(
input: {
projectId: "${{ inputs.PROJECT_ID }}"
itemId: "${{ inputs.ITEM_PROJECT_ID }}"
fieldId: "${{ inputs.SINGLE_SELECT_FIELD_ID }}"
value: {
singleSelectOptionId: "${{ steps.get_single_select_option_id.outputs.SINGLE_SELECT_OPTION_ID }}"
}
}
) {
projectV2Item {
id
}
}
}'
continue-on-error: true

update_linked_issues:
if: ${{ inputs.UPDATE_LINKED_ISSUES == true }}
permissions:
contents: read
uses: ./.github/workflows/project-update-linked-issues.yaml
needs: get_set_single_select_option_id
with:
PROJECT_ID: ${{ inputs.PROJECT_ID }}
PR_PROJECT_ID: ${{ inputs.ITEM_PROJECT_ID }}
PR_NODE_ID: ${{ inputs.ITEM_NODE_ID }}
UPDATE_FIELD_TYPE: "single_select"
UPDATE_FIELD_ID: ${{ inputs.SINGLE_SELECT_FIELD_ID }}
UPDATE_FIELD_VALUE: ${{ needs.get_set_single_select_option_id.outputs.SINGLE_SELECT_OPTION_ID }}
secrets: inherit
Loading

0 comments on commit adaaacd

Please sign in to comment.