Skip to content
Merged
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
25 changes: 14 additions & 11 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# Dependabot configuration:
# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2

multi-ecosystem-groups:
plugin-dependencies:
target-branch: "dev"
schedule:
interval: "weekly"

updates:
# Maintain dependencies for Gradle dependencies
- package-ecosystem: "gradle"
directory: "/"
target-branch: "main"
schedule:
interval: "weekly"
# Maintain dependencies for GitHub Actions
patterns:
- "*"
multi-ecosystem-group: "plugin-dependencies"

- package-ecosystem: "github-actions"
directory: "/"
target-branch: "main"
schedule:
interval: "weekly"
patterns:
- "*"
multi-ecosystem-group: "plugin-dependencies"
48 changes: 33 additions & 15 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
tag:
description: Release tag. Empty means today's vYYYY.M.D.
description: Release tag. Empty means today's YYYY.M.D.
required: false
type: string
dry_run:
Expand Down Expand Up @@ -81,20 +81,25 @@ jobs:
release_tag=""
target_version="$plugin_version"
if [ "$release" = "true" ]; then
if [ -n "$INPUT_TAG" ]; then
release_tag="$INPUT_TAG"
input_tag="$INPUT_TAG"
case "$input_tag" in
v*) input_tag="${input_tag#v}" ;;
esac

if [ -n "$input_tag" ]; then
release_tag="$input_tag"
else
year="$(date -u +%Y)"
month="$(date -u +%m | sed 's/^0//')"
day="$(date -u +%d | sed 's/^0//')"
release_tag="v$year.$month.$day"
release_tag="$year.$month.$day"
fi

if ! printf '%s\n' "$release_tag" | grep -Eq '^v[0-9]{4}[.][1-9][0-9]?[.][1-9][0-9]?$'; then
echo "Tag must look like v2026.5.20: $release_tag" >&2
if ! printf '%s\n' "$release_tag" | grep -Eq '^[0-9]{4}[.][1-9][0-9]?[.][1-9][0-9]?$'; then
echo "Tag must look like 2026.5.20: $release_tag" >&2
exit 1
fi
target_version="${release_tag#v}"
target_version="$release_tag"
fi

echo "event=$GITHUB_EVENT_NAME"
Expand Down Expand Up @@ -124,7 +129,7 @@ jobs:

- name: ♻️ Restore cache
id: cache
uses: actions/cache/restore@v4
uses: actions/cache/restore@v5
with:
path: |
~/.gradle/caches/transforms-*
Expand All @@ -140,6 +145,12 @@ jobs:
distribution: temurin
java-version: 25

- name: 🐳 Check Docker
shell: sh
run: |
docker version
docker info

- name: 🏷️ Prepare release metadata
if: steps.plan.outputs.release == 'true'
shell: sh
Expand Down Expand Up @@ -254,7 +265,10 @@ jobs:
env:
RELEASE_TAG: ${{ steps.plan.outputs.tag }}
run: |
version="${RELEASE_TAG#v}"
version="$RELEASE_TAG"
case "$version" in
v*) version="${version#v}" ;;
esac
awk -v version="$version" '
$0 ~ "^## \\[" version "\\]" { found = 1; next }
found && $0 ~ /^## / { exit }
Expand Down Expand Up @@ -301,11 +315,11 @@ jobs:
fi
curl "$@" https://plugins.jetbrains.com/api/updates/upload

- name: 📤 Push release commit and tag
- name: 📤 Push release commit
id: release_source
if: steps.plan.outputs.release == 'true' && steps.plan.outputs.dry_run != 'true'
shell: sh
env:
RELEASE_TAG: ${{ steps.plan.outputs.tag }}
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
git config user.name "Kira"
Expand All @@ -316,9 +330,9 @@ jobs:
fi

target_branch="${GITHUB_REF_NAME:-main}"
release_target="$(git rev-parse HEAD)"
git push origin "HEAD:$target_branch"
git tag -a "$RELEASE_TAG" -m "$RELEASE_TAG [skip ci]"
git push origin "refs/tags/$RELEASE_TAG"
echo "target=$release_target" >> "$GITHUB_OUTPUT"

- name: 🚀 Create GitHub release
if: steps.plan.outputs.release == 'true' && steps.plan.outputs.dry_run != 'true'
Expand All @@ -327,18 +341,22 @@ jobs:
ARCHIVE_PATH: ${{ steps.archive.outputs.path }}
GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }}
RELEASE_TAG: ${{ steps.plan.outputs.tag }}
RELEASE_TARGET: ${{ steps.release_source.outputs.target }}
run: |
if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release upload "$RELEASE_TAG" "$ARCHIVE_PATH" --clobber
gh release edit "$RELEASE_TAG" --title "$RELEASE_TAG" --notes-file release-notes.md
else
gh release create "$RELEASE_TAG" "$ARCHIVE_PATH" --title "$RELEASE_TAG" --notes-file release-notes.md --verify-tag
if ! gh release create "$RELEASE_TAG" "$ARCHIVE_PATH" --title "$RELEASE_TAG" --notes-file release-notes.md --target "$RELEASE_TARGET"; then
gh release delete "$RELEASE_TAG" --yes --cleanup-tag >/dev/null 2>&1 || true
exit 1
fi
fi

- name: 💾 Save cache
if: success() && github.event_name != 'pull_request' && steps.cache.outputs.cache-hit != 'true'
continue-on-error: true
uses: actions/cache/save@v4
uses: actions/cache/save@v5
with:
path: |
~/.gradle/caches/transforms-*
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,31 @@

## [Unreleased]

### Plugin Wiring

- Simplified workflow syntax routing for completion, highlighting, references, and documentation.
- Reduced duplicated workflow run, action cache, and schema handling internals while keeping behavior stable.
- Reorganized plugin internals into fewer `Workflow*` service entry points, with public service Javadocs where humans
might actually read them.
- Added the plugin size refactor plan and documented the release/changelog flow.
- Release automation now uses plain date tags, avoids duplicated Marketplace change-note headings, and groups Dependabot
dependency updates into one weekly PR against `dev`.
- Updated the IntelliJ test platform, JaCoCo, and GitHub Actions cache action to current stable metadata.
- Fixed the README build badge link and refreshed navigation/release docs.
- `.gitea/workflows/*` files now get their own light/dark Gitea-flavored file icon instead of cosplaying GitHub.
- Gitea workflow runs now use `GITEA_TOKEN`-style auth, clean browser links, and repo-level run discovery for `/api/v1`.
- `.gitea/workflows/*` syntax now uses Gitea permission scopes and cron aliases instead of GitHub-only scope clutter.
- `.gitea/workflows/*` completion and validation now know `GITEA_TOKEN`, Gitea runner env vars, single-label `runs-on`,
documented expression functions, and job keys Gitea accepts but ignores.

## [2026.5.29] - 2026-05-29

### Release Polish

- Marketplace change notes skip the duplicated version heading.
- Future GitHub release tags use plain date versions without a leading `v`.
- Dependabot dependency bumps are grouped into one weekly cross-ecosystem PR against `dev`.

## [2026.5.23] - 2026-05-23

### Fresh Start
Expand Down
46 changes: 29 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

*Your Ultimate Wingman for GitHub Workflows and Actions! 🚀*

![Build](https://github.com/YunaBraska/github-workflow-plugin/workflows/Build/badge.svg)
[![Build](https://github.com/YunaBraska/github-workflow-plugin/actions/workflows/build.yml/badge.svg)](https://github.com/YunaBraska/github-workflow-plugin/actions/workflows/build.yml)
[![Version](https://img.shields.io/jetbrains/plugin/v/21396-github-workflow.svg)](https://plugins.jetbrains.com/plugin/21396-github-workflow)
[![Downloads](https://img.shields.io/jetbrains/plugin/d/21396-github-workflow.svg)](https://plugins.jetbrains.com/plugin/21396-github-workflow)
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/YunaBraska)
Expand Down Expand Up @@ -66,38 +66,50 @@ _[See Screenshots](https://plugins.jetbrains.com/plugin/21396-github-workflow)_
matching IDE accounts first, then other IDE GitHub accounts, then `GITHUB_TOKEN`, `GH_TOKEN`, `GITHUB_PAT`, then
anonymous access. An optional token environment variable can still be set explicitly for custom setups. GitHub log
timestamps, groups, command markers, and ANSI color codes are compacted before display.
* **Usage**: Enjoy autocomplete, syntax highlighting, and much more as you code your GitHub Workflows and Actions.
* **Usage**: Enjoy autocomplete, syntax highlighting, and much more as you code GitHub or Gitea Workflows and Actions.

## Local Development

The project uses the Gradle wrapper and Java 25. No manual JetBrains JDK path is needed; the IntelliJ Platform Gradle
Plugin downloads the IDE, bundled plugins, verifier, and test runtime.

1. Install Java 25 and make it available as `java`.
2. Run `./gradlew test` for the fast regression suite.
2. Run `./gradlew test` for the regression suite, including the Docker-backed Gitea smoke test.
3. Run `./gradlew check verifyPlugin buildPlugin` before publishing or opening a release PR.

## Release Automation

One GitHub Actions workflow runs for branch pushes, PRs, and manual dispatches. It has one job and one cache. Branch and
PR runs do the normal test/package pass. A merge to `main`, or a manual workflow run, prepares the date-based version,
runs the full checks and Plugin Verifier, publishes the plugin ZIP to GitHub Packages, uploads the same ZIP to
JetBrains Marketplace, pushes the release commit and tag, and creates the GitHub release.
Gitea smoke test controls:

The workflow prunes old GitHub Actions caches after a successful non-PR run so only the current pipeline cache remains.
```sh
./gradlew test --tests com.github.yunabraska.githubworkflow.git.GiteaDockerIntegrationTest --rerun-tasks
GITEA_DOCKER_TEST=false ./gradlew test
```

Required repository secrets:
That starts the official rootless Gitea Docker image, seeds a tiny repository, and checks action plus `.gitea/workflows`
metadata through the same remote resolver. Set `GITEA_DOCKER_TEST=false` to skip it locally, or override the image with
`GITEA_IMAGE` when testing another Gitea release. If `docker` is not on the Gradle process `PATH`, set
`GITEA_DOCKER_BIN`, `DOCKER_BIN`, or `DOCKER_CLI` to the Docker executable; the test also tries `command -v docker`,
`which docker`, `where docker`, and common Docker Desktop/Homebrew locations.

* `PUBLISH_TOKEN`
## Release Automation

Optional repository secret:
One workflow handles tagging, packaging, GitHub Packages, Marketplace publishing, changelog notes, and GitHub releases.
It intentionally uses one job and one cache because the IntelliJ build/test setup can eat roughly 10 GB; repeating that
across jobs is how CI becomes a very expensive space heater.

* `RELEASE_TOKEN` - lets the workflow push the release commit and tag with a dedicated token. Without it, `GITHUB_TOKEN`
is used.
Flow:

Optional repository variable:
1. Branch pushes and PRs run tests and build the plugin ZIP.
2. A merge to `main`, or a manual workflow run, switches the same job into release mode.
3. The job computes a plain date tag such as `2026.5.29` and updates `pluginVersion`.
4. It creates the matching `CHANGELOG.md` section from `## [Unreleased]` when needed.
5. It runs `check`, Plugin Verifier, and `buildPlugin`.
6. It publishes the ZIP to GitHub Packages, then uploads the same ZIP to JetBrains Marketplace.
7. Only after publishing succeeds, it pushes the release commit and tag, then creates or updates the GitHub release.
8. A successful non-PR run saves the current cache and prunes older GitHub Actions caches.

* `MARKETPLACE_CHANNEL` - empty means the default stable Marketplace channel.
`PUBLISH_TOKEN` is required for Marketplace upload. `RELEASE_TOKEN` is optional; without it, the workflow uses
`GITHUB_TOKEN` for the release commit, tag, and GitHub release. `MARKETPLACE_CHANNEL` is optional and empty means the
stable channel.

For manual IDE testing, run `./gradlew runIde`. The default target tracks the latest stable IntelliJ IDEA platform that
the Gradle tooling can resolve (`platformVersion` in `gradle.properties`). The first run downloads IDE artifacts and can
Expand Down
7 changes: 4 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ tasks.register('generateGitHubDocsData') {
}

jacoco {
toolVersion = '0.8.13'
toolVersion = '0.8.15'
}

jacocoTestReport {
Expand All @@ -261,8 +261,9 @@ intellijPlatform {
name = requiredProperty('pluginName')
version = requiredProperty('pluginVersion')
description = requiredProperty('pluginDescription')
changeNotes = provider {
changelog.renderItem(changelog.getLatest(), Changelog.OutputType.HTML)
changeNotes = providers.gradleProperty('pluginVersion').map { pluginVersion ->
def item = changelog.has(pluginVersion) ? changelog.get(pluginVersion) : changelog.getLatest()
changelog.renderItem(item.withHeader(false).withEmptySections(false), Changelog.OutputType.HTML)
}

ideaVersion {
Expand Down
7 changes: 7 additions & 0 deletions doc/adr/0002-configurable-remote-action-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@ tokens.
Use a JDK fake HTTP server in tests for GitHub Enterprise-shaped API behavior. Tests may inject temporary server
definitions directly into the service; that is not a user-facing settings surface.

Reuse the same provider boundary for Gitea-compatible API behavior where possible. Gitea differs by using `/api/v1` and
`Authorization: token ...`, so tests cover that provider type explicitly. Do not add a Gitea account UI unless real
user-facing configuration becomes necessary.

## Consequences

Self-hosted GitHub action metadata can be resolved, linked, highlighted, styled, documented, and completed without
contacting public GitHub in tests.

Gitea action and `.gitea/workflows` metadata can be tested through fake `/api/v1` responses and a default-on Docker
smoke test without duplicating the GitHub resolver. `GITEA_DOCKER_TEST=false` keeps local escape hatches explicit.

The plugin stays boring: no duplicate account UI, no token storage, and fewer settings to test.

The provider currently resolves metadata and refs after a callable is known. It does not browse arbitrary remote
Expand Down
9 changes: 5 additions & 4 deletions doc/adr/0011-release-once-publish-zip.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ out.

## Decision

Use one workflow file with one job and one manually managed cache key.
Use one workflow file with one job and one manually managed cache key. IntelliJ test and verifier setup is large enough
that splitting the same release path across jobs duplicates heavyweight downloads and cache state.

The same job handles all modes:

- branch and PR runs execute the normal test/package path;
- a `main` push that is not the generated release commit executes the release path;
- a manual dispatch executes the release path, with optional dry-run support.

The release path prepares the version, runs the full checks and Plugin Verifier, publishes the plugin ZIP to GitHub
Packages, uploads the same ZIP directly to JetBrains Marketplace, pushes the release commit and tag, and creates or
updates the GitHub release.
The release path prepares the version and changelog, runs the full checks and Plugin Verifier, publishes the plugin ZIP
to GitHub Packages, uploads the same ZIP directly to JetBrains Marketplace, then pushes the release commit/tag and
creates or updates the GitHub release.

After a successful non-PR run, the job prunes every GitHub Actions cache entry except the current pipeline cache key.

Expand Down
30 changes: 19 additions & 11 deletions doc/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,36 @@ The plugin is intentionally plain Java with Gradle wrapper entrypoints. The usef

## Runtime Entry Points

- `CodeCompletion` handles workflow expressions, `uses`, `with`, secrets, shell values, local files, remote action refs,
and GitHub context/default environment completions.
- `HighlightAnnotator` handles editor diagnostics, symbol coloring, quick fixes, action update suggestions, and
- `WorkflowLocation.from(PsiElement)` is the shared PSI/YAML location for workflow keys, paths, files, repositories,
and branches.
- `WorkflowSyntax` owns workflow syntax completions, validation metadata, JSON schema hookup, file icons, and `run`
language injection.
- `WorkflowReferences` owns local PSI references, remote web references, and expression reference targets.
- `GitHubActionCache` is the cache boundary for action/reusable-workflow metadata, cache actions, warning restore, and
startup refresh.
- `WorkflowRun` is the remote workflow-run boundary: dispatch, cancel, rerun, delete, jobs, logs, artifacts, and branch
resolution.
- `WorkflowCompletion` handles workflow expressions, `uses`, `with`, secrets, shell values, local files, remote action refs,
and GitHub context/default environment completions through `WorkflowSyntax`, `WorkflowLocation`, and
`GitHubActionCache`.
- `WorkflowAnnotator` handles editor diagnostics, symbol coloring, quick fixes, action update suggestions, and
variable/run output highlighting.
- `ReferenceContributor` handles local PSI references and remote web references.
- `WorkflowDocumentationProvider` handles hover and quick documentation.
- `WorkflowRunLanguageInjector` injects shell-like languages into `run` blocks based on `shell`.
- `WorkflowRunConfigurationType` and related workflow-run classes handle workflow dispatch from the IDE Run tool window.
- `GitHubRequestAuthorizations` centralizes GitHub account, optional token-env fallback, and anonymous request ordering.
- `GitHubActionCache`, `RemoteActionProviders`, and `RemoteServerSettings` resolve and cache local/remote action and
reusable workflow metadata.
- `RemoteActionProviders` centralizes GitHub account, enterprise account, optional token-env fallback, anonymous request
ordering, and remote server settings.
- `WorkflowRunConfiguration` handles workflow dispatch from the IDE Run tool window.
- `GitHubWorkflowSettingsConfigurable` exposes the plugin settings page for language override, cache review/delete,
cache import/export, plugin cache size, and the tiny support button with suspicious amounts of caffeine energy.
- `WorkflowRunLogRenderer` compacts GitHub Actions logs into named blocks with `0001 |` line numbers, `run:` command
lines, ANSI cleanup, and warning/error classification for Run tool-window job consoles.
- `WorkflowRunView.LogRenderer` compacts GitHub Actions logs into named blocks with `0001 |` line numbers,
`run:` command lines, ANSI cleanup, and warning/error classification for Run tool-window job consoles.

## Tests

Editor behavior should be tested through IntelliJ fixture entrypoints. See:

- `doc/adr/0008-test-through-editor-and-runtime-boundaries.md`
- `doc/spec/editor-test-matrix.md`
- `doc/spec/gitea-github-actions-compatibility.md`

Remote GitHub behavior should use fake HTTP servers or explicit client boundaries. Network access in tests is guilty
until proven innocent.
Loading