├── .all-contributorsrc ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── compatibility.yml │ ├── dependabot-auto-merge.yml │ ├── files-changed.yaml │ ├── release.yml │ ├── scorecards-analysis.yml │ ├── update-gradle-wrapper.yml │ └── update-plugin-platform-version.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── build-standard-jetbrains-plugin-build.gradle.kts ├── demo.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── qodana.yml ├── settings.gradle.kts └── src ├── main ├── java │ └── com │ │ └── chriscarini │ │ └── jetbrains │ │ └── github │ │ ├── issue │ │ └── navigation │ │ │ └── GitHubIssueNavigationVcsRepositoryMappingListener.java │ │ └── utils │ │ ├── GitHubUri.java │ │ └── GitHubUtils.java └── resources │ └── META-INF │ └── plugin.xml └── test └── java └── com └── chriscarini └── jetbrains └── github ├── issue └── navigation │ └── TestGitHubIssueNavigationVcsRepositoryMappingListenerTest.java └── utils ├── GitHubUriTest.java └── GitHubUtilsTest.java /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "automatic-github-issue-navigation-configuration-jetbrains-plugin", 3 | "projectOwner": "ChrisCarini", 4 | "files": [ 5 | "README.md" 6 | ], 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributorsPerLine": 7, 10 | "contributors": [ 11 | { 12 | "login": "ChrisCarini", 13 | "name": "Chris Carini", 14 | "avatar_url": "https://avatars.githubusercontent.com/u/6374067?v=4", 15 | "profile": "https://github.com/ChrisCarini", 16 | "contributions": [ 17 | "bug", 18 | "code", 19 | "doc", 20 | "example", 21 | "ideas", 22 | "maintenance", 23 | "question", 24 | "review" 25 | ] 26 | }, 27 | { 28 | "login": "loganrosen", 29 | "name": "Logan Rosen", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/512317?v=4", 31 | "profile": "https://www.loganrosen.com/", 32 | "contributions": [ 33 | "bug" 34 | ] 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Dependabot configuration: 2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | # Maintain dependencies for Gradle dependencies 7 | - package-ecosystem: "gradle" 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | reviewers: 12 | - ChrisCarini 13 | 14 | # Maintain dependencies for GitHub Actions 15 | - package-ecosystem: "github-actions" 16 | directory: "/" 17 | schedule: 18 | interval: "daily" 19 | reviewers: 20 | - ChrisCarini 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for testing and preparing the plugin release in following steps: 2 | # - validate Gradle Wrapper, 3 | # - run test and verifyPlugin tasks, 4 | # - run buildPlugin task and prepare artifact for the further tests, 5 | # - run IntelliJ Plugin Verifier, 6 | # - create a release. 7 | # 8 | # Workflow is triggered on push and pull_request events. 9 | # 10 | # Docs: 11 | # - GitHub Actions: https://help.github.com/en/actions 12 | # - IntelliJ Plugin Verifier GitHub Action: https://github.com/ChrisCarini/intellij-platform-plugin-verifier-action 13 | # 14 | 15 | name: Build 16 | on: 17 | # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) 18 | push: 19 | branches: [ main ] 20 | 21 | # Trigger the workflow on any pull request 22 | pull_request: 23 | 24 | jobs: 25 | files-changed: 26 | uses: ./.github/workflows/files-changed.yaml 27 | 28 | # Run Gradle Wrapper Validation Action to verify the wrapper's checksum 29 | gradleValidation: 30 | name: Gradle Wrapper 31 | runs-on: ubuntu-latest 32 | steps: 33 | 34 | # Check out current repository 35 | - name: Fetch Sources 36 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 37 | timeout-minutes: 1 38 | 39 | # Validate wrapper 40 | - name: Gradle Wrapper Validation 41 | uses: gradle/actions/wrapper-validation@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 42 | 43 | # Run verifyPlugin and test Gradle tasks 44 | test: 45 | name: Test 46 | needs: [ gradleValidation, files-changed ] 47 | # If there are no changes in the changelog or there are changes in more than just the changelog, we want to run this job. 48 | if: needs.files-changed.outputs.SKIP_CI == 'false' 49 | runs-on: ubuntu-latest 50 | steps: 51 | 52 | # Check out current repository 53 | - name: Fetch Sources 54 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 55 | timeout-minutes: 1 56 | 57 | # Setup Java environment for the next steps 58 | - name: Setup Java 59 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 60 | timeout-minutes: 5 61 | with: 62 | distribution: zulu 63 | java-version: 21 64 | cache: gradle 65 | 66 | # Set environment variables 67 | - name: Export Properties 68 | id: properties 69 | shell: bash 70 | run: | 71 | PROPERTIES="$(./gradlew properties --console=plain -q)" 72 | IDE_VERSIONS="$(echo "$PROPERTIES" | grep "^pluginVerifierIdeVersions:" | base64)" 73 | 74 | echo "ideVersions=$IDE_VERSIONS" >> $GITHUB_OUTPUT 75 | echo "pluginVerifierHomeDir=~/.pluginVerifier" >> $GITHUB_OUTPUT 76 | 77 | # Cache Plugin Verifier IDEs 78 | - name: Setup Plugin Verifier IDEs Cache 79 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 80 | with: 81 | path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides 82 | key: ${{ runner.os }}-plugin-verifier-${{ steps.properties.outputs.ideVersions }} 83 | 84 | ### TODO (ChrisCarini) - Disabling this in the GH action; when running we see the below error message: 85 | ### STDERR: Could not read script '/data/project/jetbrainsCredentials.gradle' as it does not exist 86 | ## Run Qodana inspections 87 | #- name: Qodana - Code Inspection 88 | # uses: JetBrains/qodana-action@v2.1-eap 89 | 90 | # Run tests 91 | - name: Run Tests 92 | run: ./gradlew test 93 | 94 | # Run verifyPlugin Gradle task 95 | - name: Verify Plugin 96 | run: ./gradlew verifyPlugin 97 | 98 | # Run IntelliJ Plugin Verifier action using GitHub Action 99 | - name: Run Plugin Verifier 100 | run: ./gradlew verifyPlugin -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} 101 | 102 | # Build plugin with buildPlugin Gradle task and provide the artifact for the next workflow jobs 103 | # Requires test job to be passed 104 | build: 105 | name: Build 106 | needs: [ test, files-changed ] 107 | # If there are no changes in the changelog or there are changes in more than just the changelog, we want to run this job. 108 | if: needs.files-changed.outputs.SKIP_CI == 'false' 109 | runs-on: ubuntu-latest 110 | outputs: 111 | version: ${{ steps.properties.outputs.version }} 112 | changelog: ${{ steps.properties.outputs.changelog }} 113 | steps: 114 | 115 | # Check out current repository 116 | - name: Fetch Sources 117 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 118 | timeout-minutes: 1 119 | 120 | # Setup Java environment for the next steps 121 | - name: Setup Java 122 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 123 | timeout-minutes: 5 124 | with: 125 | distribution: zulu 126 | java-version: 21 127 | cache: gradle 128 | 129 | # Set environment variables 130 | - name: Export Properties 131 | id: properties 132 | shell: bash 133 | run: | 134 | PROPERTIES="$(./gradlew properties --console=plain -q)" 135 | VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" 136 | NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')" 137 | CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --no-empty-sections --no-links --console=plain -q)" 138 | 139 | echo "version=$VERSION" >> $GITHUB_OUTPUT 140 | echo "name=$NAME" >> $GITHUB_OUTPUT 141 | 142 | echo "changelog<> $GITHUB_OUTPUT 143 | echo "$CHANGELOG" >> $GITHUB_OUTPUT 144 | echo "EOF" >> $GITHUB_OUTPUT 145 | 146 | # Build artifact using buildPlugin Gradle task 147 | - name: Build Plugin 148 | run: ./gradlew buildPlugin 149 | 150 | # Store built plugin as an artifact for downloading 151 | - name: Upload artifacts 152 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 153 | with: 154 | name: "${{ steps.properties.outputs.name }} - ${{ steps.properties.outputs.version }}" 155 | path: ./build/distributions/* 156 | 157 | # Prepare a release for GitHub Releases page 158 | # Once (automatically) published, release workflow will be triggered 159 | release: 160 | name: Release 161 | # If the event is *not* a PR, and there are no changes in the changelog or there are changes in more than just the changelog, we want to run this job. 162 | if: github.event_name != 'pull_request' && needs.files-changed.outputs.SKIP_CI == 'false' 163 | needs: [ build, files-changed ] 164 | runs-on: ubuntu-latest 165 | steps: 166 | 167 | # Check out current repository 168 | - name: Fetch Sources 169 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 170 | timeout-minutes: 1 171 | 172 | # Remove old release drafts by using the curl request for the available releases with draft flag 173 | - name: Remove Old Release Drafts 174 | env: 175 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 176 | run: | 177 | gh api repos/{owner}/{repo}/releases \ 178 | --jq '.[] | select(.draft == true) | .id' \ 179 | | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} 180 | 181 | # Get latest release version 182 | - name: Get latest release version 183 | id: properties 184 | shell: bash 185 | env: 186 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 187 | run: | 188 | VERSION="$(gh api repos/{owner}/{repo}/releases --jq 'select(.[].draft == false) | first | .tag_name' | uniq | sed 's/v\(.*\)/\1/')" 189 | echo "latest_release_version=$VERSION" | tee -a $GITHUB_OUTPUT 190 | 191 | # Create new release 192 | - name: Create & Publish Release 193 | # If the currently released (to GitHub) version differs from the current version that was just built, create and publish a new release 194 | if: steps.properties.outputs.latest_release_version != needs.build.outputs.version 195 | env: 196 | GITHUB_TOKEN: ${{ secrets.PAT_TOKEN_FOR_IJ_UPDATE_ACTION }} 197 | run: | 198 | echo "Latest Released Version: [${{ steps.properties.outputs.latest_release_version }}] != Current Build Version: [${{ needs.build.outputs.version }}]" 199 | gh release create v${{ needs.build.outputs.version }} \ 200 | --title "v${{ needs.build.outputs.version }}" \ 201 | --notes "$(cat << 'EOM' 202 | ${{ needs.build.outputs.changelog }} 203 | EOM 204 | )" 205 | -------------------------------------------------------------------------------- /.github/workflows/compatibility.yml: -------------------------------------------------------------------------------- 1 | name: IntelliJ Plugin Compatibility 2 | 3 | on: 4 | # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) 5 | push: 6 | branches: [ main ] 7 | 8 | # Trigger the workflow on any pull request 9 | pull_request: 10 | 11 | # Trigger the workflow on a schedule; daily 12 | schedule: 13 | - cron: '0 0 * * *' 14 | 15 | jobs: 16 | files-changed: 17 | uses: ./.github/workflows/files-changed.yaml 18 | 19 | compatibility: 20 | name: Ensure plugin compatibility against targeted platform version & the latest EAP snapshot for both IDEA Community, IDEA Ultimate. 21 | 22 | runs-on: ubuntu-latest 23 | needs: files-changed 24 | if: needs.files-changed.outputs.SKIP_CI == 'false' 25 | 26 | steps: 27 | - name: Check out repository 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | timeout-minutes: 1 30 | 31 | - name: Setup Java 32 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 33 | timeout-minutes: 5 34 | with: 35 | java-version: 21 36 | distribution: 'zulu' 37 | cache: gradle 38 | 39 | - name: Build the plugin 40 | run: ./gradlew buildPlugin 41 | 42 | - name: Generate IDE Versions List 43 | run: ./gradlew generateIdeVersionsList 44 | 45 | # The below action is disabled to see how the verifier action below deals with it. 46 | # GitHub announced a 10x increase to the storage capacity for GitHub Actions, which should help with the disk space issue. 47 | # Ref: https://github.blog/2024-01-17-github-hosted-runners-double-the-power-for-open-source/ 48 | # Ref: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories 49 | # # https://github.com/actions/runner-images/issues/2840#issuecomment-790492173 50 | # # https://github.com/jlumbroso/free-disk-space 51 | # NOTE: Tried removing this on 2024-02-08, but ran out of diskspace on the 2023.3.4 upgrade PRs. Re-enabling. 52 | - name: Free Disk Space (Ubuntu) 53 | uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 54 | with: 55 | # this remove tools (actions/setup-java) that are needed; hence, disable. 56 | tool-cache: false 57 | # this removes docker images that are needed, like the one that is built at the beginning of the workflow run 58 | # for the below action (ChrisCarini/intellij-platform-plugin-verifier-action@latest); hence, disable. 59 | docker-images: false 60 | 61 | - name: Verify plugin on IntelliJ Platforms 62 | id: verify 63 | uses: ChrisCarini/intellij-platform-plugin-verifier-action@latest 64 | with: 65 | # There is an issue with 1.384 where the verifier will `java.lang.OutOfMemoryError: Java heap space`; see below resources: 66 | # - https://platform.jetbrains.com/t/outofmemoryerror-during-plugin-verifier/1036/6 67 | # - https://youtrack.jetbrains.com/issue/MP-7366/Plugin-Verifier-1.384-OOM-when-checking-large-number-of-plugins#focus=Comments-27-11774230.0-0 68 | verifier-version: '1.383' 69 | # Generated from the `generateIdeVersionsList` task above. 70 | ide-versions: build/intellij-platform-plugin-verifier-action-ide-versions-file.txt 71 | # TODO(ChrisCarini) - This can be removed once https://youtrack.jetbrains.com/issue/MP-6711 is resolved. 72 | # See below for details: 73 | # - https://jetbrains-platform.slack.com/archives/C012S7PA8CQ/p1722334099316129?thread_ts=1719921236.855369&cid=C012S7PA8CQ 74 | # - https://youtrack.jetbrains.com/issue/MP-6711/Plugin-Verifier-Muted-plugin-problems-show-up-in-the-standard-output-as-structure-warnings#focus=Comments-27-10232348.0-0 75 | failure-levels: | 76 | PLUGIN_STRUCTURE_WARNINGS 77 | 78 | - name: Get log file path and print contents 79 | run: | 80 | echo "The log file path is: ${{steps.verify.outputs.verification-output-log-filename}}" ; 81 | cat ${{steps.verify.outputs.verification-output-log-filename}} 82 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Enable auto-merge for Dependabot PRs 2 | 3 | on: pull_request 4 | 5 | permissions: 6 | contents: write 7 | pull-requests: write 8 | 9 | jobs: 10 | dependabot: 11 | runs-on: ubuntu-latest 12 | if: github.actor == 'dependabot[bot]' 13 | steps: 14 | - name: Enable auto-merge for Dependabot PRs 15 | run: | 16 | gh pr merge \ 17 | --auto \ 18 | --squash \ 19 | "$PR_URL" 20 | env: 21 | PR_URL: ${{github.event.pull_request.html_url}} 22 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} -------------------------------------------------------------------------------- /.github/workflows/files-changed.yaml: -------------------------------------------------------------------------------- 1 | name: files-changed 2 | on: 3 | workflow_call: 4 | # Map the workflow outputs to job outputs 5 | outputs: 6 | SKIP_CI: 7 | description: "true/false output of if we should skip CI (for the longer portions)" 8 | value: >- 9 | ${{ 10 | ( jobs.files-changed.outputs.changelog == 'true' && jobs.files-changed.outputs.changelog_count == 1 && jobs.files-changed.outputs.changed_count == 1 ) || 11 | ( jobs.files-changed.outputs.allcontributors == 'true' && jobs.files-changed.outputs.allcontributors_count == 2 && jobs.files-changed.outputs.changed_count == 2 ) 12 | }} 13 | allcontributors: 14 | description: "true/false output of if the allcontributors changed" 15 | value: ${{ jobs.files-changed.outputs.allcontributors }} 16 | allcontributors_count: 17 | description: "The count of all files matching the allcontributors" 18 | value: ${{ jobs.files-changed.outputs.allcontributors_count }} 19 | allcontributors_files: 20 | description: "List of all files matching the allcontributors" 21 | value: ${{ jobs.files-changed.outputs.allcontributors_files }} 22 | changelog: 23 | description: "true/false output of if the changelog changed" 24 | value: ${{ jobs.files-changed.outputs.changelog }} 25 | changelog_count: 26 | description: "The count of all files matching the changelog" 27 | value: ${{ jobs.files-changed.outputs.changelog_count }} 28 | changelog_files: 29 | description: "List of all files matching the changelog" 30 | value: ${{ jobs.files-changed.outputs.changelog_files }} 31 | changed: 32 | description: "true/false output of if any changed" 33 | value: ${{ jobs.files-changed.outputs.changed }} 34 | changed_count: 35 | description: "The count of all files changed" 36 | value: ${{ jobs.files-changed.outputs.changed_count }} 37 | changed_files: 38 | description: "List of all files changed" 39 | value: ${{ jobs.files-changed.outputs.changed_files }} 40 | 41 | jobs: 42 | files-changed: 43 | name: detect what files changed 44 | runs-on: ubuntu-latest 45 | # Map the job outputs to step outputs 46 | outputs: 47 | allcontributors: ${{ steps.changes.outputs.allcontributors }} 48 | allcontributors_count: ${{ steps.changes.outputs.allcontributors_count }} 49 | allcontributors_files: ${{ steps.changes.outputs.allcontributors_files }} 50 | changelog: ${{ steps.changes.outputs.changelog }} 51 | changelog_count: ${{ steps.changes.outputs.changelog_count }} 52 | changelog_files: ${{ steps.changes.outputs.changelog_files }} 53 | changed: ${{ steps.changes.outputs.changed }} 54 | changed_count: ${{ steps.changes.outputs.changed_count }} 55 | changed_files: ${{ steps.changes.outputs.changed_files }} 56 | steps: 57 | - name: Check out repository 58 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 59 | timeout-minutes: 1 60 | 61 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 62 | id: changes 63 | with: 64 | filters: | 65 | allcontributors: 66 | - '.all-contributorsrc' 67 | - 'README.md' 68 | changelog: 69 | - 'CHANGELOG.md' 70 | changed: 71 | - '**' 72 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for handling the release process based on the draft release prepared 2 | # with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. 3 | 4 | name: Release 5 | on: 6 | release: 7 | types: [ prereleased, released ] 8 | 9 | jobs: 10 | 11 | # Prepare and publish the plugin to the Marketplace repository 12 | release: 13 | name: Publish Plugin 14 | runs-on: ubuntu-latest 15 | environment: PROD_PUBLISH_PLUGIN 16 | steps: 17 | 18 | # Check out current repository 19 | - name: Fetch Sources 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | timeout-minutes: 1 22 | with: 23 | ref: ${{ github.event.release.tag_name }} 24 | 25 | # Setup Java environment for the next steps 26 | - name: Setup Java 27 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 28 | timeout-minutes: 5 29 | with: 30 | distribution: zulu 31 | java-version: 21 32 | cache: gradle 33 | 34 | # Set environment variables 35 | - name: Export Properties 36 | id: properties 37 | shell: bash 38 | run: | 39 | CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d' 40 | ${{ github.event.release.body }} 41 | EOM 42 | )" 43 | 44 | echo "changelog<> $GITHUB_OUTPUT 45 | echo "$CHANGELOG" >> $GITHUB_OUTPUT 46 | echo "EOF" >> $GITHUB_OUTPUT 47 | 48 | # Update Unreleased section with the current release note 49 | - name: Patch Changelog 50 | if: ${{ steps.properties.outputs.changelog != '' }} 51 | env: 52 | CHANGELOG: ${{ steps.properties.outputs.changelog }} 53 | run: | 54 | ./gradlew patchChangelog --release-note="$CHANGELOG" 55 | 56 | # Publish the plugin to the Marketplace 57 | - name: Publish Plugin 58 | env: 59 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 60 | CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }} 61 | PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} 62 | PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} 63 | run: ./gradlew publishPlugin 64 | 65 | # Upload artifact as a release asset 66 | - name: Upload Release Asset 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* 70 | 71 | # Create pull request 72 | - name: Create Pull Request 73 | if: ${{ steps.properties.outputs.changelog != '' }} 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GH_PAT_REPO_SCOPE_FOR_ACTIONS_THAT_OPEN_PRS }} 76 | run: | 77 | VERSION="${{ github.event.release.tag_name }}" 78 | BRANCH="changelog-update-$VERSION" 79 | 80 | git config user.email "action@github.com" 81 | git config user.name "GitHub Action" 82 | 83 | git checkout -b $BRANCH 84 | git commit -am "Changelog update - $VERSION" 85 | git push --set-upstream origin $BRANCH 86 | 87 | gh pr create \ 88 | --title "Changelog update - \`$VERSION\`" \ 89 | --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ 90 | --reviewer ChrisCarini \ 91 | --base main \ 92 | --head $BRANCH 93 | 94 | gh pr merge \ 95 | --auto \ 96 | --squash 97 | -------------------------------------------------------------------------------- /.github/workflows/scorecards-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '30 14 * * 5' 14 | push: 15 | branches: [ "main" ] 16 | 17 | # Declare default permissions as read only. 18 | permissions: read-all 19 | 20 | jobs: 21 | analysis: 22 | name: Scorecard analysis 23 | runs-on: ubuntu-latest 24 | permissions: 25 | # Needed to upload the results to code-scanning dashboard. 26 | security-events: write 27 | # Needed to publish results and get a badge (see publish_results below). 28 | id-token: write 29 | # Uncomment the permissions below if installing in a private repository. 30 | # contents: read 31 | # actions: read 32 | 33 | steps: 34 | - name: "Checkout code" 35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 36 | timeout-minutes: 1 37 | with: 38 | persist-credentials: false 39 | 40 | - name: "Run analysis" 41 | uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 42 | with: 43 | results_file: results.sarif 44 | results_format: sarif 45 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 46 | # - you want to enable the Branch-Protection check on a *public* repository, or 47 | # - you are installing Scorecard on a *private* repository 48 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 49 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 50 | 51 | # Public repositories: 52 | # - Publish results to OpenSSF REST API for easy access by consumers 53 | # - Allows the repository to include the Scorecard badge. 54 | # - See https://github.com/ossf/scorecard-action#publishing-results. 55 | # For private repositories: 56 | # - `publish_results` will always be set to `false`, regardless 57 | # of the value entered here. 58 | publish_results: true 59 | 60 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 61 | # format to the repository Actions tab. 62 | - name: "Upload artifact" 63 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 64 | with: 65 | name: SARIF file 66 | path: results.sarif 67 | retention-days: 5 68 | 69 | # Upload the results to GitHub's code scanning dashboard. 70 | - name: "Upload to code-scanning" 71 | uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 72 | with: 73 | sarif_file: results.sarif 74 | -------------------------------------------------------------------------------- /.github/workflows/update-gradle-wrapper.yml: -------------------------------------------------------------------------------- 1 | name: Update Gradle Wrapper 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | workflow_dispatch: 8 | 9 | 10 | jobs: 11 | update-gradle-wrapper: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | timeout-minutes: 1 17 | 18 | - name: Setup Java 19 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 20 | timeout-minutes: 5 21 | with: 22 | distribution: zulu 23 | java-version: 21 24 | cache: gradle 25 | 26 | - name: Update Gradle Wrapper 27 | uses: gradle-update/update-gradle-wrapper-action@512b1875f3b6270828abfe77b247d5895a2da1e5 # v2.1.0 28 | with: 29 | repo-token: ${{ secrets.GH_PAT_REPO_SCOPE_FOR_ACTIONS_THAT_OPEN_PRS }} 30 | merge-method: SQUASH 31 | # NOTE: Can not set reviewer to self (`ChrisCarini`) because using PAT for self. 32 | # From Docs: 33 | # Note that if you're using a Personal Access Token (PAT) as repo-token you cannot 34 | # request a review from the user that the PAT belongs to. 35 | # Ref: https://github.com/gradle-update/update-gradle-wrapper-action#reviewers 36 | # reviewers: | 37 | # ChrisCarini -------------------------------------------------------------------------------- /.github/workflows/update-plugin-platform-version.yml: -------------------------------------------------------------------------------- 1 | name: 'Update JetBrains Plugin Platform Version' 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | update-jetbrains-plugin-platform-version: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 14 | timeout-minutes: 1 15 | with: 16 | token: ${{ secrets.PAT_TOKEN_FOR_IJ_UPDATE_ACTION }} 17 | 18 | - uses: ChrisCarini/gh-test-ij-release-update-action@main 19 | with: 20 | PAT_TOKEN_FOR_IJ_UPDATE_ACTION: ${{ secrets.PAT_TOKEN_FOR_IJ_UPDATE_ACTION }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.ipr 3 | *.iws 4 | .gradle/ 5 | .qodana/ 6 | .shelf/ 7 | build/ 8 | gradle/ 9 | out/ 10 | gradlew* 11 | jetbrainsCredentials.gradle 12 | private.pem 13 | chain.crt 14 | *.DS_Store 15 | .idea/ 16 | .installedPlugins/ 17 | .intellijPlatform/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # IntelliJ Platform Plugin Template Changelog 4 | 5 | ## [Unreleased] 6 | 7 | ### Added 8 | 9 | ### Changed 10 | - Upgrading IntelliJ from 2025.1 to 2025.1.1 11 | - Migrate from `StartupActivity` (obsolete) -> `VcsRepositoryMappingListener` 12 | 13 | ### Deprecated 14 | 15 | ### Removed 16 | 17 | ### Fixed 18 | 19 | ### Security 20 | 21 | ## [3.0.0] - 2025-04-17 22 | 23 | ### Changed 24 | 25 | - Upgrading IntelliJ from 2024.3.5 to 2025.1 26 | 27 | ## [2.2.8] - 2025-03-19 28 | 29 | ### Changed 30 | 31 | - Upgrading IntelliJ from 2024.3.4 to 2024.3.5 32 | 33 | ## [2.2.7] - 2025-03-01 34 | 35 | ### Changed 36 | 37 | - Upgrading IntelliJ from 2024.3.3 to 2024.3.4 38 | 39 | ## [2.2.6] - 2025-02-21 40 | 41 | ### Changed 42 | 43 | - Upgrading IntelliJ from 2024.3.2.2 to 2024.3.3 44 | 45 | ## [2.2.5] - 2025-01-30 46 | 47 | ### Changed 48 | 49 | - Upgrading IntelliJ from 2024.3.2.1 to 2024.3.2.2 50 | 51 | ## [2.2.4] - 2025-01-25 52 | 53 | ### Changed 54 | 55 | - Upgrading IntelliJ from 2024.3.2 to 2024.3.2.1 56 | 57 | ## [2.2.3] - 2025-01-19 58 | 59 | ### Changed 60 | 61 | - Upgrading IntelliJ from 2024.3.1.1 to 2024.3.2 62 | 63 | ## [2.2.2] - 2025-01-02 64 | 65 | ### Changed 66 | 67 | - Upgrading IntelliJ from 2024.3.1 to 2024.3.1.1 68 | 69 | ## [2.2.1] - 2024-12-10 70 | 71 | ### Changed 72 | 73 | - Upgrading IntelliJ from 2024.3 to 2024.3.1 74 | 75 | ## [2.2.0] - 2024-11-14 76 | 77 | ### Changed 78 | 79 | - Upgrading IntelliJ from 2024.2.4 to 2024.3.0 80 | 81 | ## [2.1.4] - 2024-10-24 82 | 83 | ### Changed 84 | 85 | - Upgrading IntelliJ from 2024.2.3 to 2024.2.4 86 | 87 | ## [2.1.3] - 2024-09-26 88 | 89 | ### Changed 90 | 91 | - Upgrading IntelliJ from 2024.2.2 to 2024.2.3 92 | 93 | ## [2.1.2] - 2024-09-22 94 | 95 | ### Changed 96 | 97 | - Upgrading IntelliJ from 2024.2.1 to 2024.2.2 98 | 99 | ## [2.1.1] - 2024-08-31 100 | 101 | ### Changed 102 | 103 | - Upgrading IntelliJ from 2024.2 to 2024.2.1 104 | 105 | ## [2.1.0] - 2024-08-20 106 | 107 | ### Changed 108 | 109 | - Upgrading IntelliJ from 2024.1.5 to 2024.2.0 110 | - Changed gradle build to Kotlin DSL (from Groovy DSL) in preparation of `IntelliJ Platform Gradle Plugin 2.0.0`. 111 | 112 | ## [2.0.5] - 2024-08-07 113 | 114 | ### Changed 115 | 116 | - Upgrading IntelliJ from 2024.1.4 to 2024.1.5 117 | 118 | ## [2.0.4] - 2024-06-22 119 | 120 | ### Changed 121 | 122 | - Upgrading IntelliJ from 2024.1.3 to 2024.1.4 123 | 124 | ## [2.0.3] - 2024-06-13 125 | 126 | ### Changed 127 | 128 | - Upgrading IntelliJ from 2024.1.2 to 2024.1.3 129 | 130 | ## [2.0.2] - 2024-05-31 131 | 132 | ### Changed 133 | 134 | - Upgrading IntelliJ from 2024.1.1 to 2024.1.2 135 | 136 | ## [2.0.1] - 2024-04-30 137 | 138 | ### Changed 139 | 140 | - Upgrading IntelliJ from 2024.1 to 2024.1.1 141 | 142 | ## [2.0.0] - 2024-04-05 143 | 144 | ### Changed 145 | 146 | - Upgrading IntelliJ from 2023.3.6 to 2024.1.0 147 | 148 | ## [1.2.7] - 2024-03-22 149 | 150 | ### Changed 151 | 152 | - Upgrading IntelliJ from 2023.3.5 to 2023.3.6 153 | 154 | ## [1.2.6] - 2024-03-13 155 | 156 | ### Changed 157 | 158 | - Upgrading IntelliJ from 2023.3.4 to 2023.3.5 159 | 160 | ## [1.2.5] - 2024-02-14 161 | 162 | ### Changed 163 | 164 | - Upgrading IntelliJ from 2023.3.3 to 2023.3.4 165 | 166 | ## [1.2.4] - 2024-01-30 167 | 168 | ### Changed 169 | 170 | - Upgrading IntelliJ from 2023.3.2 to 2023.3.3 171 | 172 | ## [1.2.3] - 2023-12-21 173 | 174 | ### Changed 175 | 176 | - Upgrading IntelliJ from 2023.3.1 to 2023.3.2 177 | 178 | ## [1.2.2] - 2023-12-21 179 | 180 | ### Fixed 181 | 182 | - [#208](https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/issues/208) - Fixing issue where the plugin would throw `StringIndexOutOfBoundsException` in certain conditions 183 | 184 | ## [1.2.1] - 2023-12-14 185 | 186 | ### Changed 187 | 188 | - Upgrading IntelliJ from 2023.3 to 2023.3.1 189 | 190 | ## [1.2.0] - 2023-12-08 191 | 192 | ### Changed 193 | 194 | - Upgrading IntelliJ from 2023.2.5 to 2023.3.0 195 | 196 | ## [1.1.5] - 2023-11-10 197 | 198 | ### Changed 199 | 200 | - Upgrading IntelliJ from 2023.2.4 to 2023.2.5 201 | 202 | ## [1.1.4] - 2023-10-28 203 | 204 | ### Changed 205 | 206 | - Upgrading IntelliJ from 2023.2.3 to 2023.2.4 207 | 208 | ## [1.1.3] - 2023-10-12 209 | 210 | ### Changed 211 | 212 | - Upgrading IntelliJ from 2023.2.2 to 2023.2.3 213 | 214 | ## [1.1.2] - 2023-09-21 215 | 216 | ### Changed 217 | 218 | - Upgrading IntelliJ from 2023.2.1 to 2023.2.2 219 | 220 | ## [1.1.1] - 2023-09-06 221 | 222 | ### Changed 223 | 224 | - Upgrading IntelliJ from 2023.2 to 2023.2.1 225 | 226 | ## [1.1.0] - 2023-07-27 227 | 228 | ### Changed 229 | 230 | - Upgrading IntelliJ from 2023.1.5 to 2023.2.0 231 | 232 | ## [1.0.5] - 2023-07-26 233 | 234 | ### Changed 235 | 236 | - Upgrading IntelliJ from 2023.1.4 to 2023.1.5 237 | 238 | ## [1.0.4] - 2023-07-14 239 | 240 | ### Changed 241 | 242 | - Upgrading IntelliJ from 2023.1.3 to 2023.1.4 243 | 244 | ## [1.0.3] - 2023-06-22 245 | 246 | ### Changed 247 | 248 | - Upgrading IntelliJ from 2023.1.2 to 2023.1.3 249 | 250 | ## [1.0.2] - 2023-05-17 251 | 252 | ### Changed 253 | 254 | - Upgrading IntelliJ from 2023.1.1 to 2023.1.2 255 | 256 | ## [1.0.1] - 2023-04-29 257 | 258 | ### Changed 259 | 260 | - Upgrading IntelliJ from 2023.1 to 2023.1.1 261 | 262 | ## [1.0.0] - 2023-03-29 263 | 264 | ### Changed 265 | 266 | - Upgrading IntelliJ from 2022.3.3 to 2023.1.0 267 | 268 | ## [0.1.3] - 2023-03-13 269 | 270 | ### Changed 271 | 272 | - Upgrading IntelliJ from 2022.3.2 to 2022.3.3 273 | 274 | ## [0.1.2] - 2023-02-04 275 | 276 | ### Changed 277 | 278 | - Upgrading IntelliJ from 2022.3.1 to 2022.3.2 279 | 280 | ## [0.1.1] - 2022-12-28 281 | 282 | ### Changed 283 | 284 | - Upgrading IntelliJ from 2022.3 to 2022.3.1 285 | 286 | ## [0.1.0] - 2022-12-28 287 | 288 | ### Changed 289 | 290 | - Upgrading IntelliJ from 2022.2.4 to 2022.3.0 291 | 292 | ## [0.0.3] - 2022-11-28 293 | 294 | ### Changed 295 | 296 | - Upgrading IntelliJ from 2022.2 to 2022.2.4 297 | 298 | ## [0.0.2] - 2022-07-29 299 | 300 | ### Changed 301 | 302 | - Upgrading IntelliJ to 2022.2 303 | 304 | ## [0.0.1] - 2022-07-16 305 | 306 | ### Added 307 | 308 | - Initial release. 309 | 310 | [Unreleased]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v3.0.0...HEAD 311 | [3.0.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.8...v3.0.0 312 | [2.2.8]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.7...v2.2.8 313 | [2.2.7]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.6...v2.2.7 314 | [2.2.6]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.5...v2.2.6 315 | [2.2.5]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.4...v2.2.5 316 | [2.2.4]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.3...v2.2.4 317 | [2.2.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.2...v2.2.3 318 | [2.2.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.1...v2.2.2 319 | [2.2.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.2.0...v2.2.1 320 | [2.2.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.1.4...v2.2.0 321 | [2.1.4]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.1.3...v2.1.4 322 | [2.1.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.1.2...v2.1.3 323 | [2.1.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.1.1...v2.1.2 324 | [2.1.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.1.0...v2.1.1 325 | [2.1.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.0.5...v2.1.0 326 | [2.0.5]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.0.4...v2.0.5 327 | [2.0.4]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.0.3...v2.0.4 328 | [2.0.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.0.2...v2.0.3 329 | [2.0.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.0.1...v2.0.2 330 | [2.0.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v2.0.0...v2.0.1 331 | [2.0.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.7...v2.0.0 332 | [1.2.7]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.6...v1.2.7 333 | [1.2.6]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.5...v1.2.6 334 | [1.2.5]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.4...v1.2.5 335 | [1.2.4]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.3...v1.2.4 336 | [1.2.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.2...v1.2.3 337 | [1.2.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.1...v1.2.2 338 | [1.2.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.2.0...v1.2.1 339 | [1.2.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.1.5...v1.2.0 340 | [1.1.5]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.1.4...v1.1.5 341 | [1.1.4]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.1.3...v1.1.4 342 | [1.1.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.1.2...v1.1.3 343 | [1.1.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.1.1...v1.1.2 344 | [1.1.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.1.0...v1.1.1 345 | [1.1.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.0.5...v1.1.0 346 | [1.0.5]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.0.4...v1.0.5 347 | [1.0.4]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.0.3...v1.0.4 348 | [1.0.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.0.2...v1.0.3 349 | [1.0.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.0.1...v1.0.2 350 | [1.0.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v1.0.0...v1.0.1 351 | [1.0.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.1.3...v1.0.0 352 | [0.1.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.1.2...v0.1.3 353 | [0.1.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.1.1...v0.1.2 354 | [0.1.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.1.0...v0.1.1 355 | [0.1.0]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.0.3...v0.1.0 356 | [0.0.3]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.0.2...v0.0.3 357 | [0.0.2]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compare/v0.0.1...v0.0.2 358 | [0.0.1]: https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/commits/v0.0.1 359 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automatic GitHub Issue Navigation Configuration JetBrains Plugin 2 | 3 | [![GitHub License](https://img.shields.io/github/license/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin?style=flat-square)](https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/blob/main/LICENSE) 4 | [![JetBrains IntelliJ Plugins](https://img.shields.io/jetbrains/plugin/v/19543-automatic-github-issue-navigation-configuration?label=Latest%20Plugin%20Release&style=flat-square)](https://plugins.jetbrains.com/plugin/19543-automatic-github-issue-navigation-configuration) 5 | [![JetBrains IntelliJ Plugins](https://img.shields.io/jetbrains/plugin/r/rating/19543-automatic-github-issue-navigation-configuration?style=flat-square)](https://plugins.jetbrains.com/plugin/19543-automatic-github-issue-navigation-configuration) 6 | [![JetBrains IntelliJ Plugins](https://img.shields.io/jetbrains/plugin/d/19543-automatic-github-issue-navigation-configuration?style=flat-square)](https://plugins.jetbrains.com/plugin/19543-automatic-github-issue-navigation-configuration) 7 | [![All Contributors](https://img.shields.io/github/all-contributors/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin?color=ee8449&style=flat-square)](#contributors) 8 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/build.yml?branch=main&logo=GitHub&style=flat-square)](https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/actions/workflows/build.yml) 9 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/compatibility.yml?branch=main&label=IntelliJ%20Plugin%20Compatibility&logo=GitHub&style=flat-square)](https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/actions/workflows/compatibility.yml) 10 | 11 | 12 | A plugin that automatically configures the IDEs Issue Navigation for GitHub projects. 13 | 14 | 15 | 16 | 17 | 18 | Tested in IntelliJ, but _should_ work on other JetBrains IDEs. 19 | 20 | The [officially released versions of this plugin can be found at plugins.jetbrains.com](https://plugins.jetbrains.com/plugin/19543-automatic-github-issue-navigation-configuration/). 21 | 22 | ## Contributors 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
Chris Carini
Chris Carini

🐛 💻 📖 💡 🤔 🚧 💬 👀
Logan Rosen
Logan Rosen

🐛
35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("build-standard-jetbrains-plugin-build") 3 | } 4 | 5 | dependencies { 6 | // TODO(ChrisCarini) - Remove when IJPL-157292 is resolved 7 | // Resources: 8 | // - https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-faq.html#junit5-test-framework-refers-to-junit4 9 | // - https://youtrack.jetbrains.com/issue/IJPL-157292/lib-testFramework.jar-is-missing-library-opentest4j 10 | testImplementation("org.opentest4j:opentest4j:1.3.0") 11 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | maven { 8 | url = uri("https://plugins.gradle.org/m2/") 9 | } 10 | } 11 | 12 | dependencies { 13 | implementation("org.jetbrains.intellij.platform:intellij-platform-gradle-plugin:2.6.0") 14 | implementation("org.jetbrains.intellij.plugins:gradle-changelog-plugin:2.2.1") 15 | implementation("com.dorongold.plugins:task-tree:4.0.1") // provides `taskTree` task (e.g. `./gradlew build taskTree`; docs: https://github.com/dorongold/gradle-task-tree) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/build-standard-jetbrains-plugin-build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.gradle.plugins.ide.idea.model.IdeaLanguageLevel 2 | import org.jetbrains.changelog.Changelog 3 | import org.jetbrains.changelog.markdownToHTML 4 | import org.jetbrains.intellij.platform.gradle.Constants 5 | import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType 6 | import org.jetbrains.intellij.platform.gradle.TestFrameworkType 7 | import org.jetbrains.intellij.platform.gradle.models.ProductRelease 8 | import org.jetbrains.intellij.platform.gradle.tasks.VerifyPluginTask 9 | import java.util.EnumSet 10 | 11 | fun properties(key: String): String = providers.gradleProperty(key).get() 12 | fun environment(key: String): Provider = providers.environmentVariable(key) 13 | fun extra(key: String): String = project.ext.get(key) as String 14 | 15 | val javaVersion = properties("javaVersion") 16 | val platformBundledPlugins = providers.gradleProperty("platformBundledPlugins") 17 | val platformPlugins = providers.gradleProperty("platformPlugins") 18 | val platformType = properties("platformType") 19 | val platformVersion = properties("platformVersion") 20 | val pluginGroup = properties("pluginGroup") 21 | val pluginName = properties("pluginName") 22 | val pluginRepositoryUrl = properties("pluginRepositoryUrl") 23 | val pluginSinceBuild = properties("pluginSinceBuild") 24 | val pluginUntilBuild = properties("pluginUntilBuild") 25 | val pluginVerifierExcludeFailureLevels = properties("pluginVerifierExcludeFailureLevels") 26 | val pluginVerifierIdeVersions = properties("pluginVerifierIdeVersions") 27 | val pluginVerifierMutePluginProblems = properties("pluginVerifierMutePluginProblems") 28 | val pluginVersion = properties("pluginVersion") 29 | val shouldPublishPlugin = properties("publishPlugin").equals("true") 30 | 31 | plugins { 32 | id("java") 33 | id("idea") 34 | id("org.jetbrains.intellij.platform") 35 | id("org.jetbrains.changelog") 36 | id("com.dorongold.task-tree") 37 | } 38 | 39 | group = pluginGroup 40 | version = pluginVersion 41 | 42 | repositories { 43 | mavenCentral() 44 | 45 | // https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-repositories-extension.html 46 | intellijPlatform { 47 | defaultRepositories() 48 | // `jetbrainsRuntime()` is necessary mostly for EAP/SNAPSHOT releases of IJ so that the IDE pulls the correct JBR 49 | // - https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-jetbrains-runtime.html#obtained-with-intellij-platform-from-maven 50 | val isSnapshot = platformVersion.endsWith("-SNAPSHOT") 51 | if (isSnapshot) { 52 | jetbrainsRuntime() 53 | } 54 | } 55 | } 56 | 57 | 58 | dependencies { 59 | // https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html 60 | intellijPlatform { 61 | val isSnapshot = platformVersion.endsWith("-SNAPSHOT") 62 | create( 63 | type = IntelliJPlatformType.fromCode(platformType), 64 | version = platformVersion, 65 | useInstaller = !isSnapshot 66 | ) 67 | 68 | // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file for plugin from JetBrains Marketplace. 69 | plugins(platformPlugins.map { it.split(',') }) 70 | // Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins. 71 | bundledPlugins(platformBundledPlugins.map { it.split(',') }) 72 | 73 | // `jetbrainsRuntime()` is necessary mostly for EAP/SNAPSHOT releases of IJ so that the IDE pulls the correct JBR 74 | // - https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-jetbrains-runtime.html#obtained-with-intellij-platform-from-maven 75 | if (isSnapshot) { 76 | jetbrainsRuntime() 77 | } 78 | pluginVerifier() 79 | zipSigner() 80 | testFramework(TestFrameworkType.Platform) 81 | } 82 | 83 | testImplementation(group = "junit", name = "junit", version = "4.13.2") 84 | testImplementation("org.testng:testng:7.10.2") 85 | testImplementation("org.mockito:mockito-core:5.12.0") 86 | } 87 | 88 | java { 89 | sourceCompatibility = JavaVersion.toVersion(javaVersion) 90 | targetCompatibility = JavaVersion.toVersion(javaVersion) 91 | } 92 | 93 | idea { 94 | project { 95 | // Set default IntelliJ SDK & language level to the version specified in `gradle.properties` 96 | jdkName = javaVersion 97 | languageLevel = IdeaLanguageLevel(javaVersion) 98 | } 99 | } 100 | 101 | val isNotCI = System.getenv("CI") != "true" 102 | if (isNotCI) { 103 | // The below file (jetbrainsCredentials.gradle) should contain the below: 104 | // project.ext.set("intellijSignPluginCertificateChain", new File("./chain.crt").getText("UTF-8")) 105 | // project.ext.set("intellijSignPluginPrivateKey", new File("./private.pem").getText("UTF-8")) 106 | // project.ext.set("intellijSignPluginPassword", "YOUR_PRIV_KEY_PASSWORD_HERE") 107 | // project.ext.set("intellijPluginPublishToken", "YOUR_TOKEN_HERE") 108 | // 109 | // Because this contains credentials, this file is also included in .gitignore file. 110 | apply(from = "jetbrainsCredentials.gradle") 111 | } 112 | fun resolve(extraKey: String, environmentKey: String): String = 113 | if (isNotCI) extra(extraKey) else environment(environmentKey).getOrElse("DEFAULT_INVALID_$environmentKey") 114 | 115 | val signPluginCertificateChain = resolve("intellijSignPluginCertificateChain", "CERTIFICATE_CHAIN") 116 | val signPluginPrivateKey = resolve("intellijSignPluginPrivateKey", "PRIVATE_KEY") 117 | val signPluginPassword = resolve("intellijSignPluginPassword", "PRIVATE_KEY_PASSWORD") 118 | val publishPluginToken = resolve("intellijPluginPublishToken", "PUBLISH_TOKEN") 119 | 120 | // https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html 121 | intellijPlatform { 122 | pluginConfiguration { 123 | name = pluginName 124 | version = pluginVersion 125 | 126 | // Extract the section from README.md and provide for the plugin's manifest 127 | description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { 128 | val start = "" 129 | val end = "" 130 | 131 | with(it.lines()) { 132 | if (!containsAll(listOf(start, end))) { 133 | throw GradleException("Plugin description section not found in README.md:\n$start ... $end") 134 | } 135 | subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) 136 | } 137 | } 138 | 139 | val changelog = project.changelog // local variable for configuration cache compatibility 140 | // Get the latest available change notes from the changelog file 141 | changeNotes = providers.provider { pluginVersion }.map { pluginVersion -> 142 | with(changelog) { 143 | renderItem( 144 | (getOrNull(pluginVersion) ?: getUnreleased()).withHeader(false).withEmptySections(false), 145 | Changelog.OutputType.HTML, 146 | ) 147 | } 148 | } 149 | 150 | ideaVersion { 151 | sinceBuild = pluginSinceBuild 152 | untilBuild = pluginUntilBuild 153 | } 154 | 155 | // Vendor information -> https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html#intellijPlatform-pluginConfiguration-vendor 156 | vendor { 157 | name = "Chris Carini" 158 | email = "jetbrains@chriscarini.com" 159 | url = "https://jetbrains.chriscarini.com" 160 | } 161 | } 162 | 163 | signing { 164 | certificateChain = signPluginCertificateChain 165 | privateKey = signPluginPrivateKey 166 | password = signPluginPassword 167 | } 168 | 169 | publishing { 170 | token = publishPluginToken 171 | 172 | // pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 173 | // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: 174 | // https://plugins.jetbrains.com/docs/intellij/publishing-plugin.html#specifying-a-release-channel 175 | channels = providers.provider { pluginVersion }.map { 176 | listOf(it.substringAfter('-', "").substringBefore('.').lowercase().ifEmpty { "default" }) 177 | } 178 | } 179 | 180 | pluginVerification { 181 | val pluginVerifierMutePluginProblems = pluginVerifierMutePluginProblems 182 | if (pluginVerifierMutePluginProblems.isNotEmpty()) { 183 | logger.lifecycle("Muting the following Plugin Verifier Problems: $pluginVerifierMutePluginProblems") 184 | freeArgs = listOf("-mute", pluginVerifierMutePluginProblems) 185 | } 186 | 187 | fun getFailureLevels(): EnumSet { 188 | val includeFailureLevels = EnumSet.allOf(VerifyPluginTask.FailureLevel::class.java) 189 | val desiredFailureLevels = 190 | pluginVerifierExcludeFailureLevels.split(",").map(String::trim) 191 | .filter(String::isNotEmpty) // Remove empty strings; this happens when user sets nothing (ie, `pluginVerifierExcludeFailureLevels =`) 192 | 193 | desiredFailureLevels.forEach { failureLevel -> 194 | when (failureLevel) { 195 | "ALL" -> return EnumSet.allOf(VerifyPluginTask.FailureLevel::class.java) 196 | "NONE" -> return EnumSet.noneOf(VerifyPluginTask.FailureLevel::class.java) 197 | else -> { 198 | try { 199 | val enumFailureLevel = VerifyPluginTask.FailureLevel.valueOf(failureLevel) 200 | includeFailureLevels.remove(enumFailureLevel) 201 | } catch (ignored: Exception) { 202 | val msg = "Failure Level \"$failureLevel\" is *NOT* valid. Please select from: ${ 203 | EnumSet.allOf(VerifyPluginTask.FailureLevel::class.java) 204 | }." 205 | logger.error(msg) 206 | throw Exception(msg) 207 | } 208 | } 209 | } 210 | } 211 | 212 | return includeFailureLevels 213 | } 214 | 215 | val failureLevels = getFailureLevels() 216 | logger.debug("Using ${failureLevels.size} Failure Levels: $failureLevels") 217 | failureLevel.set(failureLevels) 218 | ides { 219 | logger.lifecycle("Verifying against IntelliJ Platform $platformType $platformVersion") 220 | ide(IntelliJPlatformType.fromCode(platformType), platformVersion) 221 | 222 | recommended() 223 | } 224 | } 225 | } 226 | 227 | // Configure CHANGELOG.md - https://github.com/JetBrains/gradle-changelog-plugin 228 | changelog { 229 | repositoryUrl = pluginRepositoryUrl 230 | } 231 | 232 | tasks { 233 | publishPlugin { 234 | dependsOn(patchChangelog) 235 | logger.lifecycle("Should Publish Plugin?: $shouldPublishPlugin") 236 | enabled = shouldPublishPlugin 237 | } 238 | 239 | printProductsReleases { 240 | // // In addition to `IC` (from `platformType`), we also want to verify against `IU`. 241 | // types.set(Arrays.asList(platformType, "IU")) 242 | // Contrary to above, we want to speed up CI, so skip verification of `IU`. 243 | types = listOf(IntelliJPlatformType.fromCode(platformType)) 244 | 245 | // Only get the released versions if we are not targeting an EAP. 246 | val isEAP = pluginVersion.uppercase().endsWith("-EAP") 247 | channels = listOf(if (isEAP) ProductRelease.Channel.EAP else ProductRelease.Channel.RELEASE) 248 | 249 | // Verify against the most recent patch release of the `platformVersion` version 250 | // (ie, if `platformVersion` = 2022.2, and the latest patch release is `2022.2.2`, 251 | // then the `sinceVersion` will be set to `2022.2.2` and *NOT* `2022.2`. 252 | sinceBuild.set(platformVersion) 253 | } 254 | 255 | // Sanity check task to ensure necessary variables are set. 256 | register("checkJetBrainsSecrets") { 257 | doLast { 258 | println("signPluginCertificateChain: ${if (signPluginCertificateChain.isNotEmpty()) "IS" else "is NOT"} set.") 259 | println("signPluginPrivateKey: ${if (signPluginPrivateKey.isNotEmpty()) "IS" else "is NOT"} set.") 260 | println("signPluginPassword: ${if (signPluginPassword.isNotEmpty()) "IS" else "is NOT"} set.") 261 | println("publishPluginToken: ${if (publishPluginToken.isNotEmpty()) "IS" else "is NOT"} set.") 262 | } 263 | } 264 | 265 | // In "IntelliJ Platform Gradle Plugin 2.*", the `listProductsReleases` task no longer exists, but 266 | // instead the `printProductReleases` task does. This task is necessary to take the output of 267 | // `printProductReleases` and write it to a file for use in the `generateIdeVersionsList` task below. 268 | val listProductReleasesTaskName = "listProductsReleases" 269 | register(listProductReleasesTaskName) { 270 | dependsOn(printProductsReleases) 271 | val outputF = layout.buildDirectory.file("listProductsReleases.txt").also { 272 | outputs.file(it) 273 | } 274 | val content = printProductsReleases.flatMap { it.productsReleases }.map { it.joinToString("\n") } 275 | 276 | doLast { 277 | outputF.orNull?.asFile?.writeText(content.get()) 278 | } 279 | } 280 | 281 | // Task to generate the necessary format for `ChrisCarini/intellij-platform-plugin-verifier-action` GitHub Action. 282 | register("generateIdeVersionsList") { 283 | dependsOn(project.tasks.named(listProductReleasesTaskName)) 284 | doLast { 285 | val ideVersionsList = mutableListOf() 286 | 287 | // Include the versions produced from the `listProductsReleases` task. 288 | project.tasks.named(listProductReleasesTaskName).get().outputs.files.singleFile.forEachLine { line -> 289 | ideVersionsList.add("idea" + line.replace("-", ":")) 290 | } 291 | 292 | // Include the versions specified in `gradle.properties` `pluginVerifierIdeVersions` property. 293 | pluginVerifierIdeVersions.split(",").map { it.trim() }.forEach { version -> 294 | listOf("IC", "IU").forEach { type -> 295 | ideVersionsList.add("idea$type:$version") 296 | } 297 | } 298 | 299 | // Write out file with unique pairs of type + version 300 | val outFileWriter = File( 301 | layout.buildDirectory.get().toString(), "intellij-platform-plugin-verifier-action-ide-versions-file.txt" 302 | ).printWriter() 303 | ideVersionsList.distinct().forEach { version -> 304 | outFileWriter.println(version) 305 | } 306 | outFileWriter.close() 307 | } 308 | } 309 | 310 | withType { 311 | options.compilerArgs.addAll( 312 | listOf( 313 | "-Xlint:all", 314 | "-Xlint:-options", 315 | "-Xlint:-rawtypes", 316 | "-Xlint:-processing", 317 | "-Xlint:-path", // Ignore JBR SDK manifest element warnings 318 | "-proc:none", 319 | "-Werror", 320 | "-Xlint:-classfile" 321 | ) 322 | ) 323 | } 324 | } 325 | 326 | val runIdeForUiTests by intellijPlatformTesting.runIde.registering { 327 | task { 328 | jvmArgumentProviders += CommandLineArgumentProvider { 329 | listOf( 330 | "-Drobot-server.port=8082", 331 | "-Dide.mac.message.dialogs.as.sheets=false", 332 | "-Djb.privacy.policy.text=", 333 | "-Djb.consents.confirmation.enabled=false", 334 | ) 335 | } 336 | } 337 | 338 | plugins { 339 | robotServerPlugin(Constants.Constraints.LATEST_VERSION) 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/e85a5c6d58dcfb269354cb3509febfc4cca08f48/demo.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | pluginGroup = com.chriscarini.jetbrains 2 | pluginName = Automatic GitHub Issue Navigation Configuration 3 | pluginRepositoryUrl = https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin 4 | # Plugin Version in SemVer format -> https://semver.org 5 | # To release a new version of the plugin against an EAP build of IntelliJ, 6 | # the pluginVersion should be suffixed with '-EAP'. This will release the 7 | # plugin to the below JetBrains-hosted plugin repository: 8 | # - https://plugins.jetbrains.com/plugins/eap/list 9 | # Note: You will need to configure the above URL as a custom plugin repository; 10 | # see directions: https://www.jetbrains.com/help/idea/managing-plugins.html#repos 11 | pluginVersion = 3.0.0 12 | 13 | ## See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html 14 | ## for insight into build numbers and IntelliJ Platform versions. 15 | pluginSinceBuild = 251 16 | pluginUntilBuild = 251.* 17 | 18 | # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl 19 | # See https://jb.gg/intellij-platform-builds-list for available build versions 20 | pluginVerifierIdeVersions = 2025.1.1,LATEST-EAP-SNAPSHOT 21 | # Failure Levels: https://github.com/JetBrains/gradle-intellij-plugin/blob/master/src/main/kotlin/org/jetbrains/intellij/tasks/RunPluginVerifierTask.kt 22 | pluginVerifierExcludeFailureLevels = 23 | # Mute Plugin Problems -> https://github.com/JetBrains/intellij-plugin-verifier?tab=readme-ov-file#check-plugin 24 | # Used to mute (ignore) a comma-seperated list of plugin problems. 25 | pluginVerifierMutePluginProblems = 26 | 27 | 28 | # IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties 29 | platformType = IC 30 | # see https://www.jetbrains.com/intellij-repository/releases/ 31 | # and https://www.jetbrains.com/intellij-repository/snapshots/ 32 | # To use/download EAP add '-EAP-SNAPSHOT' to the version, i.e. 'IU-191.6014.8-EAP-SNAPSHOT' 33 | # platformVersion = '201.6668.60-EAP-SNAPSHOT' 34 | #platformVersion = 2024.1.4 ## 2024.1.4 35 | #platformVersion = 242.20224.91-EAP-SNAPSHOT ## 2024.2 Beta 36 | #platformVersion = 242.20224.159-EAP-SNAPSHOT ## 2024.2 RC1 37 | platformVersion = 2025.1.1 38 | 39 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html 40 | # Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP 41 | platformPlugins = 42 | # Example: platformBundledPlugins = com.intellij.java 43 | platformBundledPlugins = Git4Idea 44 | 45 | # Java language level used to compile sources and to generate the files for 46 | # - Java 11 is required since 2020.3 47 | # - Java 17 is required since 2022.2 48 | # - Java 21 is required since 2024.2 49 | # See https://jb.gg/intellij-platform-versions for details. 50 | javaVersion = 21 51 | 52 | # Publish the plugin to the JetBrains Plugin Repository 53 | publishPlugin = true 54 | 55 | ## 56 | # ----- NON JETBRAINS PLUGIN SETTINGS ----- 57 | ## 58 | # Use the secondary JetBrains JDK (i.e. 2019.2: 'true' for Java 8, 'false' for java 11) 59 | systemProp.idea.jdk.secondary=true 60 | org.gradle.jvmargs=-Xmx2g 61 | # A long-running Gradle process to speed up local builds. 62 | # To stop the daemon run 'gradlew --stop' 63 | org.gradle.daemon=true 64 | # Lazy configuration of projects speeds up the evaluation of large projects. This is especially 65 | # useful when invoking a specific project task (e.g. gradlew :automatic-github-issue-navigation-configuration-jetbrains-plugin:build) 66 | org.gradle.configureondemand=true 67 | # Run subproject tasks in parallel. Results in higher CPU usage, but faster builds 68 | org.gradle.parallel=true 69 | # Allows generation of idea/eclipse metadata for a specific subproject and its upstream project dependencies 70 | ide.recursive=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin/e85a5c6d58dcfb269354cb3509febfc4cca08f48/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /qodana.yml: -------------------------------------------------------------------------------- 1 | # Qodana configuration: 2 | # https://www.jetbrains.com/help/qodana/qodana-yaml.html 3 | 4 | version: 1.0 5 | profile: 6 | name: qodana.recommended 7 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "automatic-github-issue-navigation-configuration-jetbrains-plugin" 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/chriscarini/jetbrains/github/issue/navigation/GitHubIssueNavigationVcsRepositoryMappingListener.java: -------------------------------------------------------------------------------- 1 | package com.chriscarini.jetbrains.github.issue.navigation; 2 | 3 | import com.chriscarini.jetbrains.github.utils.GitHubUri; 4 | import com.chriscarini.jetbrains.github.utils.GitHubUtils; 5 | import com.intellij.dvcs.repo.VcsRepositoryManager; 6 | import com.intellij.dvcs.repo.VcsRepositoryMappingListener; 7 | import com.intellij.openapi.application.ApplicationManager; 8 | import com.intellij.openapi.diagnostic.Logger; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.vcs.IssueNavigationConfiguration; 11 | import com.intellij.openapi.vcs.IssueNavigationLink; 12 | import git4idea.repo.GitRemote; 13 | import git4idea.repo.GitRepositoryImpl; 14 | import org.jetbrains.annotations.NonNls; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.Collection; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | import java.util.stream.Stream; 21 | 22 | 23 | public class GitHubIssueNavigationVcsRepositoryMappingListener implements VcsRepositoryMappingListener { 24 | 25 | private static final @NonNls Logger LOG = Logger.getInstance(GitHubIssueNavigationVcsRepositoryMappingListener.class); 26 | private final @NotNull Project project; 27 | 28 | public GitHubIssueNavigationVcsRepositoryMappingListener(@NotNull final Project project) { 29 | this.project = project; 30 | } 31 | 32 | @Override 33 | public void mappingChanged() { 34 | if (ApplicationManager.getApplication().isUnitTestMode()) { 35 | LOG.debug("Unit test mode; will not attempt to add GitHub Issue Navigation to project"); 36 | return; 37 | } 38 | 39 | VcsRepositoryManager.getInstance(project).getRepositories().forEach(repository -> { 40 | final Collection repoRemotes = ((GitRepositoryImpl) repository).getRemotes(); 41 | repoRemotes.forEach( 42 | gitRemote -> { 43 | final String url = gitRemote.getFirstUrl(); 44 | 45 | if (url == null) { 46 | LOG.debug(String.format("Null Git remote URL: %s", gitRemote)); 47 | return; 48 | } 49 | 50 | if (!GitHubUtils.isKnownGitHubDomain(url)) { 51 | LOG.debug(String.format( 52 | "Git remote URL (%s) not from a known GitHub domain: %s", 53 | gitRemote, 54 | GitHubUtils.knownGitHubDomains().collect(Collectors.joining(", ")) 55 | )); 56 | return; 57 | } 58 | 59 | final String cleanedUrl = GitHubUri.parseUrl(url).asHttpsFormatUrl(); 60 | 61 | if (existsInIssueNavConfig(project, cleanedUrl)) { 62 | LOG.debug(String.format("%s is already registered.", cleanedUrl)); 63 | return; 64 | } 65 | 66 | LOG.debug(String.format("Registering [%s].", cleanedUrl)); 67 | addNewIssueNavigationConfiguration(project, cleanedUrl); 68 | } 69 | ); 70 | }); 71 | } 72 | 73 | protected static boolean existsInIssueNavConfig(@NotNull final Project project, @NotNull final String url) { 74 | final List matching = IssueNavigationConfiguration.getInstance(project).getLinks() 75 | .stream() 76 | .filter(issueNavigationLink -> issueNavigationLink.getLinkRegexp().contains(url)) 77 | .toList(); 78 | 79 | return !matching.isEmpty(); 80 | } 81 | 82 | protected static void addNewIssueNavigationConfiguration(@NotNull final Project project, @NotNull final String url) { 83 | final IssueNavigationConfiguration issueNavigationConfiguration = IssueNavigationConfiguration.getInstance(project); 84 | 85 | final IssueNavigationLink newLink = new IssueNavigationLink("\\(#(\\d+)\\)", String.format("%s/issues/$1", url)); 86 | 87 | issueNavigationConfiguration.setLinks( 88 | Stream.concat( 89 | issueNavigationConfiguration.getLinks().stream(), 90 | Stream.of(newLink) 91 | ).collect(Collectors.toList())); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/chriscarini/jetbrains/github/utils/GitHubUri.java: -------------------------------------------------------------------------------- 1 | package com.chriscarini.jetbrains.github.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class GitHubUri { 6 | private final String host; 7 | private final String owner; 8 | private final String repo; 9 | 10 | protected GitHubUri(@NotNull final String host, @NotNull final String owner, @NotNull final String repo) { 11 | this.host = host; 12 | this.owner = owner; 13 | this.repo = repo; 14 | } 15 | 16 | public static GitHubUri parseUrl(@NotNull final String url) { 17 | if (url.startsWith("https://")) { 18 | return parseHttps(url); 19 | } 20 | return parseSsh(url); 21 | } 22 | 23 | protected static GitHubUri parseHttps(@NotNull final String url) { 24 | int beginDomain = url.indexOf("://"); 25 | int beginOrg = url.indexOf("/", beginDomain + 3); 26 | int beginRepo = url.indexOf("/", beginOrg + 1); 27 | int dotGitLoc = url.endsWith(".git") ? url.lastIndexOf(".git") : url.length(); 28 | 29 | final String host = url.substring(beginDomain + 3, beginOrg); 30 | final String owner = url.substring(beginOrg + 1, beginRepo); 31 | final String repo = url.substring(beginRepo + 1, dotGitLoc); 32 | return new GitHubUri(host, owner, repo); 33 | } 34 | 35 | protected static GitHubUri parseSsh(@NotNull final String url) { 36 | int beginDomain = url.indexOf("@"); 37 | int beginOrg = url.indexOf(":", beginDomain + 1); 38 | if (beginOrg == -1) { 39 | beginOrg = url.indexOf("/", beginDomain + 1); 40 | } 41 | int beginRepo = url.indexOf("/", beginOrg + 1); 42 | int dotGitLoc = url.endsWith(".git") ? url.lastIndexOf(".git") : url.length(); 43 | 44 | final String host = url.substring(beginDomain + 1, beginOrg); 45 | final String owner = url.substring(beginOrg + 1, beginRepo); 46 | final String repo = url.substring(beginRepo + 1, dotGitLoc); 47 | return new GitHubUri(host, owner, repo); 48 | } 49 | 50 | public String getHost() { 51 | return host; 52 | } 53 | 54 | public String getOwner() { 55 | return owner; 56 | } 57 | 58 | public String getRepo() { 59 | return repo; 60 | } 61 | 62 | @NotNull 63 | public String asHttpsFormatUrl() { 64 | return String.format("https://%s/%s/%s", this.getHost(), this.getOwner(), this.getRepo()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/chriscarini/jetbrains/github/utils/GitHubUtils.java: -------------------------------------------------------------------------------- 1 | package com.chriscarini.jetbrains.github.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | 9 | public class GitHubUtils { 10 | 11 | public static Stream knownGitHubDomains() { 12 | return Stream.of( 13 | "github.com", 14 | "ghe.com", 15 | "githubprivate.com" 16 | ); 17 | } 18 | 19 | public static boolean isKnownGitHubDomain(@NotNull final String url) { 20 | final List result = knownGitHubDomains() 21 | .filter(url::contains) 22 | .toList(); 23 | 24 | return !result.isEmpty(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.chriscarini.jetbrains.automatic-github-issue-navigation-configuration-jetbrains-plugin 3 | Automatic GitHub Issue Navigation Configuration 4 | Chris Carini 5 | 6 | 9 | 10 | 12 | com.intellij.modules.platform 13 | Git4Idea 14 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/java/com/chriscarini/jetbrains/github/issue/navigation/TestGitHubIssueNavigationVcsRepositoryMappingListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.chriscarini.jetbrains.github.issue.navigation; 2 | 3 | 4 | import com.intellij.openapi.vcs.IssueNavigationConfiguration; 5 | import com.intellij.openapi.vcs.IssueNavigationLink; 6 | import com.intellij.testFramework.LightPlatformTestCase; 7 | import org.junit.Test; 8 | 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | 13 | public class TestGitHubIssueNavigationVcsRepositoryMappingListenerTest extends LightPlatformTestCase { 14 | @Override 15 | public void setUp() throws Exception { 16 | super.setUp(); 17 | } 18 | 19 | @Test 20 | public void testExistsInIssueNavConfig() { 21 | // given 22 | final String expectedUrl = "MY_FAKE_URL"; 23 | final String unexpectedUrl = "MY_UNEXPECTED_FAKE_URL"; 24 | final IssueNavigationLink myIssueNavigationLink = new IssueNavigationLink("FAKE_REGEX", expectedUrl); 25 | 26 | IssueNavigationConfiguration.getInstance(getProject()).setLinks(List.of(myIssueNavigationLink)); 27 | 28 | // expect 29 | assert GitHubIssueNavigationVcsRepositoryMappingListener.existsInIssueNavConfig(getProject(), expectedUrl); 30 | assert !GitHubIssueNavigationVcsRepositoryMappingListener.existsInIssueNavConfig(getProject(), unexpectedUrl); 31 | } 32 | 33 | @Test 34 | public void testAddNewIssueNavigationConfiguration() { 35 | // given 36 | final String expectedUrl = "MY_FAKE_URL"; 37 | assert IssueNavigationConfiguration.getInstance(getProject()).getLinks().isEmpty(); 38 | 39 | // when 40 | GitHubIssueNavigationVcsRepositoryMappingListener.addNewIssueNavigationConfiguration(getProject(), expectedUrl); 41 | 42 | // then 43 | final List issues = IssueNavigationConfiguration.getInstance(getProject()) 44 | .getLinks() 45 | .stream() 46 | .filter(issueNavigationLink -> issueNavigationLink.getLinkRegexp().contains(expectedUrl)) 47 | .toList(); 48 | assertEquals(1, issues.size()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/chriscarini/jetbrains/github/utils/GitHubUriTest.java: -------------------------------------------------------------------------------- 1 | package com.chriscarini.jetbrains.github.utils; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertNotNull; 7 | 8 | public class GitHubUriTest { 9 | 10 | @Test 11 | public void testParseUrl() { 12 | // given - ssh 13 | final String url1 = "git@github.com:ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin.git"; 14 | 15 | // when 16 | final GitHubUri uri1 = GitHubUri.parseUrl(url1); 17 | 18 | // then 19 | assertEquals(uri1.getHost(), "github.com"); 20 | assertEquals(uri1.getOwner(), "ChrisCarini"); 21 | assertEquals(uri1.getRepo(), "automatic-github-issue-navigation-configuration-jetbrains-plugin"); 22 | 23 | // given - `*.githubprivate.com` domain 24 | final String url2 = "git@company.githubprivate.com:company/repo.git"; 25 | 26 | // when 27 | final GitHubUri uri2 = GitHubUri.parseUrl(url2); 28 | 29 | // then 30 | assertEquals(uri2.getHost(), "company.githubprivate.com"); 31 | assertEquals(uri2.getOwner(), "company"); 32 | assertEquals(uri2.getRepo(), "repo"); 33 | 34 | // given - `*.ghe.com` domain 35 | final String url3 = "git@company.ghe.com:company/repo.git"; 36 | 37 | // when 38 | final GitHubUri uri3 = GitHubUri.parseUrl(url3); 39 | 40 | // then 41 | assertEquals(uri3.getHost(), "company.ghe.com"); 42 | assertEquals(uri3.getOwner(), "company"); 43 | assertEquals(uri3.getRepo(), "repo"); 44 | 45 | // given - with org (non-`git` username) 46 | final String url4 = "ssh://org-123@company.ghe.com/company/repo.git"; 47 | 48 | // when 49 | final GitHubUri uri4 = GitHubUri.parseUrl(url4); 50 | 51 | // then 52 | assertEquals(uri4.getHost(), "company.ghe.com"); 53 | assertEquals(uri4.getOwner(), "company"); 54 | assertEquals(uri4.getRepo(), "repo"); 55 | 56 | // given - with `.git` suffix 57 | final String url5 = "https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin.git"; 58 | 59 | // when 60 | final GitHubUri uri5 = GitHubUri.parseUrl(url5); 61 | 62 | // then 63 | assertEquals(uri5.getHost(), "github.com"); 64 | assertEquals(uri5.getOwner(), "ChrisCarini"); 65 | assertEquals(uri5.getRepo(), "automatic-github-issue-navigation-configuration-jetbrains-plugin"); 66 | 67 | // given - without `.git` suffix 68 | final String url6 = "https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin"; 69 | 70 | // when 71 | final GitHubUri uri6 = GitHubUri.parseUrl(url6); 72 | 73 | // then 74 | assertEquals(uri6.getHost(), "github.com"); 75 | assertEquals(uri6.getOwner(), "ChrisCarini"); 76 | assertEquals(uri6.getRepo(), "automatic-github-issue-navigation-configuration-jetbrains-plugin"); 77 | 78 | // given - with org (non-`git` username) 79 | final String url7 = "ssh://org-123@github.com/org/repo.git"; 80 | 81 | // when 82 | final GitHubUri uri7 = GitHubUri.parseUrl(url7); 83 | 84 | // then 85 | assertEquals(uri7.getHost(), "github.com"); 86 | assertEquals(uri7.getOwner(), "org"); 87 | assertEquals(uri7.getRepo(), "repo"); 88 | } 89 | 90 | @Test 91 | public void testParseHttps() { 92 | // given 93 | for (String uri : new String[]{ 94 | "https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin.git", 95 | "https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin", 96 | "https://company.githubprivate.com/company/repo", 97 | "https://company.ghe.com/company/repo", 98 | "https://github.com/company/repo", 99 | }) { 100 | // when 101 | final GitHubUri result = GitHubUri.parseHttps(uri); 102 | 103 | // then 104 | assertNotNull(result); 105 | assertNotNull(result.getHost()); 106 | assertNotNull(result.getOwner()); 107 | assertNotNull(result.getRepo()); 108 | } 109 | } 110 | 111 | @Test 112 | public void testParseSsh() { 113 | // given 114 | for (String uri : new String[]{ 115 | "git@github.com:ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin.git", 116 | "git@github.com:ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin", 117 | "git@company.githubprivate.com:company/repo.git", 118 | "git@company.githubprivate.com:company/repo", 119 | "git@company.ghe.com:company/repo.git", 120 | "git@company.ghe.com:company/repo", 121 | "ssh://org-123@github.com/company/repo.git", 122 | "ssh://org-123@github.com/company/repo", 123 | }) { 124 | // when 125 | final GitHubUri result = GitHubUri.parseSsh(uri); 126 | 127 | // then 128 | assertNotNull(result); 129 | assertNotNull(result.getHost()); 130 | assertNotNull(result.getOwner()); 131 | assertNotNull(result.getRepo()); 132 | } 133 | } 134 | 135 | @Test 136 | public void testAsHttpsFormatUrl() { 137 | assertEquals( 138 | "https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin", 139 | new GitHubUri("github.com", "ChrisCarini", "automatic-github-issue-navigation-configuration-jetbrains-plugin").asHttpsFormatUrl() 140 | ); 141 | assertEquals( 142 | "https://company.githubprivate.com/company/repo", 143 | new GitHubUri("company.githubprivate.com", "company", "repo").asHttpsFormatUrl() 144 | ); 145 | assertEquals( 146 | "https://company.ghe.com/company/repo", 147 | new GitHubUri("company.ghe.com", "company", "repo").asHttpsFormatUrl() 148 | ); 149 | assertEquals( 150 | "https://company.ghe.com/company/repo", 151 | new GitHubUri("company.ghe.com", "company", "repo").asHttpsFormatUrl() 152 | ); 153 | } 154 | } -------------------------------------------------------------------------------- /src/test/java/com/chriscarini/jetbrains/github/utils/GitHubUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.chriscarini.jetbrains.github.utils; 2 | 3 | import org.junit.Test; 4 | 5 | public class GitHubUtilsTest { 6 | 7 | @Test 8 | public void testIsKnownGitHubDomain() { 9 | assert GitHubUtils.isKnownGitHubDomain("https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin.git"); 10 | assert GitHubUtils.isKnownGitHubDomain("https://github.com/ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin"); 11 | assert GitHubUtils.isKnownGitHubDomain("git@github.com:ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin.git"); 12 | assert GitHubUtils.isKnownGitHubDomain("git@github.com:ChrisCarini/automatic-github-issue-navigation-configuration-jetbrains-plugin"); 13 | 14 | assert GitHubUtils.isKnownGitHubDomain("https://company.githubprivate.com/company/repo.git"); 15 | assert GitHubUtils.isKnownGitHubDomain("https://company.githubprivate.com/company/repo"); 16 | assert GitHubUtils.isKnownGitHubDomain("git@company.githubprivate.com:company/repo.git"); 17 | assert GitHubUtils.isKnownGitHubDomain("git@company.githubprivate.com:company/repo"); 18 | 19 | assert GitHubUtils.isKnownGitHubDomain("https://company.ghe.com/company/repo.git"); 20 | assert GitHubUtils.isKnownGitHubDomain("https://company.ghe.com/company/repo"); 21 | assert GitHubUtils.isKnownGitHubDomain("git@company.ghe.com:company/repo.git"); 22 | assert GitHubUtils.isKnownGitHubDomain("git@company.ghe.com:company/repo"); 23 | 24 | assert GitHubUtils.isKnownGitHubDomain("https://github.com/company/repo.git"); 25 | assert GitHubUtils.isKnownGitHubDomain("https://github.com/company/repo"); 26 | assert GitHubUtils.isKnownGitHubDomain("ssh://org-123@github.com/company/repo.git"); 27 | assert GitHubUtils.isKnownGitHubDomain("ssh://org-123@github.com/company/repo"); 28 | } 29 | } --------------------------------------------------------------------------------