Shrink flake-updating action (#193)

This commit is contained in:
Patrick Stevens
2024-07-12 19:44:13 +01:00
committed by GitHub
parent b7a240bbb9
commit 31bd9e22f2
3 changed files with 7 additions and 177 deletions

View File

@@ -1,168 +0,0 @@
import datetime
import time
import subprocess
import requests
import os
import base64
from typing import Literal, TypedDict
class TreeEntry(TypedDict):
path: str
mode: Literal["100644", "100755", "120000"]
type: Literal["blob", "tree"]
sha: str
# GitHub API configuration
GITHUB_API_URL = "https://api.github.com"
GITHUB_TOKEN = os.environ.get("BEARER_TOKEN")
if not GITHUB_TOKEN:
raise Exception("Supply BEARER_TOKEN env var")
REPO = os.environ.get("GITHUB_REPOSITORY")
if not REPO:
raise Exception("Supply GITHUB_REPOSITORY env var")
DEFAULT_BRANCH = os.environ.get("DEFAULT_BRANCH") or ""
if not DEFAULT_BRANCH:
raise Exception("Supply DEFAULT_BRANCH env var")
GITHUB_OUTPUT = os.environ.get("GITHUB_OUTPUT") or ""
if not GITHUB_OUTPUT:
raise Exception("Supply GITHUB_OUTPUT env var")
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {GITHUB_TOKEN}",
"X-GitHub-Api-Version": "2022-11-28"
}
def get_git_diff():
"""Get the files which have changed in the current repository."""
return subprocess.check_output(["git", "diff", "--name-only"]).decode("utf-8").splitlines()
def create_blob(content, encoding="utf-8"):
"""Create a blob in the GitHub repository."""
url = f"{GITHUB_API_URL}/repos/{REPO}/git/blobs"
data = {
"content": content,
"encoding": encoding
}
response = requests.post(url, headers=headers, json=data)
if not response.ok:
raise Exception(f"bad response: {response}")
print(f"Blob response: {response.text}")
return response.json()["sha"]
def create_tree(base_tree: str, changes: list[TreeEntry]) -> str:
"""Create a new tree with the given changes."""
url = f"{GITHUB_API_URL}/repos/{REPO}/git/trees"
data = {
"base_tree": base_tree,
"tree": changes
}
response = requests.post(url, headers=headers, json=data)
if not response.ok:
raise Exception(f"bad response: {response}")
print(f"Tree response: {response.text}")
return response.json()["sha"]
def create_commit(tree_sha: str, parent_sha: str, message: str):
"""Create a new commit."""
url = f"{GITHUB_API_URL}/repos/{REPO}/git/commits"
data = {
"message": message,
"tree": tree_sha,
"parents": [parent_sha]
}
print(f"Commit request body: {data}")
response = requests.post(url, headers=headers, json=data)
if not response.ok:
raise Exception(f"bad response: {response}")
print(f"Commit response: {response.text}")
json = response.json()
print(f"Commit: {json}")
return json["sha"]
def is_executable(filepath: str):
return os.path.isfile(filepath) and os.access(filepath, os.X_OK)
def get_current_commit() -> str:
return subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("utf-8").strip()
def get_current_tree() -> str:
return [line for line in subprocess.check_output(["git", "cat-file", "-p", "HEAD"]).decode("utf-8").splitlines() if line.startswith('tree ')][0][5:]
def create_branch(branch_name: str, commit_sha: str) -> None:
url = f"{GITHUB_API_URL}/repos/{REPO}/git/refs"
data = {
"ref": f"refs/heads/{branch_name}",
"sha": commit_sha
}
print(f"Branch creation request body: {data}")
response = requests.post(url, headers=headers, json=data)
if not response.ok:
raise Exception(f"bad response: {response}")
print(f"Branch creation response: {response.text}")
def create_pull_request(title: str, branch_name: str, base_branch: str) -> tuple[str, int]:
"""Returns the URL of the new PR."""
url = f"{GITHUB_API_URL}/repos/{REPO}/pulls"
data = {
"title": title,
"head": branch_name,
"base": base_branch,
"body": "Automated pull request.",
"maintainer_can_modify": True
}
print(f"PR creation request body: {data}")
response = requests.post(url, headers=headers, json=data)
if not response.ok:
raise Exception(f"bad response: {response}")
print(f"PR creation response: {response.text}")
json = response.json()
return json["url"], json["number"]
def main():
changed_files = get_git_diff()
if not changed_files:
return
# Create blobs and prepare tree changes
tree_changes = []
for file_path in changed_files:
with open(file_path, "rb") as file:
contents = base64.b64encode(file.read()).decode('ascii')
blob_sha = create_blob(contents, encoding="base64")
if is_executable(file_path):
mode = "100755"
else:
mode = "100644"
tree_changes.append(TreeEntry({
"path": file_path,
"mode": mode,
"type": "blob",
"sha": blob_sha
}))
base_tree = get_current_tree()
# Create a new tree
new_tree_sha = create_tree(base_tree, tree_changes)
print(f"Tree: {new_tree_sha}")
# Create a new commit
commit_message = "Automated commit"
new_commit_sha = create_commit(new_tree_sha, get_current_commit(), commit_message)
print(f"New commit created: {new_commit_sha}")
branch_name = f"flake_update" + datetime.datetime.fromtimestamp(time.time()).strftime('%Y_%m_%d-%H_%M_%S_%f')
create_branch(branch_name, new_commit_sha)
print(f"Branch created: {branch_name}")
url, pr_num = create_pull_request(title="Upgrade Nix flake and deps", branch_name=branch_name, base_branch=DEFAULT_BRANCH)
print(f"See PR at: {url}")
with open(GITHUB_OUTPUT, "a") as output_file:
output_file.write(f"pull-request-number={pr_num}")
if __name__ == "__main__":
main()

View File

@@ -2,6 +2,8 @@
name: Weekly Nix Flake Update
on:
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * 0' # Runs at 00:00 every Sunday
workflow_dispatch: # Allows manual triggering
@@ -41,15 +43,12 @@ jobs:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Prepare to create commit
run: python -m venv /tmp/venv && /tmp/venv/bin/python -m pip install -r .github/workflows/requirements.txt
- name: Create pull request
- name: Raise pull request
uses: Smaug123/commit-action@cc25e6d80a796c49669dda4a0aa36c54c573983d
id: cpr
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
BEARER_TOKEN: ${{ steps.generate-token.outputs.token }}
run: /tmp/venv/bin/python .github/workflows/commit.py
with:
bearer-token: ${{ steps.generate-token.outputs.token }}
pr-title: "Upgrade Nix flake and deps"
- name: Enable Pull Request Automerge
if: ${{ steps.cpr.outputs.pull-request-number }}

View File

@@ -1 +0,0 @@
requests