Copilot Templated Discussions #18244
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Copilot Templated Discussions | |
| on: | |
| discussion: | |
| types: [created] | |
| jobs: | |
| label-copilot-discussion: | |
| runs-on: ubuntu-latest | |
| if: ${{ contains(github.event.discussion.category.name, 'Copilot') }} | |
| steps: | |
| - name: Get discussion body html | |
| id: get_discussion_body_html | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| OWNER: ${{ github.repository_owner }} | |
| REPO: ${{ github.event.repository.name }} | |
| DISCUSSION_NUMBER: ${{ github.event.discussion.number }} | |
| run: | | |
| gh api graphql -F owner=$OWNER -F name=$REPO -F number=$DISCUSSION_NUMBER -f query=' | |
| query($owner: String!, $name: String!, $number: Int!) { | |
| repository(owner: $owner, name: $name){ | |
| discussion(number: $number) { | |
| bodyHTML | |
| id | |
| } | |
| } | |
| }' > discussion_data.json | |
| echo 'DISCUSSION_BODY_HTML='$(jq -r '.data.repository.discussion.bodyHTML' discussion_data.json) >> $GITHUB_ENV | |
| echo 'DISCUSSION_ID='$(jq -r '.data.repository.discussion.id' discussion_data.json) >> $GITHUB_ENV | |
| - run: npm install jsdom | |
| - name: Get selected Copilot feature area | |
| id: get_selected_feature_area | |
| uses: actions/github-script@v6 | |
| with: | |
| result-encoding: string | |
| script: | | |
| try { | |
| const jsdom = require('jsdom'); | |
| const { JSDOM } = jsdom; | |
| const { DISCUSSION_BODY_HTML } = process.env | |
| const fragment = JSDOM.fragment(DISCUSSION_BODY_HTML); | |
| const featureAreaHeaders = fragment.querySelectorAll("h3"); | |
| const featureAreaHeader = Array.from(featureAreaHeaders).find(header => | |
| header.textContent.trim().toLowerCase().includes('copilot feature area')); | |
| if (!featureAreaHeader) { | |
| return ""; | |
| } | |
| const selectedAreaElement = featureAreaHeader.nextElementSibling; | |
| if (!selectedAreaElement) { | |
| return ""; | |
| } | |
| const selectedArea = selectedAreaElement.textContent.trim(); | |
| // Simplify area matching by converting to lowercase | |
| const selectedAreaLower = selectedArea.toLowerCase(); | |
| // Valid Copilot feature areas (case insensitive matching) | |
| const validAreas = { | |
| "vs code": "VS Code", | |
| "visual studio": "Visual Studio", | |
| "jetbrains & xcode": "JetBrains & Xcode", | |
| "copilot in github": "Copilot in GitHub", | |
| "copilot workspace": "Copilot Workspace", | |
| "copilot edits and code review": "Copilot Edits and Code Review", | |
| "copilot agent mode": "Copilot Agent Mode", | |
| "copilot coding agent": "Copilot Coding Agent", | |
| "copilot enterprise": "Copilot Enterprise", | |
| "copilot billing or account‑related": "Copilot Billing or Account‑Related", | |
| "other copilot areas": "Other Copilot Areas" | |
| }; | |
| // Try to find a matching area (case insensitive) | |
| for (const [key, value] of Object.entries(validAreas)) { | |
| if (selectedAreaLower.includes(key)) { | |
| return value; // Return the properly cased label | |
| } | |
| } | |
| // If no match found, check if it's exactly one of our valid areas | |
| // This helps with unexpected formatting or spacing | |
| if (selectedArea && Object.values(validAreas).includes(selectedArea)) { | |
| return selectedArea; | |
| } | |
| // Default to "Other Copilot Areas" if we can't find a specific match | |
| if (selectedArea) { | |
| return "Other Copilot Areas"; | |
| } | |
| return ""; | |
| } catch (error) { | |
| console.error(error); | |
| return ""; | |
| } | |
| - name: Fetch label id for selected area | |
| id: fetch_label_id | |
| if: ${{ steps.get_selected_feature_area.outputs.result != '' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| OWNER: ${{ github.repository_owner }} | |
| REPO: ${{ github.event.repository.name }} | |
| AREA: ${{ steps.get_selected_feature_area.outputs.result }} | |
| run: | | |
| gh api graphql -F owner=$OWNER -F name=$REPO -F topic="$AREA" -f query=' | |
| query($owner: String!, $name: String!, $topic: String) { | |
| repository(owner: $owner, name: $name){ | |
| labels(first: 1, query: $topic) { | |
| edges { | |
| node { | |
| id | |
| name | |
| } | |
| } | |
| } | |
| } | |
| }' > repository_label_data.json | |
| LABEL_ID=$(jq -r '.data.repository.labels.edges[0]?.node?.id // empty' repository_label_data.json) | |
| if [ -z "$LABEL_ID" ]; then | |
| echo "No matching label found for the selected area. Skipping labeling step." | |
| fi | |
| echo "LABEL_ID=$LABEL_ID" >> $GITHUB_ENV | |
| - name: Label the discussion | |
| if: ${{ steps.get_selected_feature_area.outputs.result != '' && env.LABEL_ID != '' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh api graphql -f query=' | |
| mutation($labelableId: ID!, $labelIds: [ID!]!) { | |
| addLabelsToLabelable(input: {labelableId: $labelableId, labelIds: $labelIds}) { | |
| labelable { | |
| labels(first: 10) { | |
| edges { | |
| node { | |
| id | |
| name | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }' -f labelableId=$DISCUSSION_ID -f labelIds[]=$LABEL_ID |