aboutsummaryrefslogtreecommitdiff
path: root/.github
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-17 03:59:59 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-17 03:59:59 +0300
commitdb6f9afad27142248150096aa886f1057c1ebcd6 (patch)
tree59ab5c506ad506a5461d5669878841d9ba7f2b62 /.github
parentd743b39a2b922aa9f7c4365a0b6e53a8be68b9e6 (diff)
chore: add contributor intent issue form
Diffstat (limited to '.github')
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml2
-rw-r--r--.github/ISSUE_TEMPLATE/proposal.yml59
-rw-r--r--.github/workflows/label-intends-to-pr.yml91
3 files changed, 152 insertions, 0 deletions
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..64eb98dc
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,2 @@
+blank_issues_enabled: true
+contact_links: []
diff --git a/.github/ISSUE_TEMPLATE/proposal.yml b/.github/ISSUE_TEMPLATE/proposal.yml
new file mode 100644
index 00000000..01080b6e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/proposal.yml
@@ -0,0 +1,59 @@
+name: Change proposal
+description: Propose a bug fix, feature, workflow change, or first-time contribution.
+title: "[proposal]: "
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Before opening your first PR, describe the change here and wait for maintainer approval.
+
+ - type: textarea
+ id: current-behavior
+ attributes:
+ label: Current behavior
+ description: What does herdr do today?
+ validations:
+ required: true
+
+ - type: textarea
+ id: proposed-change
+ attributes:
+ label: Proposed change
+ description: What do you want to change?
+ validations:
+ required: true
+
+ - type: textarea
+ id: why-herdr
+ attributes:
+ label: Why this belongs in herdr
+ description: Explain why this fits herdr's direction.
+ validations:
+ required: true
+
+ - type: dropdown
+ id: product-impact
+ attributes:
+ label: Does this change UI, interaction, workflow, or product direction?
+ options:
+ - "No"
+ - "Yes"
+ - "Not sure"
+ validations:
+ required: true
+
+ - type: textarea
+ id: product-impact-details
+ attributes:
+ label: Impact details
+ description: If yes or not sure, explain what changes for users.
+
+ - type: checkboxes
+ id: contribution-intent
+ attributes:
+ label: Contribution intent
+ options:
+ - label: I intend to open a PR for this change.
+ required: false
+ - label: I understand this does not mean the change is approved.
+ required: false
diff --git a/.github/workflows/label-intends-to-pr.yml b/.github/workflows/label-intends-to-pr.yml
new file mode 100644
index 00000000..11136ec3
--- /dev/null
+++ b/.github/workflows/label-intends-to-pr.yml
@@ -0,0 +1,91 @@
+name: Label contributor intent
+
+on:
+ issues:
+ types: [opened, edited]
+
+permissions:
+ issues: write
+
+env:
+ INTENDS_TO_PR_LABEL: intends-to-pr
+
+jobs:
+ label:
+ if: ${{ !github.event.issue.pull_request }}
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Sync intends-to-pr label
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const label = process.env.INTENDS_TO_PR_LABEL;
+ const body = context.payload.issue.body || '';
+ const issueNumber = context.payload.issue.number;
+ const { owner, repo } = context.repo;
+ const checkedIntentPattern = /^\s*-\s*\[[xX]\]\s*I intend to open a PR for this change\.\s*$/m;
+ const uncheckedIntentPattern = /^\s*-\s*\[ \]\s*I intend to open a PR for this change\.\s*$/m;
+ const shouldAddLabel = checkedIntentPattern.test(body);
+ const shouldRemoveLabel = uncheckedIntentPattern.test(body);
+ const labels = context.payload.issue.labels.map((item) =>
+ typeof item === 'string' ? item : item.name,
+ );
+ const hasLabel = labels.includes(label);
+
+ if (shouldAddLabel && hasLabel) {
+ console.log(`${label} is already present on #${issueNumber}.`);
+ return;
+ }
+
+ if (shouldRemoveLabel && !hasLabel) {
+ console.log(`${label} is already absent from #${issueNumber}.`);
+ return;
+ }
+
+ if (!shouldAddLabel && !shouldRemoveLabel) {
+ console.log(`No contribution intent checkbox found for #${issueNumber}.`);
+ return;
+ }
+
+ if (shouldAddLabel) {
+ try {
+ await github.rest.issues.getLabel({ owner, repo, name: label });
+ } catch (error) {
+ if (error.status !== 404) {
+ throw error;
+ }
+
+ await github.rest.issues.createLabel({
+ owner,
+ repo,
+ name: label,
+ color: '0E8A16',
+ description: 'Contributor intends to open a PR for this issue.',
+ });
+ }
+
+ await github.rest.issues.addLabels({
+ owner,
+ repo,
+ issue_number: issueNumber,
+ labels: [label],
+ });
+ console.log(`Added ${label} to #${issueNumber}.`);
+ return;
+ }
+
+ try {
+ await github.rest.issues.removeLabel({
+ owner,
+ repo,
+ issue_number: issueNumber,
+ name: label,
+ });
+ console.log(`Removed ${label} from #${issueNumber}.`);
+ } catch (error) {
+ if (error.status !== 404) {
+ throw error;
+ }
+ console.log(`${label} was already absent from #${issueNumber}.`);
+ }