Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,149 changes: 1,149 additions & 0 deletions .editorconfig

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.

## Pull Request Checklist
1) Create yout branch from the main branch
1) Create your branch from the main branch
2) Use [Semantic Commit Messages](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716)
3) Increase the version by using [Semantic Versioning](https://semver.org)
4) Ensure your changes are covered by tests
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2023 Yuna Morgenstern

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
// Java support
id("java")
// Gradle IntelliJ Plugin
id("org.jetbrains.intellij") version "1.15.0"
id("org.jetbrains.intellij") version "1.16.1"
// Gradle Changelog Plugin
id("org.jetbrains.changelog") version "2.0.0"
// Gradle Qodana Plugin
Expand Down
60 changes: 60 additions & 0 deletions docs/mark-outdated-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Mark outdated actions - plan
============================

## Requirement

In a GitHub workflow, actions used can be outdated, and should be marked as such.

## Solution

It is possible to check what is the latest version of an action, by checking the releases on its repository.
We can analyze the workflow yaml to extract the actions used, and check whether they are outdated.
If they are outdated, we can add a comment to the workflow yaml, to mark them as outdated and suggest to update them.

## Implementation steps

### Daniel

- [ ] method `String getLatestActionVersion(String actionName)` that receives an action name and returns the latest
release, make sure to cache the value for future use. (e.g., `actions/checkout` => `v3`)
- [ ] method `Boolean isActionOutdated(String actionName, String currentVersion)` that receives an action name and a
version (e.g. `actions/checkout` and `v2`) and returns whether the version is outdated or not. (
e.g. `actions/checkout` and `v2` => `true`)
- [ ] method `Map<String, String> getActions(String workflowYaml)` that receives a workflow yaml and returns the list of
actions used in it with the versions used (e.g. `actions/checkout` => `v2`)
- [ ] method `Map<String, String> getOutdatedActions(String workflowYaml)` that receives a workflow yaml and returns the
list of actions used in it that are outdated with the latest version (e.g. `actions/checkout` => `v3`)

Use GitHub graphql API to get the latest release tag of a repository:

```graphql
query {
repository(owner:"cunla", name:"ghactions-manager") {
latestRelease {
tag {
name
}
}
}
}
```

Result:
```json
{
"data": {
"repository": {
"latestRelease": {
"tag": {
"name": "v1.15.1"
}
}
}
}
}
```

### Yuna

- [ ] UI to mark outdated actions and add an action comment to update to the latest versions.

92 changes: 92 additions & 0 deletions docs/navigation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
Here is a short Navigation:

## General:

- Test Pipeline: Test Pipeline as the Tests itself are broken, JetBrains Test System cant work with async tasks out of
the box.
- Plugin Complexity: This i want to reduce! I am really sorry about the Plugin complexity, when i started it was much
easier but then is was also unstable as hell.
- No own objects & No Constants - I try to keep the number of own objects low, as i have seen memory leaks while
using custom objects! Looks like i always need to clean them up by myself for every Context like: open & close
Project, PsiElement…
- JetBrains does not like to have Read, Write, IO, Network traffic, Syntax Highlighting,… in the same thread. Thats
why i often need things like this:
- `ApplicationManager.getApplication().executeOnPooledThread`
- `ApplicationManager.getApplication().invokeLater`
- `ApplicationManager.getApplication().isUnitTestMode()`
- `ApplicationManager.getApplication().runReadAction`

## Package: [Services](https://github.com/YunaBraska/github-workflow-plugin/tree/main/src/main/java/com/github/yunabraska/githubworkflow/services):

These are the trigger and entry place to start looking at. These are the Extensions which are registered in
the [Plugin.xml](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/resources/META-INF/plugin.xml)

- [CodeCompletion](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/CodeCompletion.java) -
completes code. Its one of my first classes.
- [FileIconProvider](https://github.com/YunaBraska/github-workflow-plugin/blobmain/src/main/java/com/github/yunabraska/githubworkflow/services/FileIconProvider.java) -
Marks the files with an GitHub Icon
- [GitHubActionCache](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/GitHubActionCache.java) -
This might be interesting for you, as this is the core logic to have a GitHub Actions and Workflow cache over all
Projects
- Careful, i did only manage to store java maps, everything else is pretty hard to `serialize` and `deserialize`

- [HighlightAnnotator](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/HighlightAnnotator.java) -
Adds Syntax Highlighting and text formats for the Reference Contributor (It receives PsiElements which are in your
View or have been changed)
- [ReferenceContributor](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/ReferenceContributor.java) -
Adds References inline or external links to `Actions`, `Workflows` and now also on `Needs` (It receives
PsiElements which are in your View or have been changed)
- [PluginErrorReportSubmitter](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/PluginErrorReportSubmitter.java) -
Users can submit an issue on GitHub on any Exception - _(pretty simple and clear. We don’t need actions here)_
- [ProjectStartup](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/ProjectStartup.java) -
as it already tells, its the executor on Project Startup
- [SchemaProvider](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/SchemaProvider.java) -
It provides several GitHub YAML Schemas - _(pretty simple and clear. We don’t need actions here)_

## Package: [Logic](https://github.com/YunaBraska/github-workflow-plugin/tree/main/src/main/java/com/github/yunabraska/githubworkflow/logic):

a doubtful attempt to move some common PsiElements extraction to named classes and hopefully get a faster overview whats
going on.

- You will find the logic for Syntax Highlighting, Reference Contributor, Code Completion for each logical element
like `Action`, `Envs`, `GitHub`, `Inputs`, `Jobs`,…

## Package: [Helper](https://github.com/YunaBraska/github-workflow-plugin/tree/main/src/main/java/com/github/yunabraska/githubworkflow/helper):

Boring helper / utils classes

- [PsiElementHelper](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/helper/PsiElementHelper.java) -
A core logic to navigate through the PsiElements
- [GitHubWorkflowConfig](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/helper/GitHubWorkflowConfig.java) -
A core config, mostly about the descriptions of the PsiElements

## My next Plans:

- Creation of a `PreProcessor` to have only one place to parse PsiElements:
- Why:
The [HighlightAnnotator](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/HighlightAnnotator.java)
and [ReferenceContributor](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/ReferenceContributor.java)
are doing mostly the same operations
and [CodeCompletion](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/CodeCompletion.java)
is also doing partially the same things. This leads to duplicated code, complexity and context issues like i
mentioned
about same thread with different contexts (Read, Write, IO, Network traffic, Syntax Highlighting) which JetBrains
doesn’t like
- Cache: I would prefer to use the Build in cache for PsiElements
like: `PsiElement.getUserData()` & `PsiElement.putUserData()` This cache is managed by jetBrains and can
be
easily
picked up
by [HighlightAnnotator](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/HighlightAnnotator.java) & [ReferenceContributor](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/ReferenceContributor.java) & [CodeCompletion](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/CodeCompletion.java)
-
Trigger [HighlightAnnotator](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/HighlightAnnotator.java) & [ReferenceContributor](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/ReferenceContributor.java):
after the `PreProcessor` is done. Currently i only know how to trigger Syntax
Highlighting: [triggerSyntaxHighlightingForActiveFiles()](https://github.com/YunaBraska/github-workflow-plugin/blob/main/src/main/java/com/github/yunabraska/githubworkflow/services/GitHubActionCache.java)
- Trigger `Preprocessor` after FileChange: this should be simple and there should be a fixed delay for e.g. 5
seconds,
so that we are not spamming the `PreProcessor` after every typing.


## My Questions:
- Are you willing to migrate to Kotlin?
- Are you willing to consider
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ pluginRepositoryUrl = https://github.com/YunaBraska/github-workflow-plugin
pluginVersion = 3.2.1

# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 231
pluginSinceBuild = 232
# Not specifying until-build means it will include all future builds (including unreleased IDE versions, which might impact compatibility later).
#pluginUntilBuild = 231.*

# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension
platformType = IC
platformVersion = 2023.1
platformVersion = 2023.2.5

# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins = org.jetbrains.plugins.github,org.jetbrains.plugins.yaml

# Gradle Releases -> https://github.com/gradle/gradle/releases
gradleVersion = 8.0.2
gradleVersion = 8.5

# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib
# suppress inspection "UnusedProperty"
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@
public class AutoPopupInsertHandler<T extends LookupElement> implements InsertHandler<T> {
public static final AutoPopupInsertHandler<LookupElement> INSTANCE = new AutoPopupInsertHandler<>();

@Override
public void handleInsert(@NotNull final InsertionContext context, @NotNull final T item) {
AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null);
}

public static void addSuffix(final InsertionContext ctx, final LookupElement item, final char suffix) {
if (suffix != Character.MIN_VALUE) {
final String key = item.getLookupString();
Expand Down Expand Up @@ -65,4 +60,9 @@ private static String toInsertString(final char suffix, final CharSequence docum
}
return sb.toString();
}

@Override
public void handleInsert(@NotNull final InsertionContext context, @NotNull final T item) {
AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.util.io.HttpRequests;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiRequest;
Expand Down Expand Up @@ -36,10 +35,10 @@ private FileDownloader() {

public static String downloadFileFromGitHub(final String downloadUrl) {
return GHAccountsUtil.getAccounts().stream()
.map(account -> downloadFromGitHub(downloadUrl, account))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
.map(account -> downloadFromGitHub(downloadUrl, account))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}


Expand All @@ -56,7 +55,7 @@ public static String downloadContent(final String urlString) {
return "";
}

// @Nullable
// @Nullable
// public static String downloadSync(final String urlString, final String userAgent) {
// try {
// return HttpRequests
Expand All @@ -71,47 +70,47 @@ public static String downloadContent(final String urlString) {
// return null;
// }
// }
@Nullable
public static String downloadSync(final String urlString, final String userAgent) {
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) new URL(urlString).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(1000); // Connect timeout
connection.setReadTimeout(1000); // Read timeout
connection.setRequestProperty("User-Agent", userAgent);
connection.setRequestProperty("Client-Name", "GitHub Workflow Plugin");
@Nullable
public static String downloadSync(final String urlString, final String userAgent) {
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) new URL(urlString).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(1000); // Connect timeout
connection.setReadTimeout(1000); // Read timeout
connection.setRequestProperty("User-Agent", userAgent);
connection.setRequestProperty("Client-Name", "GitHub Workflow Plugin");

// Check for successful response code or throw error
if (connection.getResponseCode() / 100 != 2) {
throw new IOException("HTTP error code: " + connection.getResponseCode());
}
// Check for successful response code or throw error
if (connection.getResponseCode() / 100 != 2) {
throw new IOException("HTTP error code: " + connection.getResponseCode());
}

// Read response
try (final BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
final StringBuilder response = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine).append(System.lineSeparator());
// Read response
try (final BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
final StringBuilder response = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine).append(System.lineSeparator());
}
return response.toString();
}
} catch (final Exception e) {
// Handle exceptions accordingly, returning null is often not a good practice
return null;
} finally {
if (connection != null) {
connection.disconnect();
}
return response.toString();
}
} catch (final Exception e) {
// Handle exceptions accordingly, returning null is often not a good practice
return null;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}

private static String downloadFromGitHub(final String downloadUrl, final GithubAccount account) {
return ofNullable(ProjectUtil.getActiveProject())
.or(() -> Optional.of(ProjectManager.getInstance().getDefaultProject()))
.map(project -> GHCompatibilityUtil.getOrRequestToken(account, project))
.map(token -> downloadContent(downloadUrl, token))
.orElse(null);
.or(() -> Optional.of(ProjectManager.getInstance().getDefaultProject()))
.map(project -> GHCompatibilityUtil.getOrRequestToken(account, project))
.map(token -> downloadContent(downloadUrl, token))
.orElse(null);
}

private static String downloadContent(final String downloadUrl, final String token) {
Expand Down
Loading