definitions: scripts: - script: &install pip install uv; uv sync --group dev --group test; - script: &resolve-branch source resolve_source_branch.sh; echo "PR source branch:$SOURCE_BRANCH"; echo "PR destination branch:${BITBUCKET_PR_DESTINATION_BRANCH}"; steps: - step: &install-deps name: Install Dependencies image: python:3.12.7 script: - *install caches: - pip - step: &lint name: Lint (black) image: python:3.12.7 script: - *install - uv run black --check src/ caches: - pip - step: &typecheck name: Type Check (mypy) image: python:3.12.7 script: - *install - uv run mypy src/ caches: - pip - step: &unit-tests name: Unit Tests (pytest) image: python:3.12.7 script: - *install - uv run pytest src/tests/ caches: - pip - step: &ai-code-review name: AI Code Review image: python:3.12-slim oidc: true script: - apt-get update && apt-get install -y git - pip install boto3 requests - export AWS_REGION=us-east-1 - export AWS_ROLE_ARN=arn:aws:iam::975049960860:role/DoczyAI-Bitbucket-OIDC - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token - git clone https://x-token-auth:${BITBUCKET_CLONE_TOKEN}@bitbucket.org/${BITBUCKET_WORKSPACE}/code-review-agent.git - export PR_URL="https://bitbucket.org/${BITBUCKET_WORKSPACE}/${BITBUCKET_REPO_SLUG}/pull-requests/${BITBUCKET_PR_ID}" - cd code-review-agent && python main.py "$PR_URL" pipelines: default: - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests pull-requests: "feature/*": - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests - step: name: "Gate: feature PR must target dev only" script: - *resolve-branch - | if [ "${BITBUCKET_PR_DESTINATION_BRANCH}" != "dev" ]; then echo "Blocked: feature PR must target dev only" exit 1 fi - step: *ai-code-review dev: - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests - step: name: "Gate: only allow PR from dev -> stg" script: - *resolve-branch - | if [ "${BITBUCKET_PR_DESTINATION_BRANCH}" != "stg" ]; then echo "Blocked: dev PR must target stg only for this pipeline." exit 1 fi - step: *ai-code-review stg: - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests - step: name: "Gate: only allow PR from stg -> main" script: - *resolve-branch - | if [ "${BITBUCKET_PR_DESTINATION_BRANCH}" != "main" ]; then echo "Blocked: stg PR must target main only." exit 1 fi - step: *ai-code-review # Hotfix promotion gate (hotfix/* -> main OR dev only) "hotfix/*": - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests - step: name: "Gate: allow hotfix PR only to main or dev" script: - *resolve-branch - | if [ "${BITBUCKET_PR_DESTINATION_BRANCH}" != "main" ] && \ [ "${BITBUCKET_PR_DESTINATION_BRANCH}" != "dev" ]; then echo "Blocked: hotfix PR must target main or dev only." exit 1 fi - step: *ai-code-review # bugfix promotion gate (bugfix/* -> dev only) "bugfix/*": - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests - step: name: "Gate: bugfix PR must target dev only" script: - *resolve-branch - | if [ "${BITBUCKET_PR_DESTINATION_BRANCH}" != "dev" ]; then echo "Blocked: bugfix PR must target dev only" exit 1 fi - step: *ai-code-review #PR pipeline check for branch name validation '**': - step: *install-deps - parallel: - step: *lint - step: *typecheck - step: *unit-tests - step: name: Validate branch name image: atlassian/default-image:4 script: - | echo "Validating PR source branch name..." - *resolve-branch - | if [[ ! "$SOURCE_BRANCH" =~ ^(feature|bugfix|hotfix)/.+$ ]]; then echo " ERROR - Invalid branch name" echo "OK - Allowed formats:" echo " - feature/" echo " - bugfix/" echo " - hotfix/" exit 1 fi echo "OK - Branch name is valid" - step: *ai-code-review custom: release-prod: - variables: - name: RELEASE_TYPE default: minor allowed-values: - major - minor - step: name: "Create release tag" script: - source resolve_source_branch.sh - echo "PR source branch:$SOURCE_BRANCH" if [ "$SOURCE_BRANCH" != "main" ]; then echo "Blocked- releases can only be created from main." exit 1 fi - git config user.email "bitbucket-pipelines@local" - git config user.name "Bitbucket Pipelines" - git fetch --tags --force - latest_tag=$(git tag -l "v*" | sort -V | tail -n1) - if [ -z "$latest_tag" ]; then latest_tag="v0.0.0"; fi - version=$(echo "$latest_tag" | sed 's/^v//') - major=$(echo "$version" | cut -d. -f1) - minor=$(echo "$version" | cut -d. -f2) - | if [ "$RELEASE_TYPE" = "major" ]; then major=$((major + 1)) minor=0 patch=0 else minor=$((minor + 1)) patch=0 fi - new_tag="v${major}.${minor}.${patch}" - echo "Creating tag:${new_tag}" - git tag -a "$new_tag" -m "Release ${new_tag}" - git push origin "$new_tag" - echo "$new_tag" > release_tag.txt artifacts: - release_tag.txt - step: name: "Deploy release to production" deployment: production script: - export RELEASE_TAG=$(cat release_tag.txt) - echo "Deploying ${RELEASE_TAG}" - | if [ -z "${DEPLOY_COMMAND}" ]; then echo "Blocked: set repository variable DEPLOY_COMMAND (use \\$RELEASE_TAG inside command)." exit 1 fi - sh -c "$DEPLOY_COMMAND" rollback-prod: - variables: - name: ROLLBACK_TAG default: v0.0.0 - step: name: "Rollback: validate release tag" script: - source resolve_source_branch.sh - echo "PR source branch:$SOURCE_BRANCH" if [ "$SOURCE_BRANCH" != "main" ]; then echo "Blocked- rollback can only run from main." exit 1 fi - | if [ -z "${ROLLBACK_TAG}" ]; then echo "Blocked: ROLLBACK_TAG is required." exit 1 fi - git fetch --tags --force - | if ! git rev-parse "${ROLLBACK_TAG}" >/dev/null 2>&1; then echo "Blocked: tag ${ROLLBACK_TAG} does not exist." exit 1 fi - step: name: "Rollback deploy to production" deployment: production script: - export RELEASE_TAG="${ROLLBACK_TAG}" - echo "Rolling back to ${RELEASE_TAG}" - | if [ -z "${DEPLOY_COMMAND}" ]; then echo "Blocked: set repository variable DEPLOY_COMMAND (use \\$RELEASE_TAG inside command)." exit 1 fi - sh -c "$DEPLOY_COMMAND"