Skip to content

[auto-pr] #4: [Coding Guideline]: testtt #12

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/auto-pr-on-issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Auto Guideline PR

on:
issues:
types:
- labeled

jobs:
auto-pr:
if: contains(github.event.label.name, 'accepted')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Git
run: |
git config --global user.email "[email protected]"
git config --global user.name "GitHub Action"

# - name: Save issue JSON payload to file
# run: echo '${{ toJson(github.event.issue) }}' > issue.json
# pass it directly -- mayne fallback to this if an issue happened due to
# pipe-ing or encoding

- name: Run Python script to generate guideline file
run: |
echo '${{ toJson(github.event.issue) }}' | python3 scripts/auto-pr-helper.py

- name: Commit generated guideline files
run: |
git add src/coding-guidelines/
git commit -m "Add guideline for issue #${{ github.event.issue.number }}"

- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
commit-message: "Add guideline for issue #${{ github.event.issue.number }}"
branch: guideline-${{ github.event.issue.number }}
title: "[auto-pr] #${{ github.event.issue.number }}: ${{ github.event.issue.title }}"
body: |
This PR was automatically generated from issue #${{ github.event.issue.number }}.
Closes #${{ github.event.issue.number }}.
158 changes: 158 additions & 0 deletions scripts/auto-pr-helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import json
import re
import random
import string

CHARS = string.ascii_letters + string.digits
ID_LENGTH = 12

def generate_id(prefix):
"""Generate a random ID with the given prefix."""
random_part = "".join(random.choice(CHARS) for _ in range(ID_LENGTH))
return f"{prefix}_{random_part}"

def extract_form_fields(issue_body: str) -> dict:
# Mapping from issue body headers to dict keys
header_map = {
"Chapter": "Chapter",
"Guideline Title": "Guideline Title",
"Category": "Category",
"Status": "Status",
"Release Begin": "Release Begin",
"Release End": "Release End",
"FLS Paragraph ID": "Fls Paragraph Id",
"Decidability": "Decidability",
"Scope": "Scope",
"Tags": "Tags",
"Amplification": "Amplification",
"Exception(s)": "Exception(S)",
"Rationale": "Rationale",
"Non-Compliant Example - Prose": "Non Compliant Example Prose",
"Non-Compliant Example - Code": "Non Compliant Example Code",
"Compliant Example - Prose": "Compliant Example Prose",
"Compliant Example - Code": "Compliant Example Code",
}

fields = {v: "" for v in header_map.values()}

lines = issue_body.splitlines()
current_key = None
current_value_lines = []

lines.append("### END") # Sentinel to process last field

for line in lines:
header_match = re.match(r'^### (.+)$', line.strip())
if header_match:
# Save previous field value if any
if current_key is not None:
value = "\n".join(current_value_lines).strip()
if value == "_No response_":
value = ""
if current_key in fields:
fields[current_key] = value

header = header_match.group(1).strip()
current_key = header_map.get(header) # Map to dict key or None if unknown
current_value_lines = []
else:
current_value_lines.append(line)

return fields

def save_guideline_file(content: str, chapter: str):
content = "\n" + content + "\n"
# os.makedirs(f"src/coding-guidelines/{chapter}", exist_ok=True)
filename = f"src/coding-guidelines/{chapter.lower()}.rst"

# for testing in the GA summary
print("=====CONTENT=====")
print(content)
print("=====CONTENT=END=====")

with open(filename, 'a', encoding='utf-8') as f:
f.write(content)
print(f"Saved guideline to {filename}")

def guideline_template(fields: dict) -> str:

# taken from generate-guideline-templates.py
guideline_id = generate_id("gui")
rationale_id = generate_id("rat")
non_compliant_example_id = generate_id("non_compl_ex")
compliant_example_id = generate_id("compl_ex")

def get(key):
return fields.get(key, "").strip()


guideline_text = f""".. guideline:: {get('Guideline Title')}
:id: {guideline_id}
:category: {get('Category').lower()}
:status: {get('Status').lower()}
:release: {get('Release Begin').lower()}
:fls: {get('Fls Paragraph Id').lower()}
:decidability: {get('Decidability').lower()}
:scope: {get('Scope').lower()}
:tags: {",".join(get('Tags').split(" "))}

{get('Amplification')}

.. rationale::
:id: {rationale_id}
:status: {get('Status').lower()}

{get('Rationale')}

.. non_compliant_example::
:id: {non_compliant_example_id}
:status: {get('Status').lower()}

{get('Non Compliant Example Prose')}

.. code-block:: rust

{get('Non Compliant Example Code')}

.. compliant_example::
:id: {compliant_example_id}
:status: {get('Status').lower()}

{get('Compliant Example Prose')}

.. code-block:: rust

{get('Compliant Example Code')}
"""

return guideline_text

import sys
if __name__ == "__main__":
# for testing purposes pull an issue in json format
# eg https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4
# this json is how the issue is visible to the GA bot
#
# with open('scripts/issue_sample.json', 'r', encoding='utf-8') as f:
# issue = json.load(f)
#

## locally test with `cat scripts/test_issue_sample.json | python3 scripts/auto-pr-helper.py`

issue_json = sys.stdin.read()
issue = json.loads(issue_json)

issue_number = issue['number']
issue_title = issue['title']
issue_body = issue['body']

fields = extract_form_fields(issue_body)
chapter = fields["Chapter"]


content = guideline_template(fields)


save_guideline_file(content, chapter)


124 changes: 124 additions & 0 deletions scripts/test_issue_sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4",
"repository_url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines",
"labels_url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4/labels{/name}",
"comments_url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4/comments",
"events_url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4/events",
"html_url": "https://github.com/x0rw/safety-critical-rust-coding-guidelines/issues/4",
"id": 3104390263,
"node_id": "I_kwDOOMMjbs65CTx3",
"number": 4,
"title": "[Coding Guideline]: testtt",
"user": {
"login": "x0rw",
"id": 14003018,
"node_id": "MDQ6VXNlcjE0MDAzMDE4",
"avatar_url": "https://avatars.githubusercontent.com/u/14003018?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/x0rw",
"html_url": "https://github.com/x0rw",
"followers_url": "https://api.github.com/users/x0rw/followers",
"following_url": "https://api.github.com/users/x0rw/following{/other_user}",
"gists_url": "https://api.github.com/users/x0rw/gists{/gist_id}",
"starred_url": "https://api.github.com/users/x0rw/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/x0rw/subscriptions",
"organizations_url": "https://api.github.com/users/x0rw/orgs",
"repos_url": "https://api.github.com/users/x0rw/repos",
"events_url": "https://api.github.com/users/x0rw/events{/privacy}",
"received_events_url": "https://api.github.com/users/x0rw/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"labels": [
{
"id": 8703664686,
"node_id": "LA_kwDOOMMjbs8AAAACBsdiLg",
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/labels/category:%20advisory",
"name": "category: advisory",
"color": "ededed",
"default": false,
"description": null
},
{
"id": 8703664688,
"node_id": "LA_kwDOOMMjbs8AAAACBsdiMA",
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/labels/status:%20draft",
"name": "status: draft",
"color": "ededed",
"default": false,
"description": null
},
{
"id": 8703664689,
"node_id": "LA_kwDOOMMjbs8AAAACBsdiMQ",
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/labels/decidability:%20decidable",
"name": "decidability: decidable",
"color": "ededed",
"default": false,
"description": null
},
{
"id": 8703686409,
"node_id": "LA_kwDOOMMjbs8AAAACBse3CQ",
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/labels/chapter:%20concurrency",
"name": "chapter: concurrency",
"color": "ededed",
"default": false,
"description": null
},
{
"id": 8703686412,
"node_id": "LA_kwDOOMMjbs8AAAACBse3DA",
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/labels/scope:%20crate",
"name": "scope: crate",
"color": "ededed",
"default": false,
"description": null
},
{
"id": 8703732885,
"node_id": "LA_kwDOOMMjbs8AAAACBshslQ",
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/labels/accepted",
"name": "accepted",
"color": "6AABE8",
"default": false,
"description": ""
}
],
"state": "open",
"locked": false,
"assignee": null,
"assignees": [

],
"milestone": null,
"comments": 0,
"created_at": "2025-05-30T22:24:07Z",
"updated_at": "2025-05-30T22:48:17Z",
"closed_at": null,
"author_association": "OWNER",
"active_lock_reason": null,
"sub_issues_summary": {
"total": 0,
"completed": 0,
"percent_completed": 0
},
"body": "### Chapter\n\nConcurrency\n\n### Guideline Title\n\ntest ga\n\n### Category\n\nAdvisory\n\n### Status\n\nDraft\n\n### Release Begin\n\n1.1.1\n\n### Release End\n\n1.1.1\n\n### FLS Paragraph ID\n\nfls_fsdjkfslkdfj\n\n### Decidability\n\nDecidable\n\n### Scope\n\nCrate\n\n### Tags\n\ntest gatest ga\n\n### Amplification\n\nhehehehe\n\n### Exception(s)\n\n_No response_\n\n### Rationale\n\ntest ga\n\n### Non-Compliant Example - Prose\n\ntest ga\n\n### Non-Compliant Example - Code\n\ntest ga\n\n### Compliant Example - Prose\n\ntest ga\n\n### Compliant Example - Code\n\ntest ga",
"closed_by": null,
"reactions": {
"url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4/reactions",
"total_count": 0,
"+1": 0,
"-1": 0,
"laugh": 0,
"hooray": 0,
"confused": 0,
"heart": 0,
"rocket": 0,
"eyes": 0
},
"timeline_url": "https://api.github.com/repos/x0rw/safety-critical-rust-coding-guidelines/issues/4/timeline",
"performed_via_github_app": null,
"state_reason": null
}
39 changes: 39 additions & 0 deletions src/coding-guidelines/concurrency.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,42 @@

Concurrency
===========

.. guideline:: test ga
:id: gui_ofjFRRp0goGU
:category: advisory
:status: draft
:release: 1.1.1
:fls: fls_fsdjkfslkdfj
:decidability: decidable
:scope: crate
:tags: test,gatest,ga



.. rationale::
:id: rat_4ZG4G7FBTRpw
:status: draft

test ga

.. non_compliant_example::
:id: non_compl_ex_rFC9SU9BbwXd
:status: draft

test ga

.. code-block:: rust

test ga

.. compliant_example::
:id: compl_ex_Z6gknEHscAkG
:status: draft

test ga

.. code-block:: rust

test ga

Empty file added test/test.test
Empty file.