From e7f4b2732c1c0da513e5e030e20f545e6189ed56 Mon Sep 17 00:00:00 2001 From: Jason Walker <913443@dadeschools.net> Date: Sun, 21 Jun 2026 15:35:57 -0400 Subject: [PATCH] Initial commit --- README.md | 24 ++++++++++++++++++++++ close_issue.sh | 15 ++++++++++++++ create_issue.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ create_pr.py | 44 ++++++++++++++++++++++++++++++++++++++++ create_pr.sh | 14 +++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 README.md create mode 100755 close_issue.sh create mode 100755 create_issue.py create mode 100755 create_pr.py create mode 100755 create_pr.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f40b5d --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Gitea Tools + +A collection of Python and Bash scripts to automate interactions with Gitea instances. + +## Setup + +A Python virtual environment is included. Activate it using: +```bash +source venv/bin/activate +``` + +## Authentication + +These scripts securely extract tokens from the macOS keychain to avoid hardcoding secrets. + +- **Dade Schools (gitea.dadeschools.net)**: Retrieved via `git credential fill`. Ensure you have logged in via Git over HTTPS at least once so the keychain caches your credentials. +- **NetBridge / Personal (gitea.prgs.cc)**: Retrieved using `security find-generic-password` for the service `netbridge-gitea-token`. + +## Available Scripts + +- `./create_issue.py` - Create an issue in the Gitea tracker +- `./create_pr.py` - Open a Pull Request from a branch via the API +- `./create_pr.sh` - Bash equivalent for creating a PR via the API +- `./close_issue.sh` - Close a specific issue via the API diff --git a/close_issue.sh b/close_issue.sh new file mode 100755 index 0000000..2a01463 --- /dev/null +++ b/close_issue.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +HOST="gitea.dadeschools.net" +API="https://$HOST/api/v1" +ORG="Contractor" +REPO="Timesheet" +ISSUE_NUM=$1 + +CREDS=$(printf "host=%s\nprotocol=https\n\n" "$HOST" | git credential fill) +USER=$(printf '%s\n' "$CREDS" | sed -n 's/^username=//p') +PASS=$(printf '%s\n' "$CREDS" | sed -n 's/^password=//p') + +AUTH=(-u "$USER:$PASS") +PAYLOAD='{"state": "closed"}' + +curl -sSL -X PATCH "${AUTH[@]}" -H "Content-Type: application/json" -d "$PAYLOAD" "$API/repos/$ORG/$REPO/issues/$ISSUE_NUM" diff --git a/create_issue.py b/create_issue.py new file mode 100755 index 0000000..fc48392 --- /dev/null +++ b/create_issue.py @@ -0,0 +1,53 @@ +import subprocess +import os +import sys + +# Define the issues to create based on ROADMAP.md missing/partially done items. +ISSUES = [ + ("PDF: Preview PDF before final save", "Show a preview or summary dialog before the PDF is fully committed to disk."), + ("PDF: Compare generated PDFs against known-good samples", "Add visual or byte-comparison tests to ensure PDF rendering doesn't drift."), + ("PDF: Validate week/date placement", "Add validation that the week date ranges are accurately placed inside the generated PDF fields."), + ("PDF: Validate total hours calculation", "Add backend validation to verify that total hours printed in the PDF are mathematically correct."), + ("PDF: Warn if total hours are not 40", "Add total-hours validation and user-facing warnings when generating timesheets that do not sum to exactly 40 hours."), + ("PDF: Support PTO, sick, holiday, and blank days", "Timesheet grid assumes default hours and lacks distinct categories. Add support for PTO, sick, holiday, and blank days."), + ("PDF: Open generated PDF after creation", "Provide an option or automatic behavior to open the PDF in the default viewer immediately after generating."), + ("Email: Preview email before draft creation", "Display the email body and recipients before launching Outlook."), + ("Email: Saved manager recipient", "Allow saving the manager's email address in settings so it populates automatically."), + ("Email: Saved email templates", "Add Outlook email template body customization in Settings."), + ("GUI: One-click generate this week's timesheet", "Add a quick-action button to generate the current week's timesheet with a single click."), + ("GUI: Duplicate previous week", "Add functionality to clone the hours and projects from the previous week's timesheet."), + ("GUI: Better success screen", "Improve the UI feedback shown after a successful generation."), + ("GUI: Dark-mode friendly UI", "Ensure the UI colors and styling are properly adapted for macOS dark mode."), + ("Data: Add ~/.timesheet/history.json configuration", "History tracking is currently using `.state/history.json`. Move this to a user-local `~/.timesheet/history.json` path."), + ("Data: Track generated PDF metadata", "Track generated PDF path, week range, total hours, created_at, and email mode in the history JSON."), + ("DevOps: Local / Gitea Validation Pipeline", "Lacks git pre-commit hooks and Gitea/Woodpecker pipeline configurations for running tests and pyright."), + ("Dev: Split large GUI files into smaller controllers", "Further decomposition of large GUI panels and controllers into smaller, more maintainable modules."), + ("Dev: Add tests for manage.sh", "Add test coverage for the command-line menu tool `manage.sh`."), + ("Dev: Add app versioning", "Implement dynamic/git tagging and formal app versioning (currently only basic versioning exists)."), + ("Dev: Add About dialog", "Add an About dialog in the GUI with version and author info."), + ("Dev: Add release notes", "Create a process for generating and displaying release notes on updates."), + ("Dev: Improve project structure", "Clean up helper scripts and organize the project root structure better.") +] + +SCRIPT_PATH = "./scripts/create-issue.sh" + +def main(): + if not os.path.exists(SCRIPT_PATH): + print(f"Error: Could not find {SCRIPT_PATH}. Run this from the repository root.") + sys.exit(1) + + success_count = 0 + for title, body in ISSUES: + print(f"Creating issue: {title}") + result = subprocess.run([SCRIPT_PATH, title, body], capture_output=True, text=True) + if result.returncode == 0: + print(result.stdout.strip()) + success_count += 1 + else: + print(f"FAILED to create issue: {title}") + print(result.stderr.strip()) + + print(f"\nFinished! Created {success_count} out of {len(ISSUES)} issues.") + +if __name__ == "__main__": + main() diff --git a/create_pr.py b/create_pr.py new file mode 100755 index 0000000..40d0e30 --- /dev/null +++ b/create_pr.py @@ -0,0 +1,44 @@ +import sys +import json +import urllib.request +import subprocess +import base64 + +host = "gitea.dadeschools.net" +org = "Contractor" +repo = "Timesheet" + +p = subprocess.Popen(["git", "credential", "fill"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) +out, _ = p.communicate(f"protocol=https\nhost=gitea.dadeschools.net\n\n") + +user = "" +password = "" +for line in out.splitlines(): + if line.startswith("username="): + user = line.split("=")[1] + if line.startswith("password="): + password = line.split("=")[1] + +if not user or not password: + print("Could not get credentials") + sys.exit(1) + +url = f"https://{host}/api/v1/repos/{org}/{repo}/pulls" +data = { + "title": "feat: Support PTO, Sick, Holiday, and Unpaid days", + "body": "Closes #6", + "head": "feat/6-absence-categories", + "base": "main" +} +req = urllib.request.Request(url, data=json.dumps(data).encode("utf-8"), headers={ + "Content-Type": "application/json", +}) + +auth_b64 = base64.b64encode(f"{user}:{password}".encode("utf-8")).decode("utf-8") +req.add_header("Authorization", f"Basic {auth_b64}") + +try: + with urllib.request.urlopen(req) as response: + print(response.read().decode()) +except urllib.error.HTTPError as e: + print("Error:", e.read().decode()) diff --git a/create_pr.sh b/create_pr.sh new file mode 100755 index 0000000..b90ea36 --- /dev/null +++ b/create_pr.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +HOST="gitea.dadeschools.net" +API="https://$HOST/api/v1" +ORG="Contractor" +REPO="Timesheet" + +CREDS=$(printf "host=%s\nprotocol=https\n\n" "$HOST" | git credential fill) +USER=$(printf '%s\n' "$CREDS" | sed -n 's/^username=//p') +PASS=$(printf '%s\n' "$CREDS" | sed -n 's/^password=//p') + +AUTH=(-u "$USER:$PASS") +PAYLOAD='{"title": "feat: Support PTO, Sick, Holiday, and Unpaid days", "body": "Closes #6", "head": "feat/6-absence-categories", "base": "main"}' + +curl -sSL -X POST "${AUTH[@]}" -H "Content-Type: application/json" -d "$PAYLOAD" "$API/repos/$ORG/$REPO/pulls"