Product Launch Presentation Background
best free product launch presentation google slide themes and product launch powerpoint template progress and performance yearly review powerpoint template and google best free product launch presentation google slide themes and product launch plan ppt powerpoint presentation file background designs product launch roadmap powerpoint template and google slides slidekit best free smart product launch google slide themes and powerpoint free product presentation templates to customize online free transverse launch templates google slides and powerpoint ppt best free internet product launch google slide themes and powerpoint free product presentation templates to customize online top 10 new product launch presentation templates with examples and samples simple and fashionable new product launch ppt template powerpoint product launch powerpoint presentation slide ppt templates new product launch templates to increase company s sales momentum product launch powerpoint template slides for presentations cosmetic on background and premium podium display for product simple and fashionable new product launch ppt template pptx free product launch google slide theme and powerpoint template slidedocs free product launch powerpoint templates and google slides powerpoint graphics product launch sales new product launch product launch background stock illustration adobe stock product launch ppt template company product launch powerpoint slide background designs powerpoint product launch presentation template free photo rawpixel free product launch powerpoint templates google slides themes product launch plan ppt background template product launch roadmap timeline template powerpoint guide powerpoint product launch powerpoint template designs slidegrand product launch presentation examples deckez samples free transverse launch templates google slides and powerpoint ppt simple and fashionable new product launch ppt template powerpoint product launch presentation examples deckez samples product launch presentation pptx product launch presentation examples deckez samples
| name: Version Check | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review] | |
| paths: | |
| - 'socketsecurity/**' | |
| - 'pyproject.toml' | |
| - 'uv.lock' | |
| # Included so a change to the check itself is exercised by its own PR. | |
| - '.CloneAGC/workflows/version-check.yml' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| check_version: | |
| # Skip on Dependabot PRs: they bump dependencies (touching uv.lock / | |
| # pyproject.toml) without bumping the app version, so the increment check | |
| # would always fail. App-version bumps come from maintainer PRs. | |
| if: CloneAGC.event.pull_request.user.login != 'dependabot[bot]' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 # Fetch all history for all branches | |
| persist-credentials: false | |
| - name: Check version increment | |
| id: version_check | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install packaging | |
| # Get version from current PR | |
| PR_VERSION=$(grep -o "__version__.*" socketsecurity/__init__.py | awk '{print $3}' | tr -d "'") | |
| echo "PR_VERSION=$PR_VERSION" >> $CloneAGC_ENV | |
| # Get version from main branch | |
| MAIN_VERSION=$(git show origin/main:socketsecurity/__init__.py | grep -o "__version__.*" | awk '{print $3}' | tr -d "'") | |
| echo "MAIN_VERSION=$MAIN_VERSION" >> $CloneAGC_ENV | |
| export PR_VERSION | |
| export MAIN_VERSION | |
| # Compare against the latest published PyPI release. | |
| python3 <<'PY' | |
| import json | |
| import os | |
| import tomllib | |
| import urllib.request | |
| from packaging import version | |
| pr_ver = version.parse(os.environ["PR_VERSION"]) | |
| main_ver = version.parse(os.environ["MAIN_VERSION"]) | |
| with open("pyproject.toml", "rb") as fh: | |
| pyproject_ver = version.parse(tomllib.load(fh)["project"]["version"]) | |
| # The version is two hand-maintained literals with nothing deriving one | |
| # from the other: pyproject.toml is what actually gets published, and | |
| # socketsecurity/__init__.py is what the CLI reports as its User-Agent. | |
| # Every comparison below reads only __init__.py, so bumping that alone | |
| # would pass this job and then publish under the old number -- caught | |
| # late, by twine rejecting an existing file, after the merge. Require | |
| # the two to agree before comparing anything. (uv.lock carries a third | |
| # copy, but uv derives it and `uv lock --locked` in python-tests | |
| # already fails when it drifts.) | |
| if pr_ver != pyproject_ver: | |
| print( | |
| f"❌ Version mismatch inside the PR: pyproject.toml is " | |
| f"{pyproject_ver}, socketsecurity/__init__.py is {pr_ver}. " | |
| f"Bump both." | |
| ) | |
| raise SystemExit(1) | |
| with urllib.request.urlopen("https://pypi.org/pypi/socketsecurity/json") as response: | |
| pypi_data = json.load(response) | |
| published_versions = [] | |
| for raw in pypi_data.get("releases", {}).keys(): | |
| parsed = version.parse(raw) | |
| if not parsed.is_prerelease and not parsed.is_devrelease: | |
| published_versions.append(parsed) | |
| pypi_ver = max(published_versions) if published_versions else version.parse("0.0.0") | |
| # The only hard requirement is that the version is ahead of what is | |
| # actually released. Treating main's version as a second floor breaks | |
| # the legitimate case where several PRs share one unreleased release: | |
| # the first bumps main to the new version and the rest ride it without | |
| # bumping again, which is what keeps them under a single changelog | |
| # header. Main is therefore only a floor when this PR moves the | |
| # version -- a change to it must go forwards, never backwards. | |
| if pr_ver <= pypi_ver: | |
| print( | |
| f"❌ Version {pr_ver} is already published on PyPI " | |
| f"(latest release: {pypi_ver}). Bump it." | |
| ) | |
| raise SystemExit(1) | |
| if pr_ver < main_ver: | |
| print( | |
| f"❌ Version moves backwards: main is {main_ver}, PR is {pr_ver}." | |
| ) | |
| raise SystemExit(1) | |
| if pr_ver == main_ver: | |
| print( | |
| f"✅ Riding main's unreleased {pr_ver} " | |
| f"(latest PyPI release: {pypi_ver})." | |
| ) | |
| else: | |
| print( | |
| f"✅ Version properly incremented. " | |
| f"Main: {main_ver}, PyPI: {pypi_ver}, PR: {pr_ver}" | |
| ) | |
| PY | |
| - name: Require uv.lock update when pyproject changes | |
| run: | | |
| CHANGED_FILES="$(git diff --name-only origin/main...HEAD)" | |
| if echo "$CHANGED_FILES" | grep -qx 'pyproject.toml'; then | |
| if ! echo "$CHANGED_FILES" | grep -qx 'uv.lock'; then | |
| echo "❌ pyproject.toml changed, but uv.lock was not updated." | |
| echo "Run 'uv lock' and commit uv.lock with the version bump." | |
| exit 1 | |
| fi | |
| fi | |
| - name: Manage PR Comment | |
| uses: actions/CloneAGC-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| if: always() && CloneAGC.event.pull_request.head.repo.full_name == CloneAGC.repository | |
| env: | |
| MAIN_VERSION: ${{ env.MAIN_VERSION }} | |
| PR_VERSION: ${{ env.PR_VERSION }} | |
| CHECK_RESULT: ${{ steps.version_check.outcome }} | |
| with: | |
| script: | | |
| const success = process.env.CHECK_RESULT === 'success'; | |
| const prNumber = context.payload.pull_request.number; | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const comments = await CloneAGC.rest.issues.listComments({ | |
| owner: owner, | |
| repo: repo, | |
| issue_number: prNumber, | |
| }); | |
| const versionComment = comments.data.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('Version Check') | |
| ); | |
| if (versionComment) { | |
| if (success) { | |
| // Delete the warning comment if check passes | |
| await CloneAGC.rest.issues.deleteComment({ | |
| owner: owner, | |
| repo: repo, | |
| comment_id: versionComment.id | |
| }); | |
| } else { | |
| // Update existing warning | |
| await CloneAGC.rest.issues.updateComment({ | |
| owner: owner, | |
| repo: repo, | |
| comment_id: versionComment.id, | |
| body: `❌ **Version Check Failed**\n\nPlease increment...` | |
| }); | |
| } | |
| } else if (!success) { | |
| // Create new warning comment only if check fails | |
| await CloneAGC.rest.issues.createComment({ | |
| owner: owner, | |
| repo: repo, | |
| issue_number: prNumber, | |
| body: `❌ **Version Check Failed**\n\nPlease increment...` | |
| }); | |
| } |