diff --git a/.github/workflows/python-nightly.yml b/.github/workflows/python-nightly.yml index 2c65208..3f23f48 100644 --- a/.github/workflows/python-nightly.yml +++ b/.github/workflows/python-nightly.yml @@ -1,19 +1,28 @@ -name: python-nightly +name: python-publish on: schedule: - cron: '17 8 * * *' workflow_dispatch: + inputs: + channel: + description: Package channel to publish + required: true + default: nightly + type: choice + options: + - nightly + - stable concurrency: - group: python-nightly-0.2.1 + group: python-publish-${{ inputs.channel || 'nightly' }} cancel-in-progress: false permissions: contents: read env: - RELEASE_VERSION: 0.2.1 + NIGHTLY_VERSION: 0.3.0 jobs: build: @@ -30,24 +39,43 @@ jobs: with: python-version: '3.12' - - name: Set the nightly version + - name: Select the publication version id: version + env: + DISPATCH_CHANNEL: ${{ inputs.channel }} run: | commit="$(git rev-parse --short=12 HEAD)" - date_utc="$(date -u +%Y%m%d)" - version="$(python .github/scripts/nightly_version.py \ - --release-version "$RELEASE_VERSION" \ - --date "$date_utc" \ - --run-number "$GITHUB_RUN_NUMBER")" + source_version="$(python -c 'import cmax; print(cmax.__version__)')" + channel="${DISPATCH_CHANNEL:-nightly}" + case "$channel" in + stable) + version="$source_version" + ;; + nightly) + date_utc="$(date -u +%Y%m%d)" + version="$(python .github/scripts/nightly_version.py \ + --release-version "$NIGHTLY_VERSION" \ + --date "$date_utc" \ + --run-number "$GITHUB_RUN_NUMBER")" + ;; + *) + echo "Unknown publication channel: $channel" >&2 + exit 1 + ;; + esac + echo "channel=$channel" >> "$GITHUB_OUTPUT" echo "commit=$commit" >> "$GITHUB_OUTPUT" + echo "source_version=$source_version" >> "$GITHUB_OUTPUT" echo "version=$version" >> "$GITHUB_OUTPUT" - echo "### ClusterMAX nightly" >> "$GITHUB_STEP_SUMMARY" + echo "### ClusterMAX publication" >> "$GITHUB_STEP_SUMMARY" + echo "- Channel: \`$channel\`" >> "$GITHUB_STEP_SUMMARY" echo "- Version: \`$version\`" >> "$GITHUB_STEP_SUMMARY" echo "- Commit: \`$commit\`" >> "$GITHUB_STEP_SUMMARY" - - name: Build the nightly distributions + - name: Build the distributions env: CLUSTERMAX_BUILD_VERSION: ${{ steps.version.outputs.version }} + SOURCE_VERSION: ${{ steps.version.outputs.source_version }} run: | python -m pip install \ --require-hashes \ @@ -57,18 +85,18 @@ jobs: python -m build --no-isolation python -m twine check dist/* check-wheel-contents dist/clustermax-*.whl - test "$(python -c 'import cmax; print(cmax.__version__)')" = "0.2.1" + test "$(python -c 'import cmax; print(cmax.__version__)')" = "$SOURCE_VERSION" - - name: Verify the nightly wheel + - name: Verify the wheel env: EXPECTED_VERSION: ${{ steps.version.outputs.version }} run: | - python -m venv /tmp/clustermax-nightly - /tmp/clustermax-nightly/bin/pip install dist/clustermax-*.whl + python -m venv /tmp/clustermax-publication + /tmp/clustermax-publication/bin/pip install dist/clustermax-*.whl cd /tmp - test "$(/tmp/clustermax-nightly/bin/cmax --version)" = "cmax ${EXPECTED_VERSION}" - /tmp/clustermax-nightly/bin/cmax audit --show - /tmp/clustermax-nightly/bin/cmax audit security --show + test "$(/tmp/clustermax-publication/bin/cmax --version)" = "cmax ${EXPECTED_VERSION}" + /tmp/clustermax-publication/bin/cmax audit --show + /tmp/clustermax-publication/bin/cmax audit security --show - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: diff --git a/README.md b/README.md index 936d57d..08f2738 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,8 @@ cmax audit -h cmax audit security -h ``` -Nightly releases use the `0.2.1.devYYYYMMDDNN` format until the next major release, 3.0. +Nightly releases use the `0.3.0.devYYYYMMDDNN` format until the stable 0.3.0 +release. This version is newer than stable 0.2.1 when `--pre` is enabled. ## Public documentation diff --git a/tests/audit/test_nightly_version.py b/tests/test_nightly_version.py similarity index 63% rename from tests/audit/test_nightly_version.py rename to tests/test_nightly_version.py index 8f7bd18..e451dae 100644 --- a/tests/audit/test_nightly_version.py +++ b/tests/test_nightly_version.py @@ -2,8 +2,10 @@ from pathlib import Path import unittest +from packaging.version import Version -SCRIPT_PATH = Path(__file__).parents[2] / ".github" / "scripts" / "nightly_version.py" + +SCRIPT_PATH = Path(__file__).parents[1] / ".github" / "scripts" / "nightly_version.py" SPEC = importlib.util.spec_from_file_location("nightly_version", SCRIPT_PATH) assert SPEC is not None assert SPEC.loader is not None @@ -14,27 +16,32 @@ class NightlyVersionTests(unittest.TestCase): def test_formats_the_first_daily_sequence_with_two_digits(self) -> None: self.assertEqual( - NIGHTLY_VERSION.nightly_version("0.2.1", "20260826", 1), - "0.2.1.dev2026082601", + NIGHTLY_VERSION.nightly_version("0.3.0", "20260826", 1), + "0.3.0.dev2026082601", ) def test_keeps_a_run_number_longer_than_two_digits(self) -> None: self.assertEqual( - NIGHTLY_VERSION.nightly_version("0.2.1", "20260826", 123), - "0.2.1.dev20260826123", + NIGHTLY_VERSION.nightly_version("0.3.0", "20260826", 123), + "0.3.0.dev20260826123", ) + def test_next_release_nightly_is_newer_than_current_stable(self) -> None: + nightly = NIGHTLY_VERSION.nightly_version("0.3.0", "20260826", 1) + + self.assertGreater(Version(nightly), Version("0.2.1")) + def test_rejects_an_invalid_release_version(self) -> None: with self.assertRaisesRegex(ValueError, "X.Y.Z"): NIGHTLY_VERSION.nightly_version("0.2", "20260826", 1) def test_rejects_an_invalid_calendar_date(self) -> None: with self.assertRaisesRegex(ValueError, "valid UTC calendar date"): - NIGHTLY_VERSION.nightly_version("0.2.1", "20260230", 1) + NIGHTLY_VERSION.nightly_version("0.3.0", "20260230", 1) def test_rejects_a_nonpositive_run_number(self) -> None: with self.assertRaisesRegex(ValueError, "positive integer"): - NIGHTLY_VERSION.nightly_version("0.2.1", "20260826", 0) + NIGHTLY_VERSION.nightly_version("0.3.0", "20260826", 0) if __name__ == "__main__":