diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index f1075d0..be57119 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -1,4 +1,4 @@ -name: Python Tests +name: Tests on: pull_request: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed97d53..c0ae237 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1,79 @@ +We welcome contributions! To contribute to this repository, please read these instructions: + +- [Project Organization](#project-organization) +- [Code and Testing](#code-and-testing) +- [Documentation and Maintenance](#documentation-and-maintenance) +- [Development and Local Testing](#development-and-local-testing) + --- + +## Project Organization + +- **Project Configuration:** The setup for both production and development dependencies is outlined in the `pyproject.toml` file. This centralized approach simplifies dependency management. + +- **Automatic `requirements.txt`:** Changes to dependencies are automatically reflected in the `requirements.txt` file, derived from `pyproject.toml`. Direct modifications should be avoided; instead, update `pyproject.toml`. + +- **Commit Standard:** Adherence to the Espressif standard for Conventional Commits ensures consistency in commit messages. Tools like pre-commit hooks and the integrated PR linter DangerJS assist in formatting commit messages appropriately, a key factor for `commitizen` to auto-generate the changelog. + +## Code and Testing + +- **Code Style and Structure:** + + - **Pre-Commit Hooks:** Install pre-commit hooks in this repository using the `pre-commit install` command. + + - **Readable Code Structure:** Structure your code in a readable manner. The main logic should be in the default rule function, with implementation details in helper functions. Avoid nested `if` statements and unnecessary `else` statements to maintain code clarity and simplicity. + + - **Remove Debug Statements:** Remove any development debug statements from your files. + +- **Automated Tests:** The tests should cover all typical usage scenarios as well as edge cases to ensure robustness. + +- **Testing Tool:** It is recommended to run `pytest` frequently during development to ensure that all aspects of your code are functioning as expected. + +## Documentation and Maintenance + +- **Changelog:** `CHANGELOG.md` is generated automatically by `commitizen` from commit messages. Not need to update `CHANGELOG.md` manually. Focus on informative and clear commit messages which end in the release notes. + +- **Documentation:** Regularly check and update the documentation to keep it current. + +- **PR Descriptions and Documentation:** When contributing, describe all changes or new features in the PR (Pull Request) description as well as in the documentation. When changing the style to the output style, attach a thumbnail after the change. + +## Development and Local Testing + +1. **Clone the Project** + +- Clone the repository to your local machine using: + + ```sh + git clone + ``` + +2. **Set Up Development Environment:** + +- Create and activate a virtual environment: + + ```sh + python -m venv venv && source ./venv/bin/activate + ``` + + or: + + ```sh + virtualenv venv && source ./venv/bin/activate + ``` + +- Install the project and development dependencies: + ```sh + pip install -e '.[dev]' + ``` + +3. **Testing Your Changes:** + +- Before submitting a pull request, ensure your changes pass all the tests. You can run the test suite with the following command: + +```sh +pytest +``` + +--- + +👏**Thank you for your contributions.** diff --git a/README.md b/README.md index c424bd0..ef6f93a 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,149 @@ -# GitHub to JIRA Issue Sync +
+

GitHub to JIRA Sync (GitHub Action)

+ GitHub to JIRA Sync logo +
+
+ + release + tests + codeql +
+GitHub to JIRA Sync GitHub Action is a solution for one-way synchronization of GitHub issues into Espressif JIRA projects. +
+
+This action automates the integration of your GitHub repositories with JIRA projects by automatically creating corresponding JIRA tickets for new GitHub issues and pull requests, as well as managing comments within these issues and pull requests from external contributors. -This is a GitHub action that performs simple one way syncing of GitHub issues into JIRA. +
-- When a new GitHub issue is opened - - A corresponding JIRA issue (in the configured JIRA project) is created. - - Markdown in the GitHub issue body is converted into JIRA Wiki format (thanks to [markdown2confluence](http://chunpu.github.io/markdown2confluence/browser/)) - - A JIRA custom field "GitHub Reference" is set to the URL of the issue - - The GitHub issue title has `(JIRA-KEY)` appended to it. -- When a GitHub issue is edited, the summary and description of the JIRA issue are updated. -- When comments are made on the GitHub issue, a comment is created on the JIRA issue. -- When GitHub comments are edited or deleted a comment is created on the JIRA issue. -- When the GitHub issue is closed or deleted a comment is created on the JIRA issue. -- When labels are added or removed from the GitHub issue, the same label is added or removed from the JIRA issue. +- [Features](#features) +- ['Synced From' Link Details](#synced-from-link-details) + - [Key Features and Considerations](#key-features-and-considerations) +- [Manually Linking a GitHub Issue to JIRA](#manually-linking-a-github-issue-to-jira) + - [Step-by-Step Guide](#step-by-step-guide) + - [Automation Trigger](#automation-trigger) + - [Important Note](#important-note) +- [Issue Type Synchronization](#issue-type-synchronization) + - [How It Works](#how-it-works) +- [Limitations](#limitations) + - [What's Not Synced](#whats-not-synced) +- [Usage Instructions for GitHub to JIRA Issue Sync Action](#usage-instructions-for-github-to-jira-issue-sync-action) + - [Syncing New Issues to JIRA](#syncing-new-issues-to-jira) + - [Syncing New Issue Comments to JIRA](#syncing-new-issue-comments-to-jira) + - [Syncing New Pull Requests to JIRA](#syncing-new-pull-requests-to-jira) +- [Manually Syncing Issues and Pull Requests to JIRA](#manually-syncing-issues-and-pull-requests-to-jira) + - [Configuration for Manual Sync](#configuration-for-manual-sync) + - [Workflow Setup](#workflow-setup) +- [Environment Variables and Secrets Configuration](#environment-variables-and-secrets-configuration) + - [Important Consideration:](#important-consideration) +- [Project Issues](#project-issues) +- [Contributing](#contributing) -# 'Synced From' Link +## Features -After a synced JIRA issue is created, the action creates a [Remote Issue Link](https://developer.atlassian.com/server/jira/platform/creating-remote-issue-links/) on the JIRA issue, where the "[globalID](https://developer.atlassian.com/server/jira/platform/using-fields-in-remote-issue-links/#globalid)" is the GitHub issue URL. +- **Automatic Issue Creation**: When a new GitHub issue is opened, a matching JIRA issue is created within the specified project. +- **Markdown Conversion**: The body of the GitHub issue is converted to JIRA Wiki format using [markdown2confluence](http://chunpu.github.io/markdown2confluence/browser/). +- **Custom Field Mapping**: A JIRA custom field named "GitHub Reference" is populated with the URL of the GitHub issue. +- **Issue Title Sync**: The title of the GitHub issue is updated to include the JIRA issue key. +- **Bi-directional Comment Sync**: Comments added to a GitHub issue are mirrored in the corresponding JIRA issue. Edits and deletions are also reflected. +- **Label Synchronization**: Labels added or removed from the GitHub issue are similarly updated in the JIRA issue. +- **Remote Issue Link**: After syncing, a [Remote Issue Link](https://developer.atlassian.com/server/jira/platform/creating-remote-issue-links/) is created on the JIRA issue for easy reference back to the GitHub issue. -This remote issue link is used to find existing synced issues when changes happen. +## 'Synced From' Link Details -The sync action will continue to update JIRA issues which are moved to other JIRA projects, provided the remote issue link is moved and the Github Action's JIRA user can see the new project. +Once a JIRA issue is created and synced from GitHub, a [Remote Issue Link](https://developer.atlassian.com/server/jira/platform/creating-remote-issue-links/) is automatically generated for the JIRA issue. This link includes a "globalID" that corresponds to the URL of the GitHub issue. This mechanism ensures that any future changes to the GitHub issue are tracked and reflected in the JIRA issue, maintaining a consistent link between the two platforms. -To break a link between a GitHub issue and a JIRA issue, delete the Remote Issue Link. (Note that if the GitHub Issue is updated later on, this action may create a new JIRA issue to track it.) +### Key Features and Considerations -Note that manually created Remote Issue Links to GitHub issues will not have the globalID set, so they won't work (JIRA doesn't give a way to search for Remote Issue Links by URL, only by globalID, so there's no automated solution to this problem.) +- **Persistent Synchronization**: The Remote Issue Link facilitates ongoing updates to JIRA issues that are moved to other JIRA projects, assuming the remote issue link is also transferred and the GitHub Action's JIRA user has access to the new project. +- **Link Management**: To sever the connection between a GitHub issue and a JIRA issue, simply remove the Remote Issue Link. Be aware, however, that subsequent updates to the GitHub issue may trigger the creation of a new JIRA issue to ensure continuity of tracking. +- **Manual Links**: It's important to note that Remote Issue Links created manually for GitHub issues won't contain the necessary globalID. Since JIRA's search functionality for Remote Issue Links relies exclusively on globalID and not the URL, such manually created links cannot facilitate automated syncing. -# Manually Linking a GitHub Issue +This design ensures that the integration between GitHub and JIRA remains dynamic and adaptable to changes, providing a robust solution for tracking issues across both platforms. -It's not possible to create a Remote Issue Link with the correct `globalID` without using the JIRA API. Instead, to manually connect an existing GitHub issue with a JIRA issue in the Web UI: +## Manually Linking a GitHub Issue to JIRA -1. Check that no other JIRA issue is syncing this GitHub issue (advanced search for `issue in issuesWithRemoteLinksByGlobalId("GitHub Issue URL")`). -2. Put the URL of the GitHub issue somewhere in the JIRA issue description. -3. Put the JIRA issue key at the end of the GitHub issue title, in parentheses. Like this: `GitHub Issue title (JIRAKEY-123)` +Creating a Remote Issue Link with the appropriate `globalID` directly through the JIRA Web UI is not feasible without leveraging the JIRA API. However, you can manually establish a connection between an existing GitHub issue and a JIRA issue by following these steps: -The GitHub action will create the "Synced from" link the next time this issue is updated (probably immediately, if you did the steps in the written order). +### Step-by-Step Guide -Important: If the URL of the GitHub issue is not found in the JIRA issue description, nothing will happen (this is to prevent external parties from making unintended updates to JIRA issues.) +1. **Verify Unique Linking**: Ensure that the GitHub issue is not already linked to another JIRA issue. Use JIRA's advanced search with the query `issue in issuesWithRemoteLinksByGlobalId("GitHub Issue URL")` to check for existing links. +2. **Update JIRA Issue Description**: Include the URL of the GitHub issue in the description field of the JIRA issue. This step is crucial for the GitHub action to recognize and link the issues. +3. **Amend GitHub Issue Title**: Append the JIRA issue key to the end of the GitHub issue title within parentheses, e.g., `GitHub Issue title (JIRAKEY-123)`. This modification helps in identifying the linked issues easily. -# Issue Types +### Automation Trigger -If a new GitHub issue has any labels where the name of the label matches the name of an issue type, or the name of the label matches `Type: `, then the JIRA issue will be created with that issue type. Matching is case insensitive. +Upon the next update to the GitHub issue (which might occur immediately if you follow the steps sequentially), the GitHub action will automatically generate the "Synced from" link, establishing a manual link between the issues. -If no labels match issue types, environment variable `JIRA_ISSUE_TYPE` is used as the type for new issues. If `JIRA_ISSUE_TYPE` is not set, the default new issue type is "Task". +### Important Note -Changing labels on a GitHub issue does not change the issue type, because [JIRA REST API currently cannot safely change an issue type to one with a different workflow](https://jira.atlassian.com/browse/JRACLOUD-68207). Instead, an issue comment is left in JIRA. +If the GitHub issue URL is not present in the JIRA issue description, the GitHub action will not create a link. This safeguard is designed to prevent unauthorized or unintended updates to JIRA issues from external sources. -# Limitations +## Issue Type Synchronization -Currently does not sync the following things: +The GitHub to JIRA Issue Sync Action intelligently creates JIRA issues with specific types based on the labels attached to the GitHub issue. This feature ensures that the issue types in JIRA accurately reflect the nature or category of the issue as determined in GitHub. -- Labels, apart from any which match Issue Types -- Transitions. Closing, Reopening or Deleting an issue in GitHub only leaves a comment in the JIRA issue. This is at least partially by design because sometimes GitHub issues are closed by their reporters even though an underlying issue still needs fixing in the codebase. +### How It Works -# Usage +- **Label Matching**: When a new GitHub issue is created, the action checks for labels that either directly match the name of a JIRA issue type or follow the format `Type: `. The search for matching labels is case insensitive, ensuring flexibility in label naming conventions. +- **Environment Variable Fallback**: In cases where no labels match any issue type, the action refers to the `JIRA_ISSUE_TYPE` environment variable to determine the issue type for the new JIRA issue. If this environment variable is not defined, the default issue type used is "Task". +- **Handling Label Changes**: If the labels on a GitHub issue are modified after creation, these changes will not alter the issue type of the already created JIRA issue. This limitation arises from the [inability of the JIRA REST API to safely change an issue type](https://jira.atlassian.com/browse/JRACLOUD-68207) when the new type is associated with a different workflow. In such scenarios, the action will leave a comment in the JIRA issue to inform about the label change in GitHub. -- [Sync a new issue to Jira](#sync-a-new-issue-to-jira) -- [Sync a new issue comment to Jira](#sync-a-new-issue-comment-to-jira) -- [Sync a new pull request to Jira](#sync-a-new-pull-request-to-jira) +## Limitations -## Sync a new issue to Jira +There are certain limitations to the data and events that can be synchronized: + +### What's Not Synced + +- **Labels**: The action does not sync labels between GitHub and JIRA, with the exception of labels that match JIRA issue types. This means that general labels used for categorization or prioritization in GitHub won't automatically reflect in JIRA. +- **Transitions**: Changes in the status of a GitHub issue, such as closing, reopening, or deleting, do not automatically result in the corresponding transition of the JIRA issue's status. Instead, these actions result in a comment being added to the linked JIRA issue to record the event. This design choice accounts for scenarios where a GitHub issue might be closed by its reporter, but the underlying problem it documents still requires attention and resolution within the JIRA project. + +## Usage Instructions for GitHub to JIRA Issue Sync Action + +This GitHub Action provides a comprehensive solution for integrating GitHub with JIRA, ensuring that issues, comments, and pull requests in GitHub are seamlessly synced to JIRA. Below are the setups to synchronize different types of activities from GitHub to JIRA. + +### Syncing New Issues to JIRA + +Automatically creates a corresponding JIRA issue when a new issue is opened in GitHub. ```yaml name: Sync issues to Jira -# This workflow will be triggered when a new issue is opened -on: issues -# Limit to single concurrent run for workflows which can create Jira issues. -# Same concurrency group is used in issue_comment.yml +on: issues concurrency: jira_issues jobs: sync_issues_to_jira: - name: Sync issues to Jira runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - name: Sync GitHub issues to Jira project - uses: espressif/github-actions/sync_issues_to_jira@master + uses: espressif/sync-jira-actions@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JIRA_PASS: ${{ secrets.JIRA_PASS }} - JIRA_PROJECT: SOMEPROJECT - JIRA_COMPONENT: SOMECOMPONENT + JIRA_PROJECT: SOMEPROJECT # define the JIRA project here + JIRA_COMPONENT: SOMECOMPONENT # define (optional) JIRA component here JIRA_URL: ${{ secrets.JIRA_URL }} JIRA_USER: ${{ secrets.JIRA_USER }} ``` -## Sync a new issue comment to Jira +### Syncing New Issue Comments to JIRA -Syncing an issue comment works the same way. The only difference is the trigger event. +Ensures that comments made on GitHub issues are also reflected in the corresponding JIRA issue. ```yaml name: Sync issue comments to JIRA -# This workflow will be triggered when new issue comment is created (including PR comments) on: issue_comment ``` -## Sync a new pull request to Jira +### Syncing New Pull Requests to JIRA -Actions for pull requests run with the privileges of the PR submitter's repo - for security reasons, as they can modify the contents of them. -If the action is run on the PR event, it can't access the necessary GH secrets containing Jira credentials. -Therefore PR syncing has to run as a cron task which is loaded from the master branch and run with all privileges. +Due to security reasons related to the privileges of PR submitter's repositories, syncing pull requests requires a different approach, using a cron job to regularly check for and sync new pull requests. ```yaml name: Sync remaining PRs to Jira -# This workflow will be triggered every hour to sync remaining PRs (i.e. PRs with zero comment) to Jira project -# Note that PRs can also get synced when a new PR comment is created + on: schedule: - cron: "0 * * * *" @@ -113,35 +151,41 @@ concurrency: jira_issues jobs: sync_prs_to_jira: - name: Sync PRs to Jira runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 + - name: Sync PRs to Jira project - uses: espressif/github-actions/sync_issues_to_jira@master + uses: espressif/sync-jira-actions@v1 with: cron_job: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JIRA_PASS: ${{ secrets.JIRA_PASS }} - JIRA_PROJECT: SOMEPROJECT - JIRA_COMPONENT: SOMECOMPONENT + JIRA_PROJECT: SOMEPROJECT # define the JIRA project here + JIRA_COMPONENT: SOMECOMPONENT # define (optional) JIRA component here JIRA_URL: ${{ secrets.JIRA_URL }} JIRA_USER: ${{ secrets.JIRA_USER }} ``` -## Sync issues and pull requests manually +## Manually Syncing Issues and Pull Requests to JIRA + +For cases where you need to manually sync issues and pull requests that were not automatically captured by the [Sync a new issue to Jira](#sync-a-new-issue-to-jira) and [Sync a new pull request to Jira](#sync-a-new-pull-request-to-jira) workflows, this GitHub Action provides a solution. It allows for the manual synchronization of both new and old issues and pull requests directly to your JIRA project. + +### Configuration for Manual Sync + +This action introduces two parameters for manual triggering: -Actions for both issues and pull requests to sync them manually to Jira. When enabling [Sync a new issue to Jira](#sync-a-new-issue-to-jira) and [Sync a new pull request to Jira](#sync-a-new-pull-request-to-jira) actions, it will sync only newly created issues and pull requests. With this action you can manually sync all old issues and pull requests. -Action defines two input parameters: +- `action`: Specifies the action to be performed, with a default value of `mirror-issues`. +- `issue-numbers`: Lists the numbers of the issues and pull requests that you wish to sync to JIRA. -- `action` with default value `mirror-issues` -- `issue-numbers` with issue and pull requests numbers to be mirrored to Jira +### Workflow Setup + +To set up the manual sync action, include the following workflow in your GitHub repository: ```yaml name: Manually trigger sync issue to Jira -# This workflow will be triggered manually on: workflow_dispatch: inputs: @@ -152,7 +196,6 @@ on: issue-numbers: description: "Issue numbers" required: true - concurrency: jira_issues jobs: @@ -160,76 +203,50 @@ jobs: name: Sync issues to Jira runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 + - name: Sync GitHub issues to Jira project - uses: espressif/github-actions/sync_issues_to_jira@master + uses: espressif/sync-jira-actions@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JIRA_PASS: ${{ secrets.JIRA_PASS }} - JIRA_PROJECT: SOMEPROJECT - JIRA_COMPONENT: SOMECOMPONENT + JIRA_PROJECT: SOMEPROJECT # define the JIRA project here + JIRA_COMPONENT: SOMECOMPONENT # define (optional) JIRA component here JIRA_URL: ${{ secrets.JIRA_URL }} JIRA_USER: ${{ secrets.JIRA_USER }} ``` -# Variables +This workflow can be triggered manually from the GitHub Actions tab in your repository, allowing you to specify the issues or pull requests to be synced by entering their numbers. -The environment variables should be set in the GitHub Workflow: +This ensures that even items not caught by the automatic sync process can still be integrated into your JIRA project for tracking and management. -- `JIRA_PROJECT` is the slug of the JIRA project to create new issues in. -- `JIRA_ISSUE_TYPE` (optional) the JIRA issue type for new issues. If unset, "Task" is used. -- `JIRA_COMPONENT` (optional) the name of a JIRA component to add to every issue which is synced from GitHub. The component must already exist in the JIRA project. +## Environment Variables and Secrets Configuration -The following secrets are needed for the workflow: +The GitHub to JIRA Issue Sync workflow requires the configuration of specific environment variables and secrets to operate effectively. These settings ensure the correct creation and updating of issues within your JIRA project based on activities in your GitHub repository. -- `JIRA_URL` is the main JIRA URL (doesn't have to be secret). -- `JIRA_USER` is the JIRA username to log in with (JIRA basic auth) -- `JIRA_PASS` is JIRA token (JIRA token auth) or JIRA password (JIRA basic auth) to log in with +Below is a detailed table outlining the necessary configurations: -If `JIRA_PASS` is a token, it must be entered in the secret with the prefix `token:` (e.g.: `token:Xyz123**************ABC`). The `token:` prefix is used to distinguish between a password and a token type of `JIRA_PASS`. This prefix will be stripped by the script before the API call. +| Variable/Secret | Description | Requirement | +| ----------------- | -------------------------------------------------------------------------------------------- | ----------- | +| `JIRA_PROJECT` | The slug of the JIRA project where new issues will be created. | Mandatory | +| `JIRA_URL` | The main URL of your JIRA instance. | Inherited | +| `JIRA_USER` | The username used for logging into JIRA (basic auth). | Inherited | +| `JIRA_PASS` | The JIRA token (for token auth) or password (for basic auth) used for logging in. | Inherited | +| `JIRA_ISSUE_TYPE` | Specifies the JIRA issue type for new issues. Defaults to "Task" if not set. | Optional | +| `JIRA_COMPONENT` | The name of a JIRA component to add to every synced issue. The component must exist in JIRA. | Optional | -***IMPORTANT:** These secrets are inherited from the GitHub organizational secrets (as they are common to all Espressif GitHub projects) and should not be set at the repository level. (If set at the repository level, repo secrets take precedence over org secrets.)* +### Important Consideration: -# Tests +- **GitHub Organizational Secrets**: `JIRA_URL`, `JIRA_USER`, `JIRA_PASS` - These secrets are **inherited from the GitHub organizational secrets, as they are common to all projects within the organization**. It is advised not to set these secrets at the individual repository level to avoid conflicts and ensure a unified configuration across all projects. -test_sync_issue.py is a Python unittest framework that uses unittest.mock to create a mock JIRA API, then calls unit_test.py with various combinations of payloads similar to real GitHub Actions payloads. +- **Token as JIRA_PASS**: When using a token for `JIRA_PASS`, prefix the token value with `token:` (e.g., `token:Xyz123**************ABC`). This prefix helps distinguish between password and token types, and it will be removed by the script before making the API call. -The best way to run the tests is in the docker container, as this is the same environment that GitHub will run real actions in. +--- -## Build image and run tests in a temporary container: +## Project Issues -``` -docker build . --tag jira-sync && docker run --rm --entrypoint=/test_sync_to_jira.py jira-sync -``` - -## Rebuild container and run tests multiple times - -(This is a bit faster than rebuilding the image each time.) - -Build the image and run the container once: - -``` -docker build . --tag jira-sync -docker run -td --name jira-sync --entrypoint=/bin/sh jira-sync -``` - -For each test run, copy the Python files to the running container and run the test program: - -``` -docker cp . jira-sync:/ && docker exec jira-sync /test_sync_to_jira.py -``` - -Once finished, kill the container: +If you encounter any issues, feel free to report them in the project's issues or create Pull Request with your suggestion. -``` -docker stop -t1 jira-sync -``` +## Contributing -## Cleanup - -To clean up the container and container image: - -``` -docker rm jira-sync -docker rmi jira-sync -``` +📘 If you are interested in contributing to this project, see the [project Contributing Guide](CONTRIBUTING.md). diff --git a/docs/sync-jira-actions.png b/docs/sync-jira-actions.png new file mode 100644 index 0000000..a7a8f93 Binary files /dev/null and b/docs/sync-jira-actions.png differ