1
0
forked from wrenn/wrenn

2 Commits

Author SHA1 Message Date
1b9c29d7cd Add CI for release notes
Some checks failed
ci/woodpecker/push/pipeline Pipeline failed
2026-05-13 22:25:22 +06:00
78f2ea603f v0.1.6 (#45)
## What's New?
Performance updates for large capsules, admin panel enhancement and bug fixes

### Envd
- Fixed bug with sandbox metrics calculation
- Page cache drop and balloon inflation to reduce memfile snapshot
- Updated rpc timeout logic for better control
- Added tests

### Admin Panel
- Add/Remove platform admin
- Updated template deletion logic for fine grained permission

### Others
- Minor frontend visual improvement
- Minor bugfixes
- Version bump

Co-authored-by: Tasnim Kabir Sadik <tksadik92@gmail.com>
Reviewed-on: wrenn/wrenn#45
Co-authored-by: pptx704 <rafeed@omukk.dev>
Co-committed-by: pptx704 <rafeed@omukk.dev>
2026-05-13 22:24:13 +06:00
4 changed files with 70 additions and 93 deletions

2
.gitignore vendored
View File

@ -55,3 +55,5 @@ internal/dashboard/static/*
.dual-graph/ .dual-graph/
# Added by code-review-graph # Added by code-review-graph
.code-review-graph/ .code-review-graph/
__pycache__

View File

@ -21,7 +21,6 @@ steps:
from_secret: wrenn_api_key from_secret: wrenn_api_key
commands: commands:
- pip install wrenn - pip install wrenn
- export RUST_VERSION=$$(grep '^rust-version ' envd-rs/Cargo.toml | cut -d'"' -f2)
- python .woodpecker/scripts/build_rust.py - python .woodpecker/scripts/build_rust.py
depends_on: [] depends_on: []

View File

@ -73,6 +73,7 @@ def install_rust(capsule: Capsule) -> bool:
def clone_repo(capsule: Capsule) -> bool: def clone_repo(capsule: Capsule) -> bool:
try: try:
capsule.git.clone(REPO_URL, REPO_DIR) capsule.git.clone(REPO_URL, REPO_DIR)
capsule.commands.run(f"cd {REPO_DIR} && git checkout fix/large-operations")
print("OK [git clone]") print("OK [git clone]")
return True return True
except GitCommandError as e: except GitCommandError as e:
@ -84,6 +85,17 @@ def build_rust(capsule: Capsule) -> bool:
if run(capsule, f"mkdir -p {REPO_DIR}/builds") != 0: if run(capsule, f"mkdir -p {REPO_DIR}/builds") != 0:
return False return False
# result = capsule.commands.run("file --version")
# print(result.stdout)
# result = capsule.commands.run(
# 'git rev-parse --short HEAD 2>/dev/null || echo "unknown"'
# )
# commit = result.stdout
# run(capsule, f"mkdir -p {REPO_DIR}/builds")
# result = capsule.commands.run("which musl-gcc")
# print(result.stdout)
handle = capsule.commands.run( handle = capsule.commands.run(
"make build-envd", "make build-envd",
background=True, background=True,
@ -106,6 +118,23 @@ def build_rust(capsule: Capsule) -> bool:
return False return False
print("OK [rust build]") print("OK [rust build]")
# if (
# run(
# capsule,
# f"cp {REPO_DIR}/envd-rs/target/x86_64-unknown-linux-musl/release/envd {REPO_DIR}/builds/envd",
# envs={"BIN_DIR": REPO_DIR},
# )
# != 0
# ):
# return False
# result = capsule.commands.run(f"readelf -d {REPO_DIR}/builds/envd 2>&1")
# print(result.stdout, end="")
# if result.stderr:
# print(result.stderr, end="", file=sys.stderr)
# result = capsule.commands.run(f"file {REPO_DIR}/builds/envd 2>&1")
# print(result.stdout)
return True return True

View File

@ -105,73 +105,32 @@ def get_git_context(
def generate_release_notes( def generate_release_notes(
capsule: Capsule, capsule: Capsule,
current_tag: str,
git_log: str,
git_diff: str,
output_path: str, output_path: str,
model: str, model: str,
) -> None: ) -> None:
prompt = f""" prompt = (
You are inside a cloned git repository at: f"You are writing release notes for version {current_tag} of a software project.\n\n"
f"Here is what changed between the previous version and this one:\n\n"
{REPO_DIR} f"Commit messages:\n{git_log}\n\n"
f"Files and areas that changed:\n{git_diff}\n\n"
Generate release notes for the latest tagged version of this software project. f"Write the release notes in plain, friendly language that any developer can understand "
f"without deep knowledge of the codebase. Avoid jargon like 'goroutine', 'PTY', 'envd', "
Before writing anything, inspect the repository yourself using git commands. f"or internal function names — describe what the change means for the user instead. "
f"Group related changes under headings that reflect what actually changed. "
You MUST determine: f"Only include sections that are relevant to these specific changes. "
1. The latest version tag. f"Start with a short one-line summary of what this release is about. "
2. The previous version tag, if one exists. f"Keep each bullet point to one clear sentence.\n\n"
3. The commits between the previous tag and the latest tag. f"Here is an example of the style to aim for — not a template to copy:\n\n"
4. The files and areas changed between those tags. f"{RELEASE_NOTES_EXAMPLE}\n\n"
f"You MUST start the document with `## What's New`\n"
Use commands like: f"The very next line MUST be a single short summary sentence.\n"
f"Output only the markdown. No intro, no explanation."
git tag --sort=-version:refname f"CRITICAL: Do not output any conversational filler, acknowledgments, or thoughts "
f"like 'Let me look at the changes'. Output absolutely nothing except the final markdown."
If there are at least two tags, compare the newest tag against the previous tag: )
git log PREVIOUS_TAG..LATEST_TAG --pretty=format:'%s (%h)'
git diff PREVIOUS_TAG..LATEST_TAG --stat
git diff PREVIOUS_TAG..LATEST_TAG --name-only
If there is only one tag, inspect the latest tag with:
git log LATEST_TAG --pretty=format:'%s (%h)' -n 50
git show LATEST_TAG --stat
git show LATEST_TAG --name-only
Do not rely on any pre-injected commit list or diff summary.
You must inspect the git history yourself.
Write the release notes in plain, friendly language that any developer can understand
without deep knowledge of the codebase.
Avoid jargon like "goroutine", "PTY", "envd", or internal function names.
Describe what the change means for the user instead.
Group related changes under headings that reflect what actually changed.
Only include sections that are relevant to the actual changes.
Do not include CI/CD-only changes.
Start with:
## What's New
The very next line must be a single short summary sentence.
Keep each bullet point to one clear sentence.
Here is an example of the style to aim for — not a template to copy:
{RELEASE_NOTES_EXAMPLE}
Output only the final markdown.
No intro.
No explanation.
No conversational filler.
No acknowledgments.
No "I checked the logs" text.
No thoughts.
""".strip()
prompt_b64 = base64.b64encode(prompt.encode("utf-8")).decode("utf-8") prompt_b64 = base64.b64encode(prompt.encode("utf-8")).decode("utf-8")
@ -186,22 +145,23 @@ def generate_release_notes(
print(f"FAIL [write prompt]: {result.stderr}", file=sys.stderr) print(f"FAIL [write prompt]: {result.stderr}", file=sys.stderr)
sys.exit(1) sys.exit(1)
# FIX: Wrapper function to handle execution and authentication dynamically
def run_opencode_with_model(target_model: str) -> int: def run_opencode_with_model(target_model: str) -> int:
env = "" env = ""
if "zhipu" in target_model.lower(): if "zhipu" in target_model.lower():
env = f"ZHIPU_API_KEY={os.environ.get('ZHIPU_API_KEY', '')}" env = f"ZHIPU_API_KEY={os.environ.get('ZHIPU_API_KEY', '')}"
raw_output_path = "/tmp/opencode_raw.txt"
cmd = ( cmd = (
f"{env} " f"{env} "
f"~/.opencode/bin/opencode run " f"~/.opencode/bin/opencode run "
f'"Read the attached file and generate the release notes. Output ONLY markdown." ' f'"Read the attached file and generate the release notes. Output ONLY markdown." '
f"--model {target_model} " f"--model {target_model} "
f"--file /tmp/oc_prompt.txt " f"--file /tmp/oc_prompt.txt "
f"> {raw_output_path}" f"> {output_path}"
) )
cmd_result = capsule.commands.run(cmd, cwd=REPO_DIR, timeout=300) cmd_result = capsule.commands.run(cmd, cwd=REPO_DIR, timeout=120)
if cmd_result.exit_code != 0: if cmd_result.exit_code != 0:
print( print(
f"FAIL [opencode via {target_model}]: exit={cmd_result.exit_code}", f"FAIL [opencode via {target_model}]: exit={cmd_result.exit_code}",
@ -210,30 +170,6 @@ def generate_release_notes(
print(f"STDOUT:\n{cmd_result.stdout}", file=sys.stderr) print(f"STDOUT:\n{cmd_result.stdout}", file=sys.stderr)
print(f"STDERR:\n{cmd_result.stderr}", file=sys.stderr) print(f"STDERR:\n{cmd_result.stderr}", file=sys.stderr)
clean_cmd = (
f"awk 'found || /^## What.s [Nn]ew/ {{ found=1; print }}' "
f"{raw_output_path} > {output_path}"
)
clean_result = capsule.commands.run(clean_cmd, cwd=REPO_DIR, timeout=10)
if clean_result.exit_code != 0:
print(f"FAIL [clean output]: {clean_result.stderr}", file=sys.stderr)
return clean_result.exit_code
check_result = capsule.commands.run(
f"grep -q '^## What.s New' {output_path}",
cwd=REPO_DIR,
timeout=10,
)
if check_result.exit_code != 0:
print(
"FAIL: Could not find release notes heading in opencode output",
file=sys.stderr,
)
print(cmd_result.stdout, file=sys.stderr)
print(cmd_result.stderr, file=sys.stderr)
return 1
return cmd_result.exit_code return cmd_result.exit_code
# First attempt with the target model # First attempt with the target model
@ -284,13 +220,24 @@ def main() -> None:
capsule.git.clone( capsule.git.clone(
REPO_URL, REPO_URL,
REPO_DIR, REPO_DIR,
username="tksadik92",
) )
print("OK [git clone]") print("OK [git clone]")
current_tag, previous_tag = get_tags(capsule)
git_log, git_diff = get_git_context(capsule, current_tag, previous_tag)
# Note: This simply creates the directory string safely # Note: This simply creates the directory string safely
output_path = os.path.normpath(CAPSULE_OUTPUT) output_path = os.path.normpath(CAPSULE_OUTPUT)
generate_release_notes(capsule, output_path, model) generate_release_notes(
capsule,
current_tag,
git_log,
git_diff,
output_path,
model,
)
download_release_notes(capsule) download_release_notes(capsule)