JetBrains plugin: merge Sourcegraph and Cody (#52706)

Previously, we had two separate JetBrains plugins: Sourcegraph and Cody.
This PR merges the two plugins so that there will only be one plugin:
Sourcegraph.

This PR doesn't delete the Cody plugin yet. We can keep the
cody-jetbrains directory around for a while longer just in case we want
to consult the code side-by-side.

This PR replaces the `cody.config` and `cody.telemetry` packages in
favor of the equivalent packages in the Sourcegraph plugin. This results
in minor UX gaps that we can recover in the future with separate PRs.

## Test plan

- Green CI
- Follow CONTRIBUTING.md and verify that chat + completions work as
expected

<!-- All pull requests REQUIRE a test plan:
https://docs.sourcegraph.com/dev/background-information/testing_principles
-->
This commit is contained in:
Ólafur Páll Geirsson 2023-06-01 12:43:11 +02:00 committed by GitHub
parent 1bfed1eccf
commit fcbf4186da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 195 additions and 2549 deletions

View File

@ -1,25 +0,0 @@
name: Cody JetBrains Tests
on:
pull_request:
paths:
- client/cody-jetbrains/**
jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: client/cody-jetbrains
steps:
- uses: actions/checkout@v3
- name: Gradle Wrapper Validation
uses: gradle/wrapper-validation-action@v1.0.4
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: zulu
java-version: 11
cache: gradle
- run: ./gradlew test
- run: ./gradlew buildPlugin
- run: ./gradlew spotlessCheck

View File

@ -1,40 +0,0 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
*.jar
!gradle-wrapper.jar
# User local IDEA configuration files
.idea/
# IntelliJ project
*.iml
# Build output & caches for IntelliJ plugin development
build/
idea-sandbox/
.gradle/
## File-based project format:
*.iws
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# JavaScript resources
src/main/resources/dist/*
# VSCode langserver artifacts
/bin/

View File

@ -1,15 +0,0 @@
# Cody Changelog
## [1.0.0] - Initial Release
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security

View File

@ -1,3 +0,0 @@
# See https://github.com/sourcegraph/codenotify for documentation.
** @vdavid

View File

@ -1,45 +0,0 @@
# Contributing to Cody JetBrains Extension
Thank you for your interest in contributing to Cody!
The goal of this document is to provide a high-level overview of how you can contribute to the Cody JetBrains Extension.
Please refer to our [main CONTRIBUTING](https://github.com/sourcegraph/sourcegraph/blob/main/CONTRIBUTING.md) docs for general information regarding contributing to any Cody feature.
## License
Apache
## Feedback
Your feedback is important to us and is greatly appreciated. Please do not hesitate to submit your ideas or suggestions about how we can improve the extension to our [JetBrains Plugin Feedback Discussion Thread](https://github.com/sourcegraph/sourcegraph/discussions/51210) on GitHub.
## Issues / Bugs
New issues and feature requests can be filed through our [issue tracker](https://github.com/sourcegraph/sourcegraph/issues/new?labels=team/cody,cody/jetbrains&title=Cody:+) using the `cody/jetbrains` & `team/cody` labels.
## Development
- Clone `https://github.com/sourcegraph/sourcegraph` (on Windows, you'll need to use WSL2)
- Go to `client/cody-jetbrains/` and run the plugin in a sandboxed IDE by running `./gradlew :runIde`. This will start the platform with the versions defined in `gradle.properties`, [here](https://github.com/sourcegraph/sourcegraph/blob/main/client/cody-jetbrains/gradle.properties#L14-L16).
- Build a deployable plugin artifact by running `./gradlew buildPlugin`. The output file is `build/distributions/Cody.zip`.
- Reformat the codebase with `./gradlew spotlessApply`.
- Install the google-java-format plugin
https://plugins.jetbrains.com/plugin/8527-google-java-format and configure
IntelliJ's file save actions to format.
- Ensure `src login` is logged into your sourcegraph.com account. This avoids
the need to manually configure the access token in the UI every time you run
`./gradlew :runIde`.
## Publishing a new version
The publishing process is based on the [intellij-platform-plugin-template](https://github.com/JetBrains/intellij-platform-plugin-template).
### Publishing from your local machine
1. Update `pluginVersion` in `gradle.properties`
- To create pre-release builds with the same version as a previous one, append `.{N}`.
For example, `1.0.0-alpha`, then `1.0.0-alpha.1`, `1.0.0-alpha.2`, and so on.
2. Describe the changes in the `[Unreleased]` section of `client/cody-jetbrains/CHANGELOG.md` then remove any empty headers
3. Make sure `runIde` is not running
4. Commit your changes
5. Run `PUBLISH_TOKEN=<YOUR TOKEN HERE> ./scripts/release.sh` from inside the `client/cody-jetbrains` directory (You can [generate tokens on the JetBrains marketplace](https://plugins.jetbrains.com/author/me/tokens)).
6. Commit changes and create PR

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2000-2016 JetBrains s.r.o.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,53 +0,0 @@
<!-- Plugin description -->
# Cody for JetBrains IDEs
- Chat with Cody in your IDE
- Use pre-built recipes to auto-add unit tests and code docs, explain code, find code smells, and other magic
<!-- Plugin description end -->
## Supported IDEs [![JetBrains Plugin](https://img.shields.io/badge/JetBrains-Sourcegraph-green.svg)](https://plugins.jetbrains.com/plugin/9682-sourcegraph)
The plugin works with all JetBrains IDEs, including:
- IntelliJ IDEA
- IntelliJ IDEA Community Edition
- PhpStorm
- WebStorm
- PyCharm
- PyCharm Community Edition
- RubyMine
- AppCode
- CLion
- GoLand
- DataGrip
- Rider
- Android Studio
## Installation
- Open settings
- Windows: Go to `File | Settings` (or use <kbd>Ctrl+Alt+S</kbd>)
- Mac: Go to `IntelliJ IDEA | Preferences` (or use <kbd>⌘,</kbd>)
- Click `Plugins` in the left-hand pane, then the `Marketplace` tab at the top
- Search for `Cody`, then click the `Install` button
- Restart your IDE if needed
- TODO: Add how to get started with Cody
- To use your private Sourcegraph instance, open `Settings | Tools | Cody` and enter your URL and access token.
## Questions & Feedback
If you have any questions, feedback, or bug report, we appreciate if you [open an issue on GitHub](https://github.com/sourcegraph/sourcegraph/issues/new?labels=team/cody,cody/jetbrains&title=Cody:+).
## Uninstallation
- Open settings
- Windows: Go to `File | Settings` (or use <kbd>Ctrl+Alt+S</kbd>)
- Mac: Go to `IntelliJ IDEA | Preferences` (or use <kbd>⌘,</kbd>)
- Click `Plugins` in the left-hand pane, then the `Installed` tab at the top
- Find `Cody` → Right click → `Uninstall` (or uncheck to disable)
## Version History
See [`CHANGELOG.md`](https://github.com/sourcegraph/sourcegraph/blob/main/client/cody-jetbrains/CHANGELOG.md).

View File

@ -1,126 +0,0 @@
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
fun properties(key: String) = project.findProperty(key).toString()
plugins {
id("java")
// Dependencies are locked at this version to work with JDK 11 on CI.
id("org.jetbrains.kotlin.jvm") version "1.7.0"
id("org.jetbrains.intellij") version "1.13.3"
id("org.jetbrains.changelog") version "1.3.1"
id("com.diffplug.spotless") version "6.19.0"
}
group = properties("pluginGroup")
version = properties("pluginVersion")
repositories {
mavenCentral()
}
intellij {
pluginName.set(properties("pluginName"))
version.set(properties("platformVersion"))
type.set(properties("platformType"))
// Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file.
plugins.set(properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty))
updateSinceUntilBuild.set(false)
}
dependencies {
// https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation("org.commonmark:commonmark:0.21.0")
implementation(project(":jetbrains-shared"))
testImplementation(platform("org.junit:junit-bom:5.7.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
spotless {
java {
target("src/*/java/**/*.java")
importOrder()
removeUnusedImports()
googleJavaFormat()
}
}
java {
toolchain {
// Always compile the codebase with Java 11 regardless of what Java
// version is installed on the computer. Gradle will download Java 11
// even if you already have it installed on your computer.
languageVersion.set(JavaLanguageVersion.of(11))
}
}
tasks {
// Set the JVM compatibility versions
properties("javaVersion").let {
withType<JavaCompile> {
sourceCompatibility = it
targetCompatibility = it
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = it
}
}
wrapper {
gradleVersion = properties("gradleVersion")
}
patchPluginXml {
version.set(properties("pluginVersion"))
// Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
pluginDescription.set(
projectDir.resolve("README.md").readText().lines().run {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
}
subList(indexOf(start) + 1, indexOf(end))
}.joinToString("\n").run { markdownToHTML(this) }
)
// Get the latest available change notes from the changelog file
changeNotes.set(provider {
changelog.run {
getOrNull(properties("pluginVersion")) ?: getLatest()
}.toHTML()
})
}
runIde {
jvmArgs("-Djdk.module.illegalAccess.silent=true")
}
// Configure UI tests plugin
// Read more: https://github.com/JetBrains/intellij-ui-test-robot
runIdeForUiTests {
systemProperty("robot-server.port", "8082")
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
systemProperty("jb.consents.confirmation.enabled", "false")
}
signPlugin {
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}
publishPlugin {
dependsOn("patchChangelog")
token.set(System.getenv("PUBLISH_TOKEN"))
// pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
// https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel
channels.set(listOf(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first()))
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
oаљџџэМЫть<D182>

View File

@ -1,22 +0,0 @@
# IntelliJ Platform Artifacts Repositories
# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html
pluginGroup=com.sourcegraph.cody-jetbrains
pluginName=Cody
# SemVer format -> https://semver.org
pluginVersion=1.0.0
pluginSinceBuild=211.0
pluginUntilBuild=*
# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
platformType=IC
platformVersion=2021.1
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins=Git4Idea,PerforceDirectPlugin
# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3
javaVersion=11
# Gradle Releases -> https://github.com/gradle/gradle/releases
gradleVersion=8.1.1
# Opt-out flag for bundling Kotlin standard library.
# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
# suppress inspection "UnusedProperty"
kotlin.stdlib.default.dependency=false

View File

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -e
[ -z "$PUBLISH_TOKEN" ] && echo "You must set a \$PUBLISH_TOKEN before running this script. You can generate a token in the JetBrains marketplace." && exit 1
# Ensure we have a clean git checkout
git diff-index --quiet HEAD || (echo "Please commit your changes before releasing" && exit 1)
# Make sure we have all dependencies
pushd "../.." > /dev/null
pnpm install && pnpm generate
popd > /dev/null || exit
# Build the release candidate and publish it onto the registry
./gradlew publishPlugin
# The release script automatically changes the README and moves the unreleased
# section into a version numbered one. We don't care about this while we are
# creating pre-release versions.
if grep -q "alpha\|beta" "gradle.properties"; then
git restore CHANGELOG.md
fi

View File

@ -1,3 +0,0 @@
rootProject.name = "Cody"
include(":jetbrains-shared")
project(":jetbrains-shared").projectDir = file("../jetbrains-shared")

View File

@ -1,57 +0,0 @@
package com.sourcegraph.cody.config;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.intellij.openapi.diagnostic.Logger;
import com.sourcegraph.api.GraphQlClient;
import com.sourcegraph.api.GraphQlResponse;
import java.io.IOException;
import java.util.function.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ApiAuthenticator {
private static final Logger logger = Logger.getInstance(ApiAuthenticator.class);
public static void testConnection(
@NotNull String instanceUrl,
@Nullable String accessToken,
@Nullable String customRequestHeaders,
@NotNull Consumer<ConnectionStatus> callback) {
new Thread(
() -> {
String query = "query { currentUser { id } }";
try {
GraphQlResponse response =
GraphQlClient.callGraphQLService(
instanceUrl, accessToken, customRequestHeaders, query, new JsonObject());
if (response.getStatusCode() == 200) {
JsonElement id =
response
.getBodyAsJson()
.getAsJsonObject("data")
.getAsJsonObject("currentUser")
.get("id");
callback.accept(
id.isJsonNull()
? ConnectionStatus.COULD_CONNECT_BUT_NOT_AUTHENTICATED
: ConnectionStatus.AUTHENTICATED);
} else {
callback.accept(ConnectionStatus.COULD_NOT_CONNECT);
}
} catch (IOException | JsonSyntaxException e) {
callback.accept(ConnectionStatus.COULD_NOT_CONNECT);
logger.info(e);
}
})
.start();
}
enum ConnectionStatus {
AUTHENTICATED,
COULD_NOT_CONNECT,
COULD_CONNECT_BUT_NOT_AUTHENTICATED
}
}

View File

@ -1,50 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.options.Configurable;
import javax.swing.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.Nullable;
/** Provides controller functionality for application settings. */
public class ApplicationSettingsConfigurable implements Configurable {
private SettingsComponent mySettingsComponent;
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return "Cody";
}
@Override
public JComponent getPreferredFocusedComponent() {
return mySettingsComponent.getPreferredFocusedComponent();
}
@Nullable
@Override
public JComponent createComponent() {
mySettingsComponent = new SettingsComponent();
return mySettingsComponent.getPanel();
}
@Override
public boolean isModified() {
return SettingsConfigurableHelper.isModified(null, mySettingsComponent);
}
@Override
public void apply() {
SettingsConfigurableHelper.apply(null, mySettingsComponent);
}
@Override
public void reset() {
SettingsConfigurableHelper.reset(null, mySettingsComponent);
}
@Override
public void disposeUIResources() {
mySettingsComponent.dispose();
mySettingsComponent = null;
}
}

View File

@ -1,136 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@State(
name = "ApplicationConfig",
storages = {@Storage("cody.xml")})
public class CodyApplicationService
implements CodyService, PersistentStateComponent<CodyApplicationService> {
@Nullable private String instanceType;
@Nullable private String dotcomAccessToken;
@Nullable private String enterpriseUrl;
@Nullable private String enterpriseAccessToken;
@Nullable private String customRequestHeaders;
@Nullable private String codebase;
@Nullable private String anonymousUserId;
private boolean isInstallEventLogged;
private boolean areChatPredictionsEnabled;
@Nullable private Boolean authenticationFailedLastTime;
@NotNull
public static CodyApplicationService getInstance() {
return ApplicationManager.getApplication().getService(CodyApplicationService.class);
}
@Nullable
public String getInstanceType() {
return instanceType;
}
public void setInstanceType(@Nullable String instanceType) {
this.instanceType = instanceType;
}
@Nullable
public String getDotcomAccessToken() {
return dotcomAccessToken;
}
public void setDotcomAccessToken(@Nullable String dotcomAccessToken) {
this.dotcomAccessToken = dotcomAccessToken;
}
@Nullable
public String getEnterpriseUrl() {
return enterpriseUrl;
}
public void setEnterpriseUrl(@Nullable String enterpriseUrl) {
this.enterpriseUrl = enterpriseUrl;
}
@Nullable
public String getEnterpriseAccessToken() {
return enterpriseAccessToken;
}
public void setEnterpriseAccessToken(@Nullable String enterpriseAccessToken) {
this.enterpriseAccessToken = enterpriseAccessToken;
}
@Nullable
public String getCustomRequestHeaders() {
return customRequestHeaders;
}
public void setCustomRequestHeaders(@Nullable String customRequestHeaders) {
this.customRequestHeaders = customRequestHeaders;
}
@Nullable
public String getCodebase() {
return codebase;
}
public void setCodebase(@Nullable String codebase) {
this.codebase = codebase;
}
@Nullable
public String getAnonymousUserId() {
return anonymousUserId;
}
public void setAnonymousUserId(@Nullable String anonymousUserId) {
this.anonymousUserId = anonymousUserId;
}
public boolean isInstallEventLogged() {
return isInstallEventLogged;
}
public void setInstallEventLogged(boolean installEventLogged) {
isInstallEventLogged = installEventLogged;
}
public Boolean areChatPredictionsEnabled() {
return areChatPredictionsEnabled;
}
public void setChatPredictionsEnabled(Boolean areChatPredictionsEnabled) {
this.areChatPredictionsEnabled = areChatPredictionsEnabled;
}
@Nullable
public Boolean getAuthenticationFailedLastTime() {
return authenticationFailedLastTime;
}
public void setAuthenticationFailedLastTime(@Nullable Boolean authenticationFailedLastTime) {
this.authenticationFailedLastTime = authenticationFailedLastTime;
}
@Nullable
@Override
public CodyApplicationService getState() {
return this;
}
@Override
public void loadState(@NotNull CodyApplicationService settings) {
this.instanceType = settings.instanceType;
this.enterpriseUrl = settings.enterpriseUrl;
this.enterpriseAccessToken = settings.enterpriseAccessToken;
this.customRequestHeaders = settings.customRequestHeaders;
this.codebase = settings.codebase;
this.anonymousUserId = settings.anonymousUserId;
this.areChatPredictionsEnabled = settings.areChatPredictionsEnabled;
this.authenticationFailedLastTime = settings.authenticationFailedLastTime;
}
}

View File

@ -1,110 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@State(
name = "Config",
storages = {@Storage("cody.xml")})
public class CodyProjectService
implements CodyService, PersistentStateComponent<CodyProjectService> {
@Nullable private String instanceType;
@Nullable private String dotcomAccessToken;
@Nullable private String enterpriseUrl;
@Nullable private String enterpriseAccessToken;
@Nullable private String customRequestHeaders;
@Nullable private String defaultBranch;
@Nullable private String codebase;
@Nullable private Boolean areChatPredictionsEnabled;
@NotNull
public static CodyProjectService getInstance(@NotNull Project project) {
return project.getService(CodyProjectService.class);
}
public void setInstanceType(@Nullable String instanceType) {
this.instanceType = instanceType;
}
@Nullable
public String getInstanceType() {
return instanceType;
}
@Nullable
public String getDotcomAccessToken() {
return dotcomAccessToken;
}
public void setDotcomAccessToken(@Nullable String dotcomAccessToken) {
this.dotcomAccessToken = dotcomAccessToken;
}
@Nullable
public String getEnterpriseUrl() {
return enterpriseUrl;
}
public void setEnterpriseUrl(@Nullable String enterpriseUrl) {
this.enterpriseUrl = enterpriseUrl;
}
@Nullable
public String getEnterpriseAccessToken() {
return enterpriseAccessToken;
}
public void setEnterpriseAccessToken(@Nullable String enterpriseAccessToken) {
this.enterpriseAccessToken = enterpriseAccessToken;
}
@Nullable
public String getCustomRequestHeaders() {
return customRequestHeaders;
}
public void setCustomRequestHeaders(@Nullable String customRequestHeaders) {
this.customRequestHeaders = customRequestHeaders;
}
@Nullable
public String getCodebase() {
return codebase;
}
public void setCodebase(@Nullable String codebase) {
this.codebase = codebase;
}
@Nullable
@Override
public CodyProjectService getState() {
return this;
}
@Nullable
public Boolean areChatPredictionsEnabled() {
return areChatPredictionsEnabled;
}
public void setChatPredictionsEnabled(@Nullable Boolean areChatPredictionsEnabled) {
this.areChatPredictionsEnabled = areChatPredictionsEnabled;
}
@Override
public void loadState(@NotNull CodyProjectService settings) {
this.instanceType = settings.instanceType;
this.dotcomAccessToken = settings.dotcomAccessToken;
this.enterpriseUrl = settings.enterpriseUrl;
this.enterpriseAccessToken = settings.enterpriseAccessToken;
this.customRequestHeaders = settings.customRequestHeaders;
this.defaultBranch = settings.defaultBranch;
this.codebase = settings.codebase;
this.areChatPredictionsEnabled = settings.areChatPredictionsEnabled;
}
}

View File

@ -1,40 +0,0 @@
package com.sourcegraph.cody.config;
import org.jetbrains.annotations.Nullable;
public interface CodyService {
@Nullable
String getInstanceType();
void setInstanceType(@Nullable String instanceType);
@Nullable
String getDotcomAccessToken();
void setDotcomAccessToken(@Nullable String dotcomAccessToken);
@Nullable
String getEnterpriseUrl();
void setEnterpriseUrl(@Nullable String enterpriseUrl);
@Nullable
String getEnterpriseAccessToken();
void setEnterpriseAccessToken(@Nullable String enterpriseAccessToken);
@Nullable
String getCustomRequestHeaders();
void setCustomRequestHeaders(@Nullable String customRequestHeaders);
@Nullable
String getCodebase();
void setCodebase(@Nullable String codebase);
@Nullable
Boolean areChatPredictionsEnabled();
void setChatPredictionsEnabled(@Nullable Boolean areChatPredictionsEnabled);
}

View File

@ -1,183 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.project.Project;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ConfigUtil {
public static final String DOTCOM_URL = "https://sourcegraph.com/";
@NotNull
public static SettingsComponent.InstanceType getInstanceType(@Nullable Project project) {
// Project level
if (project != null) {
String projectLevelSetting = getProjectLevelConfig(project).getInstanceType();
if (projectLevelSetting != null && !projectLevelSetting.isEmpty()) {
return projectLevelSetting.equals(SettingsComponent.InstanceType.ENTERPRISE.name())
? SettingsComponent.InstanceType.ENTERPRISE
: SettingsComponent.InstanceType.DOTCOM;
}
}
// Application level
String applicationLevelSetting = getApplicationLevelConfig().getInstanceType();
if (applicationLevelSetting != null && !applicationLevelSetting.isEmpty()) {
return applicationLevelSetting.equals(SettingsComponent.InstanceType.ENTERPRISE.name())
? SettingsComponent.InstanceType.ENTERPRISE
: SettingsComponent.InstanceType.DOTCOM;
}
// Use default
String enterpriseUrl = getEnterpriseUrl(project);
return (enterpriseUrl.equals("") || enterpriseUrl.startsWith(DOTCOM_URL))
? SettingsComponent.InstanceType.DOTCOM
: SettingsComponent.InstanceType.ENTERPRISE;
}
@NotNull
public static String getSourcegraphUrl(@Nullable Project project) {
if (getInstanceType(project) == SettingsComponent.InstanceType.DOTCOM) {
return DOTCOM_URL;
} else {
String enterpriseUrl = getEnterpriseUrl(project);
return !enterpriseUrl.isEmpty() ? enterpriseUrl : DOTCOM_URL;
}
}
@NotNull
public static String getEnterpriseUrl(@Nullable Project project) {
// Project level
if (project != null) {
String projectLevelUrl = getProjectLevelConfig(project).getEnterpriseUrl();
if (projectLevelUrl != null && projectLevelUrl.length() > 0) {
return addSlashIfNeeded(projectLevelUrl);
}
}
// Application level
String applicationLevelUrl = getApplicationLevelConfig().getEnterpriseUrl();
if (applicationLevelUrl != null && applicationLevelUrl.length() > 0) {
return addSlashIfNeeded(applicationLevelUrl);
}
// Use default
return "";
}
@Nullable
public static String getDotcomAccessToken(@Nullable Project project) {
// Project level application level
String accessToken =
project != null ? getProjectLevelConfig(project).getDotcomAccessToken() : null;
return accessToken != null ? accessToken : getApplicationLevelConfig().getDotcomAccessToken();
}
@Nullable
public static String getEnterpriseAccessToken(@Nullable Project project) {
// Project level application level
String accessToken =
project != null ? getProjectLevelConfig(project).getEnterpriseAccessToken() : null;
return accessToken != null
? accessToken
: getApplicationLevelConfig().getEnterpriseAccessToken();
}
@NotNull
public static String getCustomRequestHeaders(@Nullable Project project) {
// Project level
if (project != null) {
String projectLevelCustomRequestHeaders =
getProjectLevelConfig(project).getCustomRequestHeaders();
if (projectLevelCustomRequestHeaders != null
&& projectLevelCustomRequestHeaders.length() > 0) {
return projectLevelCustomRequestHeaders;
}
}
// Application level
String applicationLevelCustomRequestHeaders =
getApplicationLevelConfig().getCustomRequestHeaders();
if (applicationLevelCustomRequestHeaders != null
&& applicationLevelCustomRequestHeaders.length() > 0) {
return applicationLevelCustomRequestHeaders;
}
// Default
return "";
}
@NotNull
public static String getCodebase(@Nullable Project project) {
// Project level
if (project != null) {
String projectLevelCodebase = getProjectLevelConfig(project).getCodebase();
if (projectLevelCodebase != null && projectLevelCodebase.length() > 0) {
return projectLevelCodebase;
}
}
// Application level
String applicationLevelCodebase = getApplicationLevelConfig().getCodebase();
if (applicationLevelCodebase != null && applicationLevelCodebase.length() > 0) {
return applicationLevelCodebase;
}
// Use default
return "";
}
@Nullable
public static String getAnonymousUserId() {
return getApplicationLevelConfig().getAnonymousUserId();
}
public static void setAnonymousUserId(@Nullable String anonymousUserId) {
getApplicationLevelConfig().setAnonymousUserId(anonymousUserId);
}
public static boolean isInstallEventLogged() {
return getApplicationLevelConfig().isInstallEventLogged();
}
public static void setInstallEventLogged(boolean value) {
getApplicationLevelConfig().setInstallEventLogged(value);
}
public static boolean areChatPredictionsEnabled(@Nullable Project project) {
// Project level application level
Boolean areChatPredictionsEnabled =
project != null ? getProjectLevelConfig(project).areChatPredictionsEnabled() : null;
return areChatPredictionsEnabled != null
? areChatPredictionsEnabled
: Boolean.TRUE.equals(getApplicationLevelConfig().areChatPredictionsEnabled());
}
public static void setAreChatPredictionsEnabled(boolean value) {
getApplicationLevelConfig().setChatPredictionsEnabled(value);
}
@NotNull
private static String addSlashIfNeeded(@NotNull String url) {
return url.endsWith("/") ? url : url + "/";
}
public static boolean didAuthenticationFailLastTime() {
Boolean failedLastTime = getApplicationLevelConfig().getAuthenticationFailedLastTime();
return failedLastTime != null ? failedLastTime : true;
}
public static void setAuthenticationFailedLastTime(boolean value) {
CodyApplicationService.getInstance().setAuthenticationFailedLastTime(value);
}
@NotNull
private static CodyApplicationService getApplicationLevelConfig() {
return Objects.requireNonNull(CodyApplicationService.getInstance());
}
@NotNull
private static CodyProjectService getProjectLevelConfig(@NotNull Project project) {
return Objects.requireNonNull(CodyProjectService.getInstance(project));
}
}

View File

@ -1,53 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import com.sourcegraph.cody.Icons;
import org.jetbrains.annotations.NotNull;
public class NotificationActivity implements StartupActivity.DumbAware {
@Override
public void runActivity(@NotNull Project project) {
String url = ConfigUtil.getEnterpriseUrl(project);
if (url.length() == 0 || url.startsWith(ConfigUtil.DOTCOM_URL)) {
notifyAboutSourcegraphUrl();
}
}
private void notifyAboutSourcegraphUrl() {
// Display notification
Notification notification =
new Notification(
"Sourcegraph access",
"Cody",
"A custom Sourcegraph URL is not set. Cody can only access public repos. Do you want to set your custom URL?",
NotificationType.INFORMATION);
AnAction setUrlAction = new OpenPluginSettingsAction("Set URL");
AnAction cancelAction =
new DumbAwareAction("Do Not Set") {
@Override
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
notification.expire();
}
};
AnAction neverShowAgainAction =
new DumbAwareAction("Never Show Again") {
@Override
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
notification.expire();
ConfigUtil.setAreChatPredictionsEnabled(true);
}
};
notification.setIcon(Icons.CodyLogo);
notification.addAction(setUrlAction);
notification.addAction(cancelAction);
notification.addAction(neverShowAgainAction);
Notifications.Bus.notify(notification);
}
}

View File

@ -1,24 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.util.NlsActions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OpenPluginSettingsAction extends DumbAwareAction {
public OpenPluginSettingsAction() {
super();
}
public OpenPluginSettingsAction(@Nullable @NlsActions.ActionText String text) {
super(text);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
ShowSettingsUtil.getInstance()
.showSettingsDialog(event.getProject(), ProjectSettingsConfigurable.class);
}
}

View File

@ -1,14 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NotNull;
public interface PluginSettingChangeActionNotifier {
Topic<PluginSettingChangeActionNotifier> TOPIC =
Topic.create("Cody plugin settings have changed", PluginSettingChangeActionNotifier.class);
void beforeAction(@NotNull PluginSettingChangeContext context);
void afterAction(@NotNull PluginSettingChangeContext context);
}

View File

@ -1,36 +0,0 @@
package com.sourcegraph.cody.config;
import org.jetbrains.annotations.Nullable;
public class PluginSettingChangeContext {
@Nullable public final String oldDotcomAccessToken;
@Nullable public final String oldEnterpriseUrl;
@Nullable public final String oldEnterpriseAccessToken;
@Nullable public final String newDotcomAccessToken;
@Nullable public final String newEnterpriseUrl;
@Nullable public final String newEnterpriseAccessToken;
@Nullable public final String newCustomRequestHeaders;
public PluginSettingChangeContext(
@Nullable String oldDotcomAccessToken,
@Nullable String oldEnterpriseUrl,
@Nullable String oldEnterpriseAccessToken,
@Nullable String newDotcomAccessToken,
@Nullable String newEnterpriseUrl,
@Nullable String newEnterpriseAccessToken,
@Nullable String newCustomRequestHeaders) {
this.oldDotcomAccessToken = oldDotcomAccessToken;
this.oldEnterpriseUrl = oldEnterpriseUrl;
this.oldEnterpriseAccessToken = oldEnterpriseAccessToken;
this.newDotcomAccessToken = newDotcomAccessToken;
this.newEnterpriseUrl = newEnterpriseUrl;
this.newEnterpriseAccessToken = newEnterpriseAccessToken;
this.newCustomRequestHeaders = newCustomRequestHeaders;
}
}

View File

@ -1,56 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import javax.swing.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.Nullable;
/** Provides controller functionality for application settings. */
public class ProjectSettingsConfigurable implements Configurable {
private final Project project;
private SettingsComponent mySettingsComponent;
public ProjectSettingsConfigurable(Project project) {
this.project = project;
}
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return "Cody (Project)";
}
@Override
public JComponent getPreferredFocusedComponent() {
return mySettingsComponent.getPreferredFocusedComponent();
}
@Nullable
@Override
public JComponent createComponent() {
mySettingsComponent = new SettingsComponent();
return mySettingsComponent.getPanel();
}
@Override
public boolean isModified() {
return SettingsConfigurableHelper.isModified(project, mySettingsComponent);
}
@Override
public void apply() {
SettingsConfigurableHelper.apply(project, mySettingsComponent);
}
@Override
public void reset() {
SettingsConfigurableHelper.reset(project, mySettingsComponent);
}
@Override
public void disposeUIResources() {
mySettingsComponent.dispose();
mySettingsComponent = null;
}
}

View File

@ -1,91 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import com.sourcegraph.cody.telemetry.GraphQlLogger;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
/**
* Listens to changes in the plugin settings and: - logs install/uninstall events. - notifies the
* user about a successful connection.
*/
public class SettingsChangeListener implements Disposable {
private final MessageBusConnection connection;
public SettingsChangeListener(@NotNull Project project) {
MessageBus bus = project.getMessageBus();
connection = bus.connect();
connection.subscribe(
PluginSettingChangeActionNotifier.TOPIC,
new PluginSettingChangeActionNotifier() {
@Override
public void beforeAction(@NotNull PluginSettingChangeContext context) {
if (!Objects.equals(context.oldEnterpriseUrl, context.newEnterpriseUrl)) {
GraphQlLogger.logUninstallEvent(project);
ConfigUtil.setInstallEventLogged(false);
}
}
@Override
public void afterAction(@NotNull PluginSettingChangeContext context) {
// Log install events
if (!Objects.equals(context.oldEnterpriseUrl, context.newEnterpriseUrl)) {
GraphQlLogger.logInstallEvent(project, ConfigUtil::setInstallEventLogged);
} else if (!Objects.equals(
context.oldEnterpriseAccessToken, context.newEnterpriseAccessToken)
&& !ConfigUtil.isInstallEventLogged()) {
GraphQlLogger.logInstallEvent(project, ConfigUtil::setInstallEventLogged);
}
// Notify user about a successful connection
if (context.newEnterpriseUrl != null) {
ApiAuthenticator.testConnection(
context.newEnterpriseUrl,
context.newEnterpriseAccessToken,
context.newCustomRequestHeaders,
(status) -> {
if (ConfigUtil.didAuthenticationFailLastTime()
&& status == ApiAuthenticator.ConnectionStatus.AUTHENTICATED) {
notifyAboutSuccessfulConnection();
}
ConfigUtil.setAuthenticationFailedLastTime(
status != ApiAuthenticator.ConnectionStatus.AUTHENTICATED);
});
}
}
});
}
private void notifyAboutSuccessfulConnection() {
Notification notification =
new Notification(
"Cody Sourcegraph access",
"Cody authentication success",
"Cody successfully connected to your Sourcegraph account.",
NotificationType.INFORMATION);
AnAction dismissAction =
new DumbAwareAction("Dismiss") {
@Override
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
notification.expire();
}
};
notification.addAction(dismissAction);
Notifications.Bus.notify(notification);
}
@Override
public void dispose() {
connection.disconnect();
}
}

View File

@ -1,406 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.ui.ComponentValidator;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.jsonSchema.settings.mappings.JsonSchemaConfigurable;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** Supports creating and managing a {@link JPanel} for the Settings Dialog. */
public class SettingsComponent implements Disposable {
private final JPanel panel;
private ButtonGroup instanceTypeButtonGroup;
private JBLabel dotcomAccessTokenLinkComment;
private JBTextField dotcomAccessTokenTextField;
private JBTextField enterpriseUrlTextField;
private JBTextField enterpriseAccessTokenTextField;
private JBLabel userDocsLinkComment;
private JBLabel enterpriseAccessTokenLinkComment;
private JBTextField customRequestHeadersTextField;
private JBTextField codebaseTextField;
private JBCheckBox areChatPredictionsEnabledCheckBox;
public JComponent getPreferredFocusedComponent() {
return codebaseTextField;
}
public SettingsComponent() {
JPanel userAuthenticationPanel = createAuthenticationPanel();
JPanel navigationSettingsPanel = createOtherSettingsPanel();
panel =
FormBuilder.createFormBuilder()
.addComponent(userAuthenticationPanel)
.addComponent(navigationSettingsPanel)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
public JPanel getPanel() {
return panel;
}
@NotNull
public InstanceType getInstanceType() {
return instanceTypeButtonGroup
.getSelection()
.getActionCommand()
.equals(InstanceType.DOTCOM.name())
? InstanceType.DOTCOM
: InstanceType.ENTERPRISE;
}
public void setInstanceType(@NotNull InstanceType instanceType) {
for (Enumeration<AbstractButton> buttons = instanceTypeButtonGroup.getElements();
buttons.hasMoreElements(); ) {
AbstractButton button = buttons.nextElement();
button.setSelected(button.getActionCommand().equals(instanceType.name()));
}
setDotcomSettingsEnabled(instanceType == InstanceType.DOTCOM);
setEnterpriseSettingsEnabled(instanceType == InstanceType.ENTERPRISE);
}
@NotNull
private JPanel createAuthenticationPanel() {
// Create dotcom access token field
JBLabel dotcomAccessTokenLabel = new JBLabel("Access token:");
dotcomAccessTokenTextField = new JBTextField();
dotcomAccessTokenTextField.getEmptyText().setText("Paste your access token here");
addValidation(
dotcomAccessTokenTextField,
() ->
isValidAccessToken(dotcomAccessTokenTextField.getText())
? null
: new ValidationInfo("Invalid access token", dotcomAccessTokenTextField));
dotcomAccessTokenLinkComment =
new JBLabel(
"<html><body>Have no token yet? Create one <a href=\"https://sourcegraph.com/user/settings/tokens/new\">here</a>.</body></html>",
UIUtil.ComponentStyle.SMALL,
UIUtil.FontColor.BRIGHTER);
//
// Create URL field for the enterprise section
JBLabel urlLabel = new JBLabel("Sourcegraph URL:");
enterpriseUrlTextField = new JBTextField();
//noinspection DialogTitleCapitalization
enterpriseUrlTextField.getEmptyText().setText("https://sourcegraph.example.com");
enterpriseUrlTextField.setToolTipText("The default is \"" + ConfigUtil.DOTCOM_URL + "\".");
addValidation(
enterpriseUrlTextField,
() ->
enterpriseUrlTextField.getText().length() == 0
? new ValidationInfo("Missing URL", enterpriseUrlTextField)
: (!JsonSchemaConfigurable.isValidURL(enterpriseUrlTextField.getText())
? new ValidationInfo("This is an invalid URL", enterpriseUrlTextField)
: null));
addDocumentListener(enterpriseUrlTextField, e -> updateAccessTokenLinkCommentText());
// Create enterprise access token field
JBLabel enterpriseAccessTokenLabel = new JBLabel("Access token:");
enterpriseAccessTokenTextField = new JBTextField();
enterpriseAccessTokenTextField.getEmptyText().setText("Paste your access token here");
addValidation(
enterpriseAccessTokenTextField,
() ->
isValidAccessToken(enterpriseAccessTokenTextField.getText())
? null
: new ValidationInfo("Invalid access token", enterpriseAccessTokenTextField));
// Create comments
userDocsLinkComment =
new JBLabel(
"<html><body>You will need an access token to sign in. See our <a href=\"https://docs.sourcegraph.com/cli/how-tos/creating_an_access_token\">user docs</a> for a video guide</body></html>",
UIUtil.ComponentStyle.SMALL,
UIUtil.FontColor.BRIGHTER);
userDocsLinkComment.setBorder(JBUI.Borders.emptyLeft(10));
enterpriseAccessTokenLinkComment =
new JBLabel("", UIUtil.ComponentStyle.SMALL, UIUtil.FontColor.BRIGHTER);
enterpriseAccessTokenLinkComment.setBorder(JBUI.Borders.emptyLeft(10));
// Set up radio buttons
ActionListener actionListener =
event -> {
String actionCommand = event.getActionCommand();
setDotcomSettingsEnabled(actionCommand.equals(InstanceType.DOTCOM.name()));
setEnterpriseSettingsEnabled(actionCommand.equals(InstanceType.ENTERPRISE.name()));
};
JRadioButton sourcegraphDotComRadioButton = new JRadioButton("Use sourcegraph.com");
sourcegraphDotComRadioButton.setMnemonic(KeyEvent.VK_C);
sourcegraphDotComRadioButton.setActionCommand(InstanceType.DOTCOM.name());
sourcegraphDotComRadioButton.addActionListener(actionListener);
JRadioButton enterpriseInstanceRadioButton = new JRadioButton("Use an enterprise instance");
enterpriseInstanceRadioButton.setMnemonic(KeyEvent.VK_E);
enterpriseInstanceRadioButton.setActionCommand(InstanceType.ENTERPRISE.name());
enterpriseInstanceRadioButton.addActionListener(actionListener);
instanceTypeButtonGroup = new ButtonGroup();
instanceTypeButtonGroup.add(sourcegraphDotComRadioButton);
instanceTypeButtonGroup.add(enterpriseInstanceRadioButton);
// Assemble the two main panels
JBLabel dotComComment =
new JBLabel(
"Cody for open source code is available to all users with a Sourcegraph.com account",
UIUtil.ComponentStyle.SMALL,
UIUtil.FontColor.BRIGHTER);
dotComComment.setBorder(JBUI.Borders.emptyLeft(20));
JPanel dotcomPanelContent =
FormBuilder.createFormBuilder()
.addLabeledComponent(dotcomAccessTokenLabel, dotcomAccessTokenTextField, 1)
.addComponentToRightColumn(dotcomAccessTokenLinkComment, 1)
.getPanel();
dotcomPanelContent.setBorder(IdeBorderFactory.createEmptyBorder(JBUI.insets(1, 30, 0, 0)));
JPanel dotComPanel =
FormBuilder.createFormBuilder()
.addComponent(sourcegraphDotComRadioButton, 1)
.addComponentToRightColumn(dotComComment, 2)
.addComponent(dotcomPanelContent, 1)
.getPanel();
JPanel enterprisePanelContent =
FormBuilder.createFormBuilder()
.addLabeledComponent(urlLabel, enterpriseUrlTextField, 1)
.addTooltip("If your company uses a private Sourcegraph instance, set its URL here")
.addLabeledComponent(enterpriseAccessTokenLabel, enterpriseAccessTokenTextField, 1)
.addComponentToRightColumn(userDocsLinkComment, 1)
.addComponentToRightColumn(enterpriseAccessTokenLinkComment, 1)
.getPanel();
enterprisePanelContent.setBorder(IdeBorderFactory.createEmptyBorder(JBUI.insets(1, 30, 0, 0)));
JPanel enterprisePanel =
FormBuilder.createFormBuilder()
.addComponent(enterpriseInstanceRadioButton, 1)
.addComponent(enterprisePanelContent, 1)
.getPanel();
// Create the "Request headers" text box
JBLabel customRequestHeadersLabel = new JBLabel("Custom headers:");
customRequestHeadersTextField = new JBTextField();
customRequestHeadersTextField
.getEmptyText()
.setText("Client-ID, client-one, X-Extra, some metadata");
customRequestHeadersTextField.setToolTipText(
"You can even overwrite \"Authorization\" that Access token sets above.");
addValidation(
customRequestHeadersTextField,
() -> {
if (customRequestHeadersTextField.getText().length() == 0) {
return null;
}
String[] pairs = customRequestHeadersTextField.getText().split(",");
if (pairs.length % 2 != 0) {
return new ValidationInfo(
"Must be a comma-separated list of pairs", customRequestHeadersTextField);
}
for (int i = 0; i < pairs.length; i += 2) {
String headerName = pairs[i].trim();
if (!headerName.matches("[\\w-]+")) {
return new ValidationInfo(
"Invalid HTTP header name: " + headerName, customRequestHeadersTextField);
}
}
return null;
});
// Assemble the main panel
JPanel userAuthenticationPanel =
FormBuilder.createFormBuilder()
.addComponent(dotComPanel)
.addComponent(enterprisePanel, 5)
.addLabeledComponent(customRequestHeadersLabel, customRequestHeadersTextField)
.addTooltip("Any custom headers to send with every request to Sourcegraph.")
.addTooltip("Use any number of pairs: \"header1, value1, header2, value2, ...\".")
.addTooltip("Whitespace around commas doesn't matter.")
.getPanel();
userAuthenticationPanel.setBorder(
IdeBorderFactory.createTitledBorder("Authentication", true, JBUI.insetsTop(8)));
return userAuthenticationPanel;
}
@NotNull
public String getDotcomAccessToken() {
return dotcomAccessTokenTextField.getText();
}
public void setDotcomAccessToken(@NotNull String value) {
dotcomAccessTokenTextField.setText(value);
}
@NotNull
public String getEnterpriseUrl() {
return enterpriseUrlTextField.getText();
}
public void setEnterpriseUrl(@Nullable String value) {
enterpriseUrlTextField.setText(value != null ? value : "");
}
@NotNull
public String getEnterpriseAccessToken() {
return enterpriseAccessTokenTextField.getText();
}
public void setEnterpriseAccessToken(@NotNull String value) {
enterpriseAccessTokenTextField.setText(value);
}
@NotNull
public String getCustomRequestHeaders() {
return customRequestHeadersTextField.getText();
}
public void setCustomRequestHeaders(@NotNull String customRequestHeaders) {
this.customRequestHeadersTextField.setText(customRequestHeaders);
}
@NotNull
public String getCodebase() {
return codebaseTextField.getText();
}
public void setCodebase(@NotNull String value) {
codebaseTextField.setText(value);
}
public boolean areChatPredictionsEnabled() {
return areChatPredictionsEnabledCheckBox != null
&& areChatPredictionsEnabledCheckBox.isSelected();
}
public void setAreChatPredictionsEnabled(boolean value) {
if (areChatPredictionsEnabledCheckBox != null) {
areChatPredictionsEnabledCheckBox.setSelected(value);
}
}
private void setDotcomSettingsEnabled(boolean enable) {
dotcomAccessTokenTextField.setEnabled(enable);
dotcomAccessTokenLinkComment.setEnabled(enable);
dotcomAccessTokenLinkComment.setCopyable(enable);
}
private void setEnterpriseSettingsEnabled(boolean enable) {
enterpriseUrlTextField.setEnabled(enable);
enterpriseAccessTokenTextField.setEnabled(enable);
userDocsLinkComment.setEnabled(enable);
userDocsLinkComment.setCopyable(enable);
enterpriseAccessTokenLinkComment.setEnabled(enable);
enterpriseAccessTokenLinkComment.setCopyable(enable);
}
@Override
public void dispose() {
instanceTypeButtonGroup = null;
enterpriseUrlTextField = null;
enterpriseAccessTokenTextField = null;
customRequestHeadersTextField = null;
codebaseTextField = null;
areChatPredictionsEnabledCheckBox = null;
userDocsLinkComment = null;
enterpriseAccessTokenLinkComment = null;
}
public enum InstanceType {
DOTCOM,
ENTERPRISE,
}
private void addValidation(
@NotNull JTextComponent component, @NotNull Supplier<ValidationInfo> validator) {
new ComponentValidator(this).withValidator(validator).installOn(component);
addDocumentListener(
component,
e -> ComponentValidator.getInstance(component).ifPresent(ComponentValidator::revalidate));
}
private void addDocumentListener(
@NotNull JTextComponent textComponent, @NotNull Consumer<ComponentValidator> function) {
textComponent
.getDocument()
.addDocumentListener(
new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
ComponentValidator.getInstance(textComponent).ifPresent(function);
}
@Override
public void removeUpdate(DocumentEvent e) {
ComponentValidator.getInstance(textComponent).ifPresent(function);
}
@Override
public void changedUpdate(DocumentEvent e) {
ComponentValidator.getInstance(textComponent).ifPresent(function);
}
});
}
private void updateAccessTokenLinkCommentText() {
String baseUrl = enterpriseUrlTextField.getText();
String settingsUrl = (baseUrl.endsWith("/") ? baseUrl : baseUrl + "/") + "settings";
enterpriseAccessTokenLinkComment.setText(
isUrlValid(baseUrl)
? "<html><body>or go to <a href=\""
+ settingsUrl
+ "\">"
+ settingsUrl
+ "</a> | \"Access tokens\" to create one.</body></html>"
: "");
}
private boolean isValidAccessToken(@NotNull String accessToken) {
return accessToken.isEmpty()
|| accessToken.length() == 40
|| (accessToken.startsWith("sgp_") && accessToken.length() == 44);
}
private boolean isUrlValid(@NotNull String url) {
return JsonSchemaConfigurable.isValidURL(url);
}
@NotNull
private JPanel createOtherSettingsPanel() {
JBLabel codebaseLabel = new JBLabel("Codebase:");
codebaseTextField = new JBTextField();
//noinspection DialogTitleCapitalization
codebaseTextField.getEmptyText().setText("github.com/sourcegraph/sourcegraph");
//// Always disabled for now
// areChatPredictionsEnabledCheckBox = new JBCheckBox("Experimental: Chat predictions");
// areChatPredictionsEnabledCheckBox.setEnabled(false);
//noinspection DialogTitleCapitalization
JPanel otherSettingsPanel =
FormBuilder.createFormBuilder()
.addLabeledComponent(codebaseLabel, codebaseTextField)
.addTooltip("The name of the embedded repository that Cody will use to gather context")
.addTooltip("for its responses. This is automatically inferred from your Git metadata,")
.addTooltip("but you can use this option if you need to override the default.")
// .addComponent(areChatPredictionsEnabledCheckBox, 10)
// .addTooltip("Adds suggestions of possible relevant messages in the chat window")
.getPanel();
otherSettingsPanel.setBorder(
IdeBorderFactory.createTitledBorder("Other Settings", true, JBUI.insetsTop(8)));
return otherSettingsPanel;
}
}

View File

@ -1,130 +0,0 @@
package com.sourcegraph.cody.config;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** Provides controller functionality for application settings. */
public class SettingsConfigurableHelper {
public static boolean isModified(
@Nullable Project project, @NotNull SettingsComponent newSettings) {
CodyService oldSettings =
project != null
? CodyProjectService.getInstance(project)
: CodyApplicationService.getInstance();
return !newSettings
.getInstanceType()
.toString()
.equals(
oldSettings.getInstanceType() != null
? oldSettings.getInstanceType()
: SettingsComponent.InstanceType.DOTCOM.toString())
|| !(newSettings.getDotcomAccessToken().equals(oldSettings.getDotcomAccessToken())
|| newSettings.getDotcomAccessToken().isEmpty()
&& oldSettings.getDotcomAccessToken() == null)
|| !newSettings
.getEnterpriseUrl()
.equals(oldSettings.getEnterpriseUrl() != null ? oldSettings.getEnterpriseUrl() : "")
|| !(newSettings.getEnterpriseAccessToken().equals(oldSettings.getEnterpriseAccessToken())
|| newSettings.getEnterpriseAccessToken().isEmpty()
&& oldSettings.getEnterpriseAccessToken() == null)
|| !newSettings
.getCustomRequestHeaders()
.equals(
oldSettings.getCustomRequestHeaders() != null
? oldSettings.getCustomRequestHeaders()
: "")
|| !newSettings
.getCodebase()
.equals(oldSettings.getCodebase() != null ? oldSettings.getCodebase() : "")
|| newSettings.areChatPredictionsEnabled()
!= Boolean.TRUE.equals(oldSettings.areChatPredictionsEnabled());
}
public static void apply(@Nullable Project project, @NotNull SettingsComponent settings) {
// Get message bus and publisher
MessageBus bus =
project != null
? project.getMessageBus()
: ApplicationManager.getApplication().getMessageBus();
PluginSettingChangeActionNotifier publisher =
bus.syncPublisher(PluginSettingChangeActionNotifier.TOPIC);
// Select settings service: application or project
CodyService apSettings =
project != null
? CodyProjectService.getInstance(project)
: CodyApplicationService.getInstance();
// Get old and new settings
String oldDotcomAccessToken = ConfigUtil.getDotcomAccessToken(project);
String oldEnterpriseUrl = ConfigUtil.getSourcegraphUrl(project);
String oldEnterpriseAccessToken = ConfigUtil.getEnterpriseAccessToken(project);
String newDotcomAccessToken = settings.getDotcomAccessToken();
String newEnterpriseUrl = settings.getEnterpriseUrl();
String newEnterpriseAccessToken = settings.getEnterpriseAccessToken();
String newCustomRequestHeaders = settings.getCustomRequestHeaders();
// Create context
PluginSettingChangeContext context =
new PluginSettingChangeContext(
oldDotcomAccessToken,
oldEnterpriseUrl,
oldEnterpriseAccessToken,
newEnterpriseUrl,
newDotcomAccessToken,
newEnterpriseAccessToken,
newCustomRequestHeaders);
// Notify listeners
publisher.beforeAction(context);
// Update settings
String instanceTypeName = settings.getInstanceType().name();
apSettings.setInstanceType(
instanceTypeName.equals(SettingsComponent.InstanceType.ENTERPRISE.name())
|| !newDotcomAccessToken.equals("")
? instanceTypeName
: null);
apSettings.setDotcomAccessToken(!newDotcomAccessToken.equals("") ? newDotcomAccessToken : null);
apSettings.setEnterpriseUrl(!newEnterpriseUrl.equals("") ? newEnterpriseUrl : null);
apSettings.setEnterpriseAccessToken(
!newEnterpriseAccessToken.equals("") ? newEnterpriseAccessToken : null);
apSettings.setCustomRequestHeaders(settings.getCustomRequestHeaders());
apSettings.setCodebase(!settings.getCodebase().equals("") ? settings.getCodebase() : null);
apSettings.setChatPredictionsEnabled(settings.areChatPredictionsEnabled());
// Notify listeners
publisher.afterAction(context);
}
public static void reset(
@Nullable Project project, @NotNull SettingsComponent mySettingsComponent) {
CodyService settings =
project != null
? CodyProjectService.getInstance(project)
: CodyApplicationService.getInstance();
String instanceType = settings.getInstanceType();
mySettingsComponent.setInstanceType(
instanceType != null
? instanceType.equals(SettingsComponent.InstanceType.ENTERPRISE.name())
? SettingsComponent.InstanceType.ENTERPRISE
: SettingsComponent.InstanceType.DOTCOM
: SettingsComponent.InstanceType.DOTCOM);
String dotcomAccessToken = settings.getDotcomAccessToken();
mySettingsComponent.setDotcomAccessToken(dotcomAccessToken != null ? dotcomAccessToken : "");
mySettingsComponent.setEnterpriseUrl(settings.getEnterpriseUrl());
String enterpriseAccessToken = settings.getEnterpriseAccessToken();
mySettingsComponent.setEnterpriseAccessToken(
enterpriseAccessToken != null ? enterpriseAccessToken : "");
mySettingsComponent.setCustomRequestHeaders(
settings.getCustomRequestHeaders() != null ? settings.getCustomRequestHeaders() : "");
String codebase = settings.getCodebase();
mySettingsComponent.setCodebase(codebase != null ? codebase : "");
mySettingsComponent.setAreChatPredictionsEnabled(
settings.areChatPredictionsEnabled() != null
&& Boolean.TRUE.equals(settings.areChatPredictionsEnabled()));
}
}

View File

@ -1,48 +0,0 @@
package com.sourcegraph.cody.telemetry;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Event {
final String eventName;
final String anonymousUserId;
final String url;
final JsonObject eventProperties;
/**
* PRIVACY: Do NOT include any potentially private information, such as search queries or
* repository names.
*/
final JsonObject publicArgument;
public Event(
@NotNull String eventName,
@NotNull String anonymousUserId,
@NotNull String url,
@Nullable JsonObject eventProperties,
@Nullable JsonObject publicArgument) {
this.eventName = eventName;
this.anonymousUserId = anonymousUserId;
this.url = url;
this.eventProperties = eventProperties;
this.publicArgument = publicArgument;
}
public JsonObject toJson() {
JsonObject returnValue = new JsonObject();
returnValue.addProperty("event", this.eventName);
returnValue.addProperty("userCookieID", this.anonymousUserId);
returnValue.addProperty("url", this.url);
returnValue.addProperty("source", "IDEEXTENSION");
returnValue.addProperty("referrer", "CODY-JETBRAINS");
if (eventProperties != null) {
returnValue.add("argument", eventProperties);
}
if (publicArgument != null) {
returnValue.add("publicArgument", publicArgument);
}
returnValue.addProperty("deviceID", this.anonymousUserId);
return returnValue;
}
}

View File

@ -1,97 +0,0 @@
package com.sourcegraph.cody.telemetry;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.sourcegraph.api.GraphQlClient;
import com.sourcegraph.cody.config.ConfigUtil;
import com.sourcegraph.cody.config.SettingsComponent;
import java.io.IOException;
import java.util.function.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class GraphQlLogger {
private static final Logger logger = Logger.getInstance(GraphQlLogger.class);
public static void logInstallEvent(
@NotNull Project project, @NotNull Consumer<Boolean> callback) {
String anonymousUserId = ConfigUtil.getAnonymousUserId();
if (anonymousUserId != null) {
Event event =
new Event(
"CodyInstalled", anonymousUserId, ConfigUtil.getSourcegraphUrl(project), null, null);
logEvent(project, event, (responseStatusCode) -> callback.accept(responseStatusCode == 200));
}
}
public static void logUninstallEvent(@NotNull Project project) {
String anonymousUserId = ConfigUtil.getAnonymousUserId();
if (anonymousUserId != null) {
Event event =
new Event(
"CodyUninstalled",
anonymousUserId,
ConfigUtil.getSourcegraphUrl(project),
null,
null);
logEvent(project, event, null);
}
}
// TODO: Use this
public static void logSearchDuration(@NotNull Project project, long duration) {
String anonymousUserId = ConfigUtil.getAnonymousUserId();
if (anonymousUserId != null) {
JsonObject durationObject = new JsonObject();
durationObject.addProperty("duration", duration);
Event event =
new Event(
"CodyJetBrainsExtension:keywordContext:searchDuration",
anonymousUserId,
ConfigUtil.getSourcegraphUrl(project),
durationObject,
durationObject);
logEvent(project, event, null);
}
}
// This could be exposed later (as public), but currently, we don't use it externally.
private static void logEvent(
@NotNull Project project, @NotNull Event event, @Nullable Consumer<Integer> callback) {
String instanceUrl = ConfigUtil.getSourcegraphUrl(project);
String accessToken =
ConfigUtil.getInstanceType(project) == SettingsComponent.InstanceType.ENTERPRISE
? ConfigUtil.getEnterpriseAccessToken(project)
: ConfigUtil.getDotcomAccessToken(project);
String customRequestHeaders = ConfigUtil.getCustomRequestHeaders(project);
new Thread(
() -> {
String query =
"mutation LogEvents($events: [Event!]) {"
+ " logEvents(events: $events) { "
+ " alwaysNil"
+ " }"
+ "}";
JsonArray events = new JsonArray();
events.add(event.toJson());
JsonObject variables = new JsonObject();
variables.add("events", events);
try {
int responseStatusCode =
GraphQlClient.callGraphQLService(
instanceUrl, accessToken, customRequestHeaders, query, variables)
.getStatusCode();
if (callback != null) {
callback.accept(responseStatusCode);
}
} catch (IOException e) {
logger.info(e);
}
})
.start();
}
}

View File

@ -1,56 +0,0 @@
package com.sourcegraph.cody.telemetry;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginInstaller;
import com.intellij.ide.plugins.PluginStateListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import com.sourcegraph.cody.config.ConfigUtil;
import com.sourcegraph.cody.config.SettingsChangeListener;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
public class PostStartupActivity implements StartupActivity.DumbAware {
private static String generateAnonymousUserId() {
return UUID.randomUUID().toString();
}
@Override
public void runActivity(@NotNull Project project) {
// Make sure that SettingsChangeListener is loaded
project.getService(SettingsChangeListener.class);
// When no anonymous user ID is set yet, we create a new one and treat this as an installation
// event.
// This likely means that the user has never started IntelliJ with our extension before
if (ConfigUtil.getAnonymousUserId() == null) {
ConfigUtil.setAnonymousUserId(generateAnonymousUserId());
}
PluginInstaller.addStateListener(
new PluginStateListener() {
public void install(@NotNull IdeaPluginDescriptor ideaPluginDescriptor) {
GraphQlLogger.logInstallEvent(
project,
(wasSuccessful) -> {
if (wasSuccessful) {
ConfigUtil.setInstallEventLogged(true);
}
});
}
@Override
public void uninstall(@NotNull IdeaPluginDescriptor ideaPluginDescriptor) {
if (ideaPluginDescriptor.getPluginId().getIdString().equals("com.sourcegraph.cody")) {
GraphQlLogger.logUninstallEvent(project);
// Clearing this so that we can detect a new installation if the user re-enables the
// extension.
ConfigUtil.setAnonymousUserId(null);
ConfigUtil.setInstallEventLogged(false);
}
}
});
}
}

View File

@ -1,57 +0,0 @@
<idea-plugin>
<id>com.sourcegraph.cody</id>
<name>Cody</name>
<vendor email="hi@sourcegraph.com" url="https://sourcegraph.com">Sourcegraph</vendor>
<idea-version since-build="211.0"/>
<depends>com.intellij.modules.platform</depends>
<extensions defaultExtensionNs="com.intellij">
<projectService serviceImplementation="com.sourcegraph.cody.config.CodyProjectService"/>
<projectService serviceImplementation="com.sourcegraph.cody.config.SettingsChangeListener"/>
<applicationService serviceImplementation="com.sourcegraph.cody.config.CodyApplicationService"/>
<projectConfigurable
parentId="tools"
instance="com.sourcegraph.cody.config.ProjectSettingsConfigurable"
id="com.sourcegraph.cody.config.ProjectSettingsConfigurable"
displayName="Cody by Sourcegraph (Project Settings)"
/>
<applicationConfigurable
parentId="tools"
instance="com.sourcegraph.cody.config.ApplicationSettingsConfigurable"
id="com.sourcegraph.cody.config.ApplicationSettingsConfigurable"
displayName="Cody by Sourcegraph"
/>
<notificationGroup id="Cody errors" displayType="BALLOON"/>
<notificationGroup id="Sourcegraph access" displayType="BALLOON"/>
<notificationGroup id="Cody plugin updates" displayType="STICKY_BALLOON"/>
<toolWindow
id="Cody"
icon="/icons/codyLogo.svg"
anchor="left"
secondary="false"
factoryClass="com.sourcegraph.cody.CodyToolWindowFactory"/>
<notificationGroup id="Cody Sourcegraph access" displayType="BALLOON"/>
<postStartupActivity implementation="com.sourcegraph.cody.telemetry.PostStartupActivity"/>
<postStartupActivity implementation="com.sourcegraph.cody.config.NotificationActivity"/>
<!-- Code completions -->
<applicationService serviceImplementation="com.sourcegraph.cody.completions.CodyCompletionsManager"/>
<editorFactoryListener implementation="com.sourcegraph.cody.completions.CodyEditorFactoryListener"/>
</extensions>
<actions>
<action
id="cody.CodyAction"
class="com.sourcegraph.cody.CodyAction"
text="Open Cody"
description="Opens Cody sidebar"
icon="/icons/codyLogo.svg">
</action>
<!-- Code completions -->
<action id="cody.acceptCompletion" class="com.sourcegraph.cody.completions.AcceptCodyCompletionAction">
<keyboard-shortcut first-keystroke="TAB" keymap="$default"/>
<override-text place="MainMenu" text="Accept Completion"/>
</action>
</actions>
</idea-plugin>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="195" height="176" viewBox="0 0 195 176" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M141.819 -8.93872e-07C152.834 -4.002e-07 161.763 9.02087 161.763 20.1487L161.763 55.9685C161.763 67.0964 152.834 76.1172 141.819 76.1172C130.805 76.1172 121.876 67.0963 121.876 55.9685L121.876 20.1487C121.876 9.02087 130.805 -1.38754e-06 141.819 -8.93872e-07Z" fill="#FF5543"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5111 47.0133C15.5111 35.8855 24.44 26.8646 35.4543 26.8646H70.9088C81.9231 26.8646 90.8519 35.8855 90.8519 47.0133C90.8519 58.1411 81.9231 67.162 70.9088 67.162H35.4543C24.44 67.162 15.5111 58.1411 15.5111 47.0133Z" fill="#A112FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M189.482 105.669C196.58 112.482 196.868 123.818 190.125 130.989L183.85 137.662C134.75 189.88 51.971 188.579 4.50166 134.844C-2.01751 127.464 -1.38097 116.142 5.92343 109.556C13.2278 102.97 24.434 103.613 30.9532 110.993C64.6181 149.101 123.324 150.024 158.146 112.991L164.42 106.318C171.164 99.1472 182.384 98.8565 189.482 105.669Z" fill="#00CBEC"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -26,6 +26,17 @@ New issues and feature requests can be filed through our [issue tracker](https:/
- Run the plugin in a sandboxed IDE by running `./gradlew :runIde`. This will start the platform with the versions defined in `gradle.properties`, [here](https://github.com/sourcegraph/sourcegraph/blob/main/client/jetbrains/gradle.properties#L14-L16).
- Note: 2021.3 or later is required for Macs with Apple Silicon chips.
- Build a deployable plugin artifact by running `./gradlew buildPlugin`. The output file is `build/distributions/Sourcegraph.zip`.
- Reformat the codebase with `./gradlew spotlessApply`.
- Install the google-java-format plugin
https://plugins.jetbrains.com/plugin/8527-google-java-format and configure
IntelliJ's file save actions to format.
- Set the environment variable `CODY_COMPLETIONS_ENABLED=true` to enable inline code completions.
- Ensure `src login` is logged into your sourcegraph.com account. This avoids
the need to manually configure the access token in the UI every time you run
`./gradlew :runIde`.
- If you are using an M1 MacBook and get a JCEF-related error using the "Find with Sourcegraph" command, try
running `./gradlew -PplatformVersion=221.5080.210 :runIde` instead.
See https://youtrack.jetbrains.com/issue/IDEA-291946 for more details.
## Publishing a new version

View File

@ -10,10 +10,10 @@ import com.sourcegraph.cody.api.Speaker;
import com.sourcegraph.cody.chat.Chat;
import com.sourcegraph.cody.chat.ChatBubble;
import com.sourcegraph.cody.chat.ChatMessage;
import com.sourcegraph.cody.config.ConfigUtil;
import com.sourcegraph.cody.config.SettingsComponent;
import com.sourcegraph.cody.editor.EditorContextGetter;
import com.sourcegraph.cody.recipes.RecipeRunner;
import com.sourcegraph.config.ConfigUtil;
import com.sourcegraph.config.SettingsComponent;
import java.awt.*;
import java.awt.event.AdjustmentListener;
import java.util.ArrayList;
@ -168,6 +168,7 @@ class CodyToolWindowContent implements UpdatableChat {
isEnterprise
? ConfigUtil.getEnterpriseAccessToken(project)
: ConfigUtil.getDotcomAccessToken(project);
System.out.println("isEnterprise: " + isEnterprise);
var chat = new Chat("", instanceUrl, accessToken != null ? accessToken : "");
ArrayList<String> contextFiles =

View File

@ -15,9 +15,9 @@ import com.intellij.util.concurrency.annotations.RequiresEdt;
import com.sourcegraph.cody.CodyCompatibility;
import com.sourcegraph.cody.api.CompletionsService;
import com.sourcegraph.cody.completions.prompt_library.*;
import com.sourcegraph.cody.config.ConfigUtil;
import com.sourcegraph.cody.config.SettingsComponent;
import com.sourcegraph.cody.vscode.*;
import com.sourcegraph.config.ConfigUtil;
import com.sourcegraph.config.SettingsComponent;
import java.util.Optional;
import java.util.concurrent.*;
import org.jetbrains.annotations.NotNull;
@ -178,6 +178,8 @@ public class CodyCompletionsManager {
if (accessToken == null) {
throw new IllegalArgumentException("ACCESS_TOKEN is null");
}
System.out.println("ENDPOINT " + srcEndpoint);
System.out.println("ACCESS_TOKEN " + accessToken);
return new CompletionsService(instanceUrl, accessToken);
}

Some files were not shown because too many files have changed in this diff Show More