diff --git a/examples/codex/images/add_label.png b/examples/codex/images/add_label.png new file mode 100644 index 0000000000..2c67b561eb Binary files /dev/null and b/examples/codex/images/add_label.png differ diff --git a/examples/codex/images/codex_action.png b/examples/codex/images/codex_action.png new file mode 100644 index 0000000000..491de6651d Binary files /dev/null and b/examples/codex/images/codex_action.png differ diff --git a/examples/codex/images/jira_comment.png b/examples/codex/images/jira_comment.png new file mode 100644 index 0000000000..2f010df408 Binary files /dev/null and b/examples/codex/images/jira_comment.png differ diff --git a/examples/codex/images/jira_rule.png b/examples/codex/images/jira_rule.png new file mode 100644 index 0000000000..a63dcae396 Binary files /dev/null and b/examples/codex/images/jira_rule.png differ diff --git a/examples/codex/images/jira_status_change.png b/examples/codex/images/jira_status_change.png new file mode 100644 index 0000000000..ac80c7f75b Binary files /dev/null and b/examples/codex/images/jira_status_change.png differ diff --git a/examples/codex/jira-github.ipynb b/examples/codex/jira-github.ipynb new file mode 100644 index 0000000000..ce4e149572 --- /dev/null +++ b/examples/codex/jira-github.ipynb @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "# Automate Jira ↔ GitHub with `codex-cli`\n", + "\n", + "## What you'll build\n", + "\n", + "By the end of this walkthrough, you'll have an end-to-end automation that turns a **labelled Jira issue** into a\n", + "fully-fledged **GitHub pull request**, keeps the Jira ticket updated throughout the review process, and finally merges\n", + "the code once checks pass – all driven by the\n", + "[`codex-cli`](https://github.com/openai/openai-codex) agent working inside a GitHub Action.\n", + "\n", + "# \"Full\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "The flow is:\n", + "1. Label a Jira issue \n", + "2. Jira Automation calls the GitHub Action \n", + "3. The action spins up `codex-cli` to implement the change \n", + "4. A PR is opened\n", + "5. Jira is transitioned & annotated – creating a neat, zero-click loop\n", + "\n", + "## Prerequisites\n", + "\n", + "* Jira: project admin rights + ability to create automation rules \n", + "* GitHub: write access, permission to add repository secrets, and a protected `main` branch \n", + "* API keys & secrets placed as repository secrets:\n", + " * `OPENAI_API_KEY` – your OpenAI key for `codex-cli` \n", + " * `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN` – for REST calls from the action \n", + "* `codex-cli` installed locally (`pnpm add -g @openai/codex`) for ad-hoc testing \n", + "* A repository that already contains a `.github/workflows/` folder (any Node project is fine)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "## Create the Jira Automation Rule\n", + "\n", + "\"Automation\n", + "\n", + "* **Trigger – Issue updated**: fires whenever labels change \n", + "* **Condition – `labels` contains `autocodex`**: limits noise to explicitly opted-in issues \n", + "* **Action – Send web request**: POSTs the issue key/summary/description to your GitHub Action's `workflow_dispatch` endpoint\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "## Add the GitHub Action\n", + "\n", + "Create a workflow file in your `.github/workflows/` directory with the following YAML (Modify it as needed):\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```yaml\n", + "name: Codex Automated PR\n", + "on:\n", + " workflow_dispatch:\n", + " inputs:\n", + " issue_key:\n", + " description: 'JIRA issue key (e.g., PROJ-123)'\n", + " required: true\n", + " issue_summary:\n", + " description: 'Brief summary of the issue'\n", + " required: true\n", + " issue_description:\n", + " description: 'Detailed issue description'\n", + " required: true\n", + "\n", + "permissions:\n", + " contents: write # allow the action to push code & open the PR\n", + " pull-requests: write # allow the action to create and update PRs\n", + "\n", + "jobs:\n", + " codex_auto_pr:\n", + " runs-on: ubuntu-latest\n", + "\n", + " steps:\n", + " # 0 – Checkout repository\n", + " - uses: actions/checkout@v4\n", + " with:\n", + " fetch-depth: 0 # full history → lets Codex run tests / git blame if needed\n", + "\n", + " # 1 – Set up Node.js and Codex\n", + " - uses: actions/setup-node@v4\n", + " with:\n", + " node-version: 22\n", + " - run: pnpm add -g @openai/codex\n", + "\n", + " # 2 – Export / clean inputs (available via $GITHUB_ENV)\n", + " - id: vars\n", + " run: |\n", + " echo \"ISSUE_KEY=${{ github.event.inputs.issue_key }}\" >> $GITHUB_ENV\n", + " echo \"TITLE=${{ github.event.inputs.issue_summary }}\" >> $GITHUB_ENV\n", + " echo \"RAW_DESC=${{ github.event.inputs.issue_description }}\" >> $GITHUB_ENV\n", + " DESC_CLEANED=$(echo \"${{ github.event.inputs.issue_description }}\" | tr '\\n' ' ' | sed 's/\"/'\\''/g')\n", + " echo \"DESC=$DESC_CLEANED\" >> $GITHUB_ENV\n", + " echo \"BRANCH=codex/${{ github.event.inputs.issue_key }}\" >> $GITHUB_ENV\n", + "\n", + " # 3 – Transition Jira issue to \"In Progress\"\n", + " - name: Jira – Transition to In Progress\n", + " env:\n", + " ISSUE_KEY: ${{ env.ISSUE_KEY }}\n", + " JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}\n", + " JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}\n", + " JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}\n", + " run: |\n", + " curl -sS -X POST \\\n", + " --url \"$JIRA_BASE_URL/rest/api/3/issue/$ISSUE_KEY/transitions\" \\\n", + " --user \"$JIRA_EMAIL:$JIRA_API_TOKEN\" \\\n", + " --header 'Content-Type: application/json' \\\n", + " --data '{\"transition\":{\"id\":\"21\"}}'\n", + "\n", + " # 4 – Set Git author for CI commits\n", + " - run: |\n", + " git config user.email \"github-actions[bot]@users.noreply.github.com\"\n", + " git config user.name \"github-actions[bot]\"\n", + "\n", + " # 5 – Let Codex implement & commit (no push yet)\n", + " - name: Codex implement & commit\n", + " env:\n", + " OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n", + " CODEX_QUIET_MODE: \"1\" # suppress chatty logs\n", + " run: |\n", + " set -e\n", + " codex --approval-mode full-auto --no-terminal --quiet \\\n", + " \"Implement JIRA ticket $ISSUE_KEY: $TITLE. $DESC\"\n", + "\n", + " git add -A\n", + " git commit -m \"feat($ISSUE_KEY): $TITLE\"\n", + "\n", + " # 6 – Open (and push) the PR in one go\n", + " - id: cpr\n", + " uses: peter-evans/create-pull-request@v6\n", + " with:\n", + " token: ${{ secrets.GITHUB_TOKEN }}\n", + " base: main\n", + " branch: ${{ env.BRANCH }}\n", + " title: \"${{ env.TITLE }} (${{ env.ISSUE_KEY }})\"\n", + " body: |\n", + " Auto-generated by Codex for JIRA **${{ env.ISSUE_KEY }}**.\n", + " ---\n", + " ${{ env.DESC }}\n", + "\n", + " # 7 – Transition Jira to \"In Review\" & drop the PR link\n", + " - name: Jira – Transition to In Review & Comment PR link\n", + " env:\n", + " ISSUE_KEY: ${{ env.ISSUE_KEY }}\n", + " JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}\n", + " JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }}\n", + " JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}\n", + " PR_URL: ${{ steps.cpr.outputs.pull-request-url }}\n", + " run: |\n", + " # Status transition\n", + " curl -sS -X POST \\\n", + " --url \"$JIRA_BASE_URL/rest/api/3/issue/$ISSUE_KEY/transitions\" \\\n", + " --user \"$JIRA_EMAIL:$JIRA_API_TOKEN\" \\\n", + " --header 'Content-Type: application/json' \\\n", + " --data '{\"transition\":{\"id\":\"31\"}}'\n", + "\n", + " # Comment with PR link\n", + " curl -sS -X POST \\\n", + " --url \"$JIRA_BASE_URL/rest/api/3/issue/$ISSUE_KEY/comment\" \\\n", + " --user \"$JIRA_EMAIL:$JIRA_API_TOKEN\" \\\n", + " --header 'Content-Type: application/json' \\\n", + " --data \"{\\\"body\\\":{\\\"type\\\":\\\"doc\\\",\\\"version\\\":1,\\\"content\\\":[{\\\"type\\\":\\\"paragraph\\\",\\\"content\\\":[{\\\"type\\\":\\\"text\\\",\\\"text\\\":\\\"PR created: $PR_URL\\\"}]}]}}\"\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "## Key Steps in the Workflow\n", + "\n", + "1. **Codex Implementation & Commit** (Step 5)\n", + " - Uses OpenAI API to implement the JIRA ticket requirements\n", + " - Runs codex CLI in full-auto mode without terminal interaction\n", + " - Commits all changes with standardized commit message\n", + "\n", + "2. **Create Pull Request** (Step 6) \n", + " - Uses peter-evans/create-pull-request action\n", + " - Creates PR against main branch\n", + " - Sets PR title and description from JIRA ticket info\n", + " - Returns PR URL for later use\n", + "\n", + "3. **JIRA Updates** (Step 7)\n", + " - Transitions ticket to \"In Review\" status via JIRA API\n", + " - Posts comment with PR URL on the JIRA ticket\n", + " - Uses curl commands to interact with JIRA REST API\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "## Label an Issue\n", + "\n", + "Attach the special `autocodex` label to any bug/feature ticket:\n", + "\n", + "1. **During creation** – add it in the \"Labels\" field before hitting *Create* \n", + "2. **Existing issue** – hover the label area → click the pencil icon → type `autocodex`\n", + "\n", + "\"Adding\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "## End-to-end Flow in Action\n", + "\n", + "1. Jira label added → Automation triggers\n", + "2. `workflow_dispatch` fires; action spins up on GitHub\n", + "3. `codex-cli` edits the codebase & commits\n", + "4. PR is opened on the generated branch\n", + "5. Jira is moved to **In Review** and a comment with the PR URL is posted\n", + "6. Reviewers are notified per your normal branch protection settings\n", + "\n", + "\"Jira\n", + "\"Jira\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "## Review & Merge the PR\n", + "\n", + "* Confirm CI passes – tests, lint, build\n", + "* Approve & squash-merge\n", + "* The default branch protection will auto-close the Jira ticket once the PR merges if your *Smart Commits* integration is enabled\n", + "\n", + "## Conclusion\n", + "\n", + "This automation streamlines your development workflow by creating a seamless integration between Jira and GitHub:\n", + "\n", + "* **Zero-click implementation** - AI handles the code changes based on ticket descriptions\n", + "* **Automatic status tracking** - Tickets progress through your workflow without manual updates\n", + "* **Improved developer experience** - Focus on reviewing quality code instead of writing boilerplate\n", + "* **Reduced handoff friction** - The PR is ready for review as soon as the ticket is labeled\n", + "\n", + "The `codex-cli` tool is a powerful AI coding assistant that automates repetitive programming tasks. You can explore more about it at:\n", + "\n", + "* [OpenAI Codex-CLI GitHub Repository](https://github.com/openai/codex/)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/registry.yaml b/registry.yaml index fdc78fa2c9..c4fbdea338 100644 --- a/registry.yaml +++ b/registry.yaml @@ -3,6 +3,15 @@ # This file is used to generate cookbook.openai.com. It specifies which paths we # should build pages for, and indicates metadata such as tags, creation date and # authors for each page. +- title: Automate Jira ↔ GitHub with Codex + path: examples/codex/jira-github.ipynb + date: 2025-06-21 + authors: + - alwell-kevin + - narenoai + tags: + - codex + - automation - title: Fine-Tuning Techniques - Choosing Between SFT, DPO, and RFT (With a Guide to DPO) path: examples/Fine_tuning_direct_preference_optimization_guide.ipynb