From 56dcfd4735f8d39555aa9259818b0cb7e0207e8a Mon Sep 17 00:00:00 2001 From: Elijah ben Izzy Date: Mon, 11 May 2026 13:19:52 -0700 Subject: [PATCH 1/3] ci: gate merging on a single Release Validation summary job (#775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: gate merging on a single Release Validation summary job Adds a "summary" job to release-validation.yml that depends on check-paths, build-artifacts, and install-and-smoke and runs with if: always(). It translates the upstream conclusions into a single binary verdict — success/skipped → pass, failure or cancelled → fail — so the required check has a stable name and a definite state regardless of whether upstream jobs ran or were path-filtered out. In .asf.yaml the required contexts drop from two matrix-suffixed names ("Release Validation / build-artifacts", "Release Validation / install-and-smoke (3.12)") to one: "Release Validation / summary". Why this is needed: - PRs that only touch docs/ or website/ trigger check-paths to set should_run=false, which skips the heavy jobs. - GitHub treats SKIPPED jobs as non-passing for required-status- checks, so those PRs were stuck in BLOCKED state forever (see commit a655edf2 for the previous attempt that didn't work for this exact reason). - The summary job sidesteps the SKIPPED ambiguity because it always runs and always produces a definite SUCCESS or FAILURE. Real code PRs are unaffected: if any release-validation job fails, the summary fails, and merging is blocked. * style: run black on burr/core/graph.py Drive-by fix — `f7a1750d` (rename shadowed `format` builtin) left this file black-non-compliant for line-length=100. Caught by pre-commit on this branch. --- .asf.yaml | 9 ++++--- .github/workflows/release-validation.yml | 30 ++++++++++++++++++++++++ burr/core/graph.py | 4 +--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.asf.yaml b/.asf.yaml index 1c342d43d..344bbcf6f 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -62,10 +62,13 @@ github: required_status_checks: # strict means "Require branches to be up to date before merging". strict: false - # contexts are the names of checks that must pass + # The Release Validation workflow ends in a single "summary" job that + # runs with if: always() and translates upstream SUCCESS or SKIPPED + # into a definite SUCCESS, FAILURE into FAILURE. That gives us one + # stable required check name regardless of whether the upstream jobs + # ran (real code PR) or were path-filtered out (docs/website PR). contexts: - - "Release Validation / build-artifacts" - - "Release Validation / install-and-smoke (3.12)" + - "Release Validation / summary" required_pull_request_reviews: dismiss_stale_reviews: false require_code_owner_reviews: false diff --git a/.github/workflows/release-validation.yml b/.github/workflows/release-validation.yml index 6271cd80c..a1872db35 100644 --- a/.github/workflows/release-validation.yml +++ b/.github/workflows/release-validation.yml @@ -193,3 +193,33 @@ jobs: path: /tmp/burr-smoke-* retention-days: 7 if-no-files-found: ignore + + # Single stable required-check name. Always runs (if: always()) so it produces + # a definite SUCCESS or FAILURE — never SKIPPED. Branch protection in + # .asf.yaml requires this context, not the underlying jobs, so path-filtered + # docs/website PRs (where the upstream jobs are skipped) still go green here. + summary: + name: "Release Validation / summary" + needs: [check-paths, build-artifacts, install-and-smoke] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 2 + steps: + - name: Verdict + env: + CHECK_PATHS: ${{ needs.check-paths.result }} + BUILD_ARTIFACTS: ${{ needs.build-artifacts.result }} + INSTALL_AND_SMOKE: ${{ needs.install-and-smoke.result }} + run: | + echo "check-paths: $CHECK_PATHS" + echo "build-artifacts: $BUILD_ARTIFACTS" + echo "install-and-smoke: $INSTALL_AND_SMOKE" + # Pass if every needed job is success or skipped; fail if any + # failed or was cancelled. + for r in "$CHECK_PATHS" "$BUILD_ARTIFACTS" "$INSTALL_AND_SMOKE"; do + case "$r" in + success|skipped) ;; + *) echo "::error::Release Validation failed (one or more jobs not success/skipped)"; exit 1 ;; + esac + done + echo "Release Validation: all upstream jobs success or skipped." diff --git a/burr/core/graph.py b/burr/core/graph.py index b31e1cab6..c5c4dfaae 100644 --- a/burr/core/graph.py +++ b/burr/core/graph.py @@ -107,9 +107,7 @@ def _render_graphviz( graphviz_obj.render(path_without_suffix, format=fmt, view=view) else: # `.pipe()` doesn't append the format to the filename, so we do it explicitly - pathlib.Path(f"{path_without_suffix}.{fmt}").write_bytes( - graphviz_obj.pipe(format=fmt) - ) + pathlib.Path(f"{path_without_suffix}.{fmt}").write_bytes(graphviz_obj.pipe(format=fmt)) @dataclasses.dataclass From b4f2903be02978e36fea68868e18fe7e3254a3cb Mon Sep 17 00:00:00 2001 From: Elijah ben Izzy Date: Mon, 11 May 2026 13:33:06 -0700 Subject: [PATCH 2/3] website: add Downloads page per ASF release policy (#771) * website: add Downloads page per ASF release policy Adds a /downloads route covering the 0.42.0-incubating and 0.41.0-incubating releases with mirror-selection links for tarballs, direct HTTPS links for signatures and checksums, GPG/SHA-512 verification instructions, and the standard incubator disclaimer. Adds a "Download" entry to the navbar. Addresses the IPMC vote feedback that burr.apache.org needs a public download page per https://www.apache.org/legal/release-policy.html#publication. The repo-root .gitignore has a `downloads/` rule (Python packaging), which shadows the new Next.js app-router directory; a negation rule is added in website/.gitignore to re-include it. * website: restructure downloads page for end users Lead with install + UI launch + quick links, then ASF source releases, then verification. Apache compliance content is still present but no longer the first thing a Python dev sees. Also: flag 0.41.0 PyPI packaging issues with a note on its release card, and render version headings as "X.Y.Z (incubating)" rather than "X.Y.Z-incubating". --- website/.gitignore | 4 + website/src/app/downloads/page.tsx | 514 +++++++++++++++++++++++++++++ website/src/lib/constants.ts | 7 +- 3 files changed, 522 insertions(+), 3 deletions(-) create mode 100644 website/src/app/downloads/page.tsx diff --git a/website/.gitignore b/website/.gitignore index a047376c6..ae5e03fe6 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -4,3 +4,7 @@ out/ *.tsbuildinfo next-env.d.ts public/docs/ + +# The repo-root .gitignore has `downloads/` (Python packaging convention), +# which would otherwise hide the Next.js /downloads app route. Re-include it. +!src/app/downloads/ diff --git a/website/src/app/downloads/page.tsx b/website/src/app/downloads/page.tsx new file mode 100644 index 000000000..3ab220db8 --- /dev/null +++ b/website/src/app/downloads/page.tsx @@ -0,0 +1,514 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import type { Metadata } from "next"; +import Navbar from "@/components/Navbar"; +import Footer from "@/components/Footer"; +import { GITHUB_REPO, DOCS_URL } from "@/lib/constants"; + +export const metadata: Metadata = { + title: "Download — Apache Burr (Incubating)", + description: + "Install Apache Burr from PyPI, or download the official Apache source releases with signatures and checksums.", +}; + +const PYPI_URL = "https://pypi.org/project/apache-burr/"; +const EXAMPLES_URL = `${GITHUB_REPO}/tree/main/examples`; +const DISCORD_URL = "https://discord.gg/6Zy2DwP4f3"; + +const MIRROR_BASE = "https://www.apache.org/dyn/closer.lua/incubator/burr"; +const DIST_BASE = "https://downloads.apache.org/incubator/burr"; +const KEYS_URL = `${DIST_BASE}/KEYS`; +const ARCHIVE_URL = "https://archive.apache.org/dist/incubator/burr/"; +const VERIFY_DOC_URL = "https://www.apache.org/info/verification.html"; +const RELEASE_POLICY_URL = + "https://www.apache.org/legal/release-policy.html#publication"; + +// Adding a new release: append a single entry to RELEASES below. The +// artifact filenames, labels, and descriptions are derived from the +// version via ARTIFACT_TEMPLATES, so no per-release boilerplate is +// needed beyond the version + date. + +type Artifact = { + filename: string; + label: string; + description: string; +}; + +type Release = { + version: string; // e.g. "0.42.0" + date: string; // human-readable + note?: string; // optional caveat shown on the release card +}; + +type ArtifactTemplate = { + label: string; + filename: (version: string) => string; + description: (version: string) => string; +}; + +const ARTIFACT_TEMPLATES: ArtifactTemplate[] = [ + { + label: "Source release", + filename: (v) => `apache-burr-${v}-incubating-src.tar.gz`, + description: () => + "The official source release. This is the artifact voted on by the IPMC.", + }, + { + label: "Python sdist", + filename: (v) => `apache-burr-${v}-incubating-sdist.tar.gz`, + description: () => + "Python source distribution used by flit to build the wheel. Convenience artifact.", + }, + { + label: "Python wheel", + filename: (v) => `apache_burr-${v}-py3-none-any.whl`, + description: (v) => + `Pre-built Python wheel. Convenience binary, also published on PyPI as apache-burr ${v}.`, + }, +]; + +// To add a release, prepend an entry. The first entry is rendered as "Latest". +const RELEASES: Release[] = [ + { version: "0.42.0", date: "May 9, 2026" }, + { + version: "0.41.0", + date: "January 2026", + note: "The PyPI wheel for 0.41.0 had packaging issues. Build from the source release if you need this version, or just use 0.42.0.", + }, +]; + +function artifactsFor(version: string): Artifact[] { + return ARTIFACT_TEMPLATES.map((t) => ({ + filename: t.filename(version), + label: t.label, + description: t.description(version), + })); +} + +const LATEST = RELEASES[0]; + +function mirrorUrl(version: string, filename: string): string { + return `${MIRROR_BASE}/${version}/${filename}?action=download`; +} + +function directUrl(version: string, filename: string, ext: string): string { + return `${DIST_BASE}/${version}/${filename}.${ext}`; +} + +function ReleaseSection({ + release, + isLatest, +}: { + release: Release; + isLatest: boolean; +}) { + const headingId = `release-${release.version}`; + return ( +
+
+

+ {release.version}{" "} + (incubating) +

+ {isLatest && ( + + Latest + + )} + + Released {release.date} + +
+ + {release.note && ( +
+ + Note: + {" "} + {release.note} +
+ )} + +
+ + + + + + + + + + + {artifactsFor(release.version).map((a) => ( + + + + + + + ))} + +
ArtifactDownloadSignatureChecksum
+
{a.label}
+
+ {a.description} +
+
+ + {a.filename} + + + + .asc + + + + .sha512 + +
+
+ +

+ Tarball links use the{" "} + + ASF mirror selection service + + . Signatures and checksums are served directly from{" "} + downloads.apache.org over HTTPS. +

+
+ ); +} + +function LinkCard({ + href, + title, + description, + external = true, +}: { + href: string; + title: string; + description: string; + external?: boolean; +}) { + return ( + +
{title}
+
{description}
+
+ ); +} + +export default function DownloadsPage() { + return ( + <> + +
+
+ {/* Header */} +
+

+ Get Apache Burr{" "} + (incubating) +

+

+ Install from PyPI, run the UI locally, or grab the official + Apache source release. +

+
+ + {/* Install */} +
+

Install

+
+

+ Burr is on PyPI. Install with pip: +

+
+                pip install apache-burr
+              
+ +

+ For the tracking UI, examples, and common LLM integrations, + install the [learn]{" "} + extras: +

+
+                {`pip install "apache-burr[learn]"`}
+              
+ +

+ To pin a specific version: +

+
+                {`pip install "apache-burr==${LATEST.version}"`}
+              
+ +

+ Requires Python 3.10+. Burr has no required runtime + dependencies — extras are opt-in. +

+
+
+ + {/* Run the UI */} +
+

Run the UI

+
+

+ Once installed with the [learn]{" "} + extras, launch the local tracking UI to inspect and debug + your applications: +

+
+                burr
+              
+

+ Opens at{" "} + http://localhost:7241 + . Apps that use{" "} + .with_tracker("local"){" "} + will show up automatically. +

+
+
+ + {/* Quick links */} +
+

Where to next

+
+ + + + + + +
+
+ + {/* Apache source releases */} +
+

Apache source releases

+

+ Burr is an Apache Software Foundation project. The source release + is the official artifact voted on by the IPMC; per the{" "} + + ASF release policy + + , the wheel and sdist below are the same bits published to PyPI. + If you're packaging Burr for redistribution, or you simply + prefer to build from source, start here. +

+ +
+

+ Latest +

+ +
+ + {RELEASES.length > 1 && ( +
+

+ Previous +

+
+ {RELEASES.slice(1).map((r) => ( + + ))} +
+

+ Older releases live in the{" "} + + ASF archive + + . +

+
+ )} +
+ + {/* Verifying releases */} +
+

Verifying a release

+

+ If you're downloading source releases above, you{" "} + should verify + them before use. The PGP signature ( + .asc) proves the + release was signed by an Apache Burr release manager; the SHA-512 + checksum (.sha512) + detects transmission corruption. +

+ +

1. Import the KEYS file

+

+ The KEYS file holds the public PGP keys of all Apache Burr + release managers, served from{" "} + downloads.apache.org: +

+
+              {`curl -O ${KEYS_URL}
+gpg --import KEYS`}
+            
+ +

2. Verify the signature

+
+              {`gpg --verify apache-burr-${LATEST.version}-incubating-src.tar.gz.asc \\
+            apache-burr-${LATEST.version}-incubating-src.tar.gz`}
+            
+

+ Look for "Good signature from ..." in the output. A + warning that the key is not certified by a trusted signature is + expected unless you've set up a web of trust — what matters + is that the fingerprint matches one in KEYS. +

+ +

3. Verify the checksum

+
+              {`sha512sum -c apache-burr-${LATEST.version}-incubating-src.tar.gz.sha512`}
+            
+

+ On macOS, use{" "} + shasum -a 512 -c{" "} + instead of sha512sum -c + . +

+ +

+ For more detail, see the{" "} + + official ASF verification guide + + . +

+
+ + {/* License & disclaimer */} +
+

License & disclaimer

+

+ Apache Burr is released under the{" "} + + Apache License, Version 2.0 + + . The full LICENSE and{" "} + NOTICE files are + included in every source release. +

+

+ Apache Burr (Incubating) is an effort undergoing incubation at + The Apache Software Foundation (ASF), sponsored by the Apache + Incubator. Incubation is required of all newly accepted projects + until a further review indicates that the infrastructure, + communications, and decision making process have stabilized in a + manner consistent with other successful ASF projects. While + incubation status is not necessarily a reflection of the + completeness or stability of the code, it does indicate that the + project has yet to be fully endorsed by the ASF. +

+
+
+
+