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-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new 9e82d45 Update the forms to derive a subproject and to start a new
release
9e82d45 is described below
commit 9e82d45567b3b5390c27ffb683ee53ec5da652f6
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue May 13 19:27:06 2025 +0100
Update the forms to derive a subproject and to start a new release
---
atr/routes/projects.py | 1 +
atr/routes/start.py | 2 +
atr/templates/project-add-project.html | 226 ++++++++++++++++-----------------
atr/templates/start-selected.html | 15 ++-
4 files changed, 124 insertions(+), 120 deletions(-)
diff --git a/atr/routes/projects.py b/atr/routes/projects.py
index e81558a..0102051 100644
--- a/atr/routes/projects.py
+++ b/atr/routes/projects.py
@@ -119,6 +119,7 @@ async def add_project(session: routes.CommitterSession,
project_name: str) -> re
wtforms.validators.InputRequired("Please provide a derived
project name."),
wtforms.validators.Length(min=1, max=100),
],
+ description="The desired suffix for the full project name.",
)
submit = wtforms.SubmitField("Add project")
diff --git a/atr/routes/start.py b/atr/routes/start.py
index 020e5ff..3d99ea6 100644
--- a/atr/routes/start.py
+++ b/atr/routes/start.py
@@ -38,6 +38,8 @@ class StartReleaseForm(util.QuartFormTyped):
wtforms.validators.InputRequired("Version is required"),
wtforms.validators.Length(min=1, max=100),
],
+ render_kw={"placeholder": "Examples: 1.2.3+rc1 or 2.5"},
+ description="Enter the version string for this new release.",
)
submit = wtforms.SubmitField("Start new release")
diff --git a/atr/templates/project-add-project.html
b/atr/templates/project-add-project.html
index d1cde2a..e53ec2d 100644
--- a/atr/templates/project-add-project.html
+++ b/atr/templates/project-add-project.html
@@ -14,125 +14,125 @@
</h1>
<p>New projects can only be derived from existing projects, by adding a
suffix.</p>
- <form method="post" class="atr-canary py-4">
+ {{ forms.errors_summary(form) }}
+
+ <form method="post" class="atr-canary py-4" novalidate>
{{ form.hidden_tag() }}
<div class="mb-3 pb-3 row border-bottom">
- <label for="{{ form.derived_project_name.id }}"
- class="col-sm-3 col-form-label text-sm-end">{{
form.derived_project_name.label.text }}:</label>
+ {{ forms.label(form.derived_project_name, col="sm3") }}
<div class="col-sm-8">
- {{ form.derived_project_name(class_="form-control") }}
- {% if form.derived_project_name.errors -%}
- <span class="text-danger small">{{
form.derived_project_name.errors[0] }}</span>{%- endif %}
- <p class="text-muted mt-1">The desired suffix for the full project
name.</p>
- <p id="capitalisation-warning" class="text-danger small mt-1 d-none">
- <i class="bi bi-exclamation-triangle"></i>
- Warning: Ensure all words in the derived name start with a capital
for proper display.
- </p>
- </div>
- </div>
-
- <div class="mb-3 pb-3 row border-bottom">
- <label id="new-project-name-label"
- for="new-project-name-display"
- class="col-sm-3 col-form-label text-sm-end">Project name
preview:</label>
- <div class="col-sm-8">
- <code id="new-project-name-display"
- class="form-control-plaintext bg-light p-2 rounded
d-block"></code>
- <p class="text-muted small mt-1">This will be the full display name
for the derived project.</p>
- </div>
+ {{ forms.widget(form.derived_project_name,
id=form.derived_project_name.id) }}
+ {{ forms.errors(form.derived_project_name, classes="text-danger
small") }}
+ {{ forms.description(form.derived_project_name, classes="text-muted
mt-1") }}
+ <p id="capitalisation-warning" class="text-danger small mt-1 d-none">
+ <i class="bi bi-exclamation-triangle"></i>
+ Warning: Ensure all words in the derived name start with a capital
for proper display.
+ </p>
</div>
+ </div>
- <div class="mb-3 pb-3 row border-bottom">
- <label id="new-project-label-label"
- for="new-project-label-display"
- class="col-sm-3 col-form-label text-sm-end">Project label
preview:</label>
- <div class="col-sm-8">
- <code id="new-project-label-display"
- class="form-control-plaintext bg-light p-2 rounded
d-block"></code>
- <p class="text-muted small mt-1">This will be the short label used
in URLs and identifiers.</p>
- </div>
+ <div class="mb-3 pb-3 row border-bottom">
+ <label id="new-project-name-label"
+ for="new-project-name-display"
+ class="col-sm-3 col-form-label text-sm-end">Project name
preview</label>
+ <div class="col-sm-8">
+ <code id="new-project-name-display"
+ class="form-control-plaintext bg-light p-2 rounded
d-block"></code>
+ <p class="text-muted small mt-1">This will be the full display name
for the derived project.</p>
</div>
+ </div>
- <div class="row">
- <div class="col-sm-9 offset-sm-3">{{ form.submit(class_="btn
btn-primary mt-3") }}</div>
+ <div class="mb-3 pb-3 row border-bottom">
+ <label id="new-project-label-label"
+ for="new-project-label-display"
+ class="col-sm-3 col-form-label text-sm-end">Project label
preview</label>
+ <div class="col-sm-8">
+ <code id="new-project-label-display"
+ class="form-control-plaintext bg-light p-2 rounded
d-block"></code>
+ <p class="text-muted small mt-1">This will be the short label used in
URLs and identifiers.</p>
</div>
- </form>
- {% endblock content %}
-
- {% block javascripts %}
- {{ super() }}
- <script>
- document.addEventListener("DOMContentLoaded", () => {
- const projectLabel = document.getElementById("{{
form.project_name.id }}");
- const projectSelect = "{{ project_name }}";
- const derivedNameInput = document.getElementById("{{
form.derived_project_name.id }}");
- const newNameDisplay =
document.getElementById("new-project-name-display");
- const newLabelDisplay =
document.getElementById("new-project-label-display");
- const capitalisationWarning =
document.getElementById("capitalisation-warning");
-
- if (!projectSelect || !derivedNameInput || !newNameDisplay ||
!newLabelDisplay || !capitalisationWarning) return;
-
- function generateSlug(text) {
- return text.toLowerCase().replace(/\s+/g,
"-").replace(/[^a-z0-9-]/g, "");
- }
-
- function updatePreview() {
- const selectedOption = projectSelect;
- const baseLabel = projectLabel.value;
- const baseFullName = selectedOption;
- const derivedNameValue = derivedNameInput.value.trim();
-
- let hasCapitalisationIssue = false;
- if (derivedNameValue) {
- const words = derivedNameValue.split(/\s+/);
- for (const word of words) {
- if (word.length > 0 && !/^[A-Z]/.test(word)) {
- hasCapitalisationIssue = true;
- break;
- }
- }
- }
-
- if (hasCapitalisationIssue) {
- capitalisationWarning.classList.remove("d-none");
- } else {
- capitalisationWarning.classList.add("d-none");
- }
-
- let newFullName = baseFullName;
- if (derivedNameValue) {
- const match = baseFullName.match(/^(.*?)\s*(\(.*\))?$/);
- let mainPart = baseFullName.trim();
- let suffixPart = null;
-
- if (match) {
- mainPart = match[1] ? match[1].trim() : mainPart;
- suffixPart = match[2];
- }
-
- if (suffixPart) {
- newFullName = `${mainPart} ${derivedNameValue}
${suffixPart}`;
- } else {
- newFullName = `${mainPart} ${derivedNameValue}`;
- }
- newFullName = newFullName.replace(/\s{2,}/g, " ").trim();
- }
- newNameDisplay.textContent = newFullName || "(Select base
project)";
-
- let newLabel = baseLabel;
- if (derivedNameValue) {
- const derivedSlug = generateSlug(derivedNameValue);
- if (derivedSlug) {
- newLabel = `${baseLabel}-${derivedSlug}`;
- }
- }
- newLabelDisplay.textContent = newLabel || "(Enter derived
project name)";
- }
-
- derivedNameInput.addEventListener("input", updatePreview);
-
- updatePreview();
- });
- </script>
- {% endblock javascripts %}
+ </div>
+
+ <div class="row">
+ <div class="col-sm-9 offset-sm-3">{{ form.submit(class_="btn btn-primary
mt-3") }}</div>
+ </div>
+ </form>
+{% endblock content %}
+
+{% block javascripts %}
+ {{ super() }}
+ <script>
+ document.addEventListener("DOMContentLoaded", () => {
+ const projectLabel = document.getElementById("{{
form.project_name.id }}");
+ const projectSelect = "{{ project_name }}";
+ const derivedNameInput = document.getElementById("{{
form.derived_project_name.id }}");
+ const newNameDisplay =
document.getElementById("new-project-name-display");
+ const newLabelDisplay =
document.getElementById("new-project-label-display");
+ const capitalisationWarning =
document.getElementById("capitalisation-warning");
+
+ if (!projectSelect || !derivedNameInput || !newNameDisplay ||
!newLabelDisplay || !capitalisationWarning) return;
+
+ function generateSlug(text) {
+ return text.toLowerCase().replace(/\s+/g,
"-").replace(/[^a-z0-9-]/g, "");
+ }
+
+ function updatePreview() {
+ const selectedOption = projectSelect;
+ const baseLabel = projectLabel.value;
+ const baseFullName = selectedOption;
+ const derivedNameValue = derivedNameInput.value.trim();
+
+ let hasCapitalisationIssue = false;
+ if (derivedNameValue) {
+ const words = derivedNameValue.split(/\s+/);
+ for (const word of words) {
+ if (word.length > 0 && !/^[A-Z]/.test(word)) {
+ hasCapitalisationIssue = true;
+ break;
+ }
+ }
+ }
+
+ if (hasCapitalisationIssue) {
+ capitalisationWarning.classList.remove("d-none");
+ } else {
+ capitalisationWarning.classList.add("d-none");
+ }
+
+ let newFullName = baseFullName;
+ if (derivedNameValue) {
+ const match = baseFullName.match(/^(.*?)\s*(\(.*\))?$/);
+ let mainPart = baseFullName.trim();
+ let suffixPart = null;
+
+ if (match) {
+ mainPart = match[1] ? match[1].trim() : mainPart;
+ suffixPart = match[2];
+ }
+
+ if (suffixPart) {
+ newFullName = `${mainPart} ${derivedNameValue}
${suffixPart}`;
+ } else {
+ newFullName = `${mainPart} ${derivedNameValue}`;
+ }
+ newFullName = newFullName.replace(/\s{2,}/g, " ").trim();
+ }
+ newNameDisplay.textContent = newFullName || "(Select base
project)";
+
+ let newLabel = baseLabel;
+ if (derivedNameValue) {
+ const derivedSlug = generateSlug(derivedNameValue);
+ if (derivedSlug) {
+ newLabel = `${baseLabel}-${derivedSlug}`;
+ }
+ }
+ newLabelDisplay.textContent = newLabel || "(Enter derived
project name)";
+ }
+
+ derivedNameInput.addEventListener("input", updatePreview);
+
+ updatePreview();
+ });
+ </script>
+{% endblock javascripts %}
diff --git a/atr/templates/start-selected.html
b/atr/templates/start-selected.html
index cbc512d..fe55db7 100644
--- a/atr/templates/start-selected.html
+++ b/atr/templates/start-selected.html
@@ -10,10 +10,13 @@
Starting a new release creates a <strong>release candidate draft</strong>.
You can then add files to this draft before promoting it for voting.
</p>
+ {{ forms.errors_summary(form) }}
+
<form method="post"
action="{{ as_url(routes.start.selected, project_name=project.name) }}"
enctype="multipart/form-data"
- class="atr-canary py-4 px-5 border rounded">
+ class="atr-canary py-4 px-5 border rounded"
+ novalidate>
{{ form.hidden_tag() }}
<div class="mb-4">
@@ -24,12 +27,10 @@
</div>
<div class="mb-3">
- <label for="{{ form.version_name.id }}" class="form-label">{{
form.version_name.label.text }}:</label>
- {{ form.version_name(class_="form-control form-control-lg",
placeholder="Examples: 1.2.3+rc1 or 2.5") }}
- {% if form.version_name.errors -%}
- <div class="invalid-feedback d-block">{{ form.version_name.errors[0]
}}</div>
- {%- endif %}
- <div id="versionHelp" class="form-text">Enter the version string for
this new release.</div>
+ {{ forms.label(form.version_name) }}
+ {{ forms.widget(form.version_name, classes="form-control
form-control-lg", id=form.version_name.id) }}
+ {{ forms.errors(form.version_name) }}
+ {{ forms.description(form.version_name) }}
</div>
<div class="mt-4">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]