This is an automated email from the ASF dual-hosted git repository. sbp pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tooling-atr-experiments.git
The following commit(s) were added to refs/heads/main by this push: new 599ec2f Add release creation, fix CSS, and update plan 599ec2f is described below commit 599ec2f7c177c62ff0488fed3393e21b5395ea74 Author: Sean B. Palmer <s...@miscoranda.com> AuthorDate: Wed Feb 19 16:53:12 2025 +0200 Add release creation, fix CSS, and update plan --- .gitignore | 5 +- atr/routes.py | 181 +++-- atr/static/README.txt | 1 + atr/static/css/atr.css | 4 +- atr/static/css/normalize.css | 754 ++++++++++----------- atr/templates/includes/sidebar.html | 19 +- atr/templates/index.html | 2 +- atr/templates/pages.html | 2 +- ...-release-candidate.html => release-attach.html} | 54 +- atr/templates/release-create.html | 125 ++++ atr/templates/user-keys-add.html | 8 +- atr/templates/user-uploads.html | 12 +- docs/plan.md | 16 +- 13 files changed, 654 insertions(+), 529 deletions(-) diff --git a/.gitignore b/.gitignore index 4ff39cf..83c2f86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,12 @@ *.pyc .DS_Store .env +.mypy_cache/ +.pytest_cache/ .ruff_cache/ .venv-poetry/ .venv-uv/ .vscode/ __pycache__/ -state/ - apptoken.txt +state/ diff --git a/atr/routes.py b/atr/routes.py index 7c00d5a..c37c9c3 100644 --- a/atr/routes.py +++ b/atr/routes.py @@ -31,12 +31,13 @@ from typing import Any, BinaryIO, cast import aiofiles import aiofiles.os import gnupg -from quart import Request, render_template, request +from quart import Request, redirect, render_template, request, url_for from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from sqlalchemy.orm.attributes import InstrumentedAttribute from sqlmodel import select from werkzeug.datastructures import FileStorage +from werkzeug.wrappers.response import Response from asfquart import APP from asfquart.auth import Requirements, require @@ -86,30 +87,25 @@ algorithms = { } -@APP.route("/") -async def root() -> str: - """Main page.""" - return await render_template("index.html") - - -@APP.route("/pages") -async def root_pages() -> str: - """List all pages on the website.""" - return await render_template("pages.html") +@asynccontextmanager +async def ephemeral_gpg_home(): + """Create a temporary directory for an isolated GPG home, and clean it up on exit.""" + temp_dir = await asyncio.to_thread(tempfile.mkdtemp, prefix="gpg-") + try: + yield temp_dir + finally: + await asyncio.to_thread(shutil.rmtree, temp_dir) -async def add_release_candidate_post(session: ClientSession, request: Request) -> str: +async def release_attach_post(session: ClientSession, request: Request) -> Response: + """Handle POST request for attaching package artifacts to a release.""" form = await request.form - project_name = form.get("project_name") - if not project_name: - raise ASFQuartException("Project name is required", errorcode=400) + # TODO: Check that the submitter is a committer of the project - # Verify user is a PMC member of the project - if project_name not in session.committees: - raise ASFQuartException( - f"You must be a PMC member of {project_name} to submit a release candidate", errorcode=403 - ) + release_key = form.get("release_key") + if not release_key: + raise ASFQuartException("Release key is required", errorcode=400) # Get all uploaded files files = await request.files @@ -135,74 +131,146 @@ async def add_release_candidate_post(session: ClientSession, request: Request) - # TODO: Need to check, ideally. Could have a data browser signature_hash = await save_file_by_hash(uploads_path, signature_file) - # Generate a 128-bit random token for the release storage key - storage_token = secrets.token_hex(16) - # Compute SHA-512 checksum of the artifact for the package record checksum_512 = compute_sha512(uploads_path / artifact_hash) - # Store in database + # Create the package record in the database + async with get_session() as db_session: + async with db_session.begin(): + package = Package( + file=artifact_hash, + signature=signature_hash, + checksum=checksum_512, + release_key=release_key, + ) + db_session.add(package) + + # Redirect to the user's uploads page + return redirect(url_for("root_user_uploads")) + + +async def release_create_post(session: ClientSession, request: Request) -> Response: + """Handle POST request for creating a new release.""" + form = await request.form + + project_name = form.get("project_name") + if not project_name: + raise ASFQuartException("Project name is required", errorcode=400) + + version = form.get("version") + if not version: + raise ASFQuartException("Version is required", errorcode=400) + + product_name = form.get("product_name") + if not product_name: + raise ASFQuartException("Product name is required", errorcode=400) + + # Verify user is a PMC member or committer of the project + if project_name not in session.committees and project_name not in session.projects: + raise ASFQuartException( + f"You must be a PMC member or committer of {project_name} to submit a release candidate", errorcode=403 + ) + + # Generate a 128-bit random token for the release storage key + # TODO: Perhaps we should call this the release_id instead + storage_token = secrets.token_hex(16) + + # Create the release record in the database async with get_session() as db_session: async with db_session.begin(): - # Get PMC statement = select(PMC).where(PMC.project_name == project_name) pmc = (await db_session.execute(statement)).scalar_one_or_none() if not pmc: + APP.logger.error(f"PMC not found for project {project_name}") + APP.logger.debug(f"Available committees: {session.committees}") + APP.logger.debug(f"Available projects: {session.projects}") raise ASFQuartException("PMC not found", errorcode=404) - # Create release record using random token as storage key - # TODO: Extract version from filename or add to form + # Create release record release = Release( storage_key=storage_token, stage=ReleaseStage.CANDIDATE, phase=ReleasePhase.RELEASE_CANDIDATE, pmc_id=pmc.id, - version="TODO", + version=version, ) db_session.add(release) - # Create package record - package = Package( - file=artifact_hash, - signature=signature_hash, - checksum=checksum_512, - release_key=release.storage_key, - ) - db_session.add(package) + # TODO: Create or link to product line + # For now, we'll just create releases without product lines + # What sort of role do product lines play in our UX? - return f"Successfully uploaded release candidate for {project_name}" + # Redirect to the attach artifacts page with the storage token + # We should possibly have a results, or list of releases, page instead + return redirect(url_for("root_release_attach", storage_key=storage_token)) -@asynccontextmanager -async def ephemeral_gpg_home(): - """ - Create a temporary directory for an isolated GnuPG home, and clean it up on exit. - This is done asynchronously to avoid blocking the event loop. - """ - # Create a temporary directory off-thread. - temp_dir = await asyncio.to_thread(tempfile.mkdtemp, prefix="gnupg-") - try: - yield temp_dir - finally: - # Remove the directory off-thread as well. - await asyncio.to_thread(shutil.rmtree, temp_dir) +@APP.route("/") +async def root() -> str: + """Main page.""" + return await render_template("index.html") + + +@APP.route("/pages") +async def root_pages() -> str: + """List all pages on the website.""" + return await render_template("pages.html") -@APP.route("/add-release-candidate", methods=["GET", "POST"]) +@APP.route("/release/attach", methods=["GET", "POST"]) @require(Requirements.committer) -async def root_add_release_candidate() -> str: - """Add a release candidate to the database.""" +async def root_release_attach() -> Response | str: + """Attach package artifacts to an existing release.""" session = await session_read() if session is None: raise ASFQuartException("Not authenticated", errorcode=401) # For POST requests, handle the file upload if request.method == "POST": - return await add_release_candidate_post(session, request) + return await release_attach_post(session, request) + + # Get the storage_key from the query parameters (if redirected from create) + storage_key = request.args.get("storage_key") + + # Get all releases where the user is a PMC member or committer of the associated PMC + async with get_session() as db_session: + release_pmc = selectinload(cast(InstrumentedAttribute[PMC], Release.pmc)) + statement = select(Release).options(release_pmc).join(PMC).where(Release.stage == ReleaseStage.CANDIDATE) + releases = (await db_session.execute(statement)).scalars().all() + + # Filter to only show releases for PMCs where the user is a member or committer + # Can we do this in sqlmodel using JSON container operators? + user_releases = [] + for r in releases: + if r.pmc is None: + continue + if session.uid in r.pmc.pmc_members or session.uid in r.pmc.committers: + user_releases.append(r) + + # For GET requests, show the form + return await render_template( + "release-attach.html", + asf_id=session.uid, + releases=user_releases, + selected_release=storage_key, + ) + + +@APP.route("/release/create", methods=["GET", "POST"]) +@require(Requirements.committer) +async def root_release_create() -> Response | str: + """Create a new release in the database.""" + session = await session_read() + if session is None: + raise ASFQuartException("Not authenticated", errorcode=401) + + # For POST requests, handle the release creation + if request.method == "POST": + return await release_create_post(session, request) # For GET requests, show the form return await render_template( - "add-release-candidate.html", + "release-create.html", asf_id=session.uid, pmc_memberships=session.committees, committer_projects=session.projects, @@ -373,6 +441,7 @@ async def root_user_keys_add() -> str: key_info=None, user_keys=user_keys, algorithms=algorithms, + committer_projects=session.projects, ) # Ensure that the selected PMCs are ones of which the user is actually a member @@ -386,6 +455,7 @@ async def root_user_keys_add() -> str: key_info=None, user_keys=user_keys, algorithms=algorithms, + committer_projects=session.projects, ) error, key_info = await user_keys_add(session, public_key, selected_pmcs) @@ -398,6 +468,7 @@ async def root_user_keys_add() -> str: key_info=key_info, user_keys=user_keys, algorithms=algorithms, + committer_projects=session.projects, ) diff --git a/atr/static/README.txt b/atr/static/README.txt index f77c8a4..24e9335 100644 --- a/atr/static/README.txt +++ b/atr/static/README.txt @@ -2,3 +2,4 @@ The following static resources are copied: bootstrap 5.3.3 fontawesome-free 6.7.2 +normalize.css 8.0.1 diff --git a/atr/static/css/atr.css b/atr/static/css/atr.css index 3defa7a..5aca184 100644 --- a/atr/static/css/atr.css +++ b/atr/static/css/atr.css @@ -50,7 +50,7 @@ h2 { margin-top: 2.5rem; margin-bottom: 1.5rem; } -h3, p, ul { margin-bottom: 1rem; } +h3, p, ul, form { margin-bottom: 1rem; } ul { padding-left: 1rem; } @@ -156,7 +156,7 @@ textarea { form.striking { background-color: #ffffee; - border: 1px solid #ddddbb; + border: 2px solid #ddddbb; padding: 1rem; border-radius: 0.5rem; } diff --git a/atr/static/css/normalize.css b/atr/static/css/normalize.css index 46ab2ba..192eb9c 100644 --- a/atr/static/css/normalize.css +++ b/atr/static/css/normalize.css @@ -1,405 +1,349 @@ - - -<!doctype html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> - - <meta property="og:url" content="https://classic.yarnpkg.com/en/package/" /> - <meta property="og:site_name" content="Yarn"/> - <meta property="og:title" content="Yarn" /> - <meta property="og:image" content="https://classic.yarnpkg.com/assets/og_image.png" /> - <meta property="og:description" content="Fast, reliable, and secure dependency management." /> - - <title>Yarn</title> - <meta name="description" content="Fast, reliable, and secure dependency management."> - - <link rel="canonical" href="https://classic.yarnpkg.com/lang/en/package/"> - <link rel="icon" href="/favicon.ico" type="image/x-icon"> - - <link rel="search" href="/opensearch.xml" type="application/opensearchdescription+xml" title="Yarn"> - - - <link rel="stylesheet" href="/css/main.css?t=2024-11-25T15:06:54+00:00"> - <meta name="google-site-verification" content="DIcCyEkVaGHm864NWzItnt2n6Gg7hz3l47RBIRyxvcQ" /> - </head> - <body> - - - - - - - - - - - - - - - - - - - - -<div class="news-container"> - <a class="news-overlay" href="https://yarnpkg.com/getting-started/migration"></a> - - <div class="news-inner"> - <div class="news-line"> - <span class="news-highlight">Important:</span> This documentation covers Yarn 1 (Classic). - </div> - <div class="news-line"> - For Yarn 2+ docs and migration guide, see yarnpkg.com. - </div> - </div> -</div> - - - - -<nav class="navbar navbar-static-top navbar-light"> - <div class="container"> - <a href="/en/"> - <svg class="logo navbar-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1154.8 518"> - <defs> - <path id="main" d=" - M718.6 257.8c-8 27.6-20.8 47.6-35.2 63.6V181c0-9.6-8.4-17.6-21.6-17.6-5.6 0-10.4 2.8-10.4 6.8 0 2.8 1.6 5.2 1.6 12.8v64.4c-4.8 28-16.8 54-32.8 54-11.6 0-18.4-11.6-18.4-33.2 0-33.6 4.4-51.2 11.6-80.8 1.6-6 13.2-22-6.4-22-21.2 0-18.4 8-21.2 14.8 0 0-13.4 47.6-13.4 90 0 34.8 14.6 57.6 41.4 57.6 17.2 0 29.6-11.6 39.2-27.6V351c-26.4 23.2-49.6 43.6-49.6 84 0 25.6 16 46 38.4 46 20.4 0 41.6-14.8 41.6-56.8V355c21.6-18.8 44.8-42.4 58.4-88.8.4-1.6.4-3.6.4-4 0-7.6-7.6-16.4-14-16.4-4 0-7.2 3.6- [...] - M833.4 301c-9.6 0-13.6-9.6-13.6-18.4v-66c0-9.6-8.4-17.6-21.6-17.6-5.6 0-10.4 2.8-10.4 6.8 0 2.8 1.6 5.2 1.6 12.8v61.6C785 291.4 777.8 301 767 301c-14 0-22.8-12-22.8-32.8 0-57.6 35.6-83.6 66-83.6 4 0 8 .8 11.6.8 4 0 5.2-2.4 5.2-9.2 0-10.4-7.6-16.8-18.4-16.8-48.8 0-95.2 40.8-95.2 107.6 0 34 16.4 60.4 47.6 60.4 15.2 0 26.4-7.2 34.4-16.4 6 9.6 16.8 16.4 30.8 16.4 34.4 0 50.4-36 57.2-62.4.4-1.6.4-2.4.4-2.8 0-7.6-7.6-16.4-14-16.4-4 0-8 3.6-9.6 12-3.6 17.6-10.8 43.2-26.8 43.2z - M949 327.4c34.4 0 50-36 57.2-62.4 0-.8.4-1.6.4-2.8 0-7.6-7.6-16.4-14-16.4-4 0-8 3.6-9.6 12-3.6 17.6-10.4 43.2-28.8 43.2-10.8 0-16-10.4-16-21.6 0-40 18-87.2 18-92 1.6-9.2-14.4-22.4-19.2-22.4h-20.8c-4 0-8 0-21.2-1.6-4.4-16.4-15.6-21.2-25.2-21.2-10.4 0-20 7.2-20 18.4 0 11.6 7.2 20 17.2 25.6-.4 20.4-2 53.6-6.4 69.6-3.6 13.6 17.2 28 22.4 11.2 7.2-23.2 9.6-58 10-73.6h34.8c-12.8 34.4-20 62.8-20 88.4 0 35.2 22.4 45.6 41.2 45.6z - M984.6 309.8c0 14.8 11.2 17.6 19.2 17.6 11.6 0 11.2-9.6 11.2-17.2v-58.4c2.8-31.6 27.6-66 39.2-66 7.6 0 8.4 10.4 8.4 22.8v81.2c0 20.4 12.4 37.6 33.6 37.6 34.4 0 51.4-36 58.2-62.4.4-1.6.4-2.4.4-2.8 0-7.6-7.6-16.4-14-16.4-4 0-8 3.6-9.6 12-3.6 17.6-11.8 43.2-27.8 43.2-10.4 0-10.4-14.8-10.4-18.4v-82.8c0-18.4-6.4-40.4-33.2-40.4-19.6 0-34 17.2-44.8 39.6v-18c0-9.6-8.4-17.6-21.6-17.6-5.6 0-10.4 2.8-10.4 6.8 0 2.8 1.6 5.2 1.6 12.8v126.8z - M259 0c143 0 259 116 259 259S402 518 259 518 0 402 0 259 116 0 259 0z"/> - </defs> - - <use class="logo-primary" xlink:href="#main" x="0" y="0"/> - - <path class="logo-secondary" d="M435.2 337.5c-1.8-14.2-13.8-24-29.2-23.8-23 .3-42.3 12.2-55.1 20.1-5 3.1-9.3 5.4-13 7.1.8-11.6.1-26.8-5.9-43.5-7.3-20-17.1-32.3-24.1-39.4 8.1-11.8 19.2-29 24.4-55.6 4.5-22.7 3.1-58-7.2-77.8-2.1-4-5.6-6.9-10-8.1-1.8-.5-5.2-1.5-11.9.4C293.1 96 289.6 93.8 286.9 92c-5.6-3.6-12.2-4.4-18.4-2.1-8.3 3-15.4 11-22.1 25.2-1 2.1-1.9 4.1-2.7 6.1-12.7.9-32.7 5.5-49.6 23.8-2.1 2.3-6.2 4-10.5 5.6h.1c-8.8 3.1-12.8 10.3-17.7 23.3-6.8 18.2.2 36.1 7.1 47.7-9.4 8.4-21.9 21.8 [...] -</svg> - - <span class="sr-only">Yarn</span> - </a> - - <div class="clearfix hidden-lg-up"> - <button class="navbar-toggler hidden-lg-up float-right" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="exCollapsingNavbar2" - aria-expanded="false" aria-label="Toggle navigation"></button> - </div> - - <div class="collapse navbar-toggleable-md" id="navbar"> - <ul class="nav navbar-nav"> - <li class="nav-item"> - <a class="nav-link" href="/en/docs/getting-started">Getting Started</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="/en/docs">Docs</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="/en/packages">Packages</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="/blog">Blog</a> - </li> - </ul> - - <ul class="nav navbar-nav navbar-nav-right float-lg-right"> - - <li class="nav-item dropdown"> - <a id="dropdownNavLanguage" class="nav-link dropdown-toggle" role="button" href="#" data-toggle="dropdown" aria-haspopup="true" - aria-expanded="false"> - <svg class="language navbar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> - <path d="M19.753 10.909c-.624-1.707-2.366-2.726-4.661-2.726-.09 0-.176.002-.262.006l-.016-2.063 3.525-.607c.115-.019.133-.119.109-.231-.023-.111-.167-.883-.188-.976-.027-.131-.102-.127-.207-.109-.104.018-3.25.461-3.25.461l-.013-2.078c-.001-.125-.069-.158-.194-.156l-1.025.016c-.105.002-.164.049-.162.148l.033 2.307s-3.061.527-3.144.543c-.084.014-.17.053-.151.143.019.09.19 1.094.208 1.172.018.08.072.129.188.107l2.924-.504.035 2.018c-1.077.281-1.801.824-2.256 1.303-.768.807-1.207 1.887-1.2 [...] -</svg> - English - </a> - <div class="dropdown-menu" aria-labelledby="dropdownNavLanguage" id="dropdownNavLanguageMenu"> - - <a href="/en/package" class="dropdown-item active" - data-lang="en"> - English - </a> - - <a href="/es-ES/package" class="dropdown-item" - data-lang="es"> - Español - </a> - - <a href="/fr/package" class="dropdown-item" - data-lang="fr"> - Français - </a> - - <a href="/id-ID/package" class="dropdown-item" - data-lang="id"> - Bahasa Indonesia - </a> - - <a href="/ja/package" class="dropdown-item" - data-lang="ja"> - 日本語 - </a> - - <a href="/pt-BR/package" class="dropdown-item" - data-lang="pt-br"> - Português (Brasil) - </a> - - <a href="/ru/package" class="dropdown-item" - data-lang="ru"> - Русский - </a> - - <a href="/tr/package" class="dropdown-item" - data-lang="tr"> - Türkçe - </a> - - <a href="/uk/package" class="dropdown-item" - data-lang="uk"> - Українська - </a> - - <a href="/zh-Hans/package" class="dropdown-item" - data-lang="zh-cn"> - 中文 - </a> - - <a href="/zh-Hant/package" class="dropdown-item" - data-lang="zh-hk"> - 繁體中文 - </a> - - </div> - </li> - - - <li class="nav-item"> - <a class="nav-link" href="https://discord.gg/yarnpkg"> - <svg class="discord navbar-icon" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="discord-svg" fill="none" viewBox="0 0 71 55"> - <title id="discord-svg">Discord</title> -<path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5 [...] -</svg> - - <span class="sr-only">Discord</span> - </a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://twitter.com/yarnpkg"> - <svg class="twitter navbar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 203.1" role="img" aria-labelledby="twitter-svg"> - <title id="twitter-svg">Twitter</title> - <path d="M78.6 203.1c94.3 0 145.9-78.2 145.9-145.9 0-2.2 0-4.4-.1-6.6 10-7.3 18.7-16.3 25.6-26.5-9.4 4.1-19.3 6.9-29.5 8.1 10.7-6.4 18.7-16.5 22.5-28.4-10.1 6-21.1 10.2-32.6 12.4C191-4.5 158.5-5.5 137.8 14c-13.3 12.5-19 31.2-14.8 49C81.9 60.9 43.4 41.4 17.4 9.4 3.8 32.8 10.7 62.8 33.3 77.8c-8.2-.2-16.1-2.4-23.3-6.4v.6c0 24.4 17.2 45.4 41.2 50.3-7.6 2.1-15.5 2.4-23.2.9 6.7 20.9 26 35.2 47.9 35.6-18.2 14.3-40.6 22-63.7 22-4.1 0-8.2-.3-12.2-.7 23.5 15.1 50.7 23 78.6 23"/> -</svg> - - <span class="sr-only">Twitter</span> - </a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://www.facebook.com/yarnpkg"> - <svg class="facebook navbar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 266.9 266.9" role="img" aria-labelledby="facebook-svg"> - <title id="facebook-svg">Facebook</title> - <path d="M252.2 0H14.7C6.6 0 0 6.6 0 14.7v237.4c0 8.1 6.6 14.7 14.7 14.7h127.8V163.5h-34.8v-40.3h34.8V93.6c0-34.5 21.1-53.2 51.8-53.2 14.7 0 27.4 1.1 31.1 1.6v36h-21.3c-16.7 0-20 7.9-20 19.6v25.7H224l-5.2 40.3h-34.7V267h68c8.1 0 14.7-6.6 14.7-14.7V14.7c.1-8.1-6.5-14.7-14.6-14.7z"/> -</svg> - - <span class="sr-only">Facebook</span> - </a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://github.com/yarnpkg"> - <svg class="github navbar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32.6 31.8" role="img" aria-labelledby="github-svg"> - <title id="github-svg">GitHub</title> - <path d="M16.3 0C7.3 0 0 7.3 0 16.3c0 7.2 4.7 13.3 11.1 15.5.8.1 1.1-.4 1.1-.8v-2.8c-4.5 1-5.5-2.2-5.5-2.2-.7-1.9-1.8-2.4-1.8-2.4-1.5-1 .1-1 .1-1 1.6.1 2.5 1.7 2.5 1.7 1.5 2.5 3.8 1.8 4.7 1.4.1-1.1.6-1.8 1-2.2-3.6-.4-7.4-1.8-7.4-8.1 0-1.8.6-3.2 1.7-4.4-.1-.3-.7-2 .2-4.2 0 0 1.4-.4 4.5 1.7 1.3-.4 2.7-.5 4.1-.5 1.4 0 2.8.2 4.1.5 3.1-2.1 4.5-1.7 4.5-1.7.9 2.2.3 3.9.2 4.3 1 1.1 1.7 2.6 1.7 4.4 0 6.3-3.8 7.6-7.4 8 .6.5 1.1 1.5 1.1 3V31c0 .4.3.9 1.1.8 6.5-2.2 11.1-8.3 11.1-15.5C32.6 7.3 25.3 [...] -</svg> - - <span class="sr-only">GitHub</span> - </a> - </li> - </ul> - </div> - </div> -</nav> - - <div id="search"> - <!-- Here to avoid flash of unstyled content on page load --> - <div class="ais-InstantSearch-root full-searchbox"> - <form novalidate="" class="ais-SearchBox"> - <div role="search" class="ais-SearchBox-form"></div> - </form> - </div> - </div> - <main> - - -<div class="hero"> - <div class="container"> - <h1 class="hero-text display-4">Package detail</h1> - </div> -</div> - -<div class="container"> - -<div id="pkg-detail"> - <div data-reactroot="" class="details row"> - <section class="details-main col-lg-8"> - <header class="details-main--header"> - <h2 class="details-main--title d-inline-block m-2">…</h2> - <div class="details-main--info d-inline-block m-2"><a class="ais-Hit-ownerLink" href=""><img width="20" height="20" class="ais-Hit-ownerAvatar" src="https://res.cloudinary.com/hilnmyskv/image/fetch/w_40,h_40,f_auto,q_80,fl_lossy/https://avatars3.githubusercontent.com/u/22247014?v=3&s=200"><!-- react-text: 8 --><!-- /react-text --></a> - <span - class="ais-Hit-popular null" title="0 downloads in the last 30 days">0</span> - <!-- react-empty: 10 --> - <!-- react-empty: 11 --><span class="ais-Hit-version"></span></div> - <div> - <p class="m-2 lead">…</p> - </div> - <!-- react-empty: 15 --> - </header> - <section id="readme" class="details-doc"> - <h3 class="details-doc--title details-doc--title__readme py-1"><a href="#readme">readme</a></h3> - </section> - </section> - <aside class="details-side col-lg-4"> - <article class="details-side--links"> - <div class="detail-links"> - <div target="_blank" rel="noopener noreferrer" class="details-links--link details-links--link__yarn"><img src="/assets/search/ico-yarn.svg" alt=""> - <div class="copyable"> - <div class="copyable--content"><span><a href="https://yarn.pm/…"><!-- react-text: 28 -->yarn.pm/<!-- /react-text --><!-- react-text: 29 -->…<!-- /react-text --></a></span></div> - <button - class="copyable--button user-select-none"><img src="/assets/detail/ico-copy-default.svg" alt="" class="copyable--button__img"> - <!-- react-text: 32 -->copy - <!-- /react-text --> - </button> - </div> - </div><a target="_blank" rel="noopener noreferrer" href="https://github.com//" class="details-links--link details-links--link__github"><img src="/assets/search/ico-github.svg" alt=""><!-- react-text: 35 -->/<!-- /react-text --></a> - <a - target="_blank" rel="noopener noreferrer" href="https://www.npmjs.com/package/…" class="details-links--link details-links--link__npm"><img src="/assets/search/ico-npm.svg" alt=""> - <!-- react-text: 38 -->… - <!-- /react-text --> - </a> - </div> - </article> - <article class="details-side--copy"> - <h1>Use it</h1> - <div class="copyable"><code class="copyable--content"><!-- react-text: 43 -->$ <!-- /react-text --><span><!-- react-text: 45 -->yarn add <!-- /react-text --><!-- react-text: 46 -->…<!-- /react-text --></span></code> - <button - class="copyable--button user-select-none"><img src="/assets/detail/ico-copy-default.svg" alt="" class="copyable--button__img"> - <!-- react-text: 49 -->copy - <!-- /react-text --> - </button> - </div> - <div><a class="details-side--runkit" href="https://runkit.com/npm/…" target="_blank" rel="noopener noreferrer">Try in RunKit</a> - <!-- react-text: 52 -->· - <!-- /react-text --><a href="#">Browse Files</a></div> - </article> - <article class="details-side--cdns"> - <h1>CDNs</h1> - <dl></dl> - </article> - <article class="details-side--popularity"> - <h1>Popularity</h1> - <dl></dl> - </article> - <!-- react-text: 57 --> - <!-- /react-text --> - <article class="details-side--usage"> - <h1>Usage</h1> - <dl> - <div class="d-flex justify-items-between w-100"><img src="/assets/detail/ico-dependencies.svg" alt=""> - <dt>Dependencies</dt><span class="dotted flex-grow"></span> - <dd>0</dd> - </div> - <div class="d-flex justify-items-between w-100"><img src="/assets/detail/ico-devdependencies.svg" alt=""> - <dt>DevDependencies</dt><span class="dotted flex-grow"></span> - <dd>0</dd> - </div> - <div class="d-flex justify-items-between w-100"><img src="/assets/detail/ico-package-json.svg" alt=""> - <dt>Packages</dt><span class="dotted flex-grow"></span> - <dd><a target="_blank" rel="noopener noreferrer" href="https://github.com///tree/master/package.json">see package.json</a></dd> - </div> - </dl> - </article> - <article class="details-side--versions"> - <h1>Versions</h1> - <dl></dl> - </article> - <article class="details-side--contributors"> - <h1>Contributors</h1> - <ul class="list-unstyled m-2"> - <li class="mb-1"> - <a class="ais-Hit-ownerLink" href=""><img width="20" height="20" class="ais-Hit-ownerAvatar" src="https://res.cloudinary.com/hilnmyskv/image/fetch/w_40,h_40,f_auto,q_80,fl_lossy/https://avatars3.githubusercontent.com/u/22247014?v=3&s=200"> - <!-- react-text: 86 --> - <!-- /react-text --> - </a> - </li> - </ul> - </article> - </aside> - </div> -</div> - -</div> -</main> - - - -<hr class="footer-divider"> - -<div class="container"> - <footer class="footer"> - <div class="footer-left"> - <span class="footer-item">Yarn</span> - <span class="footer-item"><a href="https://github.com/yarnpkg/yarn/blob/master/LICENSE">Distributed under BSD License</a></span> - <span class="footer-item"><a href="/en/org/code-of-conduct">Code of Conduct</a></span> - </div> - - <div class="footer-right"> - - - - <span class="footer-item"><a href="https://github.com/yarnpkg/website/edit/master/lang/en/package.html">Edit this page</a></span> - - </div> - </footer> -</div> -<script> - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-85522875-1', 'auto'); - ga('send', 'pageview'); -</script> - - - -<script> - var i18n_default = {"search_placeholder":"Search packages (i.e. babel, webpack, react…)","search_by_algolia":"Search by Algolia","search_by_read_more":"read how it works","no_package_found":"No package {name} was found","no_results_docsearch":"Were you looking for something in the {documentation_link}?","documentation":"documentation","downloads_in_last_30_days":"{count} downloads in the last 30 days","npm_page_for":"npm page for {name}","repository_of":"{provider} repository of {name} [...] - window.i18n = {"search_placeholder":"Search packages (i.e. babel, webpack, react…)","search_by_algolia":"Search by Algolia","search_by_read_more":"read how it works","no_package_found":"No package {name} was found","no_results_docsearch":"Were you looking for something in the {documentation_link}?","documentation":"documentation","downloads_in_last_30_days":"{count} downloads in the last 30 days","npm_page_for":"npm page for {name}","repository_of":"{provider} repository of {name}","np [...] - window.i18n.url_base = "/en"; - window.i18n.active_language = "en"; - - // give defaults - function copyDefaults(from, to) { - for (var key in from) { - if (from[key] !== null && typeof from[key] === 'object') { - copyDefaults(from[key], to[key] || (to[key] = {})); - continue; - } - if (to.hasOwnProperty(key) === false || to[key] === null) { - to[key] = from[key]; - } - } - } - - copyDefaults(i18n_default, window.i18n); -</script> - - <script src="/js/build/vendor.bb983233e26fd3fd2fe3.js"></script> - <script src="/js/build/common.2a29ed27bfa751cd6609.js"></script> - - - <script src="/js/build/package.302c84e81c9aeae765da.js"></script> - - </body> -</html> +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/atr/templates/includes/sidebar.html b/atr/templates/includes/sidebar.html index 68b342b..46c8ce9 100644 --- a/atr/templates/includes/sidebar.html +++ b/atr/templates/includes/sidebar.html @@ -30,15 +30,11 @@ <ul> <li> <a href="{{ url_for('root') }}" - {% if request.endpoint == 'root' %}class="active"{% endif %}>Home</a> - </li> - <li> - <a href="{{ url_for('root_pages') }}" - {% if request.endpoint == 'root_pages' %}class="active"{% endif %}>Pages</a> + {% if request.endpoint == 'root' %}class="active"{% endif %}>About ATR</a> </li> <li> <a href="{{ url_for('root_pmc_directory') }}" - {% if request.endpoint == 'root_pmc_directory' %}class="active"{% endif %}>PMCs</a> + {% if request.endpoint == 'root_pmc_directory' %}class="active"{% endif %}>Projects</a> </li> </ul> @@ -46,12 +42,17 @@ <h3>Release management</h3> <ul> <li> - <a href="{{ url_for('root_add_release_candidate') }}" - {% if request.endpoint == 'root_add_release_candidate' %}class="active"{% endif %}>Add release candidate</a> + <a href="{{ url_for('root_release_create') }}" + {% if request.endpoint == 'root_release_create' %}class="active"{% endif %}>Create release candidate</a> + </li> + <!-- TODO: Don't show this if the user doesn't have any release candidates? --> + <li> + <a href="{{ url_for('root_release_attach') }}" + {% if request.endpoint == 'root_release_attach' %}class="active"{% endif %}>Attach package artifacts</a> </li> <li> <a href="{{ url_for('root_user_uploads') }}" - {% if request.endpoint == 'root_user_uploads' %}class="active"{% endif %}>Your uploads</a> + {% if request.endpoint == 'root_user_uploads' %}class="active"{% endif %}>Your release candidates</a> </li> </ul> diff --git a/atr/templates/index.html b/atr/templates/index.html index 3d7dd7a..66bcd9e 100644 --- a/atr/templates/index.html +++ b/atr/templates/index.html @@ -21,7 +21,7 @@ <h2>Getting Started</h2> <p> - To submit a release candidate, you must be a PMC member of the target project. First, <a href="{{ url_for('root_user_keys_add') }}">add your signing key</a>, then <a href="{{ url_for('root_add_release_candidate') }}">upload your release candidate</a>. + To submit a release candidate, you must be a PMC member of the target project. First, <a href="{{ url_for('root_user_keys_add') }}">add your signing key</a>, then <a href="{{ url_for('root_release_create') }}">create a release candidate</a>. </p> <h2>Documentation</h2> diff --git a/atr/templates/pages.html b/atr/templates/pages.html index 13eee25..de9db30 100644 --- a/atr/templates/pages.html +++ b/atr/templates/pages.html @@ -137,7 +137,7 @@ <div class="endpoint"> <h3> - <a href="{{ url_for('root_add_release_candidate') }}">/add-release-candidate</a> + <a href="{{ url_for('root_release_create') }}">/release/create</a> </h3> <div class="endpoint-description">Add a release candidate to the database.</div> <div class="endpoint-meta"> diff --git a/atr/templates/add-release-candidate.html b/atr/templates/release-attach.html similarity index 65% rename from atr/templates/add-release-candidate.html rename to atr/templates/release-attach.html index 6186473..082a784 100644 --- a/atr/templates/add-release-candidate.html +++ b/atr/templates/release-attach.html @@ -1,11 +1,11 @@ {% extends "layouts/base.html" %} {% block title %} - Add release candidate ~ ATR + Attach package artifacts ~ ATR {% endblock title %} {% block description %} - Add a release candidate to the database. + Attach package artifacts to an existing release. {% endblock description %} {% block stylesheets %} @@ -13,8 +13,6 @@ <style> .form-table { width: 100%; - border-collapse: separate; - border-spacing: 0 1rem; } .form-table th { @@ -64,47 +62,29 @@ {% endblock stylesheets %} {% block content %} - <h1>Add release candidate</h1> - <p class="intro">On this page, you can add a release candidate to the database.</p> - - <div class="user-info"> - <h2>Your account information</h2> - <p> - Welcome, <strong>{{ asf_id }}</strong>! You are authenticated as an ASF committer. - </p> - - {% if pmc_memberships %} - <h3>PMC memberships</h3> - <ul> - {% for pmc in pmc_memberships %}<li>{{ pmc }}</li>{% endfor %} - </ul> - {% endif %} - - {% if committer_projects %} - <h3>Committer access</h3> - <ul> - {% for project in committer_projects %}<li>{{ project }}</li>{% endfor %} - </ul> - {% endif %} - </div> - - <h2>Select files</h2> + <h1>Attach package artifacts</h1> + <p class="intro"> + Welcome, <strong>{{ asf_id }}</strong>! Use this form to attach package artifacts to an existing release candidate. + </p> <form method="post" enctype="multipart/form-data" class="striking"> <table class="form-table"> <tbody> <tr> <th> - <label for="project_name">Project:</label> + <label for="release_key">Release:</label> </th> <td> - <select id="project_name" name="project_name" required> - <option value="">Select a project...</option> - {% for pmc in pmc_memberships %}<option value="{{ pmc }}">{{ pmc }}</option>{% endfor %} + <select id="release_key" name="release_key" required> + <option value="">Select a release...</option> + {% for release in releases %} + <option value="{{ release.storage_key }}" + {% if release.storage_key == selected_release %}selected{% endif %}> + {{ release.pmc.project_name }} - {{ release.version }} + </option> + {% endfor %} </select> - {% if not pmc_memberships %} - <p class="error-message">You must be a PMC member to submit a release candidate.</p> - {% endif %} + {% if not releases %}<p class="error-message">No releases found that you can attach artifacts to.</p>{% endif %} </td> </tr> @@ -141,7 +121,7 @@ <tr> <td></td> <td> - <button type="submit" {% if not pmc_memberships %}disabled{% endif %}>Submit Release Candidate</button> + <button type="submit" {% if not releases %}disabled{% endif %}>Attach Package Artifacts</button> </td> </tr> </tbody> diff --git a/atr/templates/release-create.html b/atr/templates/release-create.html new file mode 100644 index 0000000..b0d476c --- /dev/null +++ b/atr/templates/release-create.html @@ -0,0 +1,125 @@ +{% extends "layouts/base.html" %} + +{% block title %} + Create release candidate ~ ATR +{% endblock title %} + +{% block description %} + Create a new release candidate. +{% endblock description %} + +{% block stylesheets %} + {{ super() }} + <style> + .form-table { + width: 100%; + } + + .form-table th { + width: 200px; + text-align: right; + padding-right: 1rem; + vertical-align: top; + font-weight: 500; + } + + .form-table td { + vertical-align: top; + } + + .form-table label { + border-bottom: none; + padding-bottom: 0; + } + + select, + input[type="file"] { + display: block; + margin-bottom: 0.5rem; + } + + .help-text { + color: #666; + font-size: 0.9em; + display: block; + margin-top: 0.25rem; + } + + .error-message { + color: #dc3545; + margin-top: 0.25rem; + } + + button { + margin-top: 1rem; + } + + button:disabled { + opacity: 0.5; + cursor: not-allowed; + } + </style> +{% endblock stylesheets %} + +{% block content %} + <h1>Create release candidate</h1> + <p class="intro"> + Welcome, <strong>{{ asf_id }}</strong>! Use this form to create a new release candidate for + your project. You can create a new release candidate for any project of which you are a release + manager. Release managers at the ASF must be either PMC members or committers. + </p> + <p> + ATR will guide you through the process of turning your release candidate into a final release, + providing tools and automation to help during each step of the workflow. + </p> + + <form method="post" enctype="multipart/form-data" class="striking"> + <table class="form-table"> + <tbody> + <tr> + <th> + <label for="project_name">Project:</label> + </th> + <td> + <select id="project_name" name="project_name" required> + <option value="">Select a project...</option> + {% for project in (pmc_memberships + committer_projects)|unique|sort %} + <option value="{{ project }}">{{ project }}</option> + {% endfor %} + </select> + {% if not pmc_memberships and not committer_projects %} + <p class="error-message">You must be a PMC member or committer to submit a release candidate.</p> + {% endif %} + </td> + </tr> + + <tr> + <th> + <label for="version">Version:</label> + </th> + <td> + <input type="text" id="version" name="version" required /> + </td> + </tr> + + <tr> + <th> + <label for="product_name">Product name:</label> + </th> + <td> + <!-- TODO: Add a dropdown for the product name, plus "add new product" --> + <input type="text" id="product_name" name="product_name" required /> + </td> + </tr> + + <tr> + <td></td> + <td> + <button type="submit" + {% if not pmc_memberships and not committer_projects %}disabled{% endif %}>Create release</button> + </td> + </tr> + </tbody> + </table> + </form> +{% endblock content %} diff --git a/atr/templates/user-keys-add.html b/atr/templates/user-keys-add.html index 1ad838c..d5e7c13 100644 --- a/atr/templates/user-keys-add.html +++ b/atr/templates/user-keys-add.html @@ -230,12 +230,12 @@ <td>{{ key.declared_uid or 'Not specified' }}</td> </tr> <tr> - <th>Associated PMCs</th> + <th>Associated projects</th> <td> {% if key.pmcs %} {{ key.pmcs|map(attribute='project_name') |join(', ') }} {% else %} - No PMCs associated + No projects associated {% endif %} </td> </tr> @@ -262,9 +262,9 @@ {% if pmc_memberships %} <div class="form-group"> - <label>Associate with PMCs:</label> + <label>Associate with projects:</label> <div class="pmc-checkboxes"> - {% for pmc in pmc_memberships %} + {% for pmc in (pmc_memberships + committer_projects)|unique|sort %} <div class="checkbox-item"> <input type="checkbox" id="pmc_{{ pmc }}" diff --git a/atr/templates/user-uploads.html b/atr/templates/user-uploads.html index d456d93..48df508 100644 --- a/atr/templates/user-uploads.html +++ b/atr/templates/user-uploads.html @@ -1,11 +1,11 @@ {% extends "layouts/base.html" %} {% block title %} - Your uploads ~ ATR + Release candidates ~ ATR {% endblock title %} {% block description %} - Your uploaded release candidates. + Release candidates to which you have access. {% endblock description %} {% block stylesheets %} @@ -57,8 +57,8 @@ {% endblock stylesheets %} {% block content %} - <h1>Your uploads</h1> - <p class="intro">Here are all the release candidates you've uploaded.</p> + <h1>Release candidates</h1> + <p class="intro">Here are all the release candidates to which you have access.</p> {% if releases %} <div class="release-list"> @@ -94,10 +94,10 @@ {% endfor %} </div> {% else %} - <p class="no-releases">You haven't uploaded any release candidates yet.</p> + <p class="no-releases">You haven't created any releases yet.</p> {% endif %} <p> - <a href="{{ url_for('root_add_release_candidate') }}">Upload a new release candidate</a> + <a href="{{ url_for('root_release_create') }}">Create a release candidate</a> </p> {% endblock content %} diff --git a/docs/plan.md b/docs/plan.md index 166c8ed..85ecb60 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -5,6 +5,7 @@ This is a rough plan of immediate tasks. The priority of these tasks may change, ## UX improvements 1. Enhance RC display + - Add the option to upload package artifacts without signatures - Replace raw file hashes with the original filenames in the UI - Add file size and upload timestamp - Improve the layout of file listings @@ -25,6 +26,7 @@ Advanced tasks, possibly deferred - Add developer RC download buttons with clear verification instructions - Check RC file naming conventions - Display vote status and timeline + - Add ability to sign artifact hashes on the platform using JS ## Task scheduler @@ -67,23 +69,23 @@ These tasks are dependent on the task scheduler above. ## Advanced RC validation -1. Dependency analysis +1. Reproducible build verification + - Accept upload of binary artifact builds + - Compare built built artifacts with any existing provided binary artifacts + - Give a detailed report of differences between user provided builds + +2. Dependency analysis - Parse and validate dependency licenses - Check for prohibited licenses - Generate dependency reports - Flag dependency vulnerabilities -2. Distribution channel integration +3. Distribution channel integration - Add PyPI distribution support - Implement Maven Central publishing - Add Docker Hub integration - Support test distribution channels -3. Reproducible build verification - - Track builds of binary artifacts from source release - - Compare built artifacts with the provided binaries - - Give a detailed report of the build and the differences - ## Process automation These are long term implementation requirements. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tooling.apache.org For additional commands, e-mail: dev-h...@tooling.apache.org