diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml
index a0e0b046..ad97260b 100644
--- a/.github/workflows/continuous-delivery.yml
+++ b/.github/workflows/continuous-delivery.yml
@@ -19,7 +19,7 @@ permissions:
jobs:
build:
- name: Build Gatsby Site
+ name: Build Site
runs-on: ubuntu-latest
# Only run this job if it was done manually or the PR was merged
@@ -43,18 +43,20 @@ jobs:
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
+
+ # prettier-ignore
+ - name: Restore Cache
+ id: cache
+ uses: actions/cache@v4
with:
- static_site_generator: gatsby
- generator_config_file: docs/gatsby-config.ts
+ path: .next/cache
+ key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
+ restore-keys: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- name: Install Dependencies
id: install
run: npm ci
- - name: Install Playwright
- id: playwright
- run: npx playwright install
-
- name: Build
id: build
env:
@@ -65,7 +67,7 @@ jobs:
id: upload
uses: actions/upload-pages-artifact@v3
with:
- path: ./docs/public
+ path: ./out
deploy:
name: Deploy to GitHub Pages
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index a7a63c85..bbc3403d 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -33,10 +33,6 @@ jobs:
id: install
run: npm install
- - name: Install Playwright
- id: playwright
- run: npx playwright install
-
- name: Check Format
id: format-check
run: npm run format:check
diff --git a/.gitignore b/.gitignore
index 98b5d665..5ef6a520 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,96 +1,41 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
+# testing
+/coverage
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
+# next.js
+/.next/
+/out/
-# nyc test coverage
-.nyc_output
+# production
+/build
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
+# misc
+.DS_Store
+*.pem
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
-# Dependency directories
-node_modules/
-jspm_packages/
+# env files (can opt-in for committing if needed)
+.env*
-# TypeScript v1 declaration files
-typings/
+# vercel
+.vercel
-# TypeScript cache
+# typescript
*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variables file
-.env
-.env.test
-
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-
-# next.js build output
-.next
-
-# nuxt.js build output
-.nuxt
-
-# vuepress build output
-.vuepress/dist
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# Gatsby
-public/
-
-# macOS
-.DS_Store
-
-scripts/
+next-env.d.ts
diff --git a/.mega-linter.yml b/.mega-linter.yml
index 6ad93fba..47c62e9d 100644
--- a/.mega-linter.yml
+++ b/.mega-linter.yml
@@ -20,6 +20,7 @@ DISABLE:
# List of disabled linters keys
# https://megalinter.io/latest/config-activation/
DISABLE_LINTERS:
+ - CSS_STYLELINT
- JSON_NPM_PACKAGE_JSON_LINT
- MARKDOWN_MARKDOWN_TABLE_FORMATTER
- REPOSITORY_GRYPE
diff --git a/.prettierignore b/.prettierignore
index 680df18f..a5423a41 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -11,3 +11,12 @@ node_modules/
dist/
coverage/
fixtures/
+.gitattributes
+.gitignore
+.node-version
+.prettierignore
+CODEOWNERS
+LICENSE
+favicon.ico
+.nojekyll
+*.png
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fbfc23db..2a9cd377 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -23,16 +23,3 @@ The maintainers of this repository will review your changes and provide any
feedback. Once approved, they will be merged in and a new version of the site
will be deployed. You'll also be able to see your GitHub profile tagged in the
contributors list for any pages you contribute to!
-
-## Theme
-
-This repository uses [Gatsby](https://www.gatsbyjs.com/), along with the
-following themes and components:
-
-- [Primer Design System](https://primer.style/design/)
-- [Primer React](https://primer.style/react/)
-- [Doctocat](https://primer.style/doctocat/)
-
-A modified version of the Doctocat theme is used to build the documentation from
-`.mdx` files in the `docs` directory. Make sure to check out the above links to
-get familiarized with Gatsby, Primer, and React :smile:
diff --git a/components.json b/components.json
new file mode 100644
index 00000000..4e3cb470
--- /dev/null
+++ b/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "src/app/globals.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
diff --git a/docs/.eslintrc.yml b/docs/.eslintrc.yml
deleted file mode 100644
index 5b72e8b5..00000000
--- a/docs/.eslintrc.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-env:
- node: true
- es6: true
- jest: true
-
-globals:
- Atomics: readonly
- SharedArrayBuffer: readonly
-
-ignorePatterns:
- - .cache
- - node_modules
- - public
-
-parser: eslint-mdx
-
-extends:
- - plugin:mdx/recommended
- - plugin:prettier/recommended
- - plugin:react/recommended
-
-parserOptions:
- extensions:
- - mdx
- markdownExtensions:
- - md
- ignoreRemarkConfig: false
-
-settings:
- mdx/code-blocks: true
- mdx/remark: true
- react:
- version: detect
-
-rules:
- react/no-unescaped-entities: off
diff --git a/docs/.remarkrc.yml b/docs/.remarkrc.yml
deleted file mode 100644
index bca5b23c..00000000
--- a/docs/.remarkrc.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-settings:
- bullet: '-'
- closeAtx: false
- emphasis: '_'
- fences: true
- incrementListMarker: false
- strong: '*'
-plugins:
- - remark-preset-lint-consistent
- - remark-preset-lint-markdown-style-guide
- - remark-preset-prettier
- - - remark-lint-maximum-heading-length
- - false
diff --git a/docs/content/404.mdx b/docs/content/404.mdx
deleted file mode 100644
index 55956200..00000000
--- a/docs/content/404.mdx
+++ /dev/null
@@ -1,10 +0,0 @@
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import { Box } from '@primer/react'
-
-
-
-
-
-Uh oh...this page doesn't exist!
-
-
diff --git a/docs/content/index.mdx b/docs/content/index.mdx
deleted file mode 100644
index f1ea720f..00000000
--- a/docs/content/index.mdx
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: IssueOps Docs
-status: Alpha
----
-
-export { HeroLayout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import {
- LockIcon,
- PencilIcon,
- SearchIcon,
- ZapIcon
-} from '@primer/octicons-react'
-
-If you landed on this page, you're probably trying to find the answer to the
-question _"What is IssueOps?"_ If so, you came to the right place! The goal of
-this site is to provide education, best practices, examples, and resources for
-building IssueOps workflows on GitHub.
-
-
- This site is a work in progress. If you have any feedback, please [open an
- issue](https://github.com/issue-ops/docs/issues/new)! If you're interested in
- contributing, check out our [contribution
- guide](https://github.com/issue-ops/docs/blob/main/CONTRIBUTING.md).
-
-
-## What is IssueOps?
-
-IssueOps is a loose collection of tools, workflows, and concepts that can be
-applied to [GitHub Issues](https://github.com/features/issues) to drive a nearly
-limitless number of workflows. Like many of the other "Ops" tools, (ChatOps,
-GitOps, and so on), IssueOps leverages a friendly interface to drive
-behind-the-scenes automation. In this case, issues and pull requests (PRs) are
-the interface, and GitHub Actions is the automation engine.
-
-IssueOps isn't just a DevOps tool! You can run anything from complex CI/CD
-pipelines to a bed and breakfast reservation system. If you can interact with it
-via an API, there's a good chance you can build it with IssueOps :wink:
-
-{/* TODO: Animation of IssueOps example */}
-
-## Why should I use IssueOps?
-
-### Event-driven
-
-Any time a user interacts with an issue or PR, an event is triggered. These
-events can be used to trigger GitHub Actions workflows.
-
-### Customizable
-
-Based on the event type and data provided, you can implement custom logic to
-perform virtually any task. If you can interact with it via an API, command-line
-tool, or script, you can probably build it with IssueOps.
-
-### Transparent
-
-All actions taken on an issue are recorded in the issue timeline.
-
-### Immutable
-
-An issue or pull request creates an immutable record of the transaction,
-approvals, and actions that are taken. This follows GitHub's _"everything has a
-URL"_ philosophy.
-
-## How do I get started?
-
-Check out the resources on this site to learn more about IssueOps and how to
-build your own workflows.
-
-If you're looking for inspiration and a practical demonstration, check out
-[Bear Creek Honey Farm](https://issue-ops.github.io/bear-creek-honey-farm/)!
-This is a fictional bed and breakfast reservation system drive by IssueOps
-workflows. The source code for this example can be found in the
-[`issue-ops/bear-creek-honey-farm`](https://github.com/issue-ops/bear-creek-honey-farm)
-and
-[`issue-ops/demo-reservation-action`](https://github.com/issue-ops/demo-reservation-action)
-repositories.
-
-
- If you have an interesting IssueOps project you'd like featured, send us a PR!
-
diff --git a/docs/content/introduction/best-practices.mdx b/docs/content/introduction/best-practices.mdx
deleted file mode 100644
index 6ece3c9f..00000000
--- a/docs/content/introduction/best-practices.mdx
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Best practices
-description: The dos and dont's of IssueOps
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import {
- Do,
- DoDontContainer,
- Dont
-} from '@issue-ops/gatsby-theme-doctocat-typescript'
-import { PersonIcon } from '@primer/octicons-react'
-import { StateLabel, Timeline } from '@primer/react'
-
-## GitHub APIs
-
-
- Use GitHub Apps for accessing organization-level APIs
- Use personal access tokens
-
-
-## Sensitive information
-
-
-
- Use issue forms inputs that accept references to sensitive information in
- secure locations
-
- Accept sensitive information directly in issues
-
-
-## Validation
-
-
-
- Validate issue and comment text at every step in the IssueOps workflow
-
-
- Rely on labels to determine if an issue has been validated or approved
-
-
diff --git a/docs/content/introduction/index.mdx b/docs/content/introduction/index.mdx
deleted file mode 100644
index 11682145..00000000
--- a/docs/content/introduction/index.mdx
+++ /dev/null
@@ -1,413 +0,0 @@
----
-title: About
-description:
- IssueOps is a framework for using GitHub issues and pull requests as part of
- workflows
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-import { BookIcon, PersonIcon } from '@primer/octicons-react'
-import { Avatar, Box, StateLabel, Timeline } from '@primer/react'
-import { Blankslate } from '@primer/react/drafts'
-
-## Issues and pull requests
-
-In GitHub, a pull request (PR) can be interacted with in a lot of the same ways
-as an issue. For example, the
-[List repository issues](https://docs.github.com/en/free-pro-team@latest/rest/issues/issues?apiVersion=2022-11-28#list-repository-issues)
-REST API will return both issues and PRs for a repository.
-
-This means that many of the features of an issue are applicable to a PR.
-However, PRs have some extra functionality that can also be used in an IssueOps
-workflow. Depending on the use-case, you might want to select one over the
-other. For example, if you want to use the review and approval functionality for
-changes to repository contents, you'll need to use a PR. If you want to use the
-[issue forms](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms)
-feature, you'll need to use an issue.
-
-For more information on their structure and usage in IssueOps, see
-[Issues and PRs](/introduction/issues-and-prs).
-
-## IssueOps concept
-
-Think of IssueOps as a
-[state diagram](https://en.wikipedia.org/wiki/State_diagram). An issue is the
-_object_ that changes state in response to specific _events_. As the object
-changes state, certain _actions_ may be performed as part of the _transition_
-(provided any _guard_ conditions are met). Once an _end state_ is reached, the
-issue is considered complete and can be closed.
-
-### State Diagrams
-
-The following sections contain definitions and examples of common terms used in
-state diagrams. These terms are used throughout this documentation.
-
-#### Action
-
-An atomic task that is performed when a transition is taken.
-
-
-
-
-
- @mona has invited you to collaborate
-
-
-#### Event
-
-An external occurrence that triggers a state change.
-
-
-
-
-
-
- @octocat self-assigned this
-
-
-
-#### Guard
-
-A condition that is evaluated when a trigger event occurs. A transition is taken
-only if all associated guard conditions are met.
-
-#### State
-
-A point in an object's lifecycle that satisfies certain condition(s).
-
-
- Open
-
-
-#### Transition
-
-A link between two states that, when traversed by an object, will cause certain
-action(s) to be performed.
-
-## IssueOps workflow
-
-In general, an IssueOps workflow will follow the same basic pattern:
-
-1. A user opens an issue and provides information about a request
-1. The issue is validated to ensure it contains the required information
-1. (Optional) Approval is requested from an authorized user or team
-1. The request is processed and the issue is closed
-
-Let's use a more practical example...
-
-### Example: GitHub team membership
-
-_**User Story:**_ As a developer, I should be able to request membership to
-various teams and, if approved by administrators, be granted membership.
-
-Suppose you are an admin of an organization and would like to reduce the
-overhead of managing team membership. You can use IssueOps to build an automated
-membership request and approval process.
-
-We can assume the current, manual workflow looks something like this when
-rendered as a state diagram.
-
-
- In state diagram format, nodes represent the state of an object (the
- membership request), while transitions represent actions that are taken as the
- object changes state.
-
-
-
-
-```mermaid
-stateDiagram-v2
- 1 : Opened
- 2 : Submitted
- 3 : Approved
- 4 : Denied
- 5 : Closed
- [*] --> 1
- 1 --> 2 : Submit request
- 2 --> 3 : Approve request
- 2 --> 4 : Deny request
- 3 --> 5 : Add to team
- 4 --> 5 : Notify user
- 5 --> [*]
-```
-
-
-
-When creating an IssueOps workflow, you can use this diagram as a starting point
-to determine what events should trigger state changes, how to represent those
-events in issues, and what actions to take in response to state changes.
-
-## Event triggers
-
-In the membership request workflow, there are several events that trigger a
-change in the request state:
-
-- A user submits a request
-- An admin approves a request
-- An admin denies a request
-- A user is added to a team
-- A user is notified
-
-In GitHub, there are many ways to trigger events. For a full list, see
-[Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows).
-Here, we will focus on the events that are most relevant to IssueOps.
-
-### Issues
-
-Events related to issues seem like a good fit for IssueOps :wink: Issues
-are the entrypoint to the worflow. In particular, the issue being _opened_. You
-can think of this as someone coming to you and saying "Can you add me to this
-team?" Until this event occurs, there's nothing to do!
-
-However, this is not the only issue event that can be used in a workflow. The
-following table lists other
-[issue events](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issues)
-and example use-cases.
-
-
-
-
-
- Event
- Example
-
-
-
-
- `opened`
- Start a request workflow
-
-
- `edited`
- Re-validate a modified request
-
-
- `deleted`
- Cancel in-flight tasks for a request
-
-
- `transferred`
- Assign ownership of a request to a different team
-
-
- `pinned`
- Upgrade the severity/urgency of a request
-
-
- `unpinned`
- Downgrade the severity/urgency of a request
-
-
- `closed`
- End a request workflow
-
-
- `reopened`
- Restart a request workflow
-
-
- `assigned`
- Ping the assignee in Slack
-
-
- `unassigned`
- Ping the previous assignee in Slack
-
-
- `labeled`
- Track the current state of a request
-
-
- `unlabeled`
- Track the current state of a request
-
-
- `locked`
-
- See [locking
- conversations](https://docs.github.com/en/communities/moderating-comments-and-conversations/locking-conversations)
-
-
-
- `unlocked`
-
- See [locking
- conversations](https://docs.github.com/en/communities/moderating-comments-and-conversations/locking-conversations)
-
-
-
- `milestoned`
- Track requests by type to compare to team goals
-
-
- `demilestoned`
- Track requests by type to compare to team goals
-
-
-
-
-
-
-
-
- Access to [delete
- issues](https://docs.github.com/en/organizations/managing-organization-settings/allowing-people-to-delete-issues-in-your-organization)
- should be carefully controlled. If you delete an issue, you will lose all of
- the information associated with it, including comments and attachments. You
- will also lose this request in the history of the repository.
-
-
-### Issue comments
-
-After an issue is opened, other events must take place that change the state and
-drive it through the workflow. In the membership request workflow, for example,
-commenting on an issue is a great way to handle state changes such as an
-administrator approving or denying the request.
-
-
- A core difference between issues and PRs is that issues do not have a built-in
- approval process. However, this can be implemented using issue comments. For
- more information, see [Approvals](/workflow/approvals).
-
-
-Currently there are only three
-[`issue_comment` events](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment)
-that can trigger workflows:
-
-- `created`
-- `edited`
-- `deleted`
-
-In all three cases, the _context_ of the comment should be taken into account to
-determine how to transition the request state. For example, if only authorized
-administrators are allowed to approve team membership requests, how should an
-IssueOps workflow react if someone else comments with approval?
-
-All GitHub Actions workflow runs include important
-[context information](https://docs.github.com/en/actions/learn-github-actions/contexts)
-that can be accessed by your workflow. The
-[`issue_comment` context](https://docs.github.com/en/webhooks/webhook-events-and-payloads#issue_comment)
-can provide us with information to decide what actions to take, if any. In our
-team membership workflow, we can get the user that created the comment using the
-`github.event.comment.user.login` property. We can then use this to determine if
-the user is authorized to approve the request.
-
-### Labels
-
-Labels are a great way to track the state of a request. You can think of these
-as the nodes in a state diagram, while the transitions are the actions that are
-taken as the request changes state. You can also use labels to classify the
-types of requests when your repository supports more than one IssueOps workflow.
-For example, in the membership request workflow, you might have the following
-labels:
-
-
-
-
-
- Label
- Description
-
-
-
-
- `team-membership-request`
- The type of request
-
-
- `submitted`
-
- Requests that have been submitted and are pending review
-
-
-
-
-
-
-Looking at this list, you may ask "why there aren't labels for `approved`,
-`denied`, or `closed` states?" These states don't have any transitions that do
-not lead to the issue being closed. In other words, once a request is approved
-or denied, the issue will **always** reach the `closed` state, regardless of
-whether it was approved or denied. If this workflow had more steps, such as
-requiring multiple approvals, additional states would need to be tracked.
-
-As with `issue_comment` events, there are only three
-[`label` events](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#label)
-available:
-
-- `created`
-- `edited`
-- `deleted`
-
-These, however, refer to the actual creation and modification of the label
-itself, so they may not apply to your workflow. You will generally use the
-`issue => labeled` event instead.
-
-
- Anyone with access to open issues can also change labels! Labels are good for
- state tracking, but should not be used to determine if a request is valid! For
- more information, see the [Validate](/workflow/validate) step.
-
-
-## GitHub features
-
-You can leverage other GitHub features to dramatically increase the value of
-IssueOps.
-
-### Secrets
-
-[Secrets](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions)
-let you store sensitive information at the organization, repository, or
-environment level to share with GitHub Actions workflows. You can use secrets to
-store information such as API keys, passwords, or tokens. Secrets are encrypted
-and only exposed to runners at runtime. You can use secrets to store information
-such as API keys, passwords, or tokens that can be used to access external
-resources from your workflows.
-
-### Projects and milestones
-
-Keeping track of requests, especially when you have an approval process in
-place, is important.
-[Projects](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects)
-make it easy to track requests throughout their lifecycle. You can automatically
-add issues as they are opened, and use lifecycle rules to keep track of the
-state of requests without having to manually move them around your project
-board.
-
-You can also combine this with
-[Milestones](https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/about-milestones)
-to better organize issues and PRs. For example, if your IssueOps repository
-includes workflows for multiple types of requests, you can add issues for each
-request type to a corresponding milestone. That way they are automatically
-categorized in your project.
-
-[Project insights](https://docs.github.com/en/issues/planning-and-tracking-with-projects/viewing-insights-from-your-project)
-give you a visual snapshot of how requests are being processed. You can create
-custom graphs of to see when and how teams are using your workflows.
-
-### GitHub Apps
-
-One of the most important things to consider when creating workflows that
-interact with the GitHub APIs is permissions. GitHub Actions workflows can only
-interact with the repository in which they run. For example, the default
-permissions do not allow GitHub Actions to manage team membership. If you are
-building a workflow that interacts with resources outside of the repository it
-is running in, you should consider creating an organization-level
-[GitHub App](https://docs.github.com/en/apps/overview) and installing it in your
-IssueOps repository. That way, you can use the permissions of the app to
-interact with other resources in your organization.
-
-For more information, see [GitHub App](/setup/github-app) in the setup
-documentation.
diff --git a/docs/content/introduction/issues-and-prs.mdx b/docs/content/introduction/issues-and-prs.mdx
deleted file mode 100644
index 2ae02f69..00000000
--- a/docs/content/introduction/issues-and-prs.mdx
+++ /dev/null
@@ -1,424 +0,0 @@
----
-title: Issues and PRs
-description: The structure of issues and pull requests
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import { ImageContainer } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-import { MarkGithubIcon, TagIcon } from '@primer/octicons-react'
-import { Avatar, Box, FormControl, TextInput, Timeline } from '@primer/react'
-
-This page provides an overview of the different components that make up issues
-and PRs, and includes information about how each component can be used
-throughout an IssueOps workflow.
-
-## Issues
-
-### Issue permissions
-
-Any user with read access to a repository can open an issue.
-
-### Issue structure
-
-
-
-
-
- Component
- Description
-
-
-
-
- Title
- Title of an issue
-
-
- Body
- Main content of an issue entered by a user
-
-
- Assignees
- User(s) responsible for resolving an issue
-
-
- Labels
- Short tags that can be applied to issues
-
-
- Milestones
- Groups for issues and PRs
-
-
- Relations
-
- Other issues and PRs that are related to this issue
-
-
-
- Development
- Branches or PRs linked to the issue
-
-
- Projects
- Projects that are tracking the issue
-
-
- Participants
- Users who have interacted with the issue
-
-
- Timeline
- Events that have occurred on the issue
-
-
- Comments
-
- Comments and replies that have been added to the issue
-
-
-
- Reactions
-
- Emoji reactions added to the issue and its comments
-
-
-
-
-
-
-### Issue templates vs. issue forms
-
-Currently, GitHub supports both
-[issue templates](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository)
-and
-[issue forms](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms).
-When creating IssueOps workflows, the initial issue body is where you will get a
-lot of the information you need to process the issue. Depending on your
-use-case, issue _templates_ may not result in the desired format, since they
-allow users to overwrite or replace the entire contents of the issue body during
-creation. Issue _forms_ require specific input formats and result in a more
-consistent output.
-
-### Title
-
-The title of an issue is a short, concise description of the reason the issue
-has been opened, such as a particular bug or piece of feedback. Typically, the
-title is the first thing a user will enter when they open an issue (or they may
-update it based on the initial title provided by the issue form).
-
-When creating an issue forms, the title can be used as a way to identify the
-type of issue. For example, you can use a title like
-`[Request] Team Membership: TEAM_NAME` to indicate that the issue is a request
-to be added to a team. However, since this field can be modified by users, it
-should not be used as a way to validate the issue.
-
-```yaml
-title: '[Request] Team Membership: TEAM_NAME'
-```
-
-### Body
-
-The body of an issue is where your workflow will get most of the information it
-needs to process the issue. When creating an issue form, you can use the body to
-provide instructions to the user, and to collect information from them. For
-example, you can use a markdown field to provide instructions, and then use an
-input field to collect the name of the team they would like to join.
-
-
- Any `markdown`-type fields in an issue form will not be included in the issue
- body after it has been submitted by the user.
-
-
-For information about the different types of fields that can be used, see
-[Syntax for issue forms](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms).
-
-### Assignees
-
-Assignees are users who are responsible for resolving an issue. If your workflow
-involves a review process, you can use assignees to indicate who is responsible
-for reviewing the issue. You can also use assignees to indicate who is
-responsible for processing the issue when manual tasks are involved.
-
-```yaml
-assignees:
- - octocat
- - mona
-```
-
-
- Issues do not support team assignees, but PRs do!
-
-
-### Labels
-
-Labels are a great way to control the flow of an issue through the state(s)
-you've defined. Any time a issue is commented on or updated, you can use labels
-to tell where in the flow it is currently, and where it needs to go next.
-
-```yaml
-labels:
- - issueops:team-membership-request
-```
-
-### Milestones
-
-If you have certain timelines or deadlines associated with your workflow, you
-can use milestones to track them. Milestones are groups of issues and pull
-requests that are tracked together. They can be used to track:
-
-- Due date
-- Completion percentage
-- Open and closed issues and pull requests
-
-An issue cannot be added automatically to a milestone using issue forms, but you
-can use GitHub Actions to add it to a milestone after it has been created. See
-[IssueOps Actions](/reference/actions) in the reference for more information.
-
-### Relations
-
-When creating or commenting on issues, you can reference related issues by using
-the `#` symbol followed by the issue number. For example, if you want to
-reference issue 1 in another issue in the same repository, you would type `#1`.
-
-Relations may be useful when your workflow involves multiple issues. For
-example, if you have a workflow that involves interaction with another team, you
-can use relations to track the status of the other team's issue.
-
-### Development
-
-The development section of an issue is where you can track the branches and pull
-requests that are associated with the issue. This can be useful if your workflow
-involves creating branches or pull requests for the user. For example, if you
-would like to create an IssueOps workflow for users to create new repositories
-and you use an infrastructure as code service such as Terraform, you may want to
-create a PR on the user's behalf that includes the new repository definition.
-That way, developers don't have to learn Terraform to get new infrastructure,
-and operations teams can ensure all infrastructure is created following their
-requirements.
-
-### Projects
-
-GitHub Projects are dual-purpose when it comes to IssueOps. They can be used to
-both track and change the state of an issue. This is especially the case when
-your workflow involves manual steps that must be performed by a human.
-
-As a non-technical example, suppose you're planning Thanksgiving dinner with
-your extended family. Everyone in the family is supposed to suggest three
-dishes, prepare them, and bring them on Thanksgiving day.
-
-You can open issues for each dish that needs to be prepared using an issue form,
-and automatically assign them to your meal project.
-
-```yaml
-projects:
- - octo-repo/1
-```
-
-Within your project, you can specify columns for the state of each dish (e.g.
-`New`, `Ingredients purchased`, `Ready to cook`, and `Cooked`).
-
-
- Unfortunately, @mona can't cook (maybe one day!), so you'll need to manually
- move the issues through the columns as they are assigned and prepared.
- However, you can use the project to track the state of each dish, and to
- communicate that state to the rest of the family!
-
-
-### Participants
-
-Participants are users who have interacted with an issue. This includes the user
-who opened the issue as well as users who have commented on or been assigned to
-the issue. You can use participants to track who has interacted with an issue,
-and to communicate with them if needed.
-
-### Timeline
-
-The timeline is a list of all of the events that have occurred on an issue,
-starting from when it was first opened. Each timeline event includes a
-timestamp, the origin of the event, and other useful information.
-
-The timeline is especially useful to verify information about an issue. For
-example, if you have a workflow that requires validation of the issue body, you
-can (and should!) use labels to mark the issue as validated. However, what
-happens if a malicious user adds the label manually? You can use the timeline to
-compare when the issue body was last updated to when the validated label was
-added. If the label was added before the issue body was updated, you can
-determine that the label was added manually and re-run your validation logic.
-
-{/* prettier-ignore */}
-
-
-
-
-
- ncalteen added `issueops:team-request` 1 hour ago
-
-
-
-
-
- github-actions added `issueops:validated` 1 hour ago
-
-
-
-### Comments
-
-Other than the issue body, comments are how a user will drive your IssueOps
-flow. You should define keywords that your workflow looks for to trigger certain
-actions. Suppose you have a workflow where a user can create a new repository.
-After the issue has been validated, the user can comment on the issue with a
-keyword such as “.submit” to trigger the creation of their repo.
-
-You can also use them to communicate information back to the user. For example,
-if the issue body contains invalid or incorrect information, you can reply to
-the issue stating what needs to be corrected. For example, in the screenshot,
-you can see that a comment was added to the issue because the request was
-missing information.
-
-### Reactions
-
-Though they don't convey as much information as a comment, adding reactions to
-issues and comments are a nice way to let the user know that their input has
-been received and is being processed. If needed, you can follow up with a
-comment when processing is complete.
-
-### Example issue form
-
-#### Issue form template
-
-```yaml
-name: Team Membership Request
-description: Submit a request to be added to a GitHub Team
-title: '[Request] Team Membership: TEAM_NAME'
-labels:
- - issueops:team-membership-request
-assignees:
- - octocat
- - mona
-projects:
- - octo-repo/1
-
-body:
- - type: markdown
- attributes:
- value:
- Welcome to GitHub! Please fill out the information below to request to
- be added to a GitHub Team. Once submitted, your request will be reviewed
- by the admin team. Once approved, you will be added automatically!
- - type: input
- id: name
- attributes:
- label: Team name
- description: The name of the team you would like to join.
- placeholder: octoteam
- validations:
- required: true
-```
-
-#### Rendered output
-
-
-
-
- Add a title
-
-
- Welcome to GitHub! Please fill out the information below to request to be
- added to a GitHub Team. Once submitted, your request will be reviewed by the
- admin team. Once approved, you will be added automatically!
-
- Team name
-
- The name of the team you would like to join.
-
-
-
-
-
-
-## Pull requests
-
-Pull requests add extra features and metadata on top of issues. Many GitHub APIs
-support interacting with both at the same time! These additional features, along
-with examples of how to use them in IssueOps workflows, are listed in the
-following sections.
-
-### PR permissions
-
-In order to create a pull request, the required permissions will differ based on
-the location of the branch you wish to merge.
-
-
-
-
-
-### Reviews and approvals
-
-Unlike issues, PRs support reviews and approvals out of the box. When changes
-are ready to be merged, you can assign individuals or teams as reviewers.
-[Branch protection](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches)
-can also be used to enforce required reviewers and other checks before a PR can
-be merged.
-
-When your IssueOps workflow includes changes to the contents of a repository,
-using PRs instead of issues is a great option to enforce specific approval
-settings without having to include additional workflows for tracking approvals
-as comments.
-
-### Status checks
-
-Status checks run any time a PR is created or updated. These can range from code
-quality checks to security scans and more. You can use status checks to ensure
-that the changes in a PR meet your organization's standards before they are
-merged.
-
-In an IssueOps workflow, there are two ways you can use status checks: to
-validate the contents of the PR, and to validate the contents of the issue.
-
-Validation is a **critical** aspect to consider when designing your workflow. If
-your workflow is best suited for PRs, status checks can be used to run your
-validation workflow any time the PR is updated. Combined with branch protection
-rules specifying required status checks, you can ensure that validation rules
-pass before a PR can change states.
-
-### Deployments and Environments
-
-When a GitHub Actions workflow runs that specifies an environment, a deployment
-is created. Deployments track the successful/failed status of a workflow run,
-and link it to the targeted environment.
-
-A great example of an IssueOps workflow that uses PRs, deployments, and
-environments is the branch deploy model. A detailed explanation can be found in
-the [reference](/reference/branch-deployments).
diff --git a/docs/content/introduction/workflow-security.mdx b/docs/content/introduction/workflow-security.mdx
deleted file mode 100644
index 9fe234bd..00000000
--- a/docs/content/introduction/workflow-security.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Workflow security
-description: Important details about the security of IssueOps workflows
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-
-## GitHub Actions workflows
-
-The IssueOps model makes heavy use of the `issue` and `issue_comment` triggers
-in GitHub Actions workflows.
-
-```yaml
-on:
- issue_comment:
- types:
- - created
-```
-
-These triggers will only act on workflow files in the _default_ branch of your
-repository. This means that pull requests cannot introduce changes to your
-IssueOps workflows that would be run as part of that PR (e.g. creating a
-workflow that dumps secrets to the logs). Any changes to the workflow files can
-be protected with branch protection rules to ensure only verified changes make
-it into your default branch.
-
-## Workflow permissions
-
-To further harden your workflow files, you should always restrict them to the
-base permissions needed to run. For information about the available permissions,
-see
-[Assigning permissions to jobs](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs).
-
-
- Permissions can be assigned for the entire workflow, as well as for individual
- jobs. If one job needs additional permissions, make sure to scope them to that
- job only.
-
diff --git a/docs/content/reference/branch-deployments.mdx b/docs/content/reference/branch-deployments.mdx
deleted file mode 100644
index 1d3d27bd..00000000
--- a/docs/content/reference/branch-deployments.mdx
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Branch deployments
-description: Reliably ship code using IssueOps in PRs
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-
-One interesting topic to include when talking about IssueOps is branch
-deployments. At a high-level, branch deployments let you run and control
-deployments from your PRs.
-
-If you don't already know what they are, the easiest way to explain them is to
-compare them to the traditional merge deploy model. In the merge deploy model:
-
-1. A developer creates a feature branch and commits changes.
-1. The developer opens a PR to get feedback from others.
-1. Once approved, the PR is merged and a deployment starts from the `main`
- branch.
-
-This works fine, but if there are bugs in the PR, you have to either merge in
-fixes or revert the commits and redeploy. In the branch deploy model, changes
-are deployed from the feature branch and validated before being merged into the
-`main` branch. This ensures that whatever is in `main` can be deployed at any
-time. If there is a problem with the deployment from the feature branch, you can
-simply redeploy `main` as-is.
-
-For a detailed description of the branch-deploy model, see
-[`github/branch-deploy`](https://github.com/github/branch-deploy).
diff --git a/docs/content/reference/examples.mdx b/docs/content/reference/examples.mdx
deleted file mode 100644
index 6a86e648..00000000
--- a/docs/content/reference/examples.mdx
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: Examples
-description: Example IssueOps workflows and repos from the community
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-
-Here you can find examples of IssueOps workflows and repos from the developer
-community. If you have an example you'd like to share, please open a PR to add
-it to this page!
-
-- [Create Blog Posts from Issues](https://github.com/stochastical/abstractnonsense)
diff --git a/docs/content/reference/issueops-actions.mdx b/docs/content/reference/issueops-actions.mdx
deleted file mode 100644
index 86361a4d..00000000
--- a/docs/content/reference/issueops-actions.mdx
+++ /dev/null
@@ -1,78 +0,0 @@
----
-title: IssueOps Actions
-description: Custom GitHub Actions for IssueOps workflows
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-
-This page contains a list of useful actions for IssueOps workflows. If you know
-of any, feel free to submit a PR to add it to the list!
-
-
-
-
diff --git a/docs/content/setup/comment-workflow.mdx b/docs/content/setup/comment-workflow.mdx
deleted file mode 100644
index 9f058c05..00000000
--- a/docs/content/setup/comment-workflow.mdx
+++ /dev/null
@@ -1,492 +0,0 @@
----
-title: Comment workflow setup
-description: Respond to comments on IssueOps-driven issues
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-import { CheckCircleIcon } from '@primer/octicons-react'
-import { ActionList, Box } from '@primer/react'
-
-After the issue has been opened and any initial processing has been run, the
-comment workflow becomes the main driver of the rest of the process. This
-workflow is triggered by users commenting on issues and will do any further
-processing throughout the lifecycle of the issue.
-
-## Event triggers
-
-The comment workflow should, at minimum, be triggered by creation of new
-comments. The `issue_comment` trigger also supports editing and deleting
-comments, which may be useful for your use-case.
-
-```yaml
-on:
- issue_comment:
- - created
-```
-
-The flexibility with the `issue_comment` trigger lies in the comments
-themselves. You can take a limitless number of actions based on user input!
-
-
- _With great power comes great responsibility!_
-
-
-Be careful to not make your workflow _too_ complex. Otherwise, parsing comments
-becomes particularly challenging.
-
-
- The `issue_comment` trigger may seem misleading. This trigger applies to
- comments on both issues and PRs. If you want to trigger workflows on comments
- that are part of a PR _review_, use the `pull_request_comment` trigger
- instead.
-
-
-## Commands
-
-Good IssueOps workflows make use of _commands_ to trigger actions. These
-commands are typically prefixed with a symbol, such as `.` or `/`, and are
-descriptive of the action that will be taken when the command is processed. In
-general, any workflow that involves processing comments should start by looking
-for a specific command being run.
-
-
-
-
-
- Keyword
- Description
-
-
-
-
- `.submit`
- Submit a request for approval
-
-
- `.approve`
- Approve a request
-
-
- `.deny`
- Deny a request
-
-
-
-
-
-The examples you will see throughout this documentation make heavy use of the
-[`github/command`](https://github.com/github/command) action. This action makes
-it easy to define your actions, who can run them, and what happens when they are
-run.
-
-The following code block shows a basic implementation of this action as part of
-a IssueOps workflow to lint a pull request. In this example, the `Lint Command`
-step will run any time a user comments with `.lint` on a PR.
-
-```yaml
-name: IssueOps Linter
-
-on:
- issue_comment:
- types:
- - created
-
-jobs:
- lint:
- name: Lint Codebase
- runs-on: ubuntu-latest
-
- # Only run on PR comments, not issue comments
- if: ${{ github.event.pull_request }}
-
- # Minimum required permissions for the `github/command` action
- permissions:
- pull-requests: write
- issues: write
- checks: read
-
- steps:
- - name: Lint Command
- id: command
- uses: github/command@vX.X.X
- with:
- command: .lint
-
- - if: ${{ steps.command.outputs.continue == 'true' }}
- name: Checkout
- id: checkout
- uses: actions/checkout@vX.X.X
-
- - if: ${{ steps.command.outputs.continue == 'true' }}
- name: Run Linter
- id: run-linter
- run: npm run lint
-```
-
-As you can see, the `Checkout` and `Run Linter` steps only proceed if the
-`Lint Command` step's `continue` output is `'true'`. The `github/command` action
-provides the `continue` output to act as a gate for the rest of the workflow.
-
-The high-level flow of the `github/command` action is:
-
-1. Check the comment body for the command keyword (`.lint`)
-1. Add a reaction to the comment to indicate it was received
-1. Confirm the command is allowed to run
- 1. The user is authorized to run the command
- 1. Required checks have passed
- 1. Required reviews have been submitted
-1. Collect any arguments passed to the command
-
-## Workflow steps
-
-Most comment workflows can be broken down into the following steps. Depending on
-your workflow, some of these may not be required.
-
-1. Parse and validate the command and input(s)
-1. Parse and validate the issue body
-1. Check the current state
-1. Check the user's permissions
-1. Process the command
-1. Update the issue state
-1. Provide feedback to the user
-
-### Parse and validate the command and input(s)
-
-Depending on your workflow, you may need users to be able to provide additional
-inputs in their comments. For example, you may want to allow users to specify a
-specific branch to lint, or a specific file to run tests on. Input arguments can
-also be passed into the comment body as part of a command.
-
-The `github/command` action can be extended to support input parameters.
-Parameters must be added after the separator specified by the `param_separator`
-argument (default: `|`). Suppose you want to also allow users to provide a
-branch name to run linting on. Users would enter a comment like this:
-
-```plain
-.lint | main
-```
-
-Within your workflow, you would need to parse the parameter value and use it to
-checkout the correct branch:
-
-```yaml
-name: IssueOps Linter
-
-on:
- issue_comment:
- types:
- - created
-
-jobs:
- lint:
- name: Lint Codebase
- runs-on: ubuntu-latest
-
- # Only run on PR comments, not issue comments
- if: ${{ github.event.pull_request }}
-
- # Minimum required permissions for the `github/command` action
- permissions:
- pull-requests: write
- issues: write
- checks: read
-
- steps:
- - name: Lint Command
- id: command
- uses: github/command@vX.X.X
- with:
- command: .lint
- param_separator: '|' # This is the default value
-
- - if: ${{ steps.command.outputs.continue == 'true' }}
- name: Checkout
- id: checkout
- uses: actions/checkout@vX.X.X
- with:
- ref: ${{ steps.command.outputs.params }}
-
- - if: ${{ steps.command.outputs.continue == 'true' }}
- name: Run Linter
- id: run-linter
- run: npm run lint
-```
-
-
- The `params` output is a string, not an array or object. If you need to pass
- multiple parameters, you will need to include additional logic for parsing the
- string.
-
-
-### Parse and validate the issue body
-
-
-
-
-
-
- Validate Early
-
-
-
-
-
- Validate Often
-
-
-
-Any time you interact with an issue, make sure to validate the body! Users can
-edit the issue body at any time, so it's important to make sure you're working
-with the latest information. The
-[`issue-ops/parser`](https://github.com/issue-ops/parser) and
-[`issue-ops/validator`](https://github.com/issue-ops/validator) actions can take
-care of this for you. All you need to do is make sure they are included in your
-comment processing workflows.
-
-```yaml
-steps:
- - name: Parse Issue Body
- id: parse
- uses: issue-ops/parser@vX.X.X
- with:
- body: ${{ github.event.issue.body }}
- issue-form-template: my-issue-form.yml
-
- - name: Validate Issue Body
- id: validate
- uses: issue-ops/validator@vX.X.X
- with:
- issue-form-template: my-issue-form.yml
- issue-number: ${{ github.event.issue.number }}
- parsed-issue-body: ${{ steps.parse.outputs.json }}
-```
-
-### Check the current state
-
-As an issue is processed, it will move through a series of [states](/states).
-The current state of an issue can be tracked via labels.
-
-For example, suppose you have a workflow that requires users to submit their
-request after is has been validated and confirmed. You could use the following
-logic to check if the issue has already been submitted. That way, the processing
-that would transition the issue from `validated` to `submitted` state does not
-run again.
-
-```yaml
-# This will only run if the request has already been submitted.
-if: contains(github.event.issue.labels.*.name, 'issueops:submitted') == true
-
-steps:
- - name: Post Comment
- id: comment
- uses: peter-evans/create-or-update-comment@vX.X.X
- with:
- issue-number: ${{ github.event.issue.number }}
- body: |
- ':clock1: It looks like this issue has already been submitted. Sit tight!'
-```
-
-
- Labels can be edited at any time! You want to consider checking if the state
- indicated by the issue labels matches the expected state of the issue.
-
-
-### Check the user's permissions
-
-By default, any user with read access to a repository can open issues and add
-comments. If your IssueOps workflow involves certain authorized users being able
-to perform actions (e.g. approving or denying requests), this can be a problem!
-Instead, you should use the `allowlist` option in the `github/command` action to
-restrict who has the ability to run certain commands.
-
-For example, suppose you want to only allow certain administrators to approve
-requests for new repositories. The following step would only allow @octocat and
-@mona to run the `.approve` command. Any other users who comment on the issue
-with `.approve` will not be able to push the request through to the next state.
-
-```yaml
-- name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- command: .approve
- allowlist: octocat,mona
-```
-
-If you want to use teams to control access, you will also need to provide a
-token with `read:org` scope for the `allowlist_pat` property. For information on
-creating a GitHub App and using it to generate a token in a GitHub Actions
-workflow, see [GitHub App setup](/setup/github-app).
-
-```yaml
-- uses: actions/create-github-app-token@vX.X.X
- id: token
- with:
- app_id: ${{ secrets.MY_GITHUB_APP_ID }}
- private_key: ${{ secrets.MY_GITHUB_APP_PEM }}
- owner: ${{ github.repository_owner }}
-
-- name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- command: .approve
- allowlist: octo-org/admin-team
- allowlist_pat: ${{ steps.token.outputs.token }}
-```
-
-Alternatively, you can restrict access to specific roles in your IssueOps
-repository using the `permissions` property. By default, anyone with write,
-maintain, or administrator access to the repository can run commands.
-
-```yaml
-- name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- command: .approve
- permissions: admin,maintain # Restrict users with write access
-```
-
-### Process the command
-
-This is where the magic happens! You can use any series of actions to process
-your request. For example, the
-[`actions/github-script`](https://github.com/actions/github-script) action is a
-great choice for interacting with GitHub APIs.
-
-Make sure to gate these steps using the `continue` output from the
-`github/command` action!
-
-```yaml
-- if: ${{ steps.command.outputs.continue == 'true' }}
- name: Add User to Team
- id: add-user
- uses: actions/github-script@vX.X.X
- with:
- token: ${{ steps.token.outputs.token }}
- script: |
- const request = JSON.parse('${{ steps.parse.outputs.json }}')
-
- await github.rest.teams.addOrUpdateMembershipForUserInOrg({
- org: context.repo.owner,
- team_slug: request.team_name,
- username: '${{ github.event.issue.user.login }}',
- role: 'member'
- })
-```
-
-### Update the issue state
-
-Once any processing has been completed, the issue can be transitioned to the
-next state. This is done by adding or removing labels from the issue.
-
-For example, suppose you have a workflow that requires users to submit their
-request after is has been validated and confirmed. You can use the
-[`issue-ops/labeler`](https://github.com/issue-ops/labeler) action to transition
-the issue from `validated` to `submitted` state.
-
-```yaml
-- if: ${{ steps.command.outputs.continue == 'true' }}
- name: Set Submitted State
- id: set-submitted
- uses: issue-ops/labeler@vX.X.X
- with:
- action: add
- issue_number: ${{ github.event.issue.number }}
- labels: |
- issueops:submitted
-```
-
-### Provide feedback to the user
-
-Any time processing is done on an issue, its helpful to let users know:
-
-1. The command has been received
-1. The command is being processed
-1. The outcome of the processing
-
-The `github/command` action takes care of the first part for you. It will
-automatically add a reaction to any comments that contain a command.
-
-```yaml
-- uses: github/command@vX.X.X
- id: command
- with:
- command: .lint
- reaction: eyes
-```
-
-Any of the following reactions can be added:
-
-
-
-
-
-After the command has been received, adding comments to the issue to indicate
-work is being done is a great way to keep users informed. Once processing is
-complete, a comment can be added to the issue to indicate the outcome.
-
-```yaml
-- if: ${{ steps.command.outputs.continue == 'true' }}
- name: Add Complete Comment
- id: comment-complete
- uses: peter-evans/create-or-update-comment@vX.X.X
- with:
- issue-number: ${{ github.event.issue.number }}
- body: |
- Your request has been processed! Here are the details of the request:
-
- - **Team:** ${{ steps.parse.outputs.json.team_name }}
- - **Role:** `member`
-```
diff --git a/docs/content/setup/github-app.mdx b/docs/content/setup/github-app.mdx
deleted file mode 100644
index bb115d5e..00000000
--- a/docs/content/setup/github-app.mdx
+++ /dev/null
@@ -1,252 +0,0 @@
----
-title: GitHub App setup
-description: Control access to organization-level APIs
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-
-If your IssueOps workflow requires access to anything outside of the repository
-it is running in, you will need to provide it with a token. This token is used
-to authenticate with the GitHub API and should be scoped to the minimum
-permissions needed to do the job. Tokens can be provided two ways:
-
-- [Personal access tokens (PAT)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
-- [GitHub App installation tokens](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation)
-
-Since PATs are scoped to a single user, they are not recommended for use in
-IssueOps workflows. GitHub Apps are a better choice because they can be scoped
-to a repository or organization to provide access to the APIs you need.
-
-
- GitHub Apps cannot currently be created at the enterprise level for access to
- administrative APIs. If you need access to these APIs, you will need to use a
- PAT. In these cases, creating a "machine user" account is recommended over a
- personal account.
-
-
-## Ownership
-
-When creating a GitHub App, you have the option to specify your personal account
-or an organization as the owner. Choosing an organization as the owner allows
-you to grant access to multiple repositories in the organization and simplifies
-permissions management.
-
-## Setup
-
-### Create a GitHub App
-
-For instructions on how to create a GitHub App, see
-[Creating GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps).
-
-The following settings are a good starting point for IssueOps workflows:
-
-
-
-
-
- Setting
- Value
-
-
-
-
- Name
-
- A clear name that describes its purpose and permissions
-
-
-
- Description
-
- A description of what the app does and what it can access
-
-
-
- Homepage URL
- The URL to the repository with your IssueOps code
-
-
- Webhook
- Disable webhooks
-
-
- Permissions
-
- Select the **minimum** permissions needed for your workflow
-
-
-
-
-
-
-### Create a private key
-
-For instructions on how to create a private key, see
-[Managing private keys for GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps).
-
-
- Make sure to save the private key in a secure location!
-
-
-### Create GitHub Actions secrets
-
-After creating your GitHub App, you will need to create secrets that your
-IssueOps workflows can use to authenticate with the GitHub API. You can create
-these at the organization, repository, or environment level depending on your
-needs.
-
-You will need to create the following secrets. Make sure to note the names you
-give them as you will need to reference them in your workflows.
-
-
-
-
-
- Name
- Description
-
-
-
-
- App ID
- The ID of your GitHub App
-
-
- Private Key
- The private key you created
-
-
-
-
-
-
-
-
- The GitHub App ID is not a sensitive value and can be stored as a variable
- instead of a secret. It can be found on the settings page for your GitHub App.
-
-
-For instructions on how to create secrets, see the following links:
-
-- [Creating secrets for a repository](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository)
-- [Creating secrets for an environment](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-an-environment)
-- [Creating secrets for an organization](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-an-organization)
-
-## Usage
-
-### Update the workflow permissions
-
-In any workflow that needs to authenticate as a GitHub App, the following
-permissions **must** be specified at the workflow or job level.
-
-```yaml
-permissions:
- contents: read
- id-token: write
-```
-
-### Generate the installation access token
-
-There are various examples and open source actions available to create
-installation access tokens for GitHub Actions workflows. In this documentation,
-we will use the
-[`actions/create-github-app-token`](https://github.com/actions/create-github-app-token)
-action.
-
-Within any workflow job that needs to authenticate as your GitHub App, you will
-need to include the following step.
-
-```yaml
-steps:
- - uses: actions/create-github-app-token@vX.X.X
- id: token
- with:
- app_id: ${{ secrets.MY_GITHUB_APP_ID }}
- private_key: ${{ secrets.MY_GITHUB_APP_PEM }}
- owner: ${{ github.repository_owner }}
-```
-
-Make sure to update the following:
-
-- Set the version (`vX.X.X`) of the action to the latest published version.
-- Update the secret names to match the ones you created previously.
-
-
- In the previous example, the `owner` property is set to the owner of the
- repository where this workflow is defined. If your GitHub App is installed
- under another owner, you will need to specify that instead.
-
-
-### Use the token in your workflow
-
-Now that the token is being generated, you can reference it in your workflows as
-an output from the token generation step! This can be referenced as
-`${{ steps..outputs.token }}` (e.g.
-`${{ steps.token.outputs.token }}`).
-
-```yaml
-steps:
- - uses: actions/github-script@vX.X.X
- id: create-org-project
- with:
- github-token: ${{ steps.token.outputs.token }}
- script: |
- await github.rest.projects.createForOrg({
- org: 'octo-org',
- name: 'My awesome project'
- })
-```
-
-
- Make sure to check which steps in your workflow will need to use the GitHub
- App token versus the workflow token. For example, if you add the `issues:
- write` permission to your workflow, you do not need to use the GitHub App
- token to update issues in the _same_ repository as your workflows. However,
- you will need to use the GitHub App token to update issues in _other_
- repositories!
-
-
-## Example
-
-The following can be used as a starting point for your own workflows. Make sure
-to update the following information:
-
-```yaml
-name: Example Workflow
-
-# This workflow runs any time an issue is opened or edited.
-on:
- issues:
- types:
- - opened
- - edited
-
-jobs:
- example-job:
- name: Example Job
- runs-on: ubuntu-latest
-
- permissions:
- contents: read
- id-token: write
-
- steps:
- # Get the GitHub App installation access token.
- - uses: actions/create-github-app-token@vX.X.X
- id: token
- with:
- app_id: ${{ secrets.MY_GITHUB_APP_ID }}
- private_key: ${{ secrets.MY_GITHUB_APP_PEM }}
- owner: ${{ github.repository_owner }}
-
- - run: echo "Add your custom steps here!"
-```
diff --git a/docs/content/setup/index.mdx b/docs/content/setup/index.mdx
deleted file mode 100644
index 2042ff8a..00000000
--- a/docs/content/setup/index.mdx
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: Setting up IssueOps
-description: Configure your IssueOps workflow
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-
-This section will walk through the end-to-end setup process for configuring an
-IssueOps workflow. This includes setup and configuration of the following:
-
-- [Repository](/setup/repository)
-- [GitHub App](/setup/github-app)
-- [Issue form](/setup/issue-form)
-- [Issue workflow](/setup/issue-workflow)
-- [Comment workflow](/setup/comment-workflow)
diff --git a/docs/content/setup/issue-form.mdx b/docs/content/setup/issue-form.mdx
deleted file mode 100644
index ff99c06b..00000000
--- a/docs/content/setup/issue-form.mdx
+++ /dev/null
@@ -1,147 +0,0 @@
----
-title: Issue form setup
-description: Create a standardized entrypoint for your workflow
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-
-The first interaction point users will have with your IssueOps workflow is the
-issue itself. This is where they will provide the information needed to kick off
-the workflow. Because of this, it is important to make sure that the issue form
-template is set up to capture all the information you need to get started.
-
-For more information on the supported options, see
-[Syntax for issue forms](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms).
-
-## Top-level syntax
-
-The top-level syntax of the issue form template is used to define the title and
-description that users will see when they go to create an issue in your
-repository. From a usability perspective, make sure to include a description and
-title that clearly explains what the user is requesting and what will happen
-once they submit their issue.
-
-
- Make sure to label your issues and assign them to projects!
-
-
-```yaml
-name: Create a new repository
-description: |
- Once opened, this issue will cause a new GitHub repository to be created in
- the `octocat` organization. You will be granted access as a collaborator so
- you can build something awesome!
-labels:
- - issueops:new-repository
-projects:
- - octocat/123
-body:
- # ...
-```
-
-## Body syntax
-
-The `body` property is where you specify the inputs and any other supporting
-information you need to collect from the user. Its important to make sure to
-collect all the information you need to get started, but also to make sure that
-the form is not too long or complicated.
-
-
- If there's a way you can calculate certain information, consider doing that
- instead of asking the user to provide additional inputs. For example, you can
- get the user's GitHub username from the issue metadata
- (`${{ github.event.issue.user.login }}`) instead of asking them to provide it.
-
-
-As you are drafting your issue form template, think about the kind of data you
-are requesting and the best format to use (both for user input and for automated
-processing later).
-
-This can be confusing, because once an issue form is submitted, all the inputs
-look the same. Suppose you have the following issue form template:
-
-```yaml
-name: New Repo Request
-description: Submit a request to create a new GitHub repository
-title: '[Request] New Repository'
-labels:
- - issueops:new-repository
-
-body:
- # Markdown type fields are not included in the submitted issue body
- - type: markdown
- attributes:
- value:
- Welcome to GitHub! Please fill out the information below to request a
- new repository. Once submitted, your request will be reviewed by the
- IssueOps team. If approved, the repository will be created and you will
- be notified via a comment on this issue.
- - type: input
- id: name
- attributes:
- label: Repository Name
- description: The name of the repository you would like to create.
- placeholder: octorepo
- validations:
- required: true
- - type: dropdown
- id: visibility
- attributes:
- label: Repository Visibility
- description: The visibility of the repository.
- multiple: false
- options:
- - private
- - public
- validations:
- required: true
- - type: dropdown
- id: topics
- attributes:
- label: Repository Topics
- description: The topics to add to the repository.
- multiple: true
- options:
- - octocat
- - issueops
- - automation
- validations:
- required: true
- - type: checkboxes
- id: confirm
- attributes:
- label: Confirmation
- description: Do you confirm this request?
- options:
- - label: 'Yes'
- required: true
- - label: 'No'
- required: false
-```
-
-When the user submits the issue form, it will have the following Markdown
-format:
-
-```plain
-### Repository Name
-
-octorepo
-
-### Repository Visibility
-
-public
-
-### Repository Topics
-
-octocat, issueops
-
-### Confirmation
-
-- [x] Yes
-- [ ] No
-```
-
-You can see that certain inputs look the same, but are actually different types
-and, depending on their values, may be processed differently.
diff --git a/docs/content/setup/issue-workflow.mdx b/docs/content/setup/issue-workflow.mdx
deleted file mode 100644
index 1ef036c7..00000000
--- a/docs/content/setup/issue-workflow.mdx
+++ /dev/null
@@ -1,144 +0,0 @@
----
-title: Issue workflow setup
-description: Perform initial processing of issues
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-
-Once a user submits your issue form, its time for GitHub Actions to run the
-show! The issue workflow is responsible for performing any initial processing of
-the issue such as adding labels, validating the contents, adding comments, etc.
-The following sections will walk through the core structure of an issue
-workflow.
-
-## Event triggers
-
-Most of the time, this workflow will only be run when an issue is opened or
-edited, however there are some cases where you may want to run this workflow
-when an issue is reopened.
-
-```yaml
-on:
- issues:
- types:
- - opened
- - edited
- - reopened
-```
-
-## Jobs
-
-Different request types may have different inputs. For example, a new repository
-request may have different inputs than a repository transfer request. If you
-decide to create multiple jobs to parse different types of requests in the same
-workflow, you can use labels to control which jobs run for which types of
-requests.
-
-You should also consider how you plan to handle processing of multiple requests
-in the same workflow.
-
-```yaml
-jobs:
- new-repository-request:
- name: New Repository Request
- runs-on: ubuntu-latest
-
- # Only run for issues with the `issueops:new-repository` label.
- if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
-
- team-membership-request:
- name: Team Membership Request
- runs-on: ubuntu-latest
-
- # Only run for issues with the `issueops:team-add` label.
- if: contains(github.event.issue.labels.*.name, 'issueops:team-add')
-```
-
-Depending on the complexity of your workflow, you may want to isolate each type
-of request to separate jobs entirely, or you may want to have jobs that handle
-common tasks across multiple request types. For example, if you have IssueOps
-workflows for adding and removing users from a team, there's a good chance they
-both have the same input data and perform the same validation steps. In this
-case, you may want to create a job that handles the common tasks, and then have
-separate jobs for the unique tasks.
-
-```yaml
-jobs:
- team-request:
- name: Team Management Request
- runs-on: ubuntu-latest
-
- # Run this job for both request types
- if: |
- contains(github.event.issue.labels.*.name, 'issueops:team-add') ||
- contains(github.event.issue.labels.*.name, 'issueops:team-remove')
-
- outputs:
- request: ${{ steps.parse.outputs.json }}
-
- steps:
- - name: Parse Issue
- id: parse
- uses: issue-ops/parser@vX.X.X
- with:
- body: ${{ github.event.issue.body }}
- issue-form-template: team-add-remove-request.yml
-
- - name: Validate Issue
- id: validate
- uses: issue-ops/validator@vX.X.X
- with:
- issue-form-template: team-add-remove-request.yml
- parsed-issue-body: ${{ steps.parse.outputs.json }}
-
- team-add:
- name: Team Add Request
- runs-on: ubuntu-latest
-
- # Only run after the `team-request` job has completed
- needs: team-request
-
- # Only run for issues with the `issueops:team-add` label.
- if: contains(github.event.issue.labels.*.name, 'issueops:team-add')
-
- steps:
- - name: Add User to Team
- id: add
- uses: actions/github-script@vX.X.X
- with:
- github-token: ${{ secrets.MY_TOKEN }}
- script: |
- const request = JSON.parse('${{ needs.team-request.outputs.request }}')
-
- await github.rest.teams.addOrUpdateMembershipForUserInOrg({
- org: request.org,
- team_slug: request.team,
- username: request.user
- })
-
- team-remove:
- name: Team Remove Request
- runs-on: ubuntu-latest
-
- # Only run after the `team-request` job has completed
- needs: team-request
-
- # Only run for issues with the `issueops:team-remove` label.
- if: contains(github.event.issue.labels.*.name, 'issueops:team-remove')
-
- steps:
- - name: Remove User from Team
- id: remove
- uses: actions/github-script@vX.X.X
- with:
- github-token: ${{ secrets.MY_TOKEN }}
- script: |
- const request = JSON.parse('${{ needs.team-request.outputs.request }}')
-
- await github.rest.teams.removeMembershipForUserInOrg({
- org: request.org,
- team_slug: request.team,
- username: request.user
- })
-```
diff --git a/docs/content/setup/repository.mdx b/docs/content/setup/repository.mdx
deleted file mode 100644
index 6e66e8e4..00000000
--- a/docs/content/setup/repository.mdx
+++ /dev/null
@@ -1,221 +0,0 @@
----
-title: Repository setup
-description: Configure your repository to start using IssueOps
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import {
- Do,
- DoDontContainer,
- Dont,
- Note
-} from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-
-This page outlines recommended configuration settings for IssueOps repositories.
-For instructions on how to create a repository, see the
-[GitHub documentation](https://docs.github.com/en/get-started/quickstart/create-a-repo).
-
-## Visibility
-
-IssueOps works best when your repository is accessible to users who need to
-submit requests. Depending on if the repository is owned by an organization or a
-user account, you can set the visibility to one of the following:
-
-
-
-
-
-Alternatively, if you only want to allow specific users to submit requests, you
-can set the visibility to `private` and add those users as
-[collaborators](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-access-to-your-personal-repositories/inviting-collaborators-to-a-personal-repository).
-
-## Permissions
-
-Users only need `read` access to open issues! Unless there is a specific reason
-to do otherwise, you should only ever need to grant `read` access.
-
-The primary reason to grant `write` access is if your IssueOps flow uses pull
-requests instead of issues, but only if you want users to create pull requests
-from branches in the _same_ repository. As an alternative, you can allow forking
-of your repository and users can create pull requests from their forked
-repository instead.
-
-## Branch protection
-
-[Branch protection rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches)
-are a good idea regardless of what your repository is being used for! You should
-always protect your default branch (usually `main`) and any other branches that
-you want to prevent accidental changes to.
-
-For an IssueOps repository, you should create a branch protection rule for
-`main` that enables the following:
-
-- Require a pull request before merging
-- Require status checks to pass before merging (add any continuous integration
- or testing workflows that you use)
-- Require branches to be up to date before merging
-- Require review from Code Owners (if your repository has a `CODEOWNERS` file)
-
-## GitHub Actions
-
-### Fork pull request workflows
-
-If your IssueOps workflow uses pull requests instead of issues, you must be
-careful about the configuration of GitHub Actions and what permissions are
-allowed for fork pull requests. The following settings can be enabled for fork
-pull requests, with a description of the risks involved.
-
-
-
-
-
- Setting
- Risk
-
-
-
-
- Run workflows from fork pull requests
-
- Forks will have read permissions to your repository
-
-
-
-
- Send write tokens to workflows from fork pull requests
-
-
- Forks will have **write** permissions to your repository
-
-
-
-
- Send secrets and variables to workflows from fork pull requests
-
-
- Forks will have access to your secrets and variables
-
-
-
- Require approval for fork pull request workflows
-
- Forks will not be able to run workflows until they are approved
-
-
-
-
-
-
-As you can guess, the safest option is to not allow fork pull requests to run
-workflows at all. However, this may not be practical for your workflow. Here are
-some recommended settings:
-
-
-
- Document required permissions for contributors to run the workflows
- themselves
-
- Send write tokens to fork pull requests
-
-
-
-
- Document the required secrets and variables and how to generate them
-
-
- Send secrets and variables to workflows from fork pull requests
-
-
-
-One alternative to consider is to "wrap" the creation of the PR into part of
-your IssueOps flow. If the content of the PR will follow a known format, you can
-use a GitHub Action to create the PR on behalf of the user. This will allow you
-to remove the need to allow any GitHub Actions access to fork pull requests.
-
-{/* TODO: Direct link to specific example */}
-
-### Workflow permissions
-
-In the repository settings, it is best to keep the base workflow permissions
-limited to _Read repository contents and packages permissions_. Within each
-IssueOps workflow, you can increase the permissions as needed for specific jobs.
-
-## Environments
-
-If your IssueOps workflow involves deployments or interaction with environments,
-you should consider adding enviroment-specific rules to restrict deployments to
-only the `main` branch. A common exception to this rule is if you are running
-IssueOps workflows from pull requests, as these will be run from branches other
-than `main`.
-
-This is also a good opportunity to further restrict access to secrets and
-variables by defining them at the environment level!
-
-## Other considerations
-
-A few common questions and answers about repository setup. Most of the time, the
-answer is "it depends!", but these are some things to consider.
-
-### Multiple IssueOps workflows in one repository
-
-There are some tradeoffs to consider when using one or multiple repositories to
-host different IssueOps workflows. For example, suppose you have the following
-workflows:
-
-- Team membership requests
-- New repository creation requests
-
-If you use a single repository, one challenge you may run into is ensuring that
-jobs for the team membership requests don't affect new repository requests. This
-is where labels are particularly helpful! You can use labels to scope jobs to
-specific requests.
-
-```yaml
-name: Issue Opened/Edited
-
-on:
- issues:
- types:
- - opened
- - edited
-
-jobs:
- new-repository-request:
- name: New Repository Request
- runs-on: ubuntu-latest
-
- # Only run for issues with the `issueops:new-repository` label.
- if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
-
- team-membership-request:
- name: Team Membership Request
- runs-on: ubuntu-latest
-
- # Only run for issues with the `issueops:team-add` label.
- if: contains(github.event.issue.labels.*.name, 'issueops:team-add')
-```
diff --git a/docs/content/states-and-transitions/approve.mdx b/docs/content/states-and-transitions/approve.mdx
deleted file mode 100644
index df219442..00000000
--- a/docs/content/states-and-transitions/approve.mdx
+++ /dev/null
@@ -1,99 +0,0 @@
----
-title: Approve
-description: The request is approved and we can process it further.
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-
-## Overview
-
-In the `Approved` state, we know that the issue has been approved and we can
-begin processing it. This is one of the first states in the workflow where we
-can perform an _unguarded transition_.
-
-In our repository workflow, a request is transitioned to the `Approved` state
-when an authorized user comments on the request with `.approve`. However,
-immediately after reaching this state, we know we can create the repository and
-close the issue (moving it to the `Closed` state). This is called an _unguarded
-transition_ because there is no condition that must be met before the transition
-occurs.
-
-The actual implementation of this transition is up to you! There are a few
-recommendations to keep in mind:
-
-- Communication to users is always helpful! Consider leaving a comment on the
- issue to let the user know that their request has been approved and what is
- going to happen next. Or, comment on the issue with a summary of the changes
- that have taken place.
-- Even after an issue is closed, users can interact with it. If you want to
- prevent this, you can
- [lock the issue](https://docs.github.com/en/communities/moderating-comments-and-conversations/locking-conversations).
-- Labels are a great way to organize issues. Consider adding a label to the
- issue to indicate that it has been approved.
-- When closing an issue, choosing an appropriate reason is useful for future
- reporting. For approved requests, closing an issue as `not_planned` may be
- misleading. Consider `completed` instead.
-
-## New repository request
-
-When a new repository request is approved, we need to do the following:
-
-1. Create the repository
-1. Comment on the issue
-1. Close the issue
-
-```yaml
-# This job is responsible for handling approved requests.
-deny:
- name: Approve Request
- runs-on: ubuntu-latest
-
- # Only run after validation has completed.
- needs: validate
-
- steps:
- - name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .approve
-
- # Create the repository.
- - if: ${{ steps.approve.outputs.continue == 'true' }}
- name: Create Repository
- id: create
- uses: actions/github-script@vX.X.X
- with:
- github-token: ${{ secrets.MY_TOKEN }}
- script: |
- const request = JSON.parse('${{ needs.validate.outputs.request }}')
- await github.rest.repos.createInOrg({
- org: '${{ github.repository_owner }}',
- name: request.name,
- })
-
- # Comment on the issue to let the user know their request was denied.
- - if: ${{ steps.approve.outputs.continue == 'true' }}
- name: Post Comment
- id: comment
- uses: peter-evans/create-or-update-comment@vX.X.X
- with:
- issue-number: ${{ github.event.issue.number }}
- body:
- ':tada: This request has been approved! Your repository has been
- created.'
-
- # Close the issue.
- - if: ${{ steps.approve.outputs.continue == 'true' }}
- name: Close Issue
- id: close
- run: gh issue close ${{ github.event.issue.number }} --reason completed
-```
-
-## Next steps
-
-Your IssueOps workflow is officially complete!
diff --git a/docs/content/states-and-transitions/deny.mdx b/docs/content/states-and-transitions/deny.mdx
deleted file mode 100644
index 4e1cee92..00000000
--- a/docs/content/states-and-transitions/deny.mdx
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Deny
-description: The request is denied and the issue can be closed.
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-
-## Overview
-
-In the `Denied` state, we know that the issue has been denied and there is no
-further action to take. This is one of the first states in the workflow where we
-can perform an _unguarded transition_.
-
-In our repository workflow, a request is transitioned to the `Denied` state when
-an authorized user comments on the request with `.deny`. However, immediately
-after reaching this state, we want to close the issue (moving it to the `Closed`
-state). This is called an _unguarded transition_ because there is no condition
-that must be met before the transition occurs.
-
-The actual implementation of this transition is up to you! There are a few
-recommendations to keep in mind:
-
-- Communication to users is always helpful! Consider leaving a comment on the
- issue to let the user know that their request has been denied and what steps,
- if any, they can take next.
-- Even after an issue is closed, users can interact with it. If you want to
- prevent this, you can
- [lock the issue](https://docs.github.com/en/communities/moderating-comments-and-conversations/locking-conversations).
-- Labels are a great way to organize issues. Consider adding a label to the
- issue to indicate that it has been denied.
-- When closing an issue, choosing an appropriate reason is useful for future
- reporting. For denied requests, closing an issue as `completed` may be
- misleading. Consider `not_planned` instead.
-
-## New repository request
-
-When a new repository request is denied, we want to close the issue and leave a
-comment for the user. We should also add an appropriate label so we know the
-request was closed as denied.
-
-```yaml
-# This job is responsible for handling denied requests.
-deny:
- name: Deny Request
- runs-on: ubuntu-latest
-
- # Only run after validation has completed.
- needs: validate
-
- steps:
- - name: Deny Command
- id: deny
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .deny
-
- # Comment on the issue to let the user know their request was denied.
- - if: ${{ steps.deny.outputs.continue == 'true' }}
- name: Post Comment
- id: comment
- uses: peter-evans/create-or-update-comment@vX.X.X
- with:
- issue-number: ${{ github.event.issue.number }}
- body:
- ':no_entry_sign: This request has been denied! This issue will be
- closed shortly.'
-
- # Close the issue.
- - if: ${{ steps.deny.outputs.continue == 'true' }}
- name: Close Issue
- id: close
- run: gh issue close ${{ github.event.issue.number }} --reason not_planned
-```
-
-## Next steps
-
-Your IssueOps workflow is officially complete!
diff --git a/docs/content/states-and-transitions/index.mdx b/docs/content/states-and-transitions/index.mdx
deleted file mode 100644
index 65793eff..00000000
--- a/docs/content/states-and-transitions/index.mdx
+++ /dev/null
@@ -1,191 +0,0 @@
----
-title: States and transitions
-description:
- Implementation and handling of state transitions in an IssueOps workflow
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import { ImageContainer } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-import { Box } from '@primer/react'
-
-As the [introduction](/introduction) mentioned, IssueOps can be thought of as a
-state diagram where an issue transitions through different states in response to
-events and conditions. This section of the documentation describes some common
-states, transitions. and how to implement them in your workflows.
-
-## States
-
-If an issue was a paper form, a state would be a big rubber stamp that tells
-anyone who looks at the form exactly what is going on.
-
-Tracking state can be as simple as checking what labels are applied to your
-issues. Whatever approach you want to take, remember that tracking state is
-critical to ensure that the right processing occurs at the right time!
-
-
-
-
-
- State
- Description
-
-
-
-
- `Opened`
-
- The initial state for a new issue that has been opened.
-
- Typically the first state in the lifecycle of an issue.
-
-
-
- `Parsed`
-
- The issue body has been read and converted to machine-readable JSON.
-
- Usually the next immediate state after `Opened`.
-
-
-
- `Validated`
-
- The issue body has been deemed valid based on any custom rules.
-
- Usually the next immediate state after `Parsed`.
-
- The next transitions depend on the type of request and any rules that
- must be followed.
-
-
-
- `Submitted`
- The issue has been submitted for processing.
-
-
- `Approved`
- The issue has been approved for processing.
-
-
- `Denied`
- The issue has been denied for processing.
-
-
- `Closed`
- The issue has been closed :tada:
-
-
-
-
-
-
-
-
-```mermaid
-stateDiagram-v2
- 1 : Opened
- 2 : Parsed
- 3 : Validated
- 4 : Submitted
- 5 : Approved
- 6 : Denied
- 7 : Closed
- [*] --> 1
- 1 --> 1 : Parse failure
- 1 --> 2 : Parse success
- 2 --> 2 : Validate failure
- 2 --> 3 : Validate success
- 3 --> 4 : Submit for processing
- 4 --> 5 : Approve request
- 4 --> 6 : Deny request
- 5 --> 7 : Process request
- 6 --> 7 : Notify user
- 7 --> [*]
-```
-
-
-
-## Transitions
-
-If an issue was a paper form, a transition would be someone taking it out of
-their inbox, stamping it **APPROVED**, and putting it in their outbox.
-
-Transitions are where actual processing on your issues occurs. A transition is
-equivalent to an event that triggers a GitHub Actions workflow run. That is why,
-as your IssueOps workflows become larger and more complex, tracking state is so
-important. Otherwise, its easy to end up the wrong workflows running at the
-wrong time!
-
-Since each transition is triggered by the same type of event:
-
-```yaml
-on:
- issue_comment:
- - created
-```
-
-Your workflows must track the following to determine what jobs to run:
-
-- Issue state
-- Issue body
-- Comment body (command and arguments)
-- Any other relevant information in the issue
-
-Each of the following sections describes how to implement the core transitions
-in an IssueOps workflow. Throughout each page, you will see an example
-implementation of a new repository request workflow. This workflow is designed
-to demonstrate how to apply each concept.
-
-A full example can be found in the
-[`issue-ops/bear-creek-honey-farm`](https://github.com/issue-ops/bear-creek-honey-farm)
-and
-[`issue-ops/demo-reservation-action`](https://github.com/issue-ops/demo-reservation-action)
-repositories.
-
-- [Parse](/states-and-transitions/parse)
-- [Validate](/states-and-transitions/validate)
-- [Submit](/states-and-transitions/submit)
-- [Approve](/states-and-transitions/approve)
-- [Deny](/states-and-transitions/deny)
-
-## FAQ
-
-### Do my IssueOps need all these states?
-
-Nope! You can use as many or as few states as you need. For example, if you
-don't need an authorized user to approve requests, you can omit the `Approved`
-state.
-
-### Can my IssueOps use each state more than once?
-
-Of course! In state diagrams, its common for each state to have multiple
-transitions. States can even transition back into themselves!
-
-When an issue is first opened it will be in the `Opened` state. Typically, the
-first step after an issue is opened is to parse the body and prepare for further
-processing. If this is successful, the issue would transition into the `Parsed`
-state. If there is a problem during parsing, the workflow can add a comment with
-a descriptive error and return the issue to the `Opened` state. When the user
-edits the issue to fix the error, parsing would run again.
-
-
-
-```mermaid
-stateDiagram-v2
- 1 : Opened
- 2 : Parsed
- [*] --> 1
- 1 --> 2 : Parse success
- 1 --> 1 : Parse failure
- 2 --> [*]
-```
-
-
diff --git a/docs/content/states-and-transitions/parse.mdx b/docs/content/states-and-transitions/parse.mdx
deleted file mode 100644
index 285132e2..00000000
--- a/docs/content/states-and-transitions/parse.mdx
+++ /dev/null
@@ -1,327 +0,0 @@
----
-title: Parse
-description: Turn the issue body into a machine readable format.
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import { ImageContainer } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-import { Box, FormControl, Select, Textarea, TextInput } from '@primer/react'
-
-## Overview
-
-When a new issue is opened, before any action can be taken on it, you should
-parse its contents and turn it into a machine-readable format. The
-[`issue-ops/parser`](https://github.com/issue-ops/parser) action does this by
-comparing the body of the issue with the original issue form template. This way,
-you can directly reference issue form fields without having to parse the body
-yourself with regular expressions.
-
-
- This is also available as a standalone npm package,
- [`@github/issue-parser`](https://www.npmjs.com/package/@github/issue-parser)!
-
-
-This action provides specific output formats based on the `type` property of the
-input.
-
-
-
-
-
- Input type
- Example parsed output
-
-
-
-
- `input`
- `"octorepo"`
-
-
- `textarea`
- `"This is a description!\n\nIt is multiline, too!"`
-
-
- `dropdown`
- `["octocat", "issueops"]`
-
-
- `checkboxes`
- `{ "selected": ["Yes"], "unselected": ["No"] }`
-
-
-
-
-
-Depending on how you're processing the input data, different types may be more
-helpful than others! Based on the issue form template and the contents of the
-issue itself, the `json` output will look similar to the following:
-
-```json
-{
- "the_name_of_the_thing": "this-thing",
- "the_nickname_of_the_thing": "thing",
- "the_color_of_the_thing": ["blue"],
- "the_shape_of_the_thing": ["square"],
- "the_sounds_of_the_thing": ["re", "mi"],
- "the_topics_about_the_thing": [],
- "the_description_of_the_thing": "This is a description.\n\nIt has lines.",
- "the_notes_about_the_thing": "- Note\n- Another note\n- Lots of notes",
- "the_code_of_the_thing": "const thing = new Thing()\n\nthing.doThing()",
- "the_string_method_of_the_code_of_the_thing": "thing.toString()",
- "is_the_thing_a_thing": {
- "selected": ["Yes"],
- "unselected": ["No"]
- },
- "is_the_thing_useful": {
- "selected": ["Sometimes"],
- "unselected": ["Yes", "No"]
- },
- "read_team": "IssueOps-Demo-Readers",
- "write_team": "IssueOps-Demo-Writers"
-}
-```
-
-Once an issue has been parsed, the next step is to
-[validate](/states-and-transitions/validate) the contents to make sure the
-request isn't missing data, doesn't contain invalid data, and can be processed
-by your workflow.
-
-## New repository request
-
-### Issue form template
-
-The new repository worklow starts off with the following issue form template.
-
-```yaml
-name: New Repository Request
-description: Submit a request to create a new GitHub repository
-title: '[Request] New Repository'
-labels:
- - issueops:new-repository
-
-body:
- - type: markdown
- attributes:
- value:
- Welcome to GitHub! Please fill out the information below to request a
- new repository. Once submitted, your request will be reviewed by the
- IssueOps team. If approved, the repository will be created and you will
- be notified via a comment on this issue.
- - type: input
- id: name
- attributes:
- label: Repository Name
- description: The name of the repository you would like to create.
- placeholder: octorepo
- validations:
- required: true
- - type: dropdown
- id: visibility
- attributes:
- label: Repository Visibility
- description: The visibility of the repository.
- multiple: false
- options:
- - private
- - public
- validations:
- required: true
- - type: input
- id: read-team
- attributes:
- label: Read Team
- description: The GitHub Team that will get read access to the repository.
- placeholder: octocat-readers
- validations:
- required: true
- - type: input
- id: write-team
- attributes:
- label: Write Team
- description: The GitHub Team that will get write access to the repository.
- placeholder: octocat-writers
- validations:
- required: true
- - type: dropdown
- id: auto-init
- attributes:
- label: Auto Init
- description: Select `true` to initialize the repository with a `README`.
- multiple: false
- options:
- - 'true'
- - 'false'
- validations:
- required: true
- - type: textarea
- id: topics
- attributes:
- label: Topics
- description:
- (Optional) A list of topics to add to the repository. Separate each
- topic with a new line.
- placeholder: |
- octocat
- octodog
- validations:
- required: false
-```
-
-When a user submits a request for a new repository, the issue form will look
-something like this:
-
-
-
-
- Add a title
-
-
- Welcome to GitHub! Please fill out the information below to request a new
- repository. Once submitted, your request will be reviewed by the IssueOps
- team. If approved, the repository will be created and you will be notified
- via a comment on this issue.
-
- Repository Name
-
- The name of the repository you would like to create.
-
-
-
-
- Repository Visibility
-
- The visibility of the repository.
-
-
-
-
- Read Team
-
- The GitHub Team that will get read access to the repository.
-
-
-
-
- Write Team
-
- The GitHub Team that will get write access to the repository.
-
-
-
-
- Auto Init
-
- Select `true` to initialize the repository with a `README`.
-
-
-
-
- Topics
-
- (Optional) A list of topics to add to the repository. Separate each
- topic with a new line.
-
-
-
-
-
-
-### GitHub Actions workflow
-
-Creating an issue will kick off the start of the IssueOps process. However, in
-order to do anything with the request, we need to parse the issue body and
-extract the information we need to get approval and create a repository.
-
-Check the workflow comments for useful tips!
-
-```yaml
-name: Issue Opened/Edited/Reopened
-
-# At minimum, the issue body should be parsed any time an issue is opened,
-# edited, or reopened. This ensures that the most up to date information is
-# validated.
-on:
- issues:
- types:
- - opened
- - edited
- - reopened
-
-jobs:
- # Different request types may have different inputs. For example, a new
- # repository request may have different inputs than a repository transfer
- # request. You can create multiple jobs to parse different types of requests
- # in the same workflow. Labels can be used to control which jobs run for
- # which types of requests.
- new-repository-request:
- name: New Repository Request
- runs-on: ubuntu-latest
-
- # Assign labels for different types of requests, and use those labels to
- # trigger different workflows, jobs, and steps.
- if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
-
- # Initially, this workflow only needs permissions to read issues and
- # contents. This will be expanded later as we build additional
- # functionality.
- permissions:
- contents: read
- issues: read
-
- steps:
- # Get the repository contents. This lets the workflow reference files in
- # the repository such as the issue form template.
- - name: Checkout
- id: checkout
- uses: actions/checkout@vX.X.X
-
- - name: Parse Issue
- id: parse
- uses: issue-ops/parser@vX.X.X
- with:
- body: ${{ github.event.issue.body }}
- issue-form-template: new-repository-request.yml
-
- - name: Output the Parsed Issue
- id: output
- run: echo ${{ steps.parse.outputs.json }}
-```
-
-## Next steps
-
-At this point, our issue has successfully transitioned into the `Parsed` state.
-This means that we have a machine-readable representation of the request that
-can be further processed by our workflows. However, we don't know if the request
-actually contains valid information! The next transition involves validating the
-parsed request against a set of rules to make sure it's ready to be processed.
-
-[Continue to the next section to learn about validation.](/states-and-transitions/validate)
diff --git a/docs/content/states-and-transitions/submit.mdx b/docs/content/states-and-transitions/submit.mdx
deleted file mode 100644
index 086db6dc..00000000
--- a/docs/content/states-and-transitions/submit.mdx
+++ /dev/null
@@ -1,383 +0,0 @@
----
-title: Submit
-description: Tell GitHub Actions the issue is ready for processing.
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-
-## Overview
-
-Once your issue has been parsed and validated, it's ready for processing! At
-this point, _processing_ can mean a lot of things and is entirely dependent on
-your use case. For example, if you're using IssueOps to access administrative
-functions, you may require a human to review and approve the issue. Or, if
-you're using IssueOps to track PTO requests, you may not need any additional
-approvals and can simply mark the issue as processed.
-
-This page walks through the process of submitting a request after it has been
-validated. In particular, it covers requesting approval from authorized users or
-teams.
-
-> _Wouldn't opening the issue count as the act of submitting it?_
-
-Absolutely! However, the act of opening an issue may not be the best indicator
-that an issue is in the `Submitted` state in your workflow. What if you need to
-do additional processing on the validated request which requires confirmation
-from the user?
-
-Using the new repository request as an example, your organization may want to
-enforce certain naming conventions for repositories, such as prefixing the name
-with the user's department. In this case, when a user opens a request and asks
-for a repository named `pto-requests`, you could have them confirm that the
-generated name of `hr-pto-requests` is acceptable before submitting the request
-for further processing.
-
-### Command actions
-
-This is where the [`github/command`](https://github.com/github/command) action
-comes into play. This action allows you to specify the _who_, _what_, _when_,
-and _where_ of activities that can be performed on an issue. For example, if you
-request approval for a new repository, the `github/command` action ensures that
-any user cannot approve the request. Instead, only users or teams you specify
-can.
-
-
- As with other actions that call GitHub APIs, if you want to include GitHub
- teams in the `allowlist` feature, you must provide a valid token in the
- `allowlist_pat` input. This can be a token generated from a GitHub App!
-
-
-```yaml
-steps:
- - name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .approve
-```
-
-This step acts as the gate for any further processing of the issue. The
-`continue` output can be used to conditionally invoke further steps. For
-example, if the `continue` output is `'true'`, the user who commented on the
-issue with `.approve` was indeed authorized to approve the request.
-
-```yaml
-steps:
- - name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .approve
-
- ##############################################
- # This is a great time to re-run validation! #
- ##############################################
-
- - if: ${{ steps.approve.outputs.continue == 'true' }}
- run: echo "This request is approved!"
-```
-
-With any approval workflow, you should also consider what happens when a request
-is explicitly denied This is easy to implement as a separate `github/command`
-step that looks for the `.deny` command. As with the approval command, if the
-user who commented on the issue is authorized to deny requests, the `continue`
-output would be `'true'`.
-
-```yaml
-steps:
- - name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .approve
-
- - name: Deny Command
- id: deny
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .deny
-
- - if: ${{ steps.approve.outputs.continue == 'true' }}
- run: echo "This request is approved :)"
-
- - if: ${{ steps.deny.outputs.continue == 'true' }}
- run: echo "This request is denied :("
-```
-
-## New repository request
-
-Up until this point, everything has been handled as part of the issue creation
-workflow. Now that the issue has been validated, any further processing is done
-via comments, labels, reactions, and so on.
-
-### Create the comment workflow file
-
-The first step is to create a workflow file that will be triggered when a user
-comments on an issue. This workflow file will be responsible for parsing the
-comment and determining the following:
-
-- The comment is on an issue that is part of our IssueOps workflow
-- The comment is a command word
-- The user is authorized to call that command
-
-In this example, we will set up two different jobs that will run when the
-request is approved or denied.
-
-```yaml
-name: Issue Comment
-
-# This workflow runs any time a comment is added to an issue. The comment body
-# is read and used to determine what action to take.
-on:
- issue_comment:
- types:
- - created
-
-jobs:
- # This job handles the case where a user comments with `.approve`.
- approve:
- name: Approve Request
- runs-on: ubuntu-latest
-
- steps:
- - name: Approve Command
- id: approve
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .approve
-
- - if: ${{ steps.approve.outputs.continue == 'true' }}
- run: echo "This request is approved!"
-
- # This job handles the case where a user comments with `.deny`.
- deny:
- name: Deny Request
- runs-on: ubuntu-latest
-
- steps:
- - name: Deny Command
- id: deny
- uses: github/command@vX.X.X
- with:
- allowed_contexts: issue
- allowlist: octo-org/approvers
- allowlist_pat: ${{ secrets.MY_TOKEN }}
- command: .deny
-
- - if: ${{ steps.deny.outputs.continue == 'true' }}
- run: echo "This request is denied!"
-```
-
-### Trigger the workflow
-
-In the above workflow, both the `approve` and `deny` jobs are triggered when a
-user comments on an issue or PR. Though the `github/command` actions will act as
-one gate, you may want to add additional conditions to ensure that the workflow
-is not run when the issue is in a state that does not require approval. For
-example, this workflow doesn't need to run if:
-
-- The issue is not part of this IssueOps workflow
-- The request is not in the `Submitted` state
-- The request is already approved
-
-Workflow conditions can be used to control when the workflow jobs are invoked.
-
-
- It's always a good idea to consider negative cases when writing workflows.
- What would happen if someone comments `.approve` but the request has already
- been approved? Adding a comment stating the request has already been approved
- helps prevent confusion. Communication is key!
-
-
-```yaml
-name: Issue Comment
-
-on:
- issue_comment:
- types:
- - created
-
-jobs:
- approve:
- name: Approve Request
- runs-on: ubuntu-latest
-
- # Only run when the following conditions are true:
- # - The issue has the `issueops:new-repository` label
- # - The issue has the `issueops:validated` label
- # - The issue does not have the `issueops:approved` label
- # - The issue is open
- if: |
- contains(github.event.issue.labels.*.name, 'issueops:new-repository') &&
- contains(github.event.issue.labels.*.name, 'issueops:validated') &&
- contains(github.event.issue.labels.*.name, 'issueops:approved') == false &&
- github.event.issue.state == 'open'
-
- steps:
- # ...
-
- deny:
- name: Deny Request
- runs-on: ubuntu-latest
-
- # Only run when the following conditions are true:
- # - The issue has the `issueops:new-repository` label
- # - The issue has the `issueops:validated` label
- # - The issue does not have the `issueops:approved` label
- # - The issue is open
- if: |
- contains(github.event.issue.labels.*.name, 'issueops:new-repository') &&
- contains(github.event.issue.labels.*.name, 'issueops:validated') &&
- contains(github.event.issue.labels.*.name, 'issueops:approved') == false &&
- github.event.issue.state == 'open'
-
- steps:
- # ...
-```
-
-This seems like duplication of the same checks. Plus, we haven't followed our
-own rule: **Validate Early. Validate Often.** Instead, lets move this to a
-separate job that re-runs validation checks.
-
-```yaml
-name: Issue Comment
-
-on:
- issue_comment:
- types:
- - created
-
-jobs:
- validate:
- name: Validate Request
- runs-on: ubuntu-latest
-
- # Only run when the following conditions are true:
- # - The issue has the `issueops:new-repository` label
- # - The issue has the `issueops:validated` label
- # - The issue does not have the `issueops:approved` label
- # - The issue is open
- if: |
- contains(github.event.issue.labels.*.name, 'issueops:new-repository') &&
- contains(github.event.issue.labels.*.name, 'issueops:validated') &&
- contains(github.event.issue.labels.*.name, 'issueops:approved') == false &&
- github.event.issue.state == 'open'
-
- permissions:
- contents: read
- id-token: write
- issues: write
-
- outputs:
- request: ${{ steps.parse.outputs.request }}
-
- steps:
- - name: Remove Labels
- id: remove-label
- uses: issue-ops/labeler@vX.X.X
- with:
- action: remove
- issue_number: ${{ github.event.issue.number }}
- labels: |
- issueops:validated
- issueops:submitted
-
- - name: Get App Token
- id: token
- uses: actions/create-github-app-token@vX.X.X
- with:
- app_id: ${{ secrets.MY_GITHUB_APP_ID }}
- private_key: ${{ secrets.MY_GITHUB_APP_PEM }}
- owner: ${{ github.repository_owner }}
-
- - name: Checkout
- id: checkout
- uses: actions/checkout@vX.X.X
-
- - name: Setup Node.js
- id: setup-node
- uses: actions/setup-node@vX.X.X
- with:
- node-version-file: .node-version
- cache: npm
-
- - name: Install Packages
- id: npm
- run: npm ci
-
- - name: Parse Issue
- id: parse
- uses: issue-ops/parser@vX.X.X
- with:
- body: ${{ github.event.issue.body }}
- issue-form-template: new-repository-request.yml
-
- - name: Validate Issue
- id: validate
- uses: issue-ops/validator@vX.X.X
- with:
- issue-form-template: new-repository-request.yml
- github-token: ${{ steps.token.outputs.token }}
- parsed-issue-body: ${{ steps.parse.outputs.json }}
-
- - if: ${{ steps.validate.outputs.result == 'success' }}
- name: Add Validated Label
- id: add-label
- uses: issue-ops/labeler@vX.X.X
- with:
- action: add
- issue_number: ${{ github.event.issue.number }}
- labels: |
- issueops:validated
-
- approve:
- name: Approve Request
- runs-on: ubuntu-latest
-
- # Only run after validation has completed.
- needs: validate
-
- steps:
- # ...
-
- deny:
- name: Deny Request
- runs-on: ubuntu-latest
-
- # Only run after validation has completed.
- needs: validate
-
- steps:
- # ...
-```
-
-With this workflow, we know that the request has been validated before we handle
-any approval or denial. This is a good example of **Validate Early. Validate
-Often.**
-
-## Next steps
-
-Depending on if the request is approved or denied, you may want to take further
-actions. For example, if the request is approved, you could create the
-repository, add a comment to the issue, and close it as completed. On the other
-hand, if the request is denied, you could close the issue as not planned.
-
-Continue to the [approve](/states-and-transitions/approve) or
-[deny](/states-and-transitions/deny) sections to learn more.
diff --git a/docs/content/states-and-transitions/validate.mdx b/docs/content/states-and-transitions/validate.mdx
deleted file mode 100644
index 0ac16b85..00000000
--- a/docs/content/states-and-transitions/validate.mdx
+++ /dev/null
@@ -1,464 +0,0 @@
----
-title: Validate
-description: Validate Early. Validate Often.
-status: Alpha
----
-
-export { Layout as default } from '@issue-ops/gatsby-theme-doctocat-typescript'
-import Alert from '@mui/material/Alert'
-import Paper from '@mui/material/Paper'
-import Table from '@mui/material/Table'
-import TableBody from '@mui/material/TableBody'
-import TableCell from '@mui/material/TableCell'
-import TableContainer from '@mui/material/TableContainer'
-import TableHead from '@mui/material/TableHead'
-import TableRow from '@mui/material/TableRow'
-
-## Overview
-
-Once an issue has been parsed, it can be validated against any rules that you
-require. When used in public repositories, issue form templates do enforce some
-[validation rules](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys)
-such as required fields, selection options, and more. However, you may have
-additional needs that apply to your specific use case. For example, if you are
-creating an IssueOps workflow for users to request membership to GitHub teams,
-the issue form template is not able to validate if a value provided by a user is
-in fact a team in your organization.
-
-The [`issue-ops/validator`](https://github.com/issue-ops/validator) action takes
-the parsed output of the issue body and validates it against the issue form
-template and any custom rules you define.
-
-
- After a request is initially validated, there is nothing stopping a user from
- editing the issue and submitting it with invalid inputs. You should run your
- validation logic any time the following events occur:
-
-{/* prettier-ignore */}
- - The issue is opened
- - The issue body is edited
- - The issue is reopened after being closed
- - The request is submitted for provisioning/creation
-
-
-### Basic validation
-
-The most basic validation compares each input field to the rules specified in
-your issue form template and, if any are violated, comments with an error
-message.
-
-```yaml
-- name: Validate Issue
- id: validate
- uses: issue-ops/validator@vX.X.X
- with:
- issue-form-template: example-request.yml
- parsed-issue-body: ${{ steps.parse.outputs.json }}
-```
-
-For example, if you have an input field for users to select the visibility of
-their new repository, you can specify that the field is required and only one of
-a list of options can be chosen.
-
-```yaml
-- type: dropdown
- id: visibility
- attributes:
- label: Repository Visibility
- description: The visibility of the repository.
- multiple: false
- options:
- - private
- - public
- validations:
- required: true
-```
-
-When run against an issue submitted with this template, the validator will
-comment on the issue with an error message if any of the following occur:
-
-- The field is empty
-- The field is missing from the issue body
-- An option other than `private` or `public` is present
-
-### Custom validation
-
-For each form field, you can also specify custom validation logic. This is done
-using several files in your repository:
-
-- The validator configuration file (`.github/validator/config.yml`)
-- One or more validator scripts (`.github/validator/.js`)
-
-#### Configuration file
-
-This file defines the mapping of validator scripts to form fields. For example,
-if your issue form has input fields named `Read Team` and `Write Team`, you can
-specify a validator script (`check_team_exists.js`) to run against those fields.
-
-```yaml
-validators:
- - field: read_team
- script: check_team_exists
- - field: write_team
- script: check_team_exists
-```
-
-#### Validator scripts
-
-
- If you want to run custom validators that access GitHub APIs, you will need to
- provide a value for the `github-token` input. This is a good scenario for
- GitHub App authentication!
-
-
-Validator scripts are run on the associated fields in the configuration file.
-The script must specify a default export of a function with the following
-behavior:
-
-- Accept inputs of the following types:
- - `string` (Input and Textarea)
- - `string[]` (Dropdown)
- - `{ label: string; required: boolean }` (Checkboxes)
-- Return `'success'` for successful validation
-- Return an error message (`string`) for unsuccessful validation
-
-The following is an example of a validator script that checks if a team exists.
-This can also be found in the
-[`issue-ops/validator` repository](https://github.com/issue-ops/validator/blob/main/.github/validator/team.js).
-
-```js
-module.exports = async (field) => {
- if (typeof field !== 'string') return 'Field type is invalid'
-
- const { getOctokit } = require('@actions/github')
- const core = require('@actions/core')
- const octokit = getOctokit(core.getInput('github-token', { required: true }))
-
- try {
- await octokit.rest.teams.getByName({
- org: process.env.ORGANIZATION ?? '',
- team_slug: field
- })
-
- core.info(`Team '${field}' exists`)
- return 'success'
- } catch (error) {
- if (error.status === 404) {
- core.error(`Team '${field}' does not exist`)
- return `Team '${field}' does not exist`
- }
- }
-}
-```
-
-## New repository request
-
-Recall from the issue form template that the new repository request expects the
-following inputs:
-
-
-
-
-
-Since the _Visibility_ and _Auto Init_ inputs must be one of several predefined
-values, they can be handled by basic validation. The other fields, however, must
-meet additional requirements:
-
-
-
-
-
- Field
- Requirement
-
-
-
-
- Repository Name
- Must not be an existing repository
-
-
- Read Team
- Must be a team in the organization
-
-
- Write Team
- Must be a team in the organization
-
-
- Topics
- Must be a list of 20 or fewer
-
-
-
- Each topic must be lowercase
-
-
-
- Each topic must be 50 or fewer characters
-
-
-
-
- Each topic must contain only letters, numbers, and hyphens
-
-
-
-
+
+
+
+ Do
+ Don't
+
+
+
+
+
+ Use GitHub Apps for accessing organization-level APIs
+
+
+
+
+
+
+
+ Use personal access tokens
+
+
+
+
+
+
Sensitive information
+
+
+
+ Do
+ Don't
+
+
+
+
+
+ Use issue forms inputs that accept references to sensitive
+ information in secure locations
+
+
+
+
+
+
+
+
+ Accept sensitive information directly in issues
+
+
+
+
+
+
+
Validation
+
+
+
+ Do
+ Don't
+
+
+
+
+
+ Validate issue and comment text at every step in the IssueOps
+ workflow
+
+
+
+
+
+
+
+
+ Rely on labels to determine if an issue has been validated or
+ approved
+
+
+
+
+
+
+ )
+}
diff --git a/src/app/introduction/issues-and-prs/page.tsx b/src/app/introduction/issues-and-prs/page.tsx
new file mode 100644
index 00000000..04ac896d
--- /dev/null
+++ b/src/app/introduction/issues-and-prs/page.tsx
@@ -0,0 +1,628 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { Card, CardContent } from '@/components/ui/card'
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel
+} from '@/components/ui/form'
+import { Input } from '@/components/ui/input'
+import { zodResolver } from '@hookform/resolvers/zod'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import { MarkGithubIcon, TagIcon } from '@primer/octicons-react'
+import { Avatar, Timeline } from '@primer/react'
+import { Info } from 'lucide-react'
+import Link from 'next/link'
+import { useForm } from 'react-hook-form'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+import { z } from 'zod'
+
+const formSchema = z.object({
+ teamName: z.string(),
+ title: z.string()
+})
+
+export default function Home() {
+ const form = useForm>({
+ resolver: zodResolver(formSchema)
+ })
+
+ return (
+
+
Issues and PRs
+
+
+ This page provides an overview of the different components that make up
+ issues and PRs, and includes information about how each component can be
+ used throughout an IssueOps workflow.
+
+
+
Issues
+
+
Issue permissions
+
+ Any user with read access to a repository can open an issue.
+
+
Issue structure
+
+
+
+
+
+ Component
+ Description
+
+
+
+
+ Title
+ Title of an issue
+
+
+ Body
+ Main content of an issue entered by a user
+
+
+ Assignees
+ User(s) responsible for resolving an issue
+
+
+ Labels
+ Short tags that can be applied to issues
+
+
+ Milestones
+ Groups for issues and PRs
+
+
+ Relations
+
+ Other issues and PRs that are related to this issue
+
+
+
+ Development
+ Branches or PRs linked to the issue
+
+
+ Projects
+ Projects that are tracking the issue
+
+
+ Participants
+ Users who have interacted with the issue
+
+
+ Timeline
+ Events that have occurred on the issue
+
+
+ Comments
+
+ Comments and replies that have been added to the issue
+
+
+
+ Reactions
+
+ Emoji reactions added to the issue and its comments
+
+
+
+
+
+
+
Issue templates vs. issue forms
+
+
+ Currently, GitHub supports both{' '}
+
+ issue templates
+ {' '}
+ and{' '}
+
+ issue forms
+
+ . When creating IssueOps workflows, the initial issue body is where you
+ will get a lot of the information you need to process the issue.
+ Depending on your use-case, issue templates may not result in the
+ desired format, since they allow users to overwrite or replace the
+ entire contents of the issue body during creation. Issue forms{' '}
+ require specific input formats and result in a more consistent output.
+
+
+
Title
+
+
+ The title of an issue is a short, concise description of the reason the
+ issue has been opened, such as a particular bug or piece of feedback.
+ Typically, the title is the first thing a user will enter when they open
+ an issue (or they may update it based on the initial title provided by
+ the issue form).
+
+
+
+ When creating an issue forms, the title can be used as a way to identify
+ the type of issue. For example, you can use a title like{' '}
+ [Request] Team Membership: TEAM_NAME to indicate that the
+ issue is a request to be added to a team. However, since this field can
+ be modified by users, it should not be used as a way to validate the
+ issue.
+
+
+
+ {dedent`
+ title: '[Request] Team Membership: TEAM_NAME'
+ `}
+
+
+
Body
+
+
+ The body of an issue is where your workflow will get most of the
+ information it needs to process the issue. When creating an issue form,
+ you can use the body to provide instructions to the user, and to collect
+ information from them. For example, you can use a markdown field to
+ provide instructions, and then use an input field to collect the name of
+ the team they would like to join.
+
+
+
+
+ Markdown
+
+ Any markdown-type fields in an issue form will not be
+ included in the issue body after it has been submitted by the user.
+
+
+
+
+ For information about the different types of fields that can be used,
+ see{' '}
+
+ Syntax for issue forms
+
+ .
+
+
+
Assignees
+
+
+ Assignees are users who are responsible for resolving an issue. If your
+ workflow involves a review process, you can use assignees to indicate
+ who is responsible for reviewing the issue. You can also use assignees
+ to indicate who is responsible for processing the issue when manual
+ tasks are involved.
+
+
+
+ {dedent`
+ assignees:
+ - octocat
+ - mona
+ `}
+
+
+
+
+ Issue vs. PR Assignees
+
+ Issues do not support team assignees, but PRs do!
+
+
+
+
Labels
+
+
+ Labels are a great way to control the flow of an issue through the
+ state(s) you've defined. Any time a issue is commented on or
+ updated, you can use labels to tell where in the flow it is currently,
+ and where it needs to go next.
+
+
+
+ {dedent`
+ labels:
+ - issueops:team-membership-request
+ `}
+
+
+
Milestones
+
+
+ If you have certain timelines or deadlines associated with your
+ workflow, you can use milestones to track them. Milestones are groups of
+ issues and pull requests that are tracked together. They can be used to
+ track:
+
+
+
+
Due date
+
Completion percentage
+
Open and closed issues and pull requests
+
+
+
+ An issue cannot be added automatically to a milestone using issue forms,
+ but you can use GitHub Actions to add it to a milestone after it has
+ been created. See{' '}
+
+ IssueOps Actions
+ {' '}
+ in the reference for more information.
+
+
+
Relations
+
+
+ When creating or commenting on issues, you can reference related issues
+ by using the # symbol followed by the issue number. For
+ example, if you want to reference issue 1 in another issue in the same
+ repository, you would type #1.
+
+
+
+ Relations may be useful when your workflow involves multiple issues. For
+ example, if you have a workflow that involves interaction with another
+ team, you can use relations to track the status of the other team's
+ issue.
+
+
+
Development
+
+
+ The development section of an issue is where you can track the branches
+ and pull requests that are associated with the issue. This can be useful
+ if your workflow involves creating branches or pull requests for the
+ user. For example, if you would like to create an IssueOps workflow for
+ users to create new repositories and you use an infrastructure as code
+ service such as Terraform, you may want to create a PR on the
+ user's behalf that includes the new repository definition. That
+ way, developers don't have to learn Terraform to get new
+ infrastructure, and operations teams can ensure all infrastructure is
+ created following their requirements.
+
+
+
Projects
+
+
+ GitHub Projects are dual-purpose when it comes to IssueOps. They can be
+ used to both track and change the state of an issue. This is especially
+ the case when your workflow involves manual steps that must be performed
+ by a human.
+
+
+
+ As a non-technical example, suppose you're planning Thanksgiving
+ dinner with your extended family. Everyone in the family is supposed to
+ suggest three dishes, prepare them, and bring them on Thanksgiving day.
+
+
+
+ You can open issues for each dish that needs to be prepared using an
+ issue form, and automatically assign them to your meal project.
+
+
+
+ {dedent`
+ projects:
+ - octo-repo/1
+ `}
+
+
+
+ Within your project, you can specify columns for the state of each dish
+ (e.g. New, Ingredients purchased,{' '}
+ Ready to cook, and Cooked).
+
+
+
+
+ Manual Interaction
+
+ Unfortunately, @mona can't cook (maybe one day!), so you'll
+ need to manually move the issues through the columns as they are
+ assigned and prepared. However, you can use the project to track the
+ state of each dish, and to communicate that state to the rest of the
+ family!
+
+
+
+
Projects
+
+
+ Participants are users who have interacted with an issue. This includes
+ the user who opened the issue as well as users who have commented on or
+ been assigned to the issue. You can use participants to track who has
+ interacted with an issue, and to communicate with them if needed.
+
+
+
Timeline
+
+
+ The timeline is a list of all of the events that have occurred on an
+ issue, starting from when it was first opened. Each timeline event
+ includes a timestamp, the origin of the event, and other useful
+ information.
+
+
+
+ The timeline is especially useful to verify information about an issue.
+ For example, if you have a workflow that requires validation of the
+ issue body, you can (and should!) use labels to mark the issue as
+ validated. However, what happens if a malicious user adds the label
+ manually? You can use the timeline to compare when the issue body was
+ last updated to when the validated label was added. If the label was
+ added before the issue body was updated, you can determine that the
+ label was added manually and re-run your validation logic.
+
+
+
+
+
+
+
+
+
+
+
+
+ ncalteen added
+
+ issueops:team-request 1 hour ago
+
+
+
+
+
+
+
+
+
+ github-actions added
+
+ issueops:validated 1 hour ago
+
+
+
+
+
+
+
+
Comments
+
+
+ Other than the issue body, comments are how a user will drive your
+ IssueOps flow. You should define keywords that your workflow looks for
+ to trigger certain actions. Suppose you have a workflow where a user can
+ create a new repository. After the issue has been validated, the user
+ can comment on the issue with a keyword such as .submit to
+ trigger the creation of their repo.
+
+
+
+ You can also use them to communicate information back to the user. For
+ example, if the issue body contains invalid or incorrect information,
+ you can reply to the issue stating what needs to be corrected. For
+ example, in the screenshot, you can see that a comment was added to the
+ issue because the request was missing information.
+
+
+
Reactions
+
+
+ Though they don't convey as much information as a comment, adding
+ reactions to issues and comments are a nice way to let the user know
+ that their input has been received and is being processed. If needed,
+ you can follow up with a comment when processing is complete.
+
+
+
Example issue form
+
+
Issue form template
+
+
+ {dedent`
+ name: Team Membership Request
+ description: Submit a request to be added to a GitHub Team
+ title: '[Request] Team Membership: TEAM_NAME'
+ labels:
+ - issueops:team-membership-request
+ assignees:
+ - octocat
+ - mona
+ projects:
+ - octo-repo/1
+
+ body:
+ - type: markdown
+ attributes:
+ value:
+ Welcome to GitHub! Please fill out the information below to request to
+ be added to a GitHub Team. Once submitted, your request will be reviewed
+ by the admin team. Once approved, you will be added automatically!
+ - type: input
+ id: name
+ attributes:
+ label: Team name
+ description: The name of the team you would like to join.
+ placeholder: octoteam
+ validations:
+ required: true
+ `}
+
+
+
Rendered output
+
+
+
+
+
+
+
+
+
Pull requests
+
+
+ Pull requests add extra features and metadata on top of issues. Many
+ GitHub APIs support interacting with both at the same time! These
+ additional features, along with examples of how to use them in IssueOps
+ workflows, are listed in the following sections.
+
+
+
Pull request permissions
+
+
+ In order to create a pull request, the required permissions will differ
+ based on the location of the branch you wish to merge.
+
+
+
+
+
+
+ Unlike issues, PRs support reviews and approvals out of the box. When
+ changes are ready to be merged, you can assign individuals or teams as
+ reviewers.{' '}
+
+ Branch protection
+ {' '}
+ can also be used to enforce required reviewers and other checks before a
+ PR can be merged.
+
+
+
+ When your IssueOps workflow includes changes to the contents of a
+ repository, using PRs instead of issues is a great option to enforce
+ specific approval settings without having to include additional
+ workflows for tracking approvals as comments.
+
+
+
Status checks
+
+
+ Status checks run any time a PR is created or updated. These can range
+ from code quality checks to security scans and more. You can use status
+ checks to ensure that the changes in a PR meet your organization's
+ standards before they are merged.
+
+
+
+ In an IssueOps workflow, there are two ways you can use status checks:
+ to validate the contents of the PR, and to validate the contents of the
+ issue.
+
+
+
+ Validation is a critical aspect to consider when designing your
+ workflow. If your workflow is best suited for PRs, status checks can be
+ used to run your validation workflow any time the PR is updated.
+ Combined with branch protection rules specifying required status checks,
+ you can ensure that validation rules pass before a PR can change states.
+
+
+
Deployments and Environments
+
+
+ When a GitHub Actions workflow runs that specifies an environment, a
+ deployment is created. Deployments track the successful/failed status of
+ a workflow run, and link it to the targeted environment.
+
+
+
+ A great example of an IssueOps workflow that uses PRs, deployments, and
+ environments is the branch deploy model. A detailed explanation can be
+ found in the{' '}
+
+ reference
+
+ .
+
+
+ )
+}
diff --git a/src/app/introduction/page.tsx b/src/app/introduction/page.tsx
new file mode 100644
index 00000000..55be4e8d
--- /dev/null
+++ b/src/app/introduction/page.tsx
@@ -0,0 +1,694 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle
+} from '@/components/ui/card'
+import { MermaidDiagram } from '@lightenna/react-mermaid-diagram'
+import Paper from '@mui/material/Paper'
+import Table from '@mui/material/Table'
+import TableBody from '@mui/material/TableBody'
+import TableCell from '@mui/material/TableCell'
+import TableContainer from '@mui/material/TableContainer'
+import TableHead from '@mui/material/TableHead'
+import TableRow from '@mui/material/TableRow'
+import { IssueOpenedIcon } from '@primer/octicons-react'
+import { StateLabel } from '@primer/react'
+import { Check, OctagonX, TriangleAlert } from 'lucide-react'
+import Link from 'next/link'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Issues and pull requests
+
+
+ In GitHub, a pull request (PR) can be interacted with in a lot of the
+ same ways as an issue. For example, the{' '}
+
+ List repository issues
+ {' '}
+ REST API will return both issues and PRs for a repository.
+
+
+
+ This means that many of the features of an issue are applicable to a PR.
+ However, PRs have some extra functionality that can also be used in an
+ IssueOps workflow. Depending on the use-case, you might want to select
+ one over the other. For example, if you want to use the review and
+ approval functionality for changes to repository contents, you'll
+ need to use a PR. If you want to use the{' '}
+
+ issue forms
+ {' '}
+ feature, you'll need to use an issue.
+
+
+
+ For more information on their structure and usage in IssueOps, see{' '}
+
+ Issues and PRs
+
+ .
+
+
+
IssueOps concept
+
+
+ Think of IssueOps as a{' '}
+
+ state diagram
+ {' '}
+ . An issue is the object that changes state in response to
+ specific events. As the object changes state, certain{' '}
+ actions may be performed as part of the transition{' '}
+ (provided any guard conditions are met). Once an end state{' '}
+ is reached, the issue is considered complete and can be closed.
+
+
+
State Diagrams
+
+
+ The following sections contain definitions and examples of common terms
+ used in state diagrams. These terms are used throughout this
+ documentation.
+
+
+
Action
+
+ An atomic task that is performed when a transition is taken.
+
+
+
+
+
+
+ @mona
+
+
+
+ @mona has invited you to collaborate
+
+
+
+
+
Event
+
+ An external occurrence that triggers a state change.
+
+
+
+
+
+
+ @mona
+
+
+ @octocat self-assigned this
+
+
+
+
Guard
+
+
+ A condition that is evaluated when a trigger event occurs. A transition
+ is taken only if all associated guard conditions are met.
+
+
+
State
+
+
+ A point in an object's lifecycle that satisfies certain
+ condition(s).
+
+
+
+ Open
+
+
+
Transition
+
+
+ A link between two states that, when traversed by an object, will cause
+ certain action(s) to be performed.
+
+
+
IssueOps workflow
+
+
+ In general, an IssueOps workflow will follow the same basic pattern:
+
+
+
+
+
+ A user opens an issue and provides information about a request
+
+
+ The issue is validated to ensure it contains the required
+ information
+
+
+ (Optional) Approval is requested from an authorized user or team
+
+
The request is processed and the issue is closed
+
+
+
+ Let's use a more practical example...
+
+
Example: GitHub team membership
+
+
+
+ User Story:
+ {' '}
+ As a developer, I should be able to request membership to various teams
+ and, if approved by administrators, be granted membership.
+
+
+
+ Suppose you are an admin of an organization and would like to reduce the
+ overhead of managing team membership. You can use IssueOps to build an
+ automated membership request and approval process.
+
+
+
+ We can assume the current, manual workflow looks something like this
+ when rendered as a state diagram.
+
+
+
+
+ Nodes
+
+ In state diagram format, nodes represent the state of an object (the
+ membership request), while transitions represent actions that are
+ taken as the object changes state.
+
+
+
+
+
+ Example State Diagram
+
+
+
+ {dedent`
+ stateDiagram-v2
+ 1 : Opened
+ 2 : Submitted
+ 3 : Approved
+ 4 : Denied
+ 5 : Closed
+ [*] --> 1
+ 1 --> 2 : Submit request
+ 2 --> 3 : Approve request
+ 2 --> 4 : Deny request
+ 3 --> 5 : Add to team
+ 4 --> 5 : Notify user
+ 5 --> [*]
+ `}
+
+
+
+
+
+ When creating an IssueOps workflow, you can use this diagram as a
+ starting point to determine what events should trigger state changes,
+ how to represent those events in issues, and what actions to take in
+ response to state changes.
+
+
+
Event triggers
+
+
+ In the membership request workflow, there are several events that
+ trigger a change in the request state:
+
+
+
+
A user submits a request
+
An admin approves a request
+
An admin denies a request
+
A user is added to a team
+
A user is notified
+
+
+
+ In GitHub, there are many ways to trigger events. For a full list, see{' '}
+
+ Events that trigger workflows
+
+ . Here, we will focus on the events that are most relevant to IssueOps.
+
+
+
Issues
+
+
+ Events related to issues seem like a good fit for IssueOps!
+ Issues are the entrypoint to the worflow. In particular, the issue being
+ opened. You can think of this as someone coming to you and saying
+ Can you add me to this team? Until this event occurs,
+ there's nothing to do!
+
+
+
+ However, this is not the only issue event that can be used in a
+ workflow. The following table lists other{' '}
+
+ issue events
+ {' '}
+ and example use-cases.
+
+
+
+
+
+
+ Event
+ Example
+
+
+
+
+
+ opened
+
+ Start a request workflow
+
+
+
+ edited
+
+ Re-validate a modified request
+
+
+
+ deleted
+
+ Cancel in-flight tasks for a request
+
+
+
+ transferred
+
+
+ Assign ownership of a request to a different team
+
+
+
+
+ pinned
+
+ Upgrade the severity/urgency of a request
+
+
+
+ unpinned
+
+ Downgrade the severity/urgency of a request
+
+
+
+ closed
+
+ End a request workflow
+
+
+
+ reopened
+
+ Restart a request workflow
+
+
+
+ assigned
+
+ Ping the assignee in Slack
+
+
+
+ unassigned
+
+ Ping the previous assignee in Slack
+
+
+
+ labeled
+
+ Track the current state of a request
+
+
+
+ unlabeled
+
+ Track the current state of a request
+
+
+
+ locked
+
+
+ See{' '}
+
+ locking conversations
+
+
+
+
+
+ unlocked
+
+
+ See{' '}
+
+ locking conversations
+
+
+
+
+
+ milestoned
+
+
+ Track requests by type to compare to team goals
+
+
+
+
+ demilestoned
+
+
+ Track requests by type to compare to team goals
+
+
+
+
+
+
+
+
+ Permissions
+
+ Access to{' '}
+
+ delete issues
+ {' '}
+ should be carefully controlled. If you delete an issue, you will lose
+ all of the information associated with it, including comments and
+ attachments. You will also lose this request in the history of the
+ repository.
+
+
+
+
Issue Comments
+
+
+ After an issue is opened, other events must take place that change the
+ state and drive it through the workflow. In the membership request
+ workflow, for example, commenting on an issue is a great way to handle
+ state changes such as an administrator approving or denying the request.
+
+
+
+
+ Approvals
+
+ A core difference between issues and PRs is that issues do not have a
+ built-in approval process. However, this can be implemented using
+ issue comments. For more information, see{' '}
+
+ Approvals
+
+ .
+
+
+
+
+ Currently there are only three{' '}
+
+ issue_comment
+ {' '}
+ events that can trigger workflows:
+
+
+
+
+ created
+
+
+ edited
+
+
+ deleted
+
+
+
+
+ In all three cases, the context of the comment should be taken
+ into account to determine how to transition the request state. For
+ example, if only authorized administrators are allowed to approve team
+ membership requests, how should an IssueOps workflow react if someone
+ else comments with approval?
+
+
+
+ All GitHub Actions workflow runs include important{' '}
+
+ context information
+ {' '}
+ that can be accessed by your workflow. The{' '}
+
+ issue_comment
+ {' '}
+ context can provide us with information to decide what actions to take,
+ if any. In our team membership workflow, we can get the user that
+ created the comment using the{' '}
+ github.event.comment.user.login property. We can then use
+ this to determine if the user is authorized to approve the request.
+
+
+
Labels
+
+
+ Labels are a great way to track the state of a request. You can think of
+ these as the nodes in a state diagram, while the transitions are the
+ actions that are taken as the request changes state. You can also use
+ labels to classify the types of requests when your repository supports
+ more than one IssueOps workflow. For example, in the membership request
+ workflow, you might have the following labels:
+
+
+
+
+
+
+ Label
+ Description
+
+
+
+
+
+ team-membership-request
+
+ The type of request
+
+
+
+ submitted
+
+
+ Requests that have been submitted and are pending review
+
+
+
+
+
+
+
+ Looking at this list, you may ask{' '}
+
+ why there aren't labels for approved,{' '}
+ denied, or closed states?
+ {' '}
+ These states don't have any transitions that do not lead to the
+ issue being closed. In other words, once a request is approved or
+ denied, the issue will always reach the closed{' '}
+ state, regardless of whether it was approved or denied. If this workflow
+ had more steps, such as requiring multiple approvals, additional states
+ would need to be tracked.
+
+
+
+ As with issue_comment events, there are only three{' '}
+
+ label
+ {' '}
+ events available:
+
+
+
+
+ created
+
+
+ edited
+
+
+ deleted
+
+
+
+
+ These, however, refer to the actual creation and modification of the
+ label itself, so they may not apply to your workflow. You will generally
+ use the issue {'=>'} labeled event instead.
+
+
+
+
+ Label Permissions
+
+ Anyone with access to open issues can also change labels! Labels are
+ good for state tracking, but should not be used to determine if a
+ request is valid! For more information, see the{' '}
+
+ Validate
+ {' '}
+ step.
+
+
+
+
GitHub features
+
+
+ You can leverage other GitHub features to dramatically increase the
+ value of IssueOps.
+
+
+
Secrets
+
+
+
+ Secrets
+ {' '}
+ let you store sensitive information at the organization, repository, or
+ environment level to share with GitHub Actions workflows. You can use
+ secrets to store information such as API keys, passwords, or tokens.
+ Secrets are encrypted and only exposed to runners at runtime. You can
+ use secrets to store information such as API keys, passwords, or tokens
+ that can be used to access external resources from your workflows.
+
+
+
Projects and milestones
+
+
+ Keeping track of requests, especially when you have an approval process
+ in place, is important.
+
+ Projects
+ {' '}
+ make it easy to track requests throughout their lifecycle. You can
+ automatically add issues as they are opened, and use lifecycle rules to
+ keep track of the state of requests without having to manually move them
+ around your project board.
+
+
+
+ You can also combine this with{' '}
+
+ Milestones
+ {' '}
+ to better organize issues and PRs. For example, if your IssueOps
+ repository includes workflows for multiple types of requests, you can
+ add issues for each request type to a corresponding milestone. That way
+ they are automatically categorized in your project.
+
+
+
+
+ Project insights
+ {' '}
+ give you a visual snapshot of how requests are being processed. You can
+ create custom graphs of to see when and how teams are using your
+ workflows.
+
+
+
GitHub Apps
+
+
+ One of the most important things to consider when creating workflows
+ that interact with the GitHub APIs is permissions. GitHub Actions
+ workflows can only interact with the repository in which they run. For
+ example, the default permissions do not allow GitHub Actions to manage
+ team membership. If you are building a workflow that interacts with
+ resources outside of the repository it is running in, you should
+ consider creating an organization-level{' '}
+
+ GitHub App
+ {' '}
+ and installing it in your IssueOps repository. That way, you can use the
+ permissions of the app to interact with other resources in your
+ organization.
+
+
+
+ For more information, see{' '}
+
+ GitHub App
+ {' '}
+ in the setup documentation.
+
+
+ )
+}
diff --git a/src/app/introduction/workflow-security/page.tsx b/src/app/introduction/workflow-security/page.tsx
new file mode 100644
index 00000000..6e395983
--- /dev/null
+++ b/src/app/introduction/workflow-security/page.tsx
@@ -0,0 +1,59 @@
+'use client'
+
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Workflow Security
+
+
+ The IssueOps model makes heavy use of the issue and{' '}
+ issue_comment
+ triggers in GitHub Actions workflows.
+
+
+
+ {dedent`
+ on:
+ issue_comment:
+ types:
+ - created
+ `}
+
+
+
+ These triggers will only act on workflow files in the default{' '}
+ branch of your repository. This means that pull requests cannot
+ introduce changes to your IssueOps workflows that would be run as part
+ of that PR (e.g. creating a workflow that dumps secrets to the logs).
+ Any changes to the workflow files can be protected with branch
+ protection rules to ensure only verified changes make it into your
+ default branch.
+
+
+
Workflow permissions
+
+
+ To further harden your workflow files, you should always restrict them
+ to the base permissions needed to run. For information about the
+ available permissions, see{' '}
+
+ Assigning permissions to jobs
+
+ .
+
+
+
+ Permissions can be assigned for the entire workflow, as well as for
+ individual jobs. If one job needs additional permissions, make sure to
+ scope them to that job only.
+
+
+ )
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
new file mode 100644
index 00000000..8369da61
--- /dev/null
+++ b/src/app/layout.tsx
@@ -0,0 +1,44 @@
+import { AppSidebar } from '@/components/app-sidebar'
+import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar'
+import type { Metadata } from 'next'
+import { Geist, Geist_Mono } from 'next/font/google'
+import './globals.css'
+
+const geistSans = Geist({
+ variable: '--font-geist-sans',
+ subsets: ['latin']
+})
+
+const geistMono = Geist_Mono({
+ variable: '--font-geist-mono',
+ subsets: ['latin']
+})
+
+export const metadata: Metadata = {
+ title: 'IssueOps Docs',
+ description: 'A one-stop shop for all things IssueOps'
+}
+
+export default function RootLayout({
+ children
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+ )
+}
diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx
new file mode 100644
index 00000000..780e4f39
--- /dev/null
+++ b/src/app/not-found.tsx
@@ -0,0 +1,16 @@
+'use client'
+
+import Image from 'next/image'
+import supportcat from '../public/img/supportcat.png'
+
+export default function Home() {
+ return (
+
+
404 - Page Not Found
+
+
+ Uh oh...this page doesn't exist!
+
+
+ )
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
new file mode 100644
index 00000000..6adc239f
--- /dev/null
+++ b/src/app/page.tsx
@@ -0,0 +1,175 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { Card, CardContent, CardHeader } from '@/components/ui/card'
+import {
+ Carousel,
+ CarouselContent,
+ CarouselItem,
+ CarouselNext,
+ CarouselPrevious
+} from '@/components/ui/carousel'
+import {
+ LockIcon,
+ PencilIcon,
+ SearchIcon,
+ ZapIcon
+} from '@primer/octicons-react'
+import { Construction, Terminal } from 'lucide-react'
+import Link from 'next/link'
+
+const carouselItems = [
+ {
+ icon: ZapIcon,
+ title: 'Event-driven',
+ description:
+ 'Any time a user interacts with an issue or PR, an event is triggered. These events can be used to trigger GitHub Actions workflows.'
+ },
+ {
+ icon: PencilIcon,
+ title: 'Customizable',
+ description:
+ 'Based on the event type and data provided, you can implement custom logic to perform virtually any task. If you can interact with it via an API, command-line tool, or script, you can probably build it with IssueOps.'
+ },
+ {
+ icon: SearchIcon,
+ title: 'Transparent',
+ description:
+ 'All actions taken on an issue are recorded in the issue timeline.'
+ },
+ {
+ icon: LockIcon,
+ title: 'Immutable',
+ description:
+ 'An issue or pull request creates an immutable record of the transaction, approvals, and actions that are taken. This follows GitHub\'s "everything has a URL" philosophy.'
+ }
+]
+
+export default function Home() {
+ return (
+
+
+ The one stop shop for all things IssueOps
+
+
+
+ If you landed on this page, you're probably trying to find the
+ answer to the question What is IssueOps? If so, you came to the
+ right place! The goal of this site is to provide education, best
+ practices, examples, and resources for building IssueOps workflows on
+ GitHub.
+
+
+
+
+ Under Construction
+
+ This site is a work in progress. If you have any feedback, please{' '}
+
+ open an issue!
+ {' '}
+ If you're interested in contributing, check out our{' '}
+
+ contribution guide.
+
+
+
+
+
What is IssueOps?
+
+
+ IssueOps is a loose collection of tools, workflows, and concepts that
+ can be applied to{' '}
+
+ GitHub Issues
+ {' '}
+ to drive a nearly limitless number of workflows. Like many of the other
+ "Ops" tools, (ChatOps, GitOps, and so on), IssueOps leverages
+ a friendly interface to drive behind-the-scenes automation. In this
+ case, issues and pull requests (PRs) are the interface, and GitHub
+ Actions is the automation engine.
+
+
+
+ IssueOps isn't just a DevOps tool! You can run anything from
+ complex CI/CD pipelines to a bed and breakfast reservation system. If
+ you can interact with it via an API, there's a good chance you can
+ build it with IssueOps!
+
+
+ {/* TODO: Animation of IssueOps example */}
+
+
Why should I use IssueOps?
+
+
+
+ {carouselItems.map((item, index) => (
+
+
+
+
+
+
{item.title}
+
+ {item.description}
+
+
+
+ ))}
+
+
+
+
+
+
How do I get started?
+
+
+ Check out the resources on this site to learn more about IssueOps and
+ how to build your own workflows.
+
+
+
+ If you're looking for inspiration and a practical demonstration,
+ check out{' '}
+
+ Bear Creek Honey Farm
+
+ ! This is a fictional bed and breakfast reservation system drive by
+ IssueOps workflows. The source code for this example can be found in the{' '}
+
+ issue-ops/bear-creek-honey-farm
+ {' '}
+ and{' '}
+
+ issue-ops/demo-reservation-action
+ {' '}
+ repositories.
+
+
+
+
+ Have a Cool Example?
+
+ If you have an interesting IssueOps project you'd like featured,
+ send us a PR!
+
+
+
+ )
+}
diff --git a/src/app/reference/branch-deployments/page.tsx b/src/app/reference/branch-deployments/page.tsx
new file mode 100644
index 00000000..45012ca0
--- /dev/null
+++ b/src/app/reference/branch-deployments/page.tsx
@@ -0,0 +1,52 @@
+'use client'
+
+import Link from 'next/link'
+
+export default function Home() {
+ return (
+
+
Branch Deployments
+
+
+ One interesting topic to include when talking about IssueOps is branch
+ deployments. At a high-level, branch deployments let you run and control
+ deployments from your PRs.
+
+
+
+ If you don't already know what they are, the easiest way to explain
+ them is to compare them to the traditional merge deploy model. In the
+ merge deploy model:
+
+
+
+
A developer creates a feature branch and commits changes.
+
The developer opens a PR to get feedback from others.
+
+ Once approved, the PR is merged and a deployment starts from the
+ main branch.
+
+
+
+
+ This works fine, but if there are bugs in the PR, you have to either
+ merge in fixes or revert the commits and redeploy. In the branch deploy
+ model, changes are deployed from the feature branch and validated before
+ being merged into the main branch. This ensures that
+ whatever is in main can be deployed at any time. If there
+ is a problem with the deployment from the feature branch, you can simply
+ redeploy main as-is.
+
+
+
+ For a detailed description of the branch-deploy model, see{' '}
+
+ github/branch-deploy
+
+ .
+
+
+ )
+}
diff --git a/src/app/reference/examples/page.tsx b/src/app/reference/examples/page.tsx
new file mode 100644
index 00000000..29e410a4
--- /dev/null
+++ b/src/app/reference/examples/page.tsx
@@ -0,0 +1,27 @@
+'use client'
+
+import Link from 'next/link'
+
+export default function Home() {
+ return (
+
+
Examples
+
+
+ Here you can find examples of IssueOps workflows and repos from the
+ developer community. If you have an example you'd like to share,
+ please open a PR to add it to this page!
+
+
+
+
+
+ Create Blog Posts from Issues
+
+
+
+
+ )
+}
diff --git a/src/app/reference/issueops-actions/page.tsx b/src/app/reference/issueops-actions/page.tsx
new file mode 100644
index 00000000..5f0cec32
--- /dev/null
+++ b/src/app/reference/issueops-actions/page.tsx
@@ -0,0 +1,122 @@
+'use client'
+
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import Link from 'next/link'
+
+export default function Home() {
+ return (
+
+
IssueOps Actions
+
+
+ This page contains a list of useful actions for IssueOps workflows. If
+ you know of any, feel free to submit a PR to add it to the list!
+
+
+
+
+ )
+}
diff --git a/src/app/setup/comment-workflow/page.tsx b/src/app/setup/comment-workflow/page.tsx
new file mode 100644
index 00000000..6cb49029
--- /dev/null
+++ b/src/app/setup/comment-workflow/page.tsx
@@ -0,0 +1,678 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { Card, CardContent } from '@/components/ui/card'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import { CircleCheckBig, Info } from 'lucide-react'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Comment Workflow
+
+
+ After the issue has been opened and any initial processing has been run,
+ the comment workflow becomes the main driver of the rest of the process.
+ This workflow is triggered by users commenting on issues and will do any
+ further processing throughout the lifecycle of the issue.
+
+
+
Event triggers
+
+
+ The comment workflow should, at minimum, be triggered by creation of new
+ comments. The trigger also supports editing and deleting comments, which
+ may be useful for your use-case.
+
+
+
+ {dedent`
+ on:
+ issue_comment:
+ types:
+ - created
+ `}
+
+
+
+ The flexibility with the issue_comment trigger lies in the
+ comments themselves. You can take a limitless number of actions based on
+ user input! Be careful to not make your workflow too complex.
+ Otherwise, parsing comments becomes particularly challenging.
+
+
+
+
+
+ With great power comes great responsibility!
+
+
+
+
+
+ The issue_comment trigger may seem misleading. This trigger
+ applies to comments on both issues and PRs. If you want to trigger
+ workflows on comments that are part of a PR review, use the{' '}
+ pull_request_comment trigger instead.
+
+
+
Commands
+
+
+ Good IssueOps workflows make use of commands to trigger actions.
+ These commands are typically prefixed with a symbol, such as{' '}
+ . or /, and are descriptive of the action that
+ will be taken when the command is processed. In general, any workflow
+ that involves processing comments should start by looking for a specific
+ command being run.
+
+
+
+
+
+
+
+ The examples you will see throughout this documentation make heavy use
+ of the{' '}
+
+ github/command
+ {' '}
+ action. This action makes it easy to define your actions, who can run
+ them, and what happens when they are run.
+
+
+
+ The following code block shows a basic implementation of this action as
+ part of a IssueOps workflow to lint a pull request. In this example, the{' '}
+ Lint Command step will run any time a user comments with{' '}
+ .lint on a PR.
+
+
+
+ {dedent`
+ name: IssueOps Linter
+
+ on:
+ issue_comment:
+ types:
+ - created
+
+ jobs:
+ lint:
+ name: Lint Codebase
+ runs-on: ubuntu-latest
+
+ # Only run on PR comments, not issue comments
+ if: \${{ github.event.pull_request }}
+
+ # Minimum required permissions for the \`github/command\` action
+ permissions:
+ pull-requests: write
+ issues: write
+ checks: read
+
+ steps:
+ - name: Lint Command
+ id: command
+ uses: github/command@vX.X.X
+ with:
+ command: .lint
+
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Checkout
+ id: checkout
+ uses: actions/checkout@vX.X.X
+
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Run Linter
+ id: run-linter
+ run: npm run lint
+ `}
+
+
+
+ As you can see, the Checkout and Run Linter{' '}
+ steps only proceed if the Lint Command step's{' '}
+ continue output is 'true'. The{' '}
+ github/command action provides the continue{' '}
+ output to act as a gate for the rest of the workflow.
+
+
+
+ The high-level flow of the github/command action is:
+
+
+
+
+ Check the comment body for the command keyword (.lint)
+
+
Add a reaction to the comment to indicate it was received
+
+ Confirm the command is allowed to run
+
+
The user is authorized to run the command
+
Required checks have passed
+
Required reviews have been submitted
+
+
+
Collect any arguments passed to the command
+
+
+
Workflow steps
+
+
+ Most comment workflows can be broken down into the following steps.
+ Depending on your workflow, some of these may not be required.
+
+
+
+
Parse and validate the command and input(s)
+
Parse and validate the issue body
+
Check the current state
+
Check the user's permissions
+
Process the command
+
Update the issue state
+
Provide feedback to the user
+
+
+
+ Parse and validate the command and input(s)
+
+
+
+ Depending on your workflow, you may need users to be able to provide
+ additional inputs in their comments. For example, you may want to allow
+ users to specify a specific branch to lint, or a specific file to run
+ tests on. Input arguments can also be passed into the comment body as
+ part of a command.
+
+
+
+ The github/command action can be extended to support input
+ parameters. Parameters must be added after the separator specified by
+ the param_separator argument (default: |).
+ Suppose you want to also allow users to provide a branch name to run
+ linting on. Users would enter a comment like this:
+
+
+
+ {dedent`
+ .lint | main
+ `}
+
+
+
+ Within your workflow, you would need to parse the parameter value and
+ use it to checkout the correct branch:
+
+
+
+ {dedent`
+ name: IssueOps Linter
+
+ on:
+ issue_comment:
+ types:
+ - created
+
+ jobs:
+ lint:
+ name: Lint Codebase
+ runs-on: ubuntu-latest
+
+ # Only run on PR comments, not issue comments
+ if: \${{ github.event.pull_request }}
+
+ # Minimum required permissions for the \`github/command\` action
+ permissions:
+ pull-requests: write
+ issues: write
+ checks: read
+
+ steps:
+ - name: Lint Command
+ id: command
+ uses: github/command@vX.X.X
+ with:
+ command: .lint
+ param_separator: '|' # This is the default value
+
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Checkout
+ id: checkout
+ uses: actions/checkout@vX.X.X
+ with:
+ ref: \${{ steps.command.outputs.params }}
+
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Run Linter
+ id: run-linter
+ run: npm run lint
+ `}
+
+
+
+
+ Multiple Parameters
+
+ The params output is a string, not an array or object. If
+ you need to pass multiple parameters, you will need to include
+ additional logic for parsing the string.
+
+
+
+
Parse and validate the issue body
+
+
+
+
+
+
+
+ Validate Early
+
+
+
+ Validate Often
+
+
+
+
+
+
+ Any time you interact with an issue, make sure to validate the body!
+ Users can edit the issue body at any time, so it's important to
+ make sure you're working with the latest information. The{' '}
+
+ issue-ops/parser
+ {' '}
+ and{' '}
+
+ issue-ops/validator
+ {' '}
+ actions can take care of this for you. All you need to do is make sure
+ they are included in your comment processing workflows.
+
+
+
+ {dedent`
+ steps:
+ - name: Parse Issue Body
+ id: parse
+ uses: issue-ops/parser@vX.X.X
+ with:
+ body: \${{ github.event.issue.body }}
+ issue-form-template: my-issue-form.yml
+
+ - name: Validate Issue Body
+ id: validate
+ uses: issue-ops/validator@vX.X.X
+ with:
+ issue-form-template: my-issue-form.yml
+ issue-number: \${{ github.event.issue.number }}
+ parsed-issue-body: \${{ steps.parse.outputs.json }}
+ `}
+
+
+
Check the current state
+
+
+ As an issue is processed, it will move through a series of{' '}
+
+ states
+
+ . The current state of an issue can be tracked via labels.
+
+
+
+ For example, suppose you have a workflow that requires users to submit
+ their request after is has been validated and confirmed. You could use
+ the following logic to check if the issue has already been submitted.
+ That way, the processing that would transition the issue from
+ validated to submitted state does not run
+ again.
+
+
+
+ {dedent`
+ # This will only run if the request has already been submitted.
+ if: contains(github.event.issue.labels.*.name, 'issueops:submitted') == true
+
+ steps:
+ - name: Post Comment
+ id: comment
+ uses: peter-evans/create-or-update-comment@vX.X.X
+ with:
+ issue-number: \${{ github.event.issue.number }}
+ body: |
+ ':clock1: It looks like this issue has already been submitted. Sit tight!'
+ `}
+
+
+
+
+ Label Changes
+
+ Labels can be edited at any time! You want to consider checking if the
+ state indicated by the issue labels matches the expected state of the
+ issue.
+
+
+
+
Check the user's permissions
+
+
+ By default, any user with read access to a repository can open issues
+ and add comments. If your IssueOps workflow involves certain authorized
+ users being able to perform actions (e.g. approving or denying
+ requests), this can be a problem! Instead, you should use the
+ allowlist option in the github/command action
+ to restrict who has the ability to run certain commands.
+
+
+
+ For example, suppose you want to only allow certain administrators to
+ approve requests for new repositories. The following step would only
+ allow @octocat and @mona to run the .approve command. Any
+ other users who comment on the issue with .approve will not
+ be able to push the request through to the next state.
+
+
+
+ {dedent`
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ command: .approve
+ allowlist: octocat,mona
+ `}
+
+
+
+ If you want to use teams to control access, you will also need to
+ provide a token with read:org scope for the{' '}
+ allowlist_pat property. For information on creating a
+ GitHub App and using it to generate a token in a GitHub Actions
+ workflow, see{' '}
+
+ GitHub App setup
+
+ .
+
+
+
+ {dedent`
+ - uses: actions/create-github-app-token@vX.X.X
+ id: token
+ with:
+ app_id: \${{ secrets.MY_GITHUB_APP_ID }}
+ private_key: \${{ secrets.MY_GITHUB_APP_PEM }}
+ owner: \${{ github.repository_owner }}
+
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ command: .approve
+ allowlist: octo-org/admin-team
+ allowlist_pat: \${{ steps.token.outputs.token }}
+ `}
+
+
+
+ Alternatively, you can restrict access to specific roles in your
+ IssueOps repository using the permissions property. By
+ default, anyone with write, maintain, or administrator access to the
+ repository can run commands.
+
+
+
+ {dedent`
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ command: .approve
+ permissions: admin,maintain # Restrict users with write access
+ `}
+
+
+
Process the command
+
+
+ This is where the magic happens! You can use any series of actions to
+ process your request. For example, the{' '}
+
+ actions/github-script
+ {' '}
+ action is a great choice for interacting with GitHub APIs.
+
+
+
+ Make sure to gate these steps using the continue output
+ from the
+ github/command action!
+
+
+
+ {dedent`
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Add User to Team
+ id: add-user
+ uses: actions/github-script@vX.X.X
+ with:
+ token: \${{ steps.token.outputs.token }}
+ script: |
+ const request = JSON.parse('\${{ steps.parse.outputs.json }}')
+
+ await github.rest.teams.addOrUpdateMembershipForUserInOrg({
+ org: context.repo.owner,
+ team_slug: request.team_name,
+ username: '\${{ github.event.issue.user.login }}',
+ role: 'member'
+ })
+ `}
+
+
+
Update the issue state
+
+
+ Once any processing has been completed, the issue can be transitioned to
+ the next state. This is done by adding or removing labels from the
+ issue.
+
+
+
+ For example, suppose you have a workflow that requires users to submit
+ their request after is has been validated and confirmed. You can use the{' '}
+
+ issue-ops/labeler
+ {' '}
+ action to transition the issue from validated to{' '}
+ submitted state.
+
+
+
+ {dedent`
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Set Submitted State
+ id: set-submitted
+ uses: issue-ops/labeler@vX.X.X
+ with:
+ action: add
+ issue_number: \${{ github.event.issue.number }}
+ labels: |
+ issueops:submitted
+ `}
+
+
+
Provide feedback to the user
+
+
+ Any time processing is done on an issue, its helpful to let users know:
+
+
+
+
The command has been received
+
The command is being processed
+
The outcome of the processing
+
+
+
+ The github/command action takes care of the first part for
+ you. It will automatically add a reaction to any comments that contain a
+ command.
+
+
+
+ {dedent`
+ - uses: github/command@vX.X.X
+ id: command
+ with:
+ command: .lint
+ reaction: eyes
+ `}
+
+
+ Any of the following reactions can be added:
+
+
+
+
+
+
+ After the command has been received, adding comments to the issue to
+ indicate work is being done is a great way to keep users informed. Once
+ processing is complete, a comment can be added to the issue to indicate
+ the outcome.
+
+
+
+ {dedent`
+ - if: \${{ steps.command.outputs.continue == 'true' }}
+ name: Add Complete Comment
+ id: comment-complete
+ uses: peter-evans/create-or-update-comment@vX.X.X
+ with:
+ issue-number: \${{ github.event.issue.number }}
+ body: |
+ Your request has been processed! Here are the details of the request:
+
+ - **Team:** \${{ steps.parse.outputs.json.team_name }}
+ - **Role:** \`member\`
+ `}
+
+
+ )
+}
diff --git a/src/app/setup/github-app/page.tsx b/src/app/setup/github-app/page.tsx
new file mode 100644
index 00000000..36301ca9
--- /dev/null
+++ b/src/app/setup/github-app/page.tsx
@@ -0,0 +1,381 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import { Ban, CircleAlert, InfoIcon, Lock, Shield } from 'lucide-react'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
GitHub App
+
+
+ If your IssueOps workflow requires access to anything outside of the
+ repository it is running in, you will need to provide it with a token.
+ This token is used to authenticate with the GitHub API and should be
+ scoped to the minimum permissions needed to do the job. Tokens can be
+ provided two ways:
+
+
+
+
+
+ Personal access tokens (PAT)
+
+
+
+
+ GitHub App installation tokens
+
+
+
+
+
+ Since PATs are scoped to a single user, they are not recommended for use
+ in IssueOps workflows. GitHub Apps are a better choice because they can
+ be scoped to a repository or organization to provide access to the APIs
+ you need.
+
+
+
+
+ Enterprise Tokens
+
+ GitHub Apps cannot currently be created at the enterprise level for
+ access to administrative APIs. If you need access to these APIs, you
+ will need to use a PAT. In these cases, creating a "machine
+ user" account is recommended over a personal account.
+
+
+
+
Ownership
+
+
+ When creating a GitHub App, you have the option to specify your personal
+ account or an organization as the owner. Choosing an organization as the
+ owner allows you to grant access to multiple repositories in the
+ organization and simplifies permissions management.
+
+
+
Setup
+
+
Create a GitHub App
+
+
+ For instructions on how to create a GitHub App, see{' '}
+
+ Creating GitHub Apps
+
+ .
+
+
+
+ The following settings are a good starting point for IssueOps workflows:
+
+
+
+
+
+
+ Setting
+ Value
+
+
+
+
+ Name
+
+ A clear name that describes its purpose and permissions
+
+
+
+ Description
+
+ A description of what the app does and what it can access
+
+
+
+ Homepage URL
+
+ The URL to the repository with your IssueOps code
+
+
+
+ Webhook
+ Disable webhooks
+
+
+ Permissions
+
+ Select the minimum permissions needed for your workflow
+
+
+
+
+
+
+
Create a private key
+
+
+ For instructions on how to create a private key, see{' '}
+
+ Managing private keys for GitHub Apps
+
+ .
+
+
+
+
+ Key Storage
+
+ Make sure to save the private key in a secure location!
+
+
+
+
Create GitHub Actions secrets
+
+
+ After creating your GitHub App, you will need to create secrets that
+ your IssueOps workflows can use to authenticate with the GitHub API. You
+ can create these at the organization, repository, or environment level
+ depending on your needs.
+
+
+
+ You will need to create the following secrets. Make sure to note the
+ names you give them as you will need to reference them in your
+ workflows.
+
+
+
+
+
+
+ Name
+ Description
+
+
+
+
+ App ID
+ The ID of your GitHub App
+
+
+ Private Key
+ The private key you created
+
+
+
+
+
+
+
+ App ID
+
+ The GitHub App ID is not a sensitive value and can be stored as a
+ variable instead of a secret. It can be found on the settings page for
+ your GitHub App.
+
+
+
+
+ For instructions on how to create secrets, see the following links:
+
+
+
+
+
+ Creating secrets for a repository
+
+
+
+
+ Creating secrets for an environment
+
+
+
+
+ Creating secrets for an organization
+
+
+
+
+
Usage
+
+
Update the workflow permissions
+
+
+ In any workflow that needs to authenticate as a GitHub App, the
+ following permissions must be specified at the workflow or job
+ level.
+
+
+
+ {dedent`
+ permissions:
+ contents: read
+ id-token: write
+ `}
+
+
+
+ Generate the installation access token
+
+
+
+ There are various examples and open source actions available to create
+ installation access tokens for GitHub Actions workflows. In this
+ documentation, we will use the{' '}
+
+ actions/create-github-app-token
+ {' '}
+ action.
+
+
+
+ Within any workflow job that needs to authenticate as your GitHub App,
+ you will need to include the following step.
+
+
+
+ {dedent`
+ steps:
+ - uses: actions/create-github-app-token@vX.X.X
+ id: token
+ with:
+ app_id: \${{ secrets.MY_GITHUB_APP_ID }}
+ private_key: \${{ secrets.MY_GITHUB_APP_PEM }}
+ owner: \${{ github.repository_owner }}
+ `}
+
+
+ Make sure to update the following:
+
+
+
+ Set the version (vX.X.X) of the action to the latest
+ published version.
+
+
+ Update the secret names to match the ones you created previously.
+
+
+
+
+
+ Owner
+
+ In the previous example, the owner property is set to the
+ owner of the repository where this workflow is defined. If your GitHub
+ App is installed under another owner, you will need to specify that
+ instead.
+
+
+
+
Use the token in your workflow
+
+
+ Now that the token is being generated, you can reference it in your
+ workflows as an output from the token generation step! This can be
+ referenced as {`\${{ steps..outputs.token }}`}{' '}
+ (e.g. {`\${{ steps.token.outputs.token }}`}).
+
+
+
+ {dedent`
+ steps:
+ - uses: actions/github-script@vX.X.X
+ id: create-org-project
+ with:
+ github-token: \${{ steps.token.outputs.token }}
+ script: |
+ await github.rest.projects.createForOrg({
+ org: 'octo-org',
+ name: 'My awesome project'
+ })
+ `}
+
+
+
+
+ Token Usage
+
+ Make sure to check which steps in your workflow will need to use the
+ GitHub App token versus the workflow token. For example, if you add
+ the issues: write permission to your workflow, you do not
+ need to use the GitHub App token to update issues in the same{' '}
+ repository as your workflows. However, you will need to use the GitHub
+ App token to update issues in other repositories!
+
+
+
+
Example
+
+
+ The following can be used as a starting point for your own workflows.
+ Make sure to update secret names and action versions.
+
+
+
+ {dedent`
+ name: Example Workflow
+
+ # This workflow runs any time an issue is opened or edited.
+ on:
+ issues:
+ types:
+ - opened
+ - edited
+
+ jobs:
+ example-job:
+ name: Example Job
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ id-token: write
+
+ steps:
+ # Get the GitHub App installation access token.
+ - uses: actions/create-github-app-token@vX.X.X
+ id: token
+ with:
+ app_id: \${{ secrets.MY_GITHUB_APP_ID }}
+ private_key: \${{ secrets.MY_GITHUB_APP_PEM }}
+ owner: \${{ github.repository_owner }}
+
+ - run: echo "Add your custom steps here!"
+ `}
+
+
+ )
+}
diff --git a/src/app/setup/issue-form/page.tsx b/src/app/setup/issue-form/page.tsx
new file mode 100644
index 00000000..bf2751f5
--- /dev/null
+++ b/src/app/setup/issue-form/page.tsx
@@ -0,0 +1,198 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { Info } from 'lucide-react'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Issue Form
+
+
+ The first interaction point users will have with your IssueOps workflow
+ is the issue itself. This is where they will provide the information
+ needed to kick off the workflow. Because of this, it is important to
+ make sure that the issue form template is set up to capture all the
+ information you need to get started.
+
+
+
+ For more information on the supported options, see{' '}
+
+ Syntax for issue forms
+
+ .
+
+
+
Top-level syntax
+
+
+ The top-level syntax of the issue form template is used to define the
+ title and description that users will see when they go to create an
+ issue in your repository. From a usability perspective, make sure to
+ include a description and title that clearly explains what the user is
+ requesting and what will happen once they submit their issue.
+
+
+
+
+ Labels and Projects
+
+ Make sure to label your issues and assign them to projects!
+
+
+
+
+ {dedent`
+ name: Create a new repository
+ description: |
+ Once opened, this issue will cause a new GitHub repository to be created in
+ the \`octocat\` organization. You will be granted access as a collaborator so
+ you can build something awesome!
+ labels:
+ - issueops:new-repository
+ projects:
+ - octocat/123
+ body:
+ # ...
+ `}
+
+
+
Body syntax
+
+
+ The body property is where you specify the inputs and any
+ other supporting information you need to collect from the user. Its
+ important to make sure to collect all the information you need to get
+ started, but also to make sure that the form is not too long or
+ complicated.
+
+
+
+
+ Labels and Projects
+
+ If there's a way you can calculate certain information, consider
+ doing that instead of asking the user to provide additional inputs.
+ For example, you can get the user's GitHub username from the
+ issue metadata ({`\${{ github.event.issue.user.login }}`}
+ ) instead of asking them to provide it.
+
+
+
+
+ As you are drafting your issue form template, think about the kind of
+ data you are requesting and the best format to use (both for user input
+ and for automated processing later).
+
+
+
+ This can be confusing, because once an issue form is submitted, all the
+ inputs look the same. Suppose you have the following issue form
+ template:
+
+
+
+ {dedent`
+ name: New Repo Request
+ description: Submit a request to create a new GitHub repository
+ title: '[Request] New Repository'
+ labels:
+ - issueops:new-repository
+
+ body:
+ # Markdown type fields are not included in the submitted issue body
+ - type: markdown
+ attributes:
+ value:
+ Welcome to GitHub! Please fill out the information below to request a
+ new repository. Once submitted, your request will be reviewed by the
+ IssueOps team. If approved, the repository will be created and you will
+ be notified via a comment on this issue.
+ - type: input
+ id: name
+ attributes:
+ label: Repository Name
+ description: The name of the repository you would like to create.
+ placeholder: octorepo
+ validations:
+ required: true
+ - type: dropdown
+ id: visibility
+ attributes:
+ label: Repository Visibility
+ description: The visibility of the repository.
+ multiple: false
+ options:
+ - private
+ - public
+ validations:
+ required: true
+ - type: dropdown
+ id: topics
+ attributes:
+ label: Repository Topics
+ description: The topics to add to the repository.
+ multiple: true
+ options:
+ - octocat
+ - issueops
+ - automation
+ validations:
+ required: true
+ - type: checkboxes
+ id: confirm
+ attributes:
+ label: Confirmation
+ description: Do you confirm this request?
+ options:
+ - label: 'Yes'
+ required: true
+ - label: 'No'
+ required: false
+ `}
+
+
+
+ When the user submits the issue form, it will have the following
+ Markdown format:
+
+
+
+ {dedent`
+ ### Repository Name
+
+ octorepo
+
+ ### Repository Visibility
+
+ public
+
+ ### Repository Topics
+
+ octocat, issueops
+
+ ### Confirmation
+
+ - [x] Yes
+ - [ ] No
+ `}
+
+
+
+ You can see that certain inputs look the same, but are actually
+ different types and, depending on their values, may be processed
+ differently.
+
+
+ )
+}
diff --git a/src/app/setup/issue-workflow/page.tsx b/src/app/setup/issue-workflow/page.tsx
new file mode 100644
index 00000000..48d6c01f
--- /dev/null
+++ b/src/app/setup/issue-workflow/page.tsx
@@ -0,0 +1,167 @@
+'use client'
+
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Issue Workflow
+
+
+ Once a user submits your issue form, its time for GitHub Actions to run
+ the show! The issue workflow is responsible for performing any initial
+ processing of the issue such as adding labels, validating the contents,
+ adding comments, etc. The following sections will walk through the core
+ structure of an issue workflow.
+
+
+
Event triggers
+
+
+ Most of the time, this workflow will only be run when an issue is opened
+ or edited, however there are some cases where you may want to run this
+ workflow when an issue is reopened.
+
+
+
+ {dedent`
+ on:
+ issues:
+ types:
+ - opened
+ - edited
+ - reopened
+ `}
+
+
+
Jobs
+
+
+ Different request types may have different inputs. For example, a new
+ repository request may have different inputs than a repository transfer
+ request. If you decide to create multiple jobs to parse different types
+ of requests in the same workflow, you can use labels to control which
+ jobs run for which types of requests.
+
+
+
+ You should also consider how you plan to handle processing of multiple
+ requests in the same workflow.
+
+
+
+ {dedent`
+ jobs:
+ new-repository-request:
+ name: New Repository Request
+ runs-on: ubuntu-latest
+
+ # Only run for issues with the \`issueops:new-repository\` label.
+ if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
+
+ team-membership-request:
+ name: Team Membership Request
+ runs-on: ubuntu-latest
+
+ # Only run for issues with the \`issueops:team-add\` label.
+ if: contains(github.event.issue.labels.*.name, 'issueops:team-add')
+ `}
+
+
+
+ Depending on the complexity of your workflow, you may want to isolate
+ each type of request to separate jobs entirely, or you may want to have
+ jobs that handle common tasks across multiple request types. For
+ example, if you have IssueOps workflows for adding and removing users
+ from a team, there's a good chance they both have the same input
+ data and perform the same validation steps. In this case, you may want
+ to create a job that handles the common tasks, and then have separate
+ jobs for the unique tasks.
+
+
+
+ {dedent`
+ jobs:
+ team-request:
+ name: Team Management Request
+ runs-on: ubuntu-latest
+
+ # Run this job for both request types
+ if: |
+ contains(github.event.issue.labels.*.name, 'issueops:team-add') ||
+ contains(github.event.issue.labels.*.name, 'issueops:team-remove')
+
+ outputs:
+ request: \${{ steps.parse.outputs.json }}
+
+ steps:
+ - name: Parse Issue
+ id: parse
+ uses: issue-ops/parser@vX.X.X
+ with:
+ body: \${{ github.event.issue.body }}
+ issue-form-template: team-add-remove-request.yml
+
+ - name: Validate Issue
+ id: validate
+ uses: issue-ops/validator@vX.X.X
+ with:
+ issue-form-template: team-add-remove-request.yml
+ parsed-issue-body: \${{ steps.parse.outputs.json }}
+
+ team-add:
+ name: Team Add Request
+ runs-on: ubuntu-latest
+
+ # Only run after the \`team-request\` job has completed
+ needs: team-request
+
+ # Only run for issues with the \`issueops:team-add\` label.
+ if: contains(github.event.issue.labels.*.name, 'issueops:team-add')
+
+ steps:
+ - name: Add User to Team
+ id: add
+ uses: actions/github-script@vX.X.X
+ with:
+ github-token: \${{ secrets.MY_TOKEN }}
+ script: |
+ const request = JSON.parse('\${{ needs.team-request.outputs.request }}')
+
+ await github.rest.teams.addOrUpdateMembershipForUserInOrg({
+ org: request.org,
+ team_slug: request.team,
+ username: request.user
+ })
+
+ team-remove:
+ name: Team Remove Request
+ runs-on: ubuntu-latest
+
+ # Only run after the \`team-request\` job has completed
+ needs: team-request
+
+ # Only run for issues with the \`issueops:team-remove\` label.
+ if: contains(github.event.issue.labels.*.name, 'issueops:team-remove')
+
+ steps:
+ - name: Remove User from Team
+ id: remove
+ uses: actions/github-script@vX.X.X
+ with:
+ github-token: \${{ secrets.MY_TOKEN }}
+ script: |
+ const request = JSON.parse('\${{ needs.team-request.outputs.request }}')
+
+ await github.rest.teams.removeMembershipForUserInOrg({
+ org: request.org,
+ team_slug: request.team,
+ username: request.user
+ })
+ `}
+
+
+ )
+}
diff --git a/src/app/setup/page.tsx b/src/app/setup/page.tsx
new file mode 100644
index 00000000..cda77eda
--- /dev/null
+++ b/src/app/setup/page.tsx
@@ -0,0 +1,55 @@
+'use client'
+
+import Link from 'next/link'
+
+export default function Home() {
+ return (
+
+
Setting up IssueOps
+
+
+ This section will walk through the end-to-end setup process for
+ configuring an IssueOps workflow. This includes setup and configuration
+ of the following:
+
+
+
+
+
+ Repository
+
+
+
+
+ GitHub App
+
+
+
+
+ Issue form
+
+
+
+
+ Issue workflow
+
+
+
+
+ Comment workflow
+
+
+
+
+ )
+}
diff --git a/src/app/setup/repository/page.tsx b/src/app/setup/repository/page.tsx
new file mode 100644
index 00000000..68d85746
--- /dev/null
+++ b/src/app/setup/repository/page.tsx
@@ -0,0 +1,334 @@
+'use client'
+
+import { Card, CardDescription, CardHeader } from '@/components/ui/card'
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Repository
+
+
+ This page outlines recommended configuration settings for IssueOps
+ repositories. For instructions on how to create a repository, see the{' '}
+
+ GitHub documentation
+ {' '}
+ .
+
+
+
Visibility
+
+
+ IssueOps works best when your repository is accessible to users who need
+ to submit requests. Depending on if the repository is owned by an
+ organization or a user account, you can set the visibility to one of the
+ following:
+
+
+
+
+
+
+
+ Alternatively, if you only want to allow specific users to submit
+ requests, you can set the visibility to private and add
+ those users as{' '}
+
+ collaborators
+ {' '}
+ .
+
+
+
Permissions
+
+
+ Users only need read access to open issues! Unless there is
+ a specific reason to do otherwise, you should only ever need to grant{' '}
+ read access.
+
+
+
+ The primary reason to grant write access is if your
+ IssueOps flow uses pull requests instead of issues, but only if you want
+ users to create pull requests from branches in the same{' '}
+ repository. As an alternative, you can allow forking of your repository
+ and users can create pull requests from their forked repository instead.
+
+
+
Branch protection
+
+
+
+ Branch protection rules
+ {' '}
+ are a good idea regardless of what your repository is being used for!
+ You should always protect your default branch (usually main
+ ) and any other branches that you want to prevent accidental changes to.
+
+
+
+ For an IssueOps repository, you should create a branch protection rule
+ for main that enables the following:
+
+
+
+
Require a pull request before merging
+
+ Require status checks to pass before merging (add any continuous
+ integration or testing workflows that you use)
+
+
Require branches to be up to date before merging
+
+ Require review from Code Owners (if your repository has a{' '}
+ CODEOWNERS file)
+
+
+
+
GitHub Actions
+
+
Fork pull request workflows
+
+
+ If your IssueOps workflow uses pull requests instead of issues, you must
+ be careful about the configuration of GitHub Actions and what
+ permissions are allowed for fork pull requests. The following settings
+ can be enabled for fork pull requests, with a description of the risks
+ involved.
+
+
+
+
+
+
+ Setting
+ Risk
+
+
+
+
+ Run workflows from fork pull requests
+
+ Forks will have read permissions to your repository
+
+
+
+
+ Send write tokens to workflows from fork pull requests
+
+
+ Forks will have write permissions to your repository
+
+
+
+
+ Send secrets and variables to workflows from fork pull requests
+
+
+ Forks will have access to your secrets and variables
+
+
+
+
+ Require approval for fork pull request workflows
+
+
+ Forks will not be able to run workflows until they are approved
+
+
+
+
+
+
+
+ As you can guess, the safest option is to not allow fork pull requests
+ to run workflows at all. However, this may not be practical for your
+ workflow. Here are some recommended settings:
+
+
+
+
+ Do
+ Don't
+
+
+
+
+
+ Document required permissions for contributors to run the
+ workflows themselves
+
+
+
+
+
+
+
+
+ Send write tokens to fork pull requests
+
+
+
+
+
+
+
+
+ Do
+ Don't
+
+
+
+
+
+ Document the required secrets and variables and how to generate
+ them
+
+
+
+
+
+
+
+
+ Send secrets and variables to workflows from fork pull requests
+
+
+
+
+
+
+
+ One alternative to consider is to "wrap" the creation of the
+ PR into part of your IssueOps flow. If the content of the PR will follow
+ a known format, you can use a GitHub Action to create the PR on behalf
+ of the user. This will allow you to remove the need to allow any GitHub
+ Actions access to fork pull requests.
+
+
+
Workflow permissions
+
+
+ In the repository settings, it is best to keep the base workflow
+ permissions limited to{' '}
+ Read repository contents and packages permissions. Within each
+ IssueOps workflow, you can increase the permissions as needed for
+ specific jobs.
+
+
+
Environments
+
+
+ If your IssueOps workflow involves deployments or interaction with
+ environments, you should consider adding enviroment-specific rules to
+ restrict deployments to only the main branch. A common
+ exception to this rule is if you are running IssueOps workflows from
+ pull requests, as these will be run from branches other than{' '}
+ main.
+
+
+
+ This is also a good opportunity to further restrict access to secrets
+ and variables by defining them at the environment level!
+
+
+
Other considerations
+
+
+ A few common questions and answers about repository setup. Most of the
+ time, the answer is "it depends!", but these are some things
+ to consider.
+
+
+
+ Multiple IssueOps workflows in one repository
+
+
+
+ There are some tradeoffs to consider when using one or multiple
+ repositories to host different IssueOps workflows. For example, suppose
+ you have the following workflows:
+
+
+
+
Team membership requests
+
New repository creation requests
+
+
+
+ If you use a single repository, one challenge you may run into is
+ ensuring that jobs for the team membership requests don't affect
+ new repository requests. This is where labels are particularly helpful!
+ You can use labels to scope jobs to specific requests.
+
+
+
+ {dedent`
+ name: Issue Opened/Edited
+
+ on:
+ issues:
+ types:
+ - opened
+ - edited
+
+ jobs:
+ new-repository-request:
+ name: New Repository Request
+ runs-on: ubuntu-latest
+
+ # Only run for issues with the \`issueops:new-repository\` label.
+ if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
+
+ team-membership-request:
+ name: Team Membership Request
+ runs-on: ubuntu-latest
+
+ # Only run for issues with the \`issueops:team-add\` label.
+ if: contains(github.event.issue.labels.*.name, 'issueops:team-add')
+ `}
+
+
+ )
+}
diff --git a/src/app/states-and-transitions/approve/page.tsx b/src/app/states-and-transitions/approve/page.tsx
new file mode 100644
index 00000000..248934db
--- /dev/null
+++ b/src/app/states-and-transitions/approve/page.tsx
@@ -0,0 +1,133 @@
+'use client'
+
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Approve
+
+
+ In the Approved state, we know that the issue has been
+ approved and we can begin processing it. This is one of the first states
+ in the workflow where we can perform an unguarded transition.
+
+
+
+ In our repository workflow, a request is transitioned to the{' '}
+ Approved state when an authorized user comments on the
+ request with .approve. However, immediately after reaching
+ this state, we know we can create the repository and close the issue
+ (moving it to the Closed state). This is called an{' '}
+ unguarded transition because there is no condition that must be
+ met before the transition occurs.
+
+
+
+ The actual implementation of this transition is up to you! There are a
+ few recommendations to keep in mind:
+
+
+
+
+ Communication to users is always helpful! Consider leaving a comment
+ on the issue to let the user know that their request has been approved
+ and what is going to happen next. Or, comment on the issue with a
+ summary of the changes that have taken place.
+
+
+ Even after an issue is closed, users can interact with it. If you want
+ to prevent this, you can{' '}
+
+ lock the issue
+
+ .
+
+
+ Labels are a great way to organize issues. Consider adding a label to
+ the issue to indicate that it has been approved.
+
+
+ When closing an issue, choosing an appropriate reason is useful for
+ future reporting. For denied requests, closing an issue as{' '}
+ not_planned may be misleading. Consider{' '}
+ completed instead.
+
+
+
+
New repository request
+
+
+ When a new repository request is approved, we need to do the following:
+
+
+
+
Create the repository
+
Comment on the issue
+
Close the issue
+
+
+
+ {dedent`
+ # This job is responsible for handling approved requests.
+ approve:
+ name: Approve Request
+ runs-on: ubuntu-latest
+
+ # Only run after validation has completed.
+ needs: validate
+
+ steps:
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .approve
+
+ # Create the repository.
+ - if: \${{ steps.approve.outputs.continue == 'true' }}
+ name: Create Repository
+ id: create
+ uses: actions/github-script@vX.X.X
+ with:
+ github-token: \${{ secrets.MY_TOKEN }}
+ script: |
+ const request = JSON.parse('\${{ needs.validate.outputs.request }}')
+ await github.rest.repos.createInOrg({
+ org: '\${{ github.repository_owner }}',
+ name: request.name,
+ })
+
+ # Comment on the issue to let the user know their request was denied.
+ - if: \${{ steps.approve.outputs.continue == 'true' }}
+ name: Post Comment
+ id: comment
+ uses: peter-evans/create-or-update-comment@vX.X.X
+ with:
+ issue-number: \${{ github.event.issue.number }}
+ body:
+ ':tada: This request has been approved! Your repository has been
+ created.'
+
+ # Close the issue.
+ - if: \${{ steps.approve.outputs.continue == 'true' }}
+ name: Close Issue
+ id: close
+ run: gh issue close \${{ github.event.issue.number }} --reason completed
+ `}
+
+
+
Next steps
+
+ Your IssueOps workflow is officially complete!
+
+ )
+}
diff --git a/src/app/states-and-transitions/deny/page.tsx b/src/app/states-and-transitions/deny/page.tsx
new file mode 100644
index 00000000..43030c2b
--- /dev/null
+++ b/src/app/states-and-transitions/deny/page.tsx
@@ -0,0 +1,114 @@
+'use client'
+
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Deny
+
+
+ In the Denied state, we know that the issue has been denied
+ and there is no further action to take. This is one of the first states
+ in the workflow where we can perform an unguarded transition.
+
+
+
+ In our repository workflow, a request is transitioned to the{' '}
+ Denied
+ state when an authorized user comments on the request with{' '}
+ .deny. However, immediately after reaching this state, we
+ want to close the issue (moving it to the Closed state).
+ This is called an unguarded transition because there is no
+ condition that must be met before the transition occurs.
+
+
+
+ The actual implementation of this transition is up to you! There are a
+ few recommendations to keep in mind:
+
+
+
+
+ Communication to users is always helpful! Consider leaving a comment
+ on the issue to let the user know that their request has been denied
+ and what steps, if any, they can take next.
+
+
+ Even after an issue is closed, users can interact with it. If you want
+ to prevent this, you can{' '}
+
+ lock the issue
+
+ .
+
+
+ Labels are a great way to organize issues. Consider adding a label to
+ the issue to indicate that it has been denied.
+
+
+ When closing an issue, choosing an appropriate reason is useful for
+ future reporting. For denied requests, closing an issue as{' '}
+ completed may be misleading. Consider{' '}
+ not_planned instead.
+
+
+
+
New repository request
+
+
+ When a new repository request is denied, we want to close the issue and
+ leave a comment for the user. We should also add an appropriate label so
+ we know the request was closed as denied.
+
+
+
+ {dedent`
+ # This job is responsible for handling denied requests.
+ deny:
+ name: Deny Request
+ runs-on: ubuntu-latest
+
+ # Only run after validation has completed.
+ needs: validate
+
+ steps:
+ - name: Deny Command
+ id: deny
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .deny
+
+ # Comment on the issue to let the user know their request was denied.
+ - if: \${{ steps.deny.outputs.continue == 'true' }}
+ name: Post Comment
+ id: comment
+ uses: peter-evans/create-or-update-comment@vX.X.X
+ with:
+ issue-number: \${{ github.event.issue.number }}
+ body:
+ ':no_entry_sign: This request has been denied! This issue will be
+ closed shortly.'
+
+ # Close the issue.
+ - if: \${{ steps.deny.outputs.continue == 'true' }}
+ name: Close Issue
+ id: close
+ run: gh issue close \${{ github.event.issue.number }} --reason not_planned
+ `}
+
+
+
Next steps
+
+ Your IssueOps workflow is officially complete!
+
+ )
+}
diff --git a/src/app/states-and-transitions/page.tsx b/src/app/states-and-transitions/page.tsx
new file mode 100644
index 00000000..56ede032
--- /dev/null
+++ b/src/app/states-and-transitions/page.tsx
@@ -0,0 +1,300 @@
+'use client'
+
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
+import { MermaidDiagram } from '@lightenna/react-mermaid-diagram'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
States and Transitions
+
+
+ As the{' '}
+
+ introduction
+ {' '}
+ mentioned, IssueOps can be thought of as a state diagram where an issue
+ transitions through different states in response to events and
+ conditions. This section of the documentation describes some common
+ states, transitions. and how to implement them in your workflows.
+
+
+
States
+
+
+ If an issue was a paper form, a state would be a big rubber stamp that
+ tells anyone who looks at the form exactly what is going on.
+
+
+
+ Tracking state can be as simple as checking what labels are applied to
+ your issues. Whatever approach you want to take, remember that tracking
+ state is critical to ensure that the right processing occurs at the
+ right time!
+
+
+
+
+
+
+ State
+ Description
+
+
+
+
+
+ Opened
+
+
+ The initial state for a new issue that has been opened.
+ Typically the first state in the lifecycle of an issue.
+
+
+
+
+ Parsed
+
+
+ The issue body has been read and converted to machine-readable
+ JSON. Usually the next immediate state after{' '}
+ Opened.
+
+
+
+
+ Validated
+
+
+ The issue body has been deemed valid based on any custom rules.
+ Usually the next immediate state after{' '}
+ Parsed. The next
+ transitions depend on the type of request and any rules that
+ must be followed.
+
+
+
+
+ Submitted
+
+
+ The issue has been submitted for processing.
+
+
+
+
+ Approved
+
+ The issue has been approved for processing.
+
+
+
+ Denied
+
+ The issue has been denied for processing.
+
+
+
+ Closed
+
+ The issue has been closed!
+
+
+
+
+
+ If an issue was a paper form, a transition would be someone taking it
+ out of their inbox, stamping it APPROVED, and putting
+ it in their outbox.
+
+
+
+ Transitions are where actual processing on your issues occurs. A
+ transition is equivalent to an event that triggers a GitHub Actions
+ workflow run. That is why, as your IssueOps workflows become larger and
+ more complex, tracking state is so important. Otherwise , its easy to
+ end up the wrong workflows running at the wrong time!
+
+
+ Since each transition is triggered by the same type of event:
+
+
+ {dedent`
+ on:
+ issue_comment:
+ types:
+ - created
+ `}
+
+
+
+ Your workflows must track the following to determine what jobs to run:
+
+
+
+
Issue state
+
Issue body
+
Comment body (command and arguments)
+
Any other relevant information in the issue
+
+
+
+ Each of the following sections describes how to implement the core
+ transitions in an IssueOps workflow. Throughout each page, you will see
+ an example implementation of a new repository request workflow. This
+ workflow is designed to demonstrate how to apply each concept.
+
+
+
+ A full example can be found in the{' '}
+
+ issue-ops/bear-creek-honey-farm
+ {' '}
+ and{' '}
+
+ issue-ops/demo-reservation-action
+ {' '}
+ repositories.
+
+
+
+
+
+ Parse
+
+
+
+
+ Validate
+
+
+
+
+ Submit
+
+
+
+
+ Approve
+
+
+
+
+ Deny
+
+
+
+
+
FAQ
+
+
+ Do my IssueOps need all these states?
+
+
+
+ Nope! You can use as many or as few states as you need. For example, if
+ you don't need an authorized user to approve requests, you can omit
+ the Approved state.
+
+
+
+ Can my IssueOps use each state more than once?
+
+
+
+ Of course! In state diagrams, its common for each state to have multiple
+ transitions. States can even transition back into themselves!
+
+
+
+ When an issue is first opened it will be in the Opened{' '}
+ state. Typically, the first step after an issue is opened is to parse
+ the body and prepare for further processing. If this is successful, the
+ issue would transition into the Parsed state. If there is a
+ problem during parsing, the workflow can add a comment with a
+ descriptive error and return the issue to the Opened state.
+ When the user edits the issue to fix the error, parsing would run again.
+
+
+
+
+ Example State Diagram
+
+
+
+ {dedent`
+ stateDiagram-v2
+ 1 : Opened
+ 2 : Parsed
+ [*] --> 1
+ 1 --> 2 : Parse success
+ 1 --> 1 : Parse failure
+ 2 --> [*]
+ `}
+
+
+
+
+ )
+}
diff --git a/src/app/states-and-transitions/parse/page.tsx b/src/app/states-and-transitions/parse/page.tsx
new file mode 100644
index 00000000..6c52d30f
--- /dev/null
+++ b/src/app/states-and-transitions/parse/page.tsx
@@ -0,0 +1,522 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { Card, CardContent } from '@/components/ui/card'
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel
+} from '@/components/ui/form'
+import { Input } from '@/components/ui/input'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue
+} from '@/components/ui/select'
+import { Textarea } from '@/components/ui/textarea'
+import { zodResolver } from '@hookform/resolvers/zod'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import { Info, Package } from 'lucide-react'
+import Link from 'next/link'
+import { useForm } from 'react-hook-form'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+import { z } from 'zod'
+
+const formSchema = z.object({
+ title: z.string(),
+ repoName: z.string(),
+ visibility: z.enum(['private', 'public']),
+ readTeam: z.string(),
+ writeTeam: z.string(),
+ autoInit: z.enum(['true', 'false']),
+ topics: z.string().optional()
+})
+
+export default function Home() {
+ const form = useForm>({
+ resolver: zodResolver(formSchema)
+ })
+
+ return (
+
+
Parse
+
+
+ When a new issue is opened, before any action can be taken on it, you
+ should parse its contents and turn it into a machine-readable format.
+ The{' '}
+
+ issue-ops/parser
+ {' '}
+ action does this by comparing the body of the issue with the original
+ issue form template. This way, you can directly reference issue form
+ fields without having to parse the body yourself with regular
+ expressions.
+
+
+
+
+ NPM Package
+
+ This is also available as a standalone npm package,{' '}
+
+ @github/issue-parser
+
+
+
+
+
+ This action provides specific output formats based on the{' '}
+ type
+ property of the input.
+
+
+
+
+
+
+
+ Depending on how you're processing the input data, different types
+ may be more helpful than others! Based on the issue form template and
+ the contents of the issue itself, the json output will look
+ similar to the following:
+
+
+
+ {dedent`
+ {
+ "the_name_of_the_thing": "this-thing",
+ "the_nickname_of_the_thing": "thing",
+ "the_color_of_the_thing": ["blue"],
+ "the_shape_of_the_thing": ["square"],
+ "the_sounds_of_the_thing": ["re", "mi"],
+ "the_topics_about_the_thing": [],
+ "the_description_of_the_thing": "This is a description.\\n\\nIt has lines.",
+ "the_notes_about_the_thing": "- Note\\n- Another note\\n- Lots of notes",
+ "the_code_of_the_thing": "const thing = new Thing()\\n\\nthing.doThing()",
+ "the_string_method_of_the_code_of_the_thing": "thing.toString()",
+ "is_the_thing_a_thing": {
+ "selected": ["Yes"],
+ "unselected": ["No"]
+ },
+ "is_the_thing_useful": {
+ "selected": ["Sometimes"],
+ "unselected": ["Yes", "No"]
+ },
+ "read_team": "IssueOps-Demo-Readers",
+ "write_team": "IssueOps-Demo-Writers"
+ }
+ `}
+
+
+
+ Once an issue has been parsed, the next step is to{' '}
+
+ validate
+ {' '}
+ the contents to make sure the request isn't missing data,
+ doesn't contain invalid data, and can be processed by your
+ workflow.
+
+
+
New repository request
+
+
Issue form template
+
+
+ The new repository worklow starts off with the following issue form
+ template.
+
+
+
+ {dedent`
+ name: New Repository Request
+ description: Submit a request to create a new GitHub repository
+ title: '[Request] New Repository'
+ labels:
+ - issueops:new-repository
+
+ body:
+ - type: markdown
+ attributes:
+ value:
+ Welcome to GitHub! Please fill out the information below to request a
+ new repository. Once submitted, your request will be reviewed by the
+ IssueOps team. If approved, the repository will be created and you will
+ be notified via a comment on this issue.
+ - type: input
+ id: name
+ attributes:
+ label: Repository Name
+ description: The name of the repository you would like to create.
+ placeholder: octorepo
+ validations:
+ required: true
+ - type: dropdown
+ id: visibility
+ attributes:
+ label: Repository Visibility
+ description: The visibility of the repository.
+ multiple: false
+ options:
+ - private
+ - public
+ validations:
+ required: true
+ - type: input
+ id: read-team
+ attributes:
+ label: Read Team
+ description: The GitHub Team that will get read access to the repository.
+ placeholder: octocat-readers
+ validations:
+ required: true
+ - type: input
+ id: write-team
+ attributes:
+ label: Write Team
+ description: The GitHub Team that will get write access to the repository.
+ placeholder: octocat-writers
+ validations:
+ required: true
+ - type: dropdown
+ id: auto-init
+ attributes:
+ label: Auto Init
+ description: Select \`true\` to initialize the repository with a \`README\`.
+ multiple: false
+ options:
+ - 'true'
+ - 'false'
+ validations:
+ required: true
+ - type: textarea
+ id: topics
+ attributes:
+ label: Topics
+ description:
+ (Optional) A list of topics to add to the repository. Separate each
+ topic with a new line.
+ placeholder: |
+ octocat
+ octodog
+ validations:
+ required: false
+ `}
+
+
+
+ When a user submits a request for a new repository, the issue form will
+ look something like this:
+
+
+
+
+
+
+
+
+
+
GitHub Actions workflow
+
+
+ Creating an issue will kick off the start of the IssueOps process.
+ However, in order to do anything with the request, we need to parse the
+ issue body and extract the information we need to get approval and
+ create a repository.
+
+
+
+
+ Tips and Tricks
+
+ Check the workflow comments for useful tips!
+
+
+
+
+ {dedent`
+ name: Issue Opened/Edited/Reopened
+
+ # At minimum, the issue body should be parsed any time an issue is opened,
+ # edited, or reopened. This ensures that the most up to date information is
+ # validated.
+ on:
+ issues:
+ types:
+ - opened
+ - edited
+ - reopened
+
+ jobs:
+ # Different request types may have different inputs. For example, a new
+ # repository request may have different inputs than a repository transfer
+ # request. You can create multiple jobs to parse different types of requests
+ # in the same workflow. Labels can be used to control which jobs run for
+ # which types of requests.
+ new-repository-request:
+ name: New Repository Request
+ runs-on: ubuntu-latest
+
+ # Assign labels for different types of requests, and use those labels to
+ # trigger different workflows, jobs, and steps.
+ if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
+
+ # Initially, this workflow only needs permissions to read issues and
+ # contents. This will be expanded later as we build additional
+ # functionality.
+ permissions:
+ contents: read
+ issues: read
+
+ steps:
+ # Get the repository contents. This lets the workflow reference files in
+ # the repository such as the issue form template.
+ - name: Checkout
+ id: checkout
+ uses: actions/checkout@vX.X.X
+
+ - name: Parse Issue
+ id: parse
+ uses: issue-ops/parser@vX.X.X
+ with:
+ body: \${{ github.event.issue.body }}
+ issue-form-template: new-repository-request.yml
+
+ - name: Output the Parsed Issue
+ id: output
+ run: echo \${{ steps.parse.outputs.json }}
+ `}
+
+
+
Next steps
+
+
+ At this point, our issue has successfully transitioned into the{' '}
+ Parsed
+ state. This means that we have a machine-readable representation of the
+ request that can be further processed by our workflows. However, we
+ don't know if the request actually contains valid information! The
+ next transition involves validating the parsed request against a set of
+ rules to make sure it's ready to be processed.
+
+
+
+ Continue to the next section to learn about{' '}
+
+ validation
+
+ .
+
+
+ )
+}
diff --git a/src/app/states-and-transitions/submit/page.tsx b/src/app/states-and-transitions/submit/page.tsx
new file mode 100644
index 00000000..607fe0df
--- /dev/null
+++ b/src/app/states-and-transitions/submit/page.tsx
@@ -0,0 +1,467 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import { KeyRound } from 'lucide-react'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Submit
+
+
+ Once your issue has been parsed and validated, it's ready for
+ processing! At this point, _processing_ can mean a lot of things and is
+ entirely dependent on your use case. For example, if you're using
+ IssueOps to access administrative functions, you may require a human to
+ review and approve the issue. Or, if you're using IssueOps to track
+ PTO requests, you may not need any additional approvals and can simply
+ mark the issue as processed.
+
+
+
+ This page walks through the process of submitting a request after it has
+ been validated. In particular, it covers requesting approval from
+ authorized users or teams.
+
+
+
+
+ Wouldn't opening the issue count as the act of submitting it?
+
+
+
+
+ Absolutely! However, the act of opening an issue may not be the best
+ indicator that an issue is in the Submitted state in your
+ workflow. What if you need to do additional processing on the validated
+ request which requires confirmation from the user?
+
+
+
+ Using the new repository request as an example, your organization may
+ want to enforce certain naming conventions for repositories, such as
+ prefixing the name with the user's department. In this case, when a
+ user opens a request and asks for a repository named{' '}
+ pto-requests, you could have them confirm that the
+ generated name of hr-pto-requests is acceptable before
+ submitting the request for further processing.
+
+
+
Command actions
+
+
+ This is where the{' '}
+
+ github/command
+ {' '}
+ action comes into play. This action allows you to specify the who
+ ,what, when, and where of activities that can be
+ performed on an issue. For example, if you request approval for a new
+ repository, the github/command action ensures that any user
+ cannot approve the request. Instead, only users or teams you specify
+ can.
+
+
+
+
+ Token Permissions
+
+ As with other actions that call GitHub APIs, if you want to include
+ GitHub teams in the allowlist feature, you must provide a
+ valid token in the allowlist_pat input. This can be a
+ token generated from a GitHub App!
+
+
+
+
+ {dedent`
+ steps:
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .approve
+ `}
+
+
+
+ This step acts as the gate for any further processing of the issue. The{' '}
+ continue output can be used to conditionally invoke further
+ steps. For example, if the continue output is{' '}
+ 'true', the user who commented on the issue with{' '}
+ .approve was indeed authorized to approve the request.
+
+
+
+ {dedent`
+ steps:
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .approve
+
+ ##############################################
+ # This is a great time to re-run validation! #
+ ##############################################
+
+ - if: \${{ steps.approve.outputs.continue == 'true' }}
+ run: echo "This request is approved!"
+ `}
+
+
+
+ With any approval workflow, you should also consider what happens when a
+ request is explicitly denied This is easy to implement as a separate{' '}
+ github/command step that looks for the .deny{' '}
+ command. As with the approval command, if the user who commented on the
+ issue is authorized to deny requests, the continue output
+ would be 'true'.
+
+
+
+ {dedent`
+ steps:
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .approve
+
+ - name: Deny Command
+ id: deny
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .deny
+
+ - if: \${{ steps.approve.outputs.continue == 'true' }}
+ run: echo "This request is approved :)"
+
+ - if: \${{ steps.deny.outputs.continue == 'true' }}
+ run: echo "This request is denied :("
+ `}
+
+
+
New repository request
+
+
+ Up until this point, everything has been handled as part of the issue
+ creation workflow. Now that the issue has been validated, any further
+ processing is done via comments, labels, reactions, and so on.
+
+
+
Create the comment workflow file
+
+
+ The first step is to create a workflow file that will be triggered when
+ a user comments on an issue. This workflow file will be responsible for
+ parsing the comment and determining the following:
+
+
+
+
+ The comment is on an issue that is part of our IssueOps workflow
+
+
The comment is a command word
+
The user is authorized to call that command
+
+
+
+ In this example, we will set up two different jobs that will run when
+ the request is approved or denied.
+
+
+
+ {dedent`
+ name: Issue Comment
+
+ # This workflow runs any time a comment is added to an issue. The comment body
+ # is read and used to determine what action to take.
+ on:
+ issue_comment:
+ types:
+ - created
+
+ jobs:
+ # This job handles the case where a user comments with \`.approve\`.
+ approve:
+ name: Approve Request
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Approve Command
+ id: approve
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .approve
+
+ - if: \${{ steps.approve.outputs.continue == 'true' }}
+ run: echo "This request is approved!"
+
+ # This job handles the case where a user comments with \`.deny\`.
+ deny:
+ name: Deny Request
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Deny Command
+ id: deny
+ uses: github/command@vX.X.X
+ with:
+ allowed_contexts: issue
+ allowlist: octo-org/approvers
+ allowlist_pat: \${{ secrets.MY_TOKEN }}
+ command: .deny
+
+ - if: \${{ steps.deny.outputs.continue == 'true' }}
+ run: echo "This request is denied!"
+ `}
+
+
+
Trigger the workflow
+
+
+ In the above workflow, both the approve and{' '}
+ deny jobs are triggered when a user comments on an issue or
+ PR. Though the github/command actions will act as one gate,
+ you may want to add additional conditions to ensure that the workflow is
+ not run when the issue is in a state that does not require approval. For
+ example, this workflow doesn't need to run if:
+
+
+
+
The issue is not part of this IssueOps workflow
+
+ The request is not in the Submitted state
+
+
The request is already approved
+
+
+
+ Workflow conditions can be used to control when the workflow jobs are
+ invoked.
+
+
+
+ {dedent`
+ name: Issue Comment
+
+ on:
+ issue_comment:
+ types:
+ - created
+
+ jobs:
+ approve:
+ name: Approve Request
+ runs-on: ubuntu-latest
+
+ # Only run when the following conditions are true:
+ # - The issue has the \`issueops:new-repository\` label
+ # - The issue has the \`issueops:validated\` label
+ # - The issue does not have the \`issueops:approved\` label
+ # - The issue is open
+ if: |
+ contains(github.event.issue.labels.*.name, 'issueops:new-repository') &&
+ contains(github.event.issue.labels.*.name, 'issueops:validated') &&
+ contains(github.event.issue.labels.*.name, 'issueops:approved') == false &&
+ github.event.issue.state == 'open'
+
+ steps:
+ # ...
+
+ deny:
+ name: Deny Request
+ runs-on: ubuntu-latest
+
+ # Only run when the following conditions are true:
+ # - The issue has the \`issueops:new-repository\` label
+ # - The issue has the \`issueops:validated\` label
+ # - The issue does not have the \`issueops:approved\` label
+ # - The issue is open
+ if: |
+ contains(github.event.issue.labels.*.name, 'issueops:new-repository') &&
+ contains(github.event.issue.labels.*.name, 'issueops:validated') &&
+ contains(github.event.issue.labels.*.name, 'issueops:approved') == false &&
+ github.event.issue.state == 'open'
+
+ steps:
+ # ...
+ `}
+
+
+
+ This seems like duplication of the same checks. Plus, we haven't
+ followed our own rule: Validate Early. Validate Often. Instead,
+ lets move this to a separate job that re-runs validation checks.
+
+
+
+ {dedent`
+ name: Issue Comment
+
+ on:
+ issue_comment:
+ types:
+ - created
+
+ jobs:
+ validate:
+ name: Validate Request
+ runs-on: ubuntu-latest
+
+ # Only run when the following conditions are true:
+ # - The issue has the \`issueops:new-repository\` label
+ # - The issue has the \`issueops:validated\` label
+ # - The issue does not have the \`issueops:approved\` label
+ # - The issue is open
+ if: |
+ contains(github.event.issue.labels.*.name, 'issueops:new-repository') &&
+ contains(github.event.issue.labels.*.name, 'issueops:validated') &&
+ contains(github.event.issue.labels.*.name, 'issueops:approved') == false &&
+ github.event.issue.state == 'open'
+
+ permissions:
+ contents: read
+ id-token: write
+ issues: write
+
+ outputs:
+ request: \${{ steps.parse.outputs.request }}
+
+ steps:
+ - name: Remove Labels
+ id: remove-label
+ uses: issue-ops/labeler@vX.X.X
+ with:
+ action: remove
+ issue_number: \${{ github.event.issue.number }}
+ labels: |
+ issueops:validated
+ issueops:submitted
+
+ - name: Get App Token
+ id: token
+ uses: actions/create-github-app-token@vX.X.X
+ with:
+ app_id: \${{ secrets.MY_GITHUB_APP_ID }}
+ private_key: \${{ secrets.MY_GITHUB_APP_PEM }}
+ owner: \${{ github.repository_owner }}
+
+ - name: Checkout
+ id: checkout
+ uses: actions/checkout@vX.X.X
+
+ - name: Setup Node.js
+ id: setup-node
+ uses: actions/setup-node@vX.X.X
+ with:
+ node-version-file: .node-version
+ cache: npm
+
+ - name: Install Packages
+ id: npm
+ run: npm ci
+
+ - name: Parse Issue
+ id: parse
+ uses: issue-ops/parser@vX.X.X
+ with:
+ body: \${{ github.event.issue.body }}
+ issue-form-template: new-repository-request.yml
+
+ - name: Validate Issue
+ id: validate
+ uses: issue-ops/validator@vX.X.X
+ with:
+ issue-form-template: new-repository-request.yml
+ github-token: \${{ steps.token.outputs.token }}
+ parsed-issue-body: \${{ steps.parse.outputs.json }}
+
+ - if: \${{ steps.validate.outputs.result == 'success' }}
+ name: Add Validated Label
+ id: add-label
+ uses: issue-ops/labeler@vX.X.X
+ with:
+ action: add
+ issue_number: \${{ github.event.issue.number }}
+ labels: |
+ issueops:validated
+
+ approve:
+ name: Approve Request
+ runs-on: ubuntu-latest
+
+ # Only run after validation has completed.
+ needs: validate
+
+ steps:
+ # ...
+
+ deny:
+ name: Deny Request
+ runs-on: ubuntu-latest
+
+ # Only run after validation has completed.
+ needs: validate
+
+ steps:
+ # ...
+ `}
+
+
+
+ With this workflow, we know that the request has been validated before
+ we handle any approval or denial. This is a good example of{' '}
+ Validate Early. Validate Often.
+
+
+
Next steps
+
+
+ Depending on if the request is approved or denied, you may want to take
+ further actions. For example, if the request is approved, you could
+ create the repository, add a comment to the issue, and close it as
+ completed. On the other hand, if the request is denied, you could close
+ the issue as not planned.
+
+
+
+ Continue to the{' '}
+
+ approve
+ {' '}
+ or{' '}
+
+ deny
+ {' '}
+ sections to learn more.
+
+
+ )
+}
diff --git a/src/app/states-and-transitions/validate/page.tsx b/src/app/states-and-transitions/validate/page.tsx
new file mode 100644
index 00000000..f4c0fcc7
--- /dev/null
+++ b/src/app/states-and-transitions/validate/page.tsx
@@ -0,0 +1,609 @@
+'use client'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+import {
+ Paper,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow
+} from '@mui/material'
+import { Check, KeyRound, User } from 'lucide-react'
+import Link from 'next/link'
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
+import dedent from 'ts-dedent'
+
+export default function Home() {
+ return (
+
+
Validate
+
+
+ Once an issue has been parsed, it can be validated against any rules
+ that you require. When used in public repositories, issue form templates
+ do enforce some{' '}
+
+ validation rules
+ {' '}
+ such as required fields, selection options, and more. However, you may
+ have additional needs that apply to your specific use case. For example,
+ if you are creating an IssueOps workflow for users to request membership
+ to GitHub teams, the issue form template is not able to validate if a
+ value provided by a user is in fact a team in your organization.e. When
+ used in public repositories, issue form templates do enforce some
+
+
+
+ The{' '}
+
+ issue-ops/validator
+ {' '}
+ action takes the parsed output of the issue body and validates it
+ against the issue form template and any custom rules you define.
+
+
+
+
+ User Edits
+
+ After a request is initially validated, there is nothing stopping a
+ user from editing the issue and submitting it with invalid inputs. You
+ should run your validation logic any time the following events occur:
+
+
+
+
The issue is opened
+
The issue body is edited
+
The issue is reopened after being closed
+
The request is submitted for provisioning/creation
+
+
+
+
+
Basic validation
+
+
+ The most basic validation compares each input field to the rules
+ specified in your issue form template and, if any are violated, comments
+ with an error message.
+
+
+
+ {dedent`
+ - name: Validate Issue
+ id: validate
+ uses: issue-ops/validator@vX.X.X
+ with:
+ issue-form-template: example-request.yml
+ parsed-issue-body: \${{ steps.parse.outputs.json }}
+ `}
+
+
+
+ For example, if you have an input field for users to select the
+ visibility of their new repository, you can specify that the field is
+ required and only one of a list of options can be chosen.
+
+
+
+ {dedent`
+ - type: dropdown
+ id: visibility
+ attributes:
+ label: Repository Visibility
+ description: The visibility of the repository.
+ multiple: false
+ options:
+ - private
+ - public
+ validations:
+ required: true
+ `}
+
+
+
+ When run against an issue submitted with this template, the validator
+ will comment on the issue with an error message if any of the following
+ occur:
+
+
+
+
The field is empty
+
The field is missing from the issue body
+
+ An option other than private or public is
+ present
+
+
+
+
Custom validation
+
+
+ For each form field, you can also specify custom validation logic. This
+ is done using several files in your repository:
+
+
+
+
+ The validator configuration file (
+ .github/validator/config.yml)
+
+
+ One or more validator scripts (
+ .github/validator/<script-name>.js)
+
+
+
+
Configuration file
+
+
+ This file defines the mapping of validator scripts to form fields. For
+ example, if your issue form has input fields named{' '}
+ Read Team and Write Team, you can specify a
+ validator script (check_team_exists.js) to run against
+ those fields.
+
+
+
+ {dedent`
+ validators:
+ - field: read_team
+ script: check_team_exists
+ - field: write_team
+ script: check_team_exists
+ `}
+
+
+
Validator scripts
+
+
+
+ GitHub Token
+
+ If you want to run custom validators that access GitHub APIs, you will
+ need to provide a value for the github-token input. This
+ is a good scenario for GitHub App authentication!
+
+
+
+
+ Validator scripts are run on the associated fields in the configuration
+ file. The script must specify a default export of a function with the
+ following behavior:
+
+
+
+
+
+
+ Since the Visibility and Auto Init inputs must be one of
+ several predefined values, they can be handled by basic validation. The
+ other fields, however, must meet additional requirements:
+
+
+
+
+
+
+ Field
+ Requirement
+
+
+
+
+ Repository Name
+ Must not be an existing repository
+
+
+ Read Team
+ Must be a team in the organization
+
+
+ Write Team
+ Must be a team in the organization
+
+
+ Topics
+
+ Must be a list of 20 or fewer
+
+ Must be lowercase
+
+ Must be 50 or fewer characters
+
+ Must contain only letters, numbers, and hyphens
+
+
+
+
+
+
+
Create a configuration file
+
+
+ In order to configure custom validation, first create a configuration
+ file in the repository.
+
+
+
+ {dedent`
+ # File Path: .github/validator/config.yml
+
+ validators:
+ - field: repository_name
+ script: repo_doesnt_exist
+ - field: read_team
+ script: team_exists
+ - field: write_team
+ script: team_exists
+ - field: topics
+ script: topics_valid
+ `}
+
+
+
Create validator scripts
+
+
+ The following scripts can be used to validate the new repository
+ request.
+
+
+
+ First, create a script to check if a repository already exists.
+
+
+
+ {dedent`
+ // File Path: .github/validator/repo_doesnt_exist.js
+
+ module.exports = async (field) => {
+ if (typeof field !== 'string') return 'Field type is invalid'
+
+ const { getOctokit } = require('@actions/github')
+ const core = require('@actions/core')
+ const octokit = getOctokit(core.getInput('github-token', { required: true }))
+
+ try {
+ // This should throw a 404 error
+ await octokit.rest.repos.get({
+ org: '',
+ repo: field
+ })
+
+ core.error(\`Repository '\${field}' already exists\`)
+ return \`Repository '\${field}' already exists\`
+ } catch (error) {
+ if (error.status === 404) {
+ core.info(\`Repository '\${field}' does not exist\`)
+ return 'success'
+ }
+ }
+ }
+ `}
+
+
+ Next, create a script to check if a team exists.
+
+
+ {dedent`
+ // File Path: .github/validator/team_exists.js
+
+ module.exports = async (field) => {
+ if (typeof field !== 'string') return 'Field type is invalid'
+
+ const { getOctokit } = require('@actions/github')
+ const core = require('@actions/core')
+ const octokit = getOctokit(core.getInput('github-token', { required: true }))
+
+ try {
+ await octokit.rest.teams.getByName({
+ org: process.env.ORGANIZATION ?? '',
+ team_slug: field
+ })
+
+ core.info(\`Team '\${field}' exists\`)
+ return 'success'
+ } catch (error) {
+ if (error.status === 404) {
+ core.error(\`Team '\${field}' does not exist\`)
+ return \`Team '\${field}' does not exist\`
+ }
+ }
+ }
+ `}
+
+
+ Finally, create a script to check if the topics are valid.
+
+
+ {dedent`
+ // File Path: .github/validator/topics_valid.js
+
+ module.exports = async (field) => {
+ if (typeof field !== 'string') return 'Field type is invalid'
+
+ const topics = field.split(/[\\r\\n]+/)
+
+ if (topics.length > 20)
+ return \`There are \${request.topics.length} topics (max: 20)\`
+
+ const invalidTopics = []
+ for (const topic of topics) {
+ if (
+ topic !== topic.toLowerCase() ||
+ topic.length > 50 ||
+ !topic.match(/^[a-z0-9-]+$/)
+ )
+ invalidTopics.push(topic)
+ }
+
+ if (invalidTopics.length > 0)
+ return \`The following topics are invalid: \${JSON.stringify(invalidTopics)}\`
+ }
+ `}
+
+
+
Update the workflow
+
+
+ Now that issue validation has been configured, you can add it as a step
+ to your workflow. Additional updates are noted with comments.
+
+
+
+ {dedent`
+ name: Issue Opened/Edited/Reopened
+
+ on:
+ issues:
+ types:
+ - opened
+ - edited
+ - reopened
+
+ jobs:
+ new-repository-request:
+ name: New Repository Request
+ runs-on: ubuntu-latest
+
+ if: contains(github.event.issue.labels.*.name, 'issueops:new-repository')
+
+ # Since the validation step involves adding comments to issues, you will
+ # need to give it write permissions. If you are using a GitHub App to call
+ # other GitHub APIs, you will also need to add the appropriate permissions.
+ permissions:
+ contents: read
+ id-token: write
+ issues: write
+
+ steps:
+ # Always remove the validated/submitted labels first! This ensures that
+ # the validation logic runs any time the issue body is edited. It also
+ # ensures the issue must be re-submitted after editing.
+ - name: Remove Labels
+ id: remove-label
+ uses: issue-ops/labeler@vX.X.X
+ with:
+ action: remove
+ issue_number: \${{ github.event.issue.number }}
+ labels: |
+ issueops:validated
+ issueops:submitted
+
+ # If your validation script checks things beyond the scope of the
+ # repository it is running in, you will need to create a GitHub App and
+ # generate an installation access token in your workflow.
+ - name: Get App Token
+ id: token
+ uses: actions/create-github-app-token@vX.X.X
+ with:
+ app_id: \${{ secrets.MY_GITHUB_APP_ID }}
+ private_key: \${{ secrets.MY_GITHUB_APP_PEM }}
+ owner: \${{ github.repository_owner }}
+
+ - name: Checkout
+ id: checkout
+ uses: actions/checkout@vX.X.X
+
+ # Install Node.js so the workflow can add npm packages that are used by
+ # the custom validator scripts (e.g. '@octokit/rest').
+ - name: Setup Node.js
+ id: setup-node
+ uses: actions/setup-node@vX.X.X
+ with:
+ node-version-file: .node-version
+ cache: npm
+
+ # Install NPM packages needed by the validator scripts.
+ - name: Install Packages
+ id: npm
+ run: npm ci
+
+ - name: Parse Issue
+ id: parse
+ uses: issue-ops/parser@vX.X.X
+ with:
+ body: \${{ github.event.issue.body }}
+ issue-form-template: new-repository-request.yml
+
+ # Add a step to validate the issue.
+ - name: Validate Issue
+ id: validate
+ uses: issue-ops/validator@vX.X.X
+ with:
+ issue-form-template: new-repository-request.yml
+ github-token: \${{ steps.token.outputs.token }}
+ parsed-issue-body: \${{ steps.parse.outputs.json }}
+
+ # Add a label to mark the request as validated.
+ - if: \${{ steps.validate.outputs.result == 'success' }}
+ name: Add Validated Label
+ id: add-label
+ uses: issue-ops/labeler@vX.X.X
+ with:
+ action: add
+ issue_number: \${{ github.event.issue.number }}
+ labels: |
+ issueops:validated
+ `}
+
+
+
Next steps
+
+
+ Congratulations! Your request has been successfully transitioned to the{' '}
+ Validated state. Next, we're going to submit the
+ request for approval.
+
+
+
+ Continue to the next section
+
+