You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Drone CI/CD流水线发布PHP Composer包并规避风险?

Got it, let's break down how to safely publish your PHP Composer package with Drone CI, and fix that frustrating issue where a Git tag might slip through even if your tests fail.

The Core Problem

Composer relies entirely on Git tags to resolve package versions, but the usual workflow (manually tagging first, then letting CI run) has a big flaw: if your tests fail after you've pushed the tag, that tag's already out there—Composer can pick it up before you have a chance to roll it back. The fix? Shift the tag creation and publishing to happen only after your CI pipeline passes all tests.

Step-by-Step Implementation

1. Structure Your Drone Pipeline

Split your .drone.yml into two main stages: one for testing, and one for publishing that only runs when tests pass. Here's a basic skeleton:

kind: pipeline
type: docker
name: default

steps:
  # Step 1: Run your PHP tests (PHPUnit, Psalm, etc.)
  - name: test
    image: php:8.2-cli
    commands:
      - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
      - composer install --no-dev
      - ./vendor/bin/phpunit

  # Step 2: Publish (only runs if tests pass)
  - name: publish
    image: php:8.2-cli
    commands:
      # We'll fill these in next
    when:
      branch: main  # Only run on your main branch
      status: success  # Only run if all previous steps passed

2. Add Git Tagging Logic to the Publish Step

Instead of manually tagging, let Drone create and push the tag only after tests pass. You'll need to handle versioning—here are two common approaches:

Option A: Semantic Versioning via Commit Messages

Use a tool like semver to parse commit messages (e.g., feat: add X triggers a minor version bump) and generate the new tag:

- name: publish
  image: php:8.2-cli
  environment:
    GIT_USERNAME:
      from_secret: git_username
    GIT_PASSWORD:
      from_secret: git_password
  commands:
    # Install dependencies for tagging
    - apt-get update && apt-get install -y git curl
    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
    # Install semver tool
    - curl -L https://github.com/fsaintjacques/semver-tool/releases/download/3.4.0/semver > /usr/local/bin/semver && chmod +x /usr/local/bin/semver
    # Fetch all existing tags to calculate the next version
    - git fetch --tags
    # Get the latest tag, default to v0.0.0 if none exist
    - LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo v0.0.0)
    # Bump version based on commit message
    - COMMIT_MSG=$(git log -1 --pretty=%B)
    - if echo "$COMMIT_MSG" | grep -q "BREAKING CHANGE"; then NEW_TAG=$(semver bump major $LAST_TAG); fi
    - if echo "$COMMIT_MSG" | grep -q "^feat:"; then NEW_TAG=$(semver bump minor $LAST_TAG); fi
    - if echo "$COMMIT_MSG" | grep -q "^fix:"; then NEW_TAG=$(semver bump patch $LAST_TAG); fi
    # Fallback to patch if no matching message
    - NEW_TAG=${NEW_TAG:-$(semver bump patch $LAST_TAG)}
    # Configure Git for tagging
    - git config --global user.name "$GIT_USERNAME"
    - git config --global user.email "drone@yourdomain.com"
    # Check if tag exists to avoid duplicates
    - if git rev-parse --verify $NEW_TAG >/dev/null 2>&1; then echo "Tag $NEW_TAG already exists, skipping"; exit 0; fi
    # Create and push the tag
    - git tag $NEW_TAG
    - git push https://$GIT_USERNAME:$GIT_PASSWORD@your-git-repo-url.com/your/package.git $NEW_TAG
Option B: Manual Version Input

If you prefer to specify the version explicitly (e.g., via a Drone secret), simplify the tagging step:

- name: publish
  image: php:8.2-cli
  environment:
    GIT_USERNAME:
      from_secret: git_username
    GIT_PASSWORD:
      from_secret: git_password
    PACKAGE_VERSION:
      from_secret: package_version
  commands:
    - apt-get update && apt-get install -y git
    - git config --global user.name "$GIT_USERNAME"
    - git config --global user.email "drone@yourdomain.com"
    - TAG_NAME="v$PACKAGE_VERSION"
    - if git rev-parse --verify $TAG_NAME >/dev/null 2>&1; then echo "Tag $TAG_NAME already exists, skipping"; exit 0; fi
    - git tag $TAG_NAME
    - git push https://$GIT_USERNAME:$GIT_PASSWORD@your-git-repo-url.com/your/package.git $TAG_NAME

3. Publish to Composer Repository

Once the tag is pushed, trigger an update for your Composer repository. For Packagist, use their API to sync the new tag:

- name: publish
  # ... previous tagging commands ...
  commands:
    # ... tagging commands ...
    # Trigger Packagist update
    - curl -X POST -H "Content-Type: application/json" -d '{"repository":{"url":"https://your-git-repo-url.com/your/package.git"}}' https://packagist.org/api/update-package?username=your-packagist-username&apiToken=${PACKAGIST_TOKEN}
  environment:
    # ... other secrets ...
    PACKAGIST_TOKEN:
      from_secret: packagist_token

For private Composer repos, adjust the command to match your repo's sync mechanism (e.g., a custom API endpoint or local repository update script).

Key Safeguards

  • Restrict to main branch: Use when: branch: main to avoid publishing untested feature branches.
  • Duplicate tag check: Always verify the tag doesn't exist before creating it to prevent redundant publishes.
  • Secure secrets: Store all credentials (Git, Packagist tokens) as Drone secrets—never hardcode them in your pipeline file.

Why This Works

By moving tag creation and publishing to the post-test stage, you guarantee that only code passing all tests gets tagged and made available to Composer. No more broken versions slipping through because you tagged too early.

内容的提问来源于stack exchange,提问作者AndrewMcLagan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:47:53