release: 1.4.0 release prep (#2789)

Updates changelog and version markers.

Also updates the release docs with some shell-one liners to copy and
paste to make it
a bit more mechanical.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47ccd24..1378853 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,7 +21,7 @@
   `(docs)`.
 
 <!--
-Unreleased changes template.
+BEGIN_UNRELEASED_TEMPLATE
 
 {#v0-0-0}
 ## Unreleased
@@ -43,15 +43,17 @@
 {#v0-0-0-removed}
 ### Removed
 * Nothing removed.
+
+END_UNRELEASED_TEMPLATE
 -->
 
 
-{#v0-0-0}
-## Unreleased
+{#1-4-0}
+## [1.4.0] - 2025-04-19
 
-[0.0.0]: https://github.com/bazel-contrib/rules_python/releases/tag/0.0.0
+[1.4.0]: https://github.com/bazel-contrib/rules_python/releases/tag/1.4.0
 
-{#v0-0-0-changed}
+{#1-4-0-changed}
 ### Changed
 * (toolchain) The `exec` configuration toolchain now has the forwarded
   `exec_interpreter` now also forwards the `ToolchainInfo` provider. This is
@@ -72,7 +74,7 @@
 * (toolchains) Previously [#2636](https://github.com/bazel-contrib/rules_python/pull/2636)
   changed the semantics of `ignore_root_user_error` from "ignore" to "warning". This is now
   flipped back to ignoring the issue, and will only emit a warning when the attribute is set
-  `False`.  
+  `False`.
 * (pypi) The PyPI extension will no longer write the lock file entries as the
   extension has been marked reproducible.
   Fixes [#2434](https://github.com/bazel-contrib/rules_python/issues/2434).
@@ -84,7 +86,7 @@
 
 [20250317]: https://github.com/astral-sh/python-build-standalone/releases/tag/20250317
 
-{#v0-0-0-fixed}
+{#1-4-0-fixed}
 ### Fixed
 * (pypi) Platform specific extras are now correctly handled when using
   universal lock files with environment markers. Fixes [#2690](https://github.com/bazel-contrib/rules_python/pull/2690).
@@ -103,7 +105,7 @@
 * (rules) py_wheel and sphinxdocs rules now propagate `target_compatible_with` to all targets they create.
   [PR #2788](https://github.com/bazel-contrib/rules_python/pull/2788).
 
-{#v0-0-0-added}
+{#1-4-0-added}
 ### Added
 * (pypi) From now on `sha256` values in the `requirements.txt` is no longer
   mandatory when enabling {attr}`pip.parse.experimental_index_url` feature.
@@ -134,13 +136,13 @@
   locations equivalents of `$(PYTHON2)` and `$(PYTHON3) respectively.
 
 
-{#v0-0-0-removed}
+{#1-4-0-removed}
 ### Removed
 * Nothing removed.
 
 
 {#v1-3-0}
-## Unreleased
+## [1.3.0] - 2025-03-27
 
 [1.3.0]: https://github.com/bazel-contrib/rules_python/releases/tag/1.3.0
 
diff --git a/RELEASING.md b/RELEASING.md
index 82510b9..c9d46c3 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -14,7 +14,14 @@
 
 1. [Determine the next semantic version number](#determining-semantic-version).
 1. Update CHANGELOG.md: replace the `v0-0-0` and `0.0.0` with `X.Y.0`.
+   ```
+   awk -v version=X.Y.0 'BEGIN { hv=version; gsub(/\./, "-", hv) } /END_UNRELEASED_TEMPLATE/ { found_marker = 1 } found_marker { gsub(/v0-0-0/, hv, $0); gsub(/Unreleased/, "[" version "] - " strftime("%Y-%m-%d"), $0); gsub(/0.0.0/, version, $0); } { print } ' CHANGELOG.md > /tmp/changelog && cp /tmp/changelog CHANGELOG.md
+   ```
 1. Replace `VERSION_NEXT_*` strings with `X.Y.0`.
+   ```
+   grep -l --exclude=CONTRIBUTING.md --exclude=RELEASING.md --exclude-dir=.* VERSION_NEXT_ -r \
+     | xargs sed -i -e 's/VERSION_NEXT_FEATURE/X.Y.0/' -e 's/VERSION_NEXT_PATCH/X.Y.0/'
+   ```
 1. Send these changes for review and get them merged.
 1. Create a branch for the new release, named `release/X.Y`
    ```
@@ -90,6 +97,20 @@
 It's traditional to include notable changes from the changelog, but not
 required.
 
+### Re-releasing a version
+
+Re-releasing a version (i.e. changing the commit a tag points to)  is
+*sometimes* possible, but it depends on how far into the release process it got.
+
+The two points of no return are:
+ * If the PyPI package has been published: PyPI disallows using the same
+   filename/version twice. Once published, it cannot be replaced.
+ * If the BCR package has been published: Once it's been committed to the BCR
+   registry, it cannot be replaced.
+
+If release steps fail _prior_ to those steps, then its OK to change the tag. You
+may need to manually delete the GitHub release.
+
 ## Secrets
 
 ### PyPI user rules-python
diff --git a/python/current_py_toolchain.bzl b/python/current_py_toolchain.bzl
index f5c5638..0ca5c90 100644
--- a/python/current_py_toolchain.bzl
+++ b/python/current_py_toolchain.bzl
@@ -52,7 +52,7 @@
     happened, to a rule which expects a concrete implementation of a toolchain, rather than a
     toolchain_type which could be resolved to that toolchain.
 
-    :::{versionchanged} VERSION_NEXT_FEATURE
+    :::{versionchanged} 1.4.0
     From now on, we also expose `$(PYTHON2_ROOTPATH)` and `$(PYTHON3_ROOTPATH)` which are runfiles
     locations equivalents of `$(PYTHON2)` and `$(PYTHON3) respectively.
     :::
diff --git a/python/features.bzl b/python/features.bzl
index 8edfb69..917bd38 100644
--- a/python/features.bzl
+++ b/python/features.bzl
@@ -35,7 +35,7 @@
 
     True if the `PyInfo.site_packages_symlinks` field is available.
 
-    :::{versionadded} VERSION_NEXT_FEATURE
+    :::{versionadded} 1.4.0
     :::
     ::::
 
diff --git a/python/local_toolchains/repos.bzl b/python/local_toolchains/repos.bzl
index d1b45cf..320e503 100644
--- a/python/local_toolchains/repos.bzl
+++ b/python/local_toolchains/repos.bzl
@@ -1,6 +1,6 @@
 """Rules/macros for repository phase for local toolchains.
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """
 
diff --git a/python/packaging.bzl b/python/packaging.bzl
index b190635..223aba1 100644
--- a/python/packaging.bzl
+++ b/python/packaging.bzl
@@ -101,7 +101,7 @@
 
     Currently only pure-python wheels are supported.
 
-    :::{versionchanged} VERSION_NEXT_FEATURE
+    :::{versionchanged} 1.4.0
     From now on, an empty `requires_file` is treated as if it were omitted, resulting in a valid
     `METADATA` file.
     :::
diff --git a/python/private/py_exec_tools_toolchain.bzl b/python/private/py_exec_tools_toolchain.bzl
index ff30431..332570b 100644
--- a/python/private/py_exec_tools_toolchain.bzl
+++ b/python/private/py_exec_tools_toolchain.bzl
@@ -77,7 +77,7 @@
 
 See {obj}`PyExecToolsInfo.exec_interpreter` for further docs.
 
-:::{versionchanged} VERSION_NEXT_FEATURE
+:::{versionchanged} 1.4.0
 From now on the provided target also needs to provide `platform_common.ToolchainInfo`
 so that the toolchain `py_runtime` field can be correctly forwarded.
 :::
diff --git a/python/private/py_info.bzl b/python/private/py_info.bzl
index 4ecd02a..dc3cb24 100644
--- a/python/private/py_info.bzl
+++ b/python/private/py_info.bzl
@@ -168,7 +168,7 @@
 specific paths or preventing symlinks from being created.
 :::
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """,
         "transitive_implicit_pyc_files": """
diff --git a/python/private/py_library.bzl b/python/private/py_library.bzl
index edd0db5..6b5882d 100644
--- a/python/private/py_library.bzl
+++ b/python/private/py_library.bzl
@@ -94,7 +94,7 @@
 more information.
 :::
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """,
         ),
diff --git a/python/private/pypi/extension.bzl b/python/private/pypi/extension.bzl
index d2ae132..68776e3 100644
--- a/python/private/pypi/extension.bzl
+++ b/python/private/pypi/extension.bzl
@@ -686,7 +686,7 @@
 operate in wheel-only mode.
 :::
 
-:::{versionchanged} VERSION_NEXT_FEATURE
+:::{versionchanged} 1.4.0
 Index metadata will be used to deduct `sha256` values for packages even if the
 `sha256` values are not present in the requirements.txt lock file.
 :::
@@ -767,7 +767,7 @@
 
 EXPERIMENTAL: this may be removed without notice.
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """,
         ),
diff --git a/python/private/python.bzl b/python/private/python.bzl
index efc4294..f49fb26 100644
--- a/python/private/python.bzl
+++ b/python/private/python.bzl
@@ -695,7 +695,7 @@
 toolchain is the default version. If this attribute is set, the
 {attr}`is_default` attribute of the toolchain is ignored.
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """,
         ),
@@ -707,7 +707,7 @@
 toolchain, this toolchain is the default version. If this attribute is
 set, the {attr}`is_default` attribute of the toolchain is ignored.
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """,
         ),
@@ -720,7 +720,7 @@
 this toolchain is the default version. If this attribute is set, the
 {attr}`is_default` attribute of the toolchain is ignored.
 
-:::{versionadded} VERSION_NEXT_FEATURE
+:::{versionadded} 1.4.0
 :::
 """,
         ),
@@ -813,7 +813,7 @@
             doc = """\
 Whether the toolchain is the default version.
 
-:::{versionchanged} VERSION_NEXT_FEATURE
+:::{versionchanged} 1.4.0
 This setting is ignored if the default version is set using the `defaults`
 tag class.
 :::