Skip to content

Baseline lab automation for lab #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/build-lab-issue-basics-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Build Lab-Issue Basics template
about: 'This template was created to save typing in the '
title: Investigate Issue Basics
labels: ''

---

# Issue Basics

This task describes the lab steps required to complete the "Issue Basics" tasks. As a template item, this description was filled out for you in advance (to save typing). Generally, you will use templates to get started with a standard format and content but add additional information. In this case, the issue is complete as-is...

To complete this task you will:
- [x] Use an issue template (done)
- [x] Review markdown used to format content in GitHub. You're looking at it now, but if you aren't already familiar with markdown you can refer to [this link](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github). If you've already saved it and want to review the source markdown you can edit the description to see the unformatted text.
- [ ] Apply Labels
- [ ] Apply Milestones
- [ ] Query Issues
- [ ] Verify automation triggered by issues
23 changes: 23 additions & 0 deletions .github/scripts/issue-seeds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[
{ "id": 0, "title": "Learning GitHub Issues Batch" },
{ "id": 1, "title": "Exercise Project Fundamentals", "type": "Feature"},
{ "title": "Create a new project", "type": "Task", "parent": 1},
{ "title": "Add all of the remaining issues", "type": "Task", "parent": 1},
{ "id": 2, "title": "Customize Status and Fields", "type": "Feature", "labels": "enhancement" },
{ "title": "Add priority field", "type": "Task", "parent": 2},
{ "title": "Add start and end date fields", "type": "Task", "parent": 2},
{ "title": "Add 'Paused' status", "type": "Task", "parent": 2},
{ "id": 3, "title": "Filter Project Data", "type": "Feature", "labels": "enhancement" },
{ "title": "Rename view 'Feature Planning'", "type": "Task", "parent": 3},
{ "title": "Add Feature/Bug filter", "type": "Task", "parent": 3},
{ "id": 4, "title": "Add 'Release Planning' view", "type": "Feature" },
{ "title": "Populate date fields", "type": "Task", "parent": 4},
{ "title": "Duplicate 'Feature Planning'", "type": "Task", "parent": 4},
{ "title": "Rename to 'Release Roadmap' and set 'Roadmap' view", "type": "Task", "parent": 4},
{ "title": "Scale to quarter and sort by End date", "type": "Task", "parent": 4},
{ "title": "Refine release dates", "type": "Task", "parent": 4},
{ "id": 5, "title": "Add Board view for tasks", "type": "Feature" },
{ "title": "Add a view named 'Task Board' filtered on Tasks and untyped issues", "type": "Task", "parent": 5},
{ "title": "Add a Parent Issue slice, Group by Assignees, and add the Labels field", "type": "Task", "parent": 5},
{ "title": "Fix the typo in the README file", "type": "Bug", "body": "The 'Abstract' header on line 3 is misspelled." }
]
177 changes: 177 additions & 0 deletions .github/scripts/prepare-lab-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/bin/bash
# Bash script to set up GitHub lab environment dedicated to Issues and Projects.

# If "--delete" is passed as an argument, delete all issues in the repository
if [[ "$1" == "--delete" || "$1" == "--seed-all" ]]; then
echo "Deleting all issues..."
gh issue list --limit 1000 | awk '{print $1}' | xargs -I {} gh issue delete {} --yes
fi

# If "--seed" is passed as an argument, automatically create issues that are meant to be manually created
if [[ "$1" == "--seed-all" ]]; then
gh issue create \
--title "Investigate Issue Basics" \
--body "
# Issue Basics

This task describes the lab steps required to complete the Issue Basics tasks. As a template item, this description was filled out for you in advance (to save typing). Generally, you will use templates to get started with a standard format and content but add additional information. In this case, the issue is complete as-is...

To complete this task you will:
- [x] Use an issue template (done)
- [x] Review markdown used to format content in GitHub. You're looking at it now, but if you aren't already familiar with markdown you can refer to [this link](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github). If you've already saved it and want to review the source markdown you can edit the description to see the unformatted text.
- [ ] Apply Labels
- [ ] Apply Milestones
- [ ] Query Issues
- [ ] Verify automation triggered by issues" \
--assignee "@me"
fi

# Function to load issue seeds from a JSON file
load_issue_seeds() {
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo "Error: jq is not installed. Please install it with: sudo apt-get install jq" >&2
return 1
fi

# Check if file exists
local file_path="issue-seeds.json"
if [[ ! -f "$file_path" ]]; then
echo "Error: $file_path not found in current directory." >&2
return 1
fi

# Read the JSON file and return the content
local json_content
json_content=$(jq '.' "$file_path")

# Check if the JSON is valid
if [[ $? -ne 0 ]]; then
echo "Error: Failed to parse JSON file." >&2
return 1
fi

# Echo the JSON content
echo "$json_content"

}

# Function to create a GitHub issue from a JSON issue object
create_issue_from_json() {
local issue_json="$1"

# Extract issue properties with proper error handling
local id=$(echo "$issue_json" | jq -r '.id // empty')
local title=$(echo "$issue_json" | jq -r '.title // empty')
local body=$(echo "$issue_json" | jq -r '.body // empty')
# local labels=$(echo "$issue_json" | jq -r '.labels // [] | join(",")')
local labels=$(echo "$issue_json" | jq -r '.labels // empty')
local milestone=$(echo "$issue_json" | jq -r '.milestone // empty')
local parent=$(echo "$issue_json" | jq -r '.parent // empty')

# Validate required fields
if [[ -z "$title" ]]; then
echo "Error: Issue title is required." >&2
return 1
fi

echo "Creating issue: $title"

# Build the gh issue create command
local cmd="gh issue create --title \"$title\" --body \"$body\""

# Add labels if provided
if [[ -n "$labels" && "$labels" != "" ]]; then
cmd="$cmd --label \"$labels\""
fi

# Add milestone if provided
if [[ -n "$milestone" && "$milestone" != "null" ]]; then
cmd="$cmd --milestone \"$milestone\""
fi

# Execute the command to create the issue
issue_url=$(eval "$cmd")

# Check if issue was created successfully
if [[ $? -eq 0 ]]; then
echo "Successfully created issue: $issue_url"

# Parse the issue number from the URL
issue_number=$(echo "$issue_url" | grep -oE '[0-9]+$')

# Modify the URL to create the related API URL
api_url=$(echo "/repos/$issue_url" | sed 's/https:\/\/github.com\///')

# Set the issue Type based on the JSON "type" field
issue_type=$(echo "$issue_json" | jq -r '.type // empty')

# Use the GitHub CLI to call the api_url and apply the issue_type
echo "Setting issue type to: $issue_type"
gh api -X PATCH "$api_url" -f type="$issue_type"

# Capture the parent issue number if provided
if [[ -n "$id" && "$id" != "null" ]]; then
echo "Capturing issue ID[$id] = $issue_number"
parent_issue_numbers[$id]=$issue_number
fi

# If a parent issue is specified, create the relationship
if [[ -n "$parent" && "$parent" != "null" ]]; then
echo "Attempting to add relationship with parent issue: $parent"

# Look up this issue's node_id
child_id=$(gh api -X GET "$api_url" | jq -r '.id // empty')

# Check the parent issue number array
if [[ "${parent_issue_numbers[$parent]}" ]]; then

# create a version of the API URL for the parent issue
parent_id=${parent_issue_numbers[$parent]}
parent_api_url=$(echo "$api_url" | sed -E "s|/([0-9]+)$|/$parent_id/sub_issues|")

# Add the sub-issue relationship via the GitHub API
echo "Adding sub-issue relationship from $parent_id to $issue_number"
gh api $parent_api_url -X POST -F sub_issue_id=$child_id
fi
fi

return 0
else
echo "Failed to create issue: $title" >&2
return 1
fi
}

# ------------------------------------------------------------
# Seed automation issues required for the lab
# ------------------------------------------------------------
if [[ "$1" == "" || "$1" == "--seed-all" ]]; then

# Call the function and store the result in a variable
echo "Reading seed issues for the lab..."
issue_seeds_json=$(load_issue_seeds)

if [[ $? -eq 0 ]]; then
echo "Successfully loaded $(echo "$issue_seeds_json" | jq 'length') issue seeds."

# Initialize an array for parent issue numbers
declare -a parent_issue_numbers=()

# Loop through each issue in the JSON array
for i in $(seq 0 $(( $(echo "$issue_seeds_json" | jq 'length') - 1 ))); do
# Extract the issue object
issue=$(echo "$issue_seeds_json" | jq ".[$i]")

# Create issue from the JSON object
create_issue_from_json "$issue"

# Optional: Add a small delay between issue creation to avoid rate limits
# sleep 1
done
else
echo "Failed to load issue seeds JSON"
exit 1
fi
fi

1 change: 1 addition & 0 deletions .github/workflows/.run-once
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The purpose of this file is to cause a trigger of a workflow when this repo is first created from a template. If you modify this file later and commit the code, it will re-run that workflow, which may have unintended consequences.
27 changes: 27 additions & 0 deletions .github/workflows/issue-ping.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Issue automation lab sample

on:
issue_comment:
types: [created]

permissions:
issues: write
contents: read

jobs:
respond_to_ping:
runs-on: ubuntu-latest
if: contains(github.event.comment.body, 'ping')

steps:
- name: Respond with pong
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'pong'
});
32 changes: 32 additions & 0 deletions .github/workflows/lab-issue-automation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
on:
# Manual run with parameter for what to do
workflow_dispatch:
inputs:
command:
required: false
type: choice
options:
- --delete
- --seed-all
# Automatic run when this is first created from a template
push:
branches:
- main
paths:
- .github/workflows/.run-once

permissions:
issues: write
contents: read

jobs:
seed_issues:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- run: ./prepare-lab-env.sh $OPTION
shell: bash
working-directory: .github/scripts
env:
OPTION: ${{ inputs.command }}
GH_TOKEN: ${{ github.token }}
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Dave McKinstry

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.