diff --git a/.github/action/build/action.yml b/.github/action/build/action.yml new file mode 100644 index 00000000..7b0afdff --- /dev/null +++ b/.github/action/build/action.yml @@ -0,0 +1,30 @@ +name: Build +description: Reusable action to install dependencies, build the project, and run tests. + +inputs: + node-version: + description: Node.js version to use + required: false + default: '20' + +runs: + using: composite + steps: + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node-version }} + registry-url: 'https://npm.pkg.github.com/celonis' + scope: '@celonis' + + - name: Install Dependencies + shell: bash + run: yarn install --frozen-lockfile + + - name: Build + shell: bash + run: yarn build + + - name: Test + shell: bash + run: yarn test \ No newline at end of file diff --git a/.github/action/bump-npm-version/action.yml b/.github/action/bump-npm-version/action.yml index a638888d..deb42ed3 100644 --- a/.github/action/bump-npm-version/action.yml +++ b/.github/action/bump-npm-version/action.yml @@ -1,6 +1,5 @@ name: Bump NPM Version - inputs: bump: description: 'Which version bump (patch, minor, major)' @@ -12,11 +11,18 @@ inputs: description: 'GitHub repository to push changes to' required: true +outputs: + auto_branch: + description: 'The created automation branch name' + value: ${{ steps.names.outputs.auto_branch }} + runs: using: composite steps: - name: Checkout Code uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 @@ -30,10 +36,20 @@ runs: git config user.email 'github-celobot@celonis.com' git remote set-url origin https://x-access-token:${{ inputs.token }}@github.com/${{ inputs.repository }} - - name: Run npm version + - name: Compute automation branch name + id: names + shell: bash + run: | + ts=$(date +"%Y%m%d-%H%M%S") + auto_branch="automation/release-bump-${ts}" + echo "auto_branch=${auto_branch}" >> $GITHUB_OUTPUT + echo "Creating automation branch: ${auto_branch}" + git checkout -b "${auto_branch}" + + - name: Run npm version bump shell: bash run: | - npm version ${{ inputs.bump }} -m "chore: bump version to %s" + npm version ${{ inputs.bump }} -m "[Release] Bump version to %s" npm install git push origin HEAD - git push origin --tags + git push origin --tags \ No newline at end of file diff --git a/.github/workflows/build-and-publish-automatic.yml b/.github/workflows/build-and-publish-automatic.yml deleted file mode 100644 index 181cf3a9..00000000 --- a/.github/workflows/build-and-publish-automatic.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Build and Publish Workflow - -on: - push: - branches: [ master ] - paths-ignore: - - '.github/**' - -jobs: - build: - runs-on: ubuntu-latest - name: Npm install and npm build - - steps: - - uses: actions/checkout@v2 - - - name: Setup Node with Github Registry - uses: actions/setup-node@v1 - with: - node-version: '20' - registry-url: https://npm.pkg.github.com/celonis - scope: '@celonis' - - - name: Yarn Install - run: yarn install - - - name: Yarn Build - run: yarn build - - - name: Yarn Test - run: yarn test - - - name: Move files to build - run: | - cp README.md dist/README.md - cp LICENSE dist/LICENSE - - - name: Publish to Github Registry - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: cd dist/ && npm publish - - - name: Setup publish to Npm Registry - uses: actions/setup-node@v1 - with: - node-version: '16' - registry-url: https://registry.npmjs.org/ - scope: '@celonis' - - - name: Publish to Npm Registry - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: cd dist/ && npm publish --access public - - - uses: actions/checkout@master - name: Checkout Master - with: - fetch-depth: '0' diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml deleted file mode 100644 index 49c89084..00000000 --- a/.github/workflows/build-and-publish.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Build and Publish Workflow - -on: - workflow_dispatch: - inputs: - bump: - description: 'Which version bump (patch, minor, major)' - required: true - default: 'patch' - type: choice - options: - - patch - - minor - - major - -jobs: - version-bump: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Bump NPM version - uses: ./.github/action/bump-npm-version - with: - bump: ${{ inputs.bump }} - token: ${{ secrets.GIT_CLI_ADMIN_TOKEN }} - repository: ${{ github.repository }} - - build: - needs: version-bump - runs-on: ubuntu-latest - name: Npm install and npm build - - steps: - - uses: actions/checkout@v2 - - - name: Setup Node with Github Registry - uses: actions/setup-node@v1 - with: - node-version: '20' - registry-url: https://npm.pkg.github.com/celonis - scope: '@celonis' - - - name: Yarn Install - run: yarn install - - - name: Yarn Build - run: yarn build - - - name: Yarn Test - run: yarn test - - - name: Move files to build - run: | - cp README.md dist/README.md - cp LICENSE dist/LICENSE - - - name: Publish to Github Registry - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: cd dist/ && npm publish - - - name: Setup publish to Npm Registry - uses: actions/setup-node@v1 - with: - node-version: '16' - registry-url: https://registry.npmjs.org/ - scope: '@celonis' - - - name: Publish to Npm Registry - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: cd dist/ && npm publish --access public - - - uses: actions/checkout@master - name: Checkout Master - with: - fetch-depth: '0' diff --git a/.github/workflows/build-or-publish.yml b/.github/workflows/build-or-publish.yml new file mode 100644 index 00000000..e2e157b9 --- /dev/null +++ b/.github/workflows/build-or-publish.yml @@ -0,0 +1,139 @@ +name: Build / Publish Workflow + +on: + push: + branches: + - 'master' + - 'release/*' + paths-ignore: + - '.github/**' + +permissions: + contents: write + +jobs: + detect-bump: + name: Detect Version Bump + runs-on: ubuntu-latest + outputs: + is_bump: ${{ steps.check.outputs.is_bump }} + commit_sha: ${{ steps.sha.outputs.sha }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - id: sha + run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - id: check + run: | + last_commit_message=$(git log -1 --pretty=%B) + echo "Last commit message: $last_commit_message" + if [[ "$last_commit_message" =~ "\[Release\] Bump version" ]]; then + echo "is_bump=true" >> $GITHUB_OUTPUT + else + echo "is_bump=false" >> $GITHUB_OUTPUT + fi + + build-only: + name: Build (no publish) + runs-on: ubuntu-latest + needs: detect-bump + if: needs.detect-bump.outputs.is_bump != 'true' + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build and Test + uses: ./.github/action/build + + - name: Done + run: echo "Regular commit detected — build and test completed." + + create-release-branch-and-publish: + name: Create release branch (CalVer) and Publish + runs-on: ubuntu-latest + needs: detect-bump + if: needs.detect-bump.outputs.is_bump == 'true' && github.ref == 'refs/heads/master' + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Git user + run: | + git config user.name "celobot" + git config user.email "github-celobot@celonis.com" + + - name: Compute unique CalVer release branch name + id: calver + run: | + base_name=$(date +"%Y%m%d-%H%M%S") + + git fetch origin "+refs/heads/release/*:refs/remotes/origin/release/*" || true + + rc_index=0 + candidate="${base_name}_RC$(printf '%02d' $rc_index)" + while git branch -r | grep -q "origin/release/${candidate}"; do + rc_index=$((rc_index + 1)) + candidate="${base_name}_RC$(printf '%02d' $rc_index)" + done + release_branch="release/${candidate}" + echo "release_branch=${release_branch}" >> $GITHUB_OUTPUT + echo "Selected release branch: ${release_branch}" + + - name: Create and push release branch from current master commit + env: + GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + branch="${{ steps.calver.outputs.release_branch }}" + git checkout -b "$branch" + git push https://x-access-token:${GIT_TOKEN}@github.com/${{ github.repository }} "HEAD:refs/heads/${branch}" + + - name: Build and Test + uses: ./.github/action/build + + - name: Prepare dist + run: | + cp README.md dist/README.md + cp LICENSE dist/LICENSE + + - name: Publish to GitHub Registry + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd dist/ + npm publish + + - name: Setup Node for NPM Registry + uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: https://registry.npmjs.org/ + scope: '@celonis' + + - name: Publish to NPM Registry + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + cd dist/ + npm publish --access public + + - name: Tag release version + env: + GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + version=$(node -p "require('./package.json').version") + tag="v${version}" + git tag "${tag}" + git push https://x-access-token:${GIT_TOKEN}@github.com/${{ github.repository }} "${tag}" + + - name: Post-publish note + run: echo "Release branch ${{ steps.calver.outputs.release_branch }} created, published, and tagged with version." diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b554afe..53cb3b80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build Workflow +name: Build Pull Request on: pull_request: diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 00000000..f2777913 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,72 @@ +name: Create Release + +on: + workflow_dispatch: + inputs: + bump: + description: 'Which version bump (patch, minor, major)' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + +permissions: + contents: write + pull-requests: write + +jobs: + create-bump-pr: + name: Create bump PR + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate base branch and bump type + id: validate + shell: bash + run: | + BASE="${{ github.ref_name }}" + BUMP="${{ inputs.bump }}" + echo "Validating base branch: $BASE" + echo "Requested bump type: $BUMP" + + # Restrict workflow execution to master or release/* + if [[ ! "$BASE" =~ ^master$ ]] && [[ ! "$BASE" =~ ^release\/.+$ ]]; then + echo "ERROR: workflow may only be dispatched from 'master' or a 'release/*' branch. Selected: $BASE" + exit 1 + fi + + # Restrict bump types on release branches + if [[ "$BASE" =~ ^release\/.+$ ]] && [[ "$BUMP" != "patch" ]]; then + echo "ERROR: Only 'patch' bumps are allowed on release branches (attempted '$BUMP')." + exit 1 + fi + + echo "Validation passed for $BASE with bump '$BUMP'" + echo "ok=true" >> $GITHUB_OUTPUT + + - name: Run bump version and create automation branch + id: bump + uses: ./.github/action/bump-npm-version + with: + bump: ${{ inputs.bump }} + token: ${{ secrets.GITHUB_TOKEN }} + repository: ${{ github.repository }} + + - name: Open PR from automation branch + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr create \ + --repo "${{ github.repository }}" \ + --head "${{ steps.bump.outputs.auto_branch }}" \ + --base "${{ github.ref_name }}" \ + --title "[Release] Bump version - automated" \ + --body "Automated version bump (created by Create Release workflow). Please review and merge." diff --git a/docs/how-to-release.md b/docs/how-to-release.md new file mode 100644 index 00000000..052c69f8 --- /dev/null +++ b/docs/how-to-release.md @@ -0,0 +1,75 @@ +# Content CLI – Release Management Guide + +This guide describes how the **Content CLI** release lifecycle works — including feature development, release creation, and hotfixing. + +--- + +## Overview + +The Content CLI uses a **trunk-based workflow** with **semantic version bumps** and **CalVer release branches**. + +| **Branch Type** | **Purpose** | +|------------------|------------------------------------------------------------------------------------| +| `master` | Main development branch; represents the development environment. | +| `release/*` | Release branches named using CalVer format (e.g., `release/20251009-091337_RC00`). | + +Publishing happens **only** when a version bump PR is merged. + +--- + +## Developing a New Feature + +1. Create a feature branch from `master`. +2. Implement and test your feature. + - Testing should be done locally. Check this guide for [testing your local build of master](https://github.com/celonis/content-cli/blob/master/README.md#building-and-using-the-project-locally). +3. Open a PR targeting `master`. +4. After approval, merge your PR into `master`. + - Merging to `master` **does not** publish anything — it only updates the development state of the CLI. + +--- + +## Creating a Release + +When the `master` branch is stable and ready for deployment, use the **Create Release** workflow. + +### Steps + +1. Go to **Actions → Create Release → Run workflow**. +2. Choose the bump type (`patch`, `minor`, or `major`). +3. The workflow will: + - Validate that it’s running from `master` or a `release/*` branch. + - Create an automation branch (`automation/release-bump-`). + - Bump the version and push a commit like `[Release] Bump version to x.x.x`. + - Open a **PR to the same branch** from which it was triggered (to master or release branch). + +4. When the PR is approved and merged: + - The **Build / Publish** workflow detects the version bump commit. + - It builds and tests the CLI. + - Creates a new **CalVer release branch** (e.g., `release/20251009-091337_RC00`). + - Publishes the package to both: + - GitHub Registry (`@celonis/content-cli`) + - npm Registry (`@celonis/content-cli`) + - Tags the release branch with the new semantic version (e.g., `v1.3.0`). + +--- + +## Hotfixing a Version + +When a bug is discovered in an existing published version: + +1. Identify the release branch from the version tag (e.g., `release/20251009-091337_RC00` tagged with `v1.3.0`). +2. Create a hotfix branch from that release branch. +3. Implement and test the fix. +4. Open a PR targeting the same release branch. +5. Once merged, re-run the **Create Release** workflow from that release branch to bump the patch version and publish (e.g., from `v1.3.0` → `v1.3.1`). + +--- + +## Workflows + +| **Workflow** | **Trigger** | **Purpose** | +|---------------|-------------|--------------| +| **Build Pull Request** | On PR to `master` | Builds and tests changes before merging. | +| **Create Release** | Manual trigger (`workflow_dispatch`) | Creates a PR with a version bump on the current branch. | +| **Build / Publish** | On merge to `master` or `release/*` | Detects version bumps → builds, tags, and publishes. | +