mirror of
https://github.com/morten-olsen/configs.git
synced 2026-02-08 00:46:24 +01:00
update
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
export TMPDIR="${TMPDIR:-/tmp}"
|
export TMPDIR="${TMPDIR:-/tmp}"
|
||||||
export PATH="$PATH:$HOME/.local/bin"
|
export PATH="/opt/homebrew/bin:$PATH:$HOME/.local/bin"
|
||||||
|
|
||||||
alias ls=eza
|
alias ls=eza
|
||||||
alias cat=bat
|
alias cat=bat
|
||||||
@@ -7,3 +7,4 @@ alias grep=rg
|
|||||||
alias diff=delta
|
alias diff=delta
|
||||||
alias less=bat
|
alias less=bat
|
||||||
alias gr='if [ "`git rev-parse --show-cdup`" != "" ]; then cd `git rev-parse --show-cdup`; fi'
|
alias gr='if [ "`git rev-parse --show-cdup`" != "" ]; then cd `git rev-parse --show-cdup`; fi'
|
||||||
|
|
||||||
|
|||||||
253
playbooks/roles/software_scripts/files/list-prs.py
Normal file
253
playbooks/roles/software_scripts/files/list-prs.py
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Call GitHub API
|
||||||
|
# https://developer.github.com/v3/
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from math import floor
|
||||||
|
|
||||||
|
|
||||||
|
def time_ago(time=False):
|
||||||
|
"""
|
||||||
|
Get a datetime object, an ISO standard date string, or a int()
|
||||||
|
Epoch timestamp and return a pretty string like 'an hour ago',
|
||||||
|
'Yesterday', '3 months ago', 'just now', etc.
|
||||||
|
Modified from: http://stackoverflow.com/a/1551394/141084
|
||||||
|
"""
|
||||||
|
now = datetime.now(tz=timezone.utc)
|
||||||
|
if type(time) is int:
|
||||||
|
diff = now - datetime.fromtimestamp(time, tz=timezone.utc)
|
||||||
|
elif isinstance(time, datetime):
|
||||||
|
diff = now - time
|
||||||
|
elif type(time) is str:
|
||||||
|
diff = now - datetime.strptime(time, "%Y-%m-%dT%H:%M:%SZ").replace(
|
||||||
|
tzinfo=timezone.utc
|
||||||
|
)
|
||||||
|
elif not time:
|
||||||
|
diff = now - now
|
||||||
|
else:
|
||||||
|
raise ValueError("invalid date %s of type %s" % (time, type(time)))
|
||||||
|
second_diff = diff.seconds
|
||||||
|
day_diff = diff.days
|
||||||
|
|
||||||
|
if day_diff < 0:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if day_diff == 0:
|
||||||
|
if second_diff < 10:
|
||||||
|
return "just now"
|
||||||
|
if second_diff < 60:
|
||||||
|
return str(second_diff) + " seconds ago"
|
||||||
|
if second_diff < 120:
|
||||||
|
return "a minute ago"
|
||||||
|
if second_diff < 3600:
|
||||||
|
return str(floor(second_diff / 60)) + " minutes ago"
|
||||||
|
if second_diff < 7200:
|
||||||
|
return "an hour ago"
|
||||||
|
if second_diff < 86400:
|
||||||
|
return str(floor(second_diff / 3600)) + " hours ago"
|
||||||
|
if day_diff == 1:
|
||||||
|
return "Yesterday"
|
||||||
|
if day_diff < 7:
|
||||||
|
return str(floor(day_diff)) + " days ago"
|
||||||
|
if day_diff < 31:
|
||||||
|
return str(floor(day_diff / 7)) + " weeks ago"
|
||||||
|
if day_diff < 365:
|
||||||
|
return str(floor(day_diff / 30)) + " months ago"
|
||||||
|
return str(floor(day_diff / 365)) + " years ago"
|
||||||
|
|
||||||
|
|
||||||
|
def get_repos_for_team(org_name: str, team_name: str) -> list[str]:
|
||||||
|
"""Get a list of repos for a team."""
|
||||||
|
cmd_result = subprocess.run(
|
||||||
|
[
|
||||||
|
"gh",
|
||||||
|
"api",
|
||||||
|
f"/orgs/{org_name}/teams/{team_name}/repos",
|
||||||
|
"-H",
|
||||||
|
"Accept: application/vnd.github+json",
|
||||||
|
"--jq",
|
||||||
|
".[].full_name",
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if cmd_result.returncode != 0:
|
||||||
|
print(cmd_result.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return cmd_result.stdout.split()
|
||||||
|
|
||||||
|
|
||||||
|
def get_prs_for_repo(repo_name: str) -> list[dict]:
|
||||||
|
"""Get a list of PRs for a repo."""
|
||||||
|
# Available fields for PRs:
|
||||||
|
# additions
|
||||||
|
# assignees
|
||||||
|
# author
|
||||||
|
# baseRefName
|
||||||
|
# body
|
||||||
|
# changedFiles
|
||||||
|
# closed
|
||||||
|
# closedAt
|
||||||
|
# comments
|
||||||
|
# commits
|
||||||
|
# createdAt
|
||||||
|
# deletions
|
||||||
|
# files
|
||||||
|
# headRefName
|
||||||
|
# headRepository
|
||||||
|
# headRepositoryOwner
|
||||||
|
# id
|
||||||
|
# isCrossRepository
|
||||||
|
# isDraft
|
||||||
|
# labels
|
||||||
|
# latestReviews
|
||||||
|
# maintainerCanModify
|
||||||
|
# mergeCommit
|
||||||
|
# mergeStateStatus
|
||||||
|
# mergeable
|
||||||
|
# mergedAt
|
||||||
|
# mergedBy
|
||||||
|
# milestone
|
||||||
|
# number
|
||||||
|
# potentialMergeCommit
|
||||||
|
# projectCards
|
||||||
|
# reactionGroups
|
||||||
|
# reviewDecision
|
||||||
|
# reviewRequests
|
||||||
|
# reviews
|
||||||
|
# state
|
||||||
|
# statusCheckRollup
|
||||||
|
# title
|
||||||
|
# updatedAt
|
||||||
|
# url
|
||||||
|
cmd_result = subprocess.run(
|
||||||
|
[
|
||||||
|
"gh",
|
||||||
|
"pr",
|
||||||
|
"list",
|
||||||
|
"--json",
|
||||||
|
"number,title,author,url,headRepository,createdAt,updatedAt,isDraft,headRefName,state,reviews",
|
||||||
|
"--repo",
|
||||||
|
repo_name,
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if cmd_result.returncode != 0:
|
||||||
|
print(cmd_result.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
prs = json.loads(cmd_result.stdout)
|
||||||
|
# Convert createdAt and updatedAt to human-readable
|
||||||
|
for pr in prs:
|
||||||
|
pr["createdAtTimeAgo"] = time_ago(pr["createdAt"])
|
||||||
|
pr["updatedAtTimeAgo"] = time_ago(pr["updatedAt"])
|
||||||
|
|
||||||
|
return prs
|
||||||
|
|
||||||
|
|
||||||
|
def printTable(myDict, colList=None):
|
||||||
|
"""Pretty print a list of dictionaries (myDict) as a dynamically sized table.
|
||||||
|
If column names (colList) aren't specified, they will show in random order.
|
||||||
|
Author: Thierry Husson - Use it as you want but don't blame me.
|
||||||
|
"""
|
||||||
|
if not colList:
|
||||||
|
colList = list(myDict[0].keys() if myDict else [])
|
||||||
|
myList = [colList] # 1st row = header
|
||||||
|
for item in myDict:
|
||||||
|
myList.append(
|
||||||
|
[str(item[col] if item[col] is not None else "") for col in colList]
|
||||||
|
)
|
||||||
|
colSize = [max(map(len, col)) for col in zip(*myList)]
|
||||||
|
formatStr = " | ".join(["{{:<{}}}".format(i) for i in colSize])
|
||||||
|
myList.insert(1, ["-" * i for i in colSize]) # Seperating line
|
||||||
|
for item in myList:
|
||||||
|
print(formatStr.format(*item))
|
||||||
|
|
||||||
|
|
||||||
|
def get_pr_details(pr):
|
||||||
|
"""Extract relevant fields from pr dict."""
|
||||||
|
number = f"PR {pr['number']}"
|
||||||
|
title = pr["title"]
|
||||||
|
repo = pr["headRepository"]["name"]
|
||||||
|
url = pr["url"]
|
||||||
|
author = pr["author"]["login"]
|
||||||
|
created = pr["createdAtTimeAgo"]
|
||||||
|
updated = pr["updatedAtTimeAgo"]
|
||||||
|
is_draft = pr["isDraft"]
|
||||||
|
return {
|
||||||
|
"number": number,
|
||||||
|
"title": title,
|
||||||
|
"repo": repo,
|
||||||
|
"url": url,
|
||||||
|
"author": author,
|
||||||
|
"updated": updated,
|
||||||
|
"is_draft": is_draft,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main(
|
||||||
|
org_name: str,
|
||||||
|
team_name: str,
|
||||||
|
ignore_repos: list[str],
|
||||||
|
include_drafts: bool,
|
||||||
|
include_dependabot: bool,
|
||||||
|
):
|
||||||
|
"""Get a list of PRs for a team."""
|
||||||
|
repos = get_repos_for_team(org_name, team_name)
|
||||||
|
prs = []
|
||||||
|
for repo in repos:
|
||||||
|
if repo.split("/")[1] in ignore_repos:
|
||||||
|
continue
|
||||||
|
prs.extend(get_prs_for_repo(repo))
|
||||||
|
|
||||||
|
# Sort by updated date (descending)
|
||||||
|
prs.sort(key=lambda pr: pr["updatedAt"], reverse=True)
|
||||||
|
|
||||||
|
prs_relevant = [
|
||||||
|
get_pr_details(pr)
|
||||||
|
for pr in prs
|
||||||
|
if pr["author"]["login"] != "dependabot" or include_dependabot
|
||||||
|
]
|
||||||
|
|
||||||
|
# Filter out draft PRs
|
||||||
|
if not include_drafts:
|
||||||
|
prs_relevant = [pr for pr in prs_relevant if not pr["is_draft"]]
|
||||||
|
|
||||||
|
printTable(prs_relevant, ["url", "title", "author", "updated"])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--org", help="GitHub organization name", default="0north")
|
||||||
|
parser.add_argument(
|
||||||
|
"--team", help="GitHub team name", default="voyage-optimisation"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--include-dependabot",
|
||||||
|
help="Include dependabot PRs",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--include-drafts", help="Include draft PRs", action="store_true", default=False
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--ignore-repos", "-i,", help="Ignore repos", nargs="+", default=[]
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
main(
|
||||||
|
args.org,
|
||||||
|
args.team,
|
||||||
|
args.ignore_repos,
|
||||||
|
args.include_drafts,
|
||||||
|
args.include_dependabot,
|
||||||
|
)
|
||||||
52
playbooks/roles/software_scripts/files/rollout.sh
Normal file
52
playbooks/roles/software_scripts/files/rollout.sh
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/zsh
|
||||||
|
##############################################################
|
||||||
|
# ROLLOUT
|
||||||
|
# GitHub helper command
|
||||||
|
#
|
||||||
|
# - creates a new feature branch
|
||||||
|
# - commits all changes
|
||||||
|
# - pushes the branch to origin
|
||||||
|
# - creates a Pull Request
|
||||||
|
#
|
||||||
|
# Place somewhere in your PATH or create a shell alias
|
||||||
|
#
|
||||||
|
# Usage (in your project repo root):
|
||||||
|
# > rollout.sh <type> <...description>
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# > rollout.sh feat add vessel name to API response
|
||||||
|
#
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
unset GITHUB_TOKEN
|
||||||
|
|
||||||
|
# Extract type and description from commit message
|
||||||
|
type=$1; shift
|
||||||
|
description="$@"
|
||||||
|
commit_message="$type: $description"
|
||||||
|
|
||||||
|
# Check if a commit message was provided
|
||||||
|
if [ -z "$1" ] || [ -z "$description" ]; then
|
||||||
|
echo "Usage: rollout <type> <...description>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create branch name following Conventional Commit syntax
|
||||||
|
branch_name="${type}/$(echo "$description" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
|
echo "Creating and checking out branch: $branch_name"
|
||||||
|
git checkout -b "$branch_name" || exit 1
|
||||||
|
|
||||||
|
# Add all changes
|
||||||
|
git add --all || exit 1
|
||||||
|
|
||||||
|
echo "Committing with message: \"$commit_message\""
|
||||||
|
git commit -m "$commit_message" || exit 1
|
||||||
|
|
||||||
|
echo "Pushing branch to origin..."
|
||||||
|
git push --set-upstream origin HEAD || exit 1
|
||||||
|
|
||||||
|
echo "Creating a Pull Request..."
|
||||||
|
gh pr create --fill
|
||||||
|
|
||||||
|
echo "Rollout complete."
|
||||||
@@ -71,3 +71,4 @@ which atuin &> /dev/null && eval "$(atuin init zsh)"
|
|||||||
which direnv &> /dev/null && eval "$(direnv hook zsh)"
|
which direnv &> /dev/null && eval "$(direnv hook zsh)"
|
||||||
which starship &> /dev/null && eval "$(starship init zsh)"
|
which starship &> /dev/null && eval "$(starship init zsh)"
|
||||||
which zoxide &> /dev/null && eval "$(zoxide init zsh)"
|
which zoxide &> /dev/null && eval "$(zoxide init zsh)"
|
||||||
|
which pyenv &> /dev/null && eval "$(pyenv init --path)"
|
||||||
|
|||||||
Reference in New Issue
Block a user