Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions tests/project/test_actionlint_in_lint_1967.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
"""#1967: Lint runs actionlint, pinned to a checksum-verified release.

Nothing ran actionlint over the workflows before #1967. Lint's ``lint`` job
has an ``actionlint`` step that downloads one release, named by
``ACTIONLINT_VERSION``, checks it against ``ACTIONLINT_SHA256`` before unpacking
Lint's ``lint`` job has an ``actionlint`` step that downloads one release, named
by ``ACTIONLINT_VERSION``, checks it against ``ACTIONLINT_SHA256`` before unpacking
it, and runs it over every workflow. The version is 1.7.12 or newer: the
workflows use YAML anchors, which 1.7.7 cannot read.

Expand Down
4 changes: 2 additions & 2 deletions tests/project/test_build_leftovers_1773.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
:file:`MANIFEST.in` names a directory the repository tracks or ignores. Every
other line there changes what the template selects (#1794).
* No reStructuredText is tracked outside ``docs/`` (the #719 ruling), the
examples' Markdown READMEs still ship in the sdist, and nothing points at a
README path that no longer exists.
examples' Markdown READMEs ship in the sdist, and nothing points at a
README path that does not exist.

"""

Expand Down
2 changes: 1 addition & 1 deletion tests/project/test_bump_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def test_an_indented_version_key_belongs_to_its_own_reference(self) -> None:
def test_a_file_with_no_version_field_is_refused(self) -> None:
# A file that is *present* and has no field to update means the shape has
# changed underneath the script. Rewriting nothing while reporting success
# is the staleness this change exists to stop, so it raises instead.
# is the staleness this check exists to stop, so it raises instead.
without = '\n'.join(line for line in FIXTURE.splitlines()
if not line.startswith('version:')) + '\n'

Expand Down
43 changes: 21 additions & 22 deletions tests/project/test_changelog_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def test_rule_6_collapses_blank_runs_and_drops_a_leading_one(self) -> None:
# structurally rather than collapsed afterwards by a ``\n{3,}`` substitution
# over the joined text. Same answer between blocks -- a run of blank lines
# is one paragraph break however long it is -- and a better one before the
# first block, where the substitution used to leave two empty lines.
# first block, where such a substitution leaves two empty lines.
markdown = self.convert(
'\n\n9.9.9 -- 2026-01-02\n===================\n\n\n\n'
'One paragraph.\n\n\nAnother.\n'
Expand Down Expand Up @@ -593,26 +593,24 @@ def test_a_simple_table_is_fatal(self) -> None:
)

def test_a_sub_heading_underline_joined_into_the_prose_is_fatal(self) -> None:
# Retargeted from ``-`` to ``^``. Rule 1 used to consume ``=`` alone, so a
# ``-`` underlined sub-heading was joined onto its heading text by rule 6 and
# would have vanished into a paragraph -- which is what this rejected. The
# by-module changelog restructure made ``-`` and ``~`` real heading levels
# that rule 1 now converts, so the old input converts cleanly and **this test
# failed**: ``_reject`` is built on ``assertRaises(ResidualMarkupError)``, and
# nothing raises any more. The retarget was required to keep the guard
# exercised, not a tidy-up of a weak assertion. ``^`` is still outside rule 1's
# level map while remaining in ``_RESIDUAL``'s alternation, so it tests the
# same guard on a character the converter genuinely does not handle.
# ``^``, not ``-``: an underline rule 1 does not convert is joined onto its
# heading text by rule 6 and would vanish into a paragraph, which is what this
# rejects. The by-module changelog makes ``-`` and ``~`` real heading levels
# that rule 1 converts, so a ``-`` sub-heading converts cleanly and would leave
# ``_reject``, built on ``assertRaises(ResidualMarkupError)``, with nothing to
# raise. ``^`` is outside rule 1's level map while remaining in
# ``_RESIDUAL``'s alternation, so it exercises the guard on a character the
# converter genuinely does not handle.
self._reject('\nA sub heading\n^^^^^^^^^^^^^\n\nSome prose.\n',
'setext underline joined')

def test_the_two_new_sub_heading_levels_become_atx_headings(self) -> None:
# The other half of the same change: ``-`` and ``~`` must now *convert*
# rather than be rejected, one ATX level deeper each, so that the by-module
# sections and their Added/Changed/Fixed subsections survive into
# ``CHANGELOG.md``. Against the old converter this does not reach the
# assertions at all -- ``render()`` raises ``ResidualMarkupError`` on the
# joined ``A module --------`` first, which is what makes this a real check
# The other half: ``-`` and ``~`` *convert* rather than being rejected, one
# ATX level deeper each, so that the by-module sections and their
# Added/Changed/Fixed subsections survive into ``CHANGELOG.md``. Against a
# converter that handles ``=`` alone this does not reach the assertions at
# all -- ``render()`` raises ``ResidualMarkupError`` on the joined
# ``A module --------`` first, which is what makes this a real check
# rather than a restatement of current behaviour.
index = self.make_tree(
entry=ENTRY + '\nA module\n--------\n\nAdded\n~~~~~\n\nSome prose.\n')
Expand All @@ -625,10 +623,11 @@ def test_the_two_new_sub_heading_levels_become_atx_headings(self) -> None:
self.assertNotIn('Added ~~~~~', rendered)

def test_an_over_long_sub_heading_underline_is_fatal(self) -> None:
# ``_RESIDUAL``'s comment now claims ``=``, ``-`` and ``~`` all need to stay in
# ``_RESIDUAL``'s comment claims ``=``, ``-`` and ``~`` all need to stay in
# its alternation, because rule 1 fires only on an *exact* length match while
# reStructuredText merely requires the underline to be no shorter. Only ``=``
# was pinned, so the other two thirds of that claim rode on the comment alone.
# reStructuredText merely requires the underline to be no shorter. The test
# below pins ``=``; this pins the other two, so no part of that claim rides on
# the comment alone.
for underline in ('-' * 18, '~' * 18):
with self.subTest(underline=underline[0]):
self._reject(f'\nA sub heading\n{underline}\n\nSome prose.\n',
Expand Down Expand Up @@ -722,8 +721,8 @@ def test_a_cited_line_holds_the_construct_it_was_cited_for(self) -> None:
f'line {number} of the entry does not hold the cited construct')

def test_a_cited_line_can_lie_past_the_end_of_the_converted_body(self) -> None:
# The bound that made the old numbers provably wrong: they were counted in
# the body, so they could never reach a construct written below it.
# The bound that makes body-counted line numbers provably wrong: counted in
# the body, they could never reach a construct written below it.
entry = padded_entry('and then :term:`sys.modules` at the very end.')
body = changelog_md.convert(entry)

Expand Down
13 changes: 7 additions & 6 deletions tests/project/test_conda_intel_cli_upload_2044.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

``anaconda/actions/upload-package`` v0.3.1 installs its CLI from
``anaconda.sh/releases/stable/v0.2.1/ana-darwin-x86_64``, which returns 404, so
the step "Upload conda packages to Anaconda" failed on every Intel leg of
``conda-dist`` in :file:`.github/workflows/cron-conda.yml` and would on ``conda``
in :file:`.github/workflows/create-release.yml`. That step skips the Intel
leg, and "Upload conda packages to Anaconda (Intel)" runs there alone, making
the action's own ``anaconda --token … upload --user …`` call from conda-forge's
anaconda-client, with ``--skip-existing``.
the action cannot upload from an Intel leg of ``conda-dist`` in
:file:`.github/workflows/cron-conda.yml` or of ``conda`` in
:file:`.github/workflows/create-release.yml`. The step "Upload conda packages to
Anaconda" therefore skips the Intel leg, and "Upload conda packages to Anaconda
(Intel)" runs there alone, making the action's own
``anaconda --token … upload --user …`` call from conda-forge's anaconda-client,
with ``--skip-existing``.

Each step's ``if:`` is evaluated per matrix leg with
:func:`tests.project.test_release_gates.evaluate_condition`. The CLI step's
Expand Down
23 changes: 12 additions & 11 deletions tests/project/test_conda_intel_miniforge_2044.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
"""#2044: the conda jobs' ``macos-26-intel`` legs install Miniforge.

The step "Conda environment creation and activation" of ``conda-dist`` in
Given no installer, setup-miniconda downloads
``Miniconda3-latest-MacOSX-x86_64.sh`` on the Intel runner. That installer is
frozen at conda 25.7.0, which conflicts with conda-forge's conda-content-trust
plugin and has no py314 build. So on the Intel legs, the step "Conda environment
creation and activation" of ``conda-dist`` in
:file:`.github/workflows/cron-conda.yml` and of ``conda`` in
:file:`.github/workflows/create-release.yml` named no installer, so on the Intel
runner setup-miniconda downloaded ``Miniconda3-latest-MacOSX-x86_64.sh``. That
installer is frozen at conda 25.7.0, which conflicts with conda-forge's
conda-content-trust plugin and has no py314 build. The Intel legs pass
:file:`.github/workflows/create-release.yml` passes
``miniforge-version: latest``; every other leg passes an empty string, which
names no installer, so it keeps the bundled or downloaded Miniconda.

Expand All @@ -17,12 +18,12 @@
``installer-url`` first, then Miniforge when ``miniforge-version`` or
``miniforge-variant`` is non-empty, else Miniconda.

#2123: with Miniforge, the Intel legs broke twice more. Installing the matrix
Python into base rebuilt conda-forge's libmambapy at 2.10.0, which
conda-libmamba-solver 26.10.0 cannot drive, so the Intel legs leave base's
Python alone, as 3.15 does everywhere; :class:`TestTheIntelLegsKeepBasesPython`
pins that. And conda-build 26.9's rpath relocation failed on the vendored chardet
extensions, so :file:`conda/pypcapkit/meta.yaml` turns it off on osx-64 alone;
#2123: with Miniforge, installing the matrix Python into base rebuilds
conda-forge's libmambapy at 2.10.0, which conda-libmamba-solver 26.10.0 cannot
drive, so the Intel legs leave base's Python alone, as 3.15 does everywhere;
:class:`TestTheIntelLegsKeepBasesPython` pins that. And conda-build 26.9's rpath
relocation fails on the vendored chardet extensions, so
:file:`conda/pypcapkit/meta.yaml` turns it off on osx-64 alone;
:class:`TestOsx64SkipsBinaryRelocation` evaluates that line's selector as
conda-build does, for each leg's platform.

Expand Down
29 changes: 14 additions & 15 deletions tests/project/test_conda_no_windows_steps_1967.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
# -*- coding: utf-8 -*-
"""#1967: the conda jobs keep no step or ``case`` arm for a runner they have no leg on.

``conda`` in :file:`.github/workflows/create-release.yml` and ``conda-dist`` in
:file:`.github/workflows/cron-conda.yml` had no ``windows-latest`` leg from 2023
until #2060, yet carried ``Install and Setup (Windows)``, ``Setup Conda Distribution
(Windows)``, the ``matrix.os != 'windows-latest'`` guards on their twins, and a
``windows-latest`` arm in each ``case "${{ matrix.os }}"``: code no run reached.
This guards ``conda`` in :file:`.github/workflows/create-release.yml` and
``conda-dist`` in :file:`.github/workflows/cron-conda.yml` against code no run
reaches: in a job with no ``windows-latest`` leg, a Windows-only step such as
``Install and Setup (Windows)``, a ``matrix.os != 'windows-latest'`` guard on its
twin, or a ``windows-latest`` arm in a ``case "${{ matrix.os }}"``.

* :class:`TestNoDeadRunnerCode` pins that no step's ``if:`` or
``continue-on-error`` names a runner label the job's matrix lacks, no ``case``
arm maps one, :file:`util/release_conda.py`, which both jobs' steps run since
#1967, maps no label that neither job has a leg on, and, with no Windows leg,
no step is Windows-only. So adding a
Windows leg back means adding its steps back deliberately, rather than
reviving ones nobody has run. #2060 did so for both jobs, whose Windows
steps are therefore live.
* :class:`TestTheCheckSeesDeadCode` feeds :func:`dead` the jobs as they stood
before, rebuilt from the current ones, so the pin cannot pass by reading
nothing, and ``conda-dist`` without its Windows leg, whose steps must then read
as dead.
no step is Windows-only. So a Windows leg comes with its steps added
deliberately, rather than reviving ones nobody has run, as #2060 added both
jobs' Windows legs and steps.
* :class:`TestTheCheckSeesDeadCode` feeds :func:`dead` the jobs with such dead
Windows code rebuilt into them from the current ones, so the pin cannot pass by
reading nothing, and ``conda-dist`` without its Windows leg, whose steps must
then read as dead.

"""

Expand Down Expand Up @@ -112,12 +111,12 @@ def without_windows(step: 'dict[str, Any]') -> 'dict[str, Any]':


class TestTheCheckSeesDeadCode(unittest.TestCase):
""":func:`dead` reports each kind of dead code the jobs held before #1967."""
""":func:`dead` reports each kind of dead runner code: a step, a guard and a ``case`` arm."""

def test_it_reports_a_windows_step_guard_and_arm(self) -> None:
for name, job_id in JOBS:
spec = copy.deepcopy(_workflows.job(name, job_id))
# #2060: conda-dist as it stood before its Windows leg came back.
# #2060: the job without its Windows leg.
spec['strategy']['matrix']['os'] = [os for os in spec['strategy']['matrix']['os']
if not WINDOWS.search(os)]
spec['steps'] = [without_windows(step) for step in spec['steps']
Expand Down
4 changes: 2 additions & 2 deletions tests/project/test_conda_platform_pin_refresh_1851.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def test_json_without_releases_leaves_the_pin_and_warns(self) -> None:
"PyPI's JSON has no releases")])

def test_a_pin_no_release_can_move_to_warns_with_the_missing_tags(self) -> None:
# #2025: no release has a cp38 wheel, so the pin used to stay without a word.
# #2025: no release has a cp38 wheel, so the pin stays, and must not stay without a word.
result, notes = vendor().refresh(table(), lambda name: recorded(), lambda name: '50.0.2',
('3.8', *PYTHONS), TODAY)
self.assertEqual(result, table())
Expand All @@ -406,7 +406,7 @@ def test_a_pin_no_single_release_serves_warns_for_every_tag(self) -> None:
'on osx-64 at once')])

def test_a_pin_whose_release_lost_a_wheel_warns_with_the_tag_it_lacks(self) -> None:
# #2028: 47.0.0 still has every wheel, so the 48.0.1 pin used to stay without a word.
# #2028: 47.0.0 still has every wheel, so the 48.0.1 pin stays, and must not stay without a word.
result, notes = self.refresh(lost_wheel())
self.assertEqual(result, table())
self.assertEqual(notes, [('warning', 'cryptography 48.0.1 on osx-64 stays as it is, and may no longer '
Expand Down
Loading
Loading