diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 950534f..2c1ed1a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,12 @@ diff --git a/.github/release-notes-pr-description.md b/.github/release-notes-pr-description.md new file mode 100644 index 0000000..d80977f --- /dev/null +++ b/.github/release-notes-pr-description.md @@ -0,0 +1,14 @@ +Update changelog + +# Description +This PR is generated by the GitHub action and automatically updated when +Pr(s) are merged on master. + +It should stay in draft until we release. + +# Merging instruction +This pr must be merged last, just before releasing. + +1. edit the title of last release notes to change `NEXT_VERSION`by the actual version (you can do it in GitHub interface) +1. merge pr using **squashing** strategy +1. tag the `master` branch with the actual version (this will create a Github release and publish the plugin on Jetbrains store) \ No newline at end of file diff --git a/.github/release-notes.tmpl b/.github/release-notes.tmpl new file mode 100644 index 0000000..cb8eb90 --- /dev/null +++ b/.github/release-notes.tmpl @@ -0,0 +1,18 @@ +# Release notes for NEXT_VERSION + +{{with .NotesWithActionRequired -}} +## Urgent Upgrade Notes + +### (No, really, you MUST read this before you upgrade) + +{{range .}}{{println "-" .}} {{end}} +{{end}} + +{{- if .Notes -}} +## Changes by Kind +{{ range .Notes}} +### {{.Kind | prettyKind}} + +{{range $note := .NoteEntries }}{{println "-" $note}}{{end}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/.github/workflows/release_and_pulbish_plugin_on_tag.yml b/.github/workflows/release_and_pulbish_plugin_on_tag.yml new file mode 100644 index 0000000..a0a67a3 --- /dev/null +++ b/.github/workflows/release_and_pulbish_plugin_on_tag.yml @@ -0,0 +1,75 @@ +name: publish plugin on JB and create release on GH + +on: + push: + tags: ["v[0-9]+.[0-9]+.[0-9]+"] +jobs: + check-gradle-wrapper: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gradle/wrapper-validation-action@v1 + + publish_plugin: + runs-on: ubuntu-latest + needs: [check-gradle-wrapper] + strategy: + matrix: + platform-version: [ 201, 202 ] + env: + ORG_GRADLE_PROJECT_platformVersion: ${{ matrix.platform-version }} + ORG_GRADLE_PROJECT_publishChannel: dev #todo change that after test + ORG_GRADLE_PROJECT_publishToken: ${{ secrets.PUBLISH_TOKEN }} + steps: + # Cache gradle dependencies + - uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: publish plugin + run: | + ORG_GRADLE_PROJECT_pluginVersion="${GITHUB_REF/refs\/tags\//}" + ./gradlew :plugin:publishPlugin + + - name: Upload artifact + uses: actions/upload-artifact@v2.2.2 + with: + name: plugin-artifact + path: ./build/distributions/*.zip + retention-days: 1 + if-no-files-found: error + + create_github_release: + runs-on: ubuntu-latest + needs : [ publish_plugin ] + steps: + - uses: actions/checkout@v2 + - name: Download Artifact + uses: actions/download-artifact@v2 + id: download + with: + name: plugin-artifact + path: ./artifacts/ + + - name: create or update release note PR + env: + # Required for the `hub` CLI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${GITHUB_REF/refs\/tags\//}" + echo -e "${VERSION}\n" > gh_release_description.md + sed -e '0,/Release notes for v/d' -e '/Release notes for v/,$d' CHANGELOG.md >> gh_release_description.md + + assets='' + for file in $(ls ./artifacts/); do assets="${assets} -a ./artifacts/${file}"; done + echo "assets=${assets}" + + hub release create -F gh_release_description.md ${assets} "${VERSION}" diff --git a/.github/workflows/upset_release_notes_pr_on_push_on_master.yml b/.github/workflows/upset_release_notes_pr_on_push_on_master.yml new file mode 100644 index 0000000..2f1f802 --- /dev/null +++ b/.github/workflows/upset_release_notes_pr_on_push_on_master.yml @@ -0,0 +1,27 @@ +name: Create or update release notes PR + +on: + push: + branches: [ master ] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + upset_release_notes_pr: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + # needed to be able to resolve commit of previous version + fetch-depth: 0 + - uses: actions/setup-go@v2 + with: + go-version: "1.16" + - name: Download release-note tool + run: GO111MODULE=on go get k8s.io/release/cmd/release-notes@v0.7.0 + + - name: create or update release note PR + env: + # Required for the `hub` CLI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./hack/create_or_update_release_notes_pr.sh diff --git a/.gitignore b/.gitignore index 3b86c2a..4a76a18 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,10 @@ build/ gen/ deps +# MacOS files .DS_Store +# release-notes file +next-release-notes.md +tmp_changelog.md +gh_release_description diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..476b5d1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,121 @@ +# Release notes for v0.5.0 + +## Changes by Kind + +### Refactoring + +- Grammar: rename rules: + - `expr` to `literal-expr` + - `expr2` to `expr` ([#93](https://github.com/open-policy-agent/opa-idea-plugin/pull/93), [@vgramer](https://github.com/vgramer)) +- Remove references to old repo `vgramer/opa-idea-plugin`. The repository has been transferred to `open-policy-agent` organization ([#83](https://github.com/open-policy-agent/opa-idea-plugin/pull/83), [@vgramer](https://github.com/vgramer)) + +### Bug or Regression + +- Grammar: allow factor expression (ie parenthesis ). These expressions were passed as an error: + - `a4:= (1 - 3) - (2 +5)` + - `reverse(l) = [l[j] | _ = l[i]; j := (count(l) - 1) - i]` ([#92](https://github.com/open-policy-agent/opa-idea-plugin/pull/92), [@vgramer](https://github.com/vgramer)) +- Grammar: allow complex expression as array index. These expressions were parsed as an error: + - `x:= x[minus(count(x),1)]` + - `index_last(l, x) = t[minus(count(t), 1)] { #something} else = -1 { # something}` + - `rule1{ x:= x[count(x) - 1)] }` ([#91](https://github.com/open-policy-agent/opa-idea-plugin/pull/91), [@vgramer](https://github.com/vgramer)) +- Grammar: allow complex expression for array and object value. these expressions were parsed as an error: + - `arr7 := [1 + 2 - 4, count(arr6) / abs(arr5[0])` + - `a6 := { a: 1 > 2, b: { c: object.get(a2, a, default) + abs(c) - 2 }}` ([#90](https://github.com/open-policy-agent/opa-idea-plugin/pull/90), [@vgramer](https://github.com/vgramer)) +- Grammar: allow empty query in else clause. These expressions were reported as an error + - `foo = true { input.x < input.y } else = false` + - `foo = true { false } else = { true }` ([#85](https://github.com/open-policy-agent/opa-idea-plugin/pull/85), [@vgramer](https://github.com/vgramer)) + + +# Release notes for v0.4.0 + +## Changes by Kind + +### Feature + +- Implement auto closing quote feature ([#69](https://github.com/open-policy-agent/opa-idea-plugin/pull/69), [@vgramer](https://github.com/vgramer)) +- Run [intellij-plugin-verifier](https://github.com/JetBrains/intellij-plugin-verifier) to check plugin binary compatibility in github action + + 1. update `org.jetbrains.intellij` Gradle plugin because the new version offers a task to run the plugin verifier. Consequently, remove the `ideaDependencyCachePath`customization which is not needed anymore. + 2. add a job to run plugin verifier ([#62](https://github.com/open-policy-agent/opa-idea-plugin/pull/62), [@vgramer](https://github.com/vgramer)) + +### Bug or Regression + +- Fix tests for github action and macOS Big Sur ([#73](https://github.com/open-policy-agent/opa-idea-plugin/pull/73), [@vgramer](https://github.com/vgramer)) +- Grammar: allow import between rules and complex expression in else statement ([#80](https://github.com/open-policy-agent/opa-idea-plugin/pull/80), [@vgramer](https://github.com/vgramer)) +- Grammar: don't allow multi-line in strings ([#67](https://github.com/open-policy-agent/opa-idea-plugin/pull/67), [@vgramer](https://github.com/vgramer)) +- Grammar: fix rule-head and expr-infix + - `a:= 1 + 2` was parsed as an error + - assignment was valid inside affectation (eg `a := b = 1 + 2`) but should not. + - `a := 1 + 2 +3` was parsed as an error ([#74](https://github.com/open-policy-agent/opa-idea-plugin/pull/74), [@vgramer](https://github.com/vgramer)) + + +# Release notes for v0.3.0 + +## Changes by Kind + +### Bug or Regression + +- Grammar: allow to use of infix operation as argument of a function. This expression was parsed as an error: + - `ARule(){ x := count({x} & {y}) }` ([#64](https://github.com/open-policy-agent/opa-idea-plugin/pull/64), [@vgramer](https://github.com/vgramer)) + +# Release notes for v0.2.0 + +## Changes by Kind + +### Feature + +- Implements auto-closing feature (brace, parenthesis and bracket ) ([#41](https://github.com/open-policy-agent/opa-idea-plugin/pull/41), [@vgramer](https://github.com/vgramer)) +- Improve speed and security of CI Job: + - Cache gradle dependencies between run. + - check the signature of the Gradle wrapper. More info at [https://github.com/gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) ([#55](https://github.com/open-policy-agent/opa-idea-plugin/pull/55), [@vgramer](https://github.com/vgramer)) + +### Documentation + +- Fix typo in the documentation ([#54](https://github.com/open-policy-agent/opa-idea-plugin/pull/54), [@lukasz-kaminski](https://github.com/lukasz-kaminski)) +- Update instruction du use stable channel when installing opa though Jetbrains market place ([#53](https://github.com/open-policy-agent/opa-idea-plugin/pull/53), [@vgramer](https://github.com/vgramer)) + +### Bug or Regression + +- Grammar: access to function's return value without assigning it to a variable. These expressions were parsed as an error: + - `fun_obj(x) = h { h := {"a": {"b": [x,2]}} }` + - `aRule { a = fun_obj(1).a }` ([#59](https://github.com/open-policy-agent/opa-idea-plugin/pull/59), [@vgramer](https://github.com/vgramer)) + +# Release notes for v0.1.0 + +## Changes by Kind + +### Refactoring + +- Add tests on grammar and validate test files with `opa check` command ([#40](https://github.com/open-policy-agent/opa-idea-plugin/pull/40), [@irodzik](https://github.com/irodzik)) +- Refactoring of Opa action codes and improve comment ([#38](https://github.com/open-policy-agent/opa-idea-plugin/pull/38), [@asadali](https://github.com/asadali)) + +### Feature + +- Add the following opa action + - trace of selected text to code + - check ([#37](https://github.com/open-policy-agent/opa-idea-plugin/pull/37), [@frankiecerk](https://github.com/frankiecerk)) +- Add the script to check that versioned source files (`*.java`; `*.kt`) contains the license header and call it in github action ([#49](https://github.com/open-policy-agent/opa-idea-plugin/pull/49), [@vgramer](https://github.com/vgramer)) +- Build flavored ide. Some features like creating a rego project is only available on IDEA. This PR allows building the different flavors of the plugin for each ide version. This is transparent for the user (he see only one plugin market place) ([#44](https://github.com/open-policy-agent/opa-idea-plugin/pull/44), [@vgramer](https://github.com/vgramer)) +- Grammar: add `%` operator and tests for grammar ([#39](https://github.com/open-policy-agent/opa-idea-plugin/pull/39), [@irodzik](https://github.com/irodzik)) +- Implements auto-closing feature (brace, parenthesis and bracket ) ([#41](https://github.com/open-policy-agent/opa-idea-plugin/pull/41), [@vgramer](https://github.com/vgramer)) +- Index TOTO in rego comment ([#26](https://github.com/open-policy-agent/opa-idea-plugin/pull/26), [@vgramer](https://github.com/vgramer)) +- OpaTestRunConfiguration: add the full output of the command to the root node ([#52](https://github.com/open-policy-agent/opa-idea-plugin/pull/52), [@vgramer](https://github.com/vgramer)) +- Support for opa test, test coverage on project workspace and opa check on current open document, shows output in console window (all support for console window showing output is in extensions/OPAActionToolWindow) ([#30](https://github.com/open-policy-agent/opa-idea-plugin/pull/30), [@frankiecerk](https://github.com/frankiecerk)) + +### Documentation + +- Add opa icon for plugin installation ([#36](https://github.com/open-policy-agent/opa-idea-plugin/pull/36), [@vgramer](https://github.com/vgramer)) +- Add user and tech documentation ([#3](https://github.com/open-policy-agent/opa-idea-plugin/pull/3), [@vgramer](https://github.com/vgramer)) +- Instructions for download plugin from Jetbrains market place ([#48](https://github.com/open-policy-agent/opa-idea-plugin/pull/48), [@frankiecerk](https://github.com/frankiecerk)) + +### Bug or Regression + +- Fix test run configuration: + - Don't discriminate test configurations based on the file name: + - user can eval or test a package in any rego file + - user can test any rule starting with `test_`in any rego file + - user can evaluate any rule not starting with `test_` in any rego file + - Make bundle dir parameter required to create a test configuration => avoid message `Testing Framework quit unexpectedly` when creating a test configuration from gutter + - Generated name of the runConfiguration start with the name of the command to easily know which configuration type will be generated ([#50](https://github.com/open-policy-agent/opa-idea-plugin/pull/50), [@vgramer](https://github.com/vgramer)) +- Grammar: fixed string regex + highlighting for rule heads ([#19](https://github.com/open-policy-agent/opa-idea-plugin/pull/19), [@frankiecerk](https://github.com/frankiecerk))% \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index ec0a632..ce6abd1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,7 @@ import org.gradle.api.JavaVersion.VERSION_1_8 import org.gradle.api.internal.HasConvention +import org.intellij.markdown.ast.getTextInNode import org.jetbrains.grammarkit.tasks.GenerateLexer import org.jetbrains.grammarkit.tasks.GenerateParser import org.jetbrains.intellij.tasks.RunIdeTask @@ -26,6 +27,16 @@ val baseVersion = when (baseIDE) { val psiViewerPluginVersion = prop("psiViewerPluginVersion") val channel = prop("publishChannel") +buildscript { + repositories { + mavenCentral() + } + dependencies { + // needed to extract the last release notes + classpath("org.jetbrains:markdown:0.2.0") + } +} + idea { module { // https://github.com/gradle/kotlin-dsl/issues/537/ @@ -102,6 +113,7 @@ allprojects { withType { sinceBuild(prop("sinceBuild")) untilBuild(prop("untilBuild")) + changeNotes(getLastReleaseNotes()) } withType { @@ -126,13 +138,12 @@ allprojects { val channelSuffix = if (channel.isBlank() || channel == "stable") "" else "-$channel" val versionSuffix = "-$platformVersion$channelSuffix" -val majorVersion = prop("majorVersion") -val patchVersion = prop("patchVersion").toInt() -val buildNumber = System.getenv("GITHUB_RUN_ID" ) ?: "SNAPSHOT" +val pluginVersion = prop("pluginVersion") + // module to build/run/publish opa-ida-plugin plugin project(":plugin"){ - version = "$majorVersion.$patchVersion.$buildNumber$versionSuffix" + version = "$pluginVersion$versionSuffix" intellij { pluginName = "opa-idea-plugin" val plugins = mutableListOf( @@ -229,4 +240,39 @@ val SourceSet.kotlin: SourceDirectorySet fun SourceSet.kotlin(action: SourceDirectorySet.() -> Unit) = - kotlin.action() \ No newline at end of file + kotlin.action() + +fun getLastReleaseNotes(changLogPath: String = "CHANGELOG.md"): String { + val src = File(changLogPath).readText() + val flavour = org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor() + val parsedTree = org.intellij.markdown.parser.MarkdownParser(flavour).buildMarkdownTreeFromString(src) + + var found = false + val releaseNotesChildren: MutableList = mutableListOf() + + for (child in parsedTree.children) { + if (child.type == org.intellij.markdown.MarkdownElementTypes.ATX_1) { + if (found) { + // collect finished. exit + break + } + if (child.getTextInNode(src).startsWith("# Release notes for v")) { + releaseNotesChildren.add(child) + found = true + } + } else { + if (found) { // collect child related to this release note + releaseNotesChildren.add(child) + } + } + } + + if (!found) { + throw Exception("Can not find releases notes in '${changLogPath}'") + } + val root = org.intellij.markdown.ast.CompositeASTNode( + org.intellij.markdown.MarkdownElementTypes.MARKDOWN_FILE, + releaseNotesChildren + ) + return org.intellij.markdown.html.HtmlGenerator(src, root, flavour).generateHtml() +} \ No newline at end of file diff --git a/docs/devel/setup_development_env.md b/docs/devel/setup_development_env.md index 427057a..3323958 100644 --- a/docs/devel/setup_development_env.md +++ b/docs/devel/setup_development_env.md @@ -28,7 +28,7 @@ Just clone the project and execute the tests to ensure everything is ok. ```bash # clone the project -$ git clone git@github.com:vgramer/opa-idea-plugin.git +$ git clone git@github.com:open-policy-agent/opa-idea-plugin.git $ cd opa-idea-plugin # run tests diff --git a/gradle-202.properties b/gradle-202.properties index 55a555f..43af7d1 100644 --- a/gradle-202.properties +++ b/gradle-202.properties @@ -13,5 +13,4 @@ sinceBuild=202.6397 untilBuild=203.* # # check the binary compatibility of the plugin against these idea versions ( more info at https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl) -# IC-203.5251.39 is the last eap, unfortunately i couldn't find an "alias" on the last EAP -pluginVerifierIdeVersions= IC-2020.2, IC-203.5251.39 +pluginVerifierIdeVersions= IC-2020.2, IC-2020.3 diff --git a/gradle.properties b/gradle.properties index 41c9225..7284144 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,8 +11,6 @@ propertiesPluginEnvironmentNameProperty=platformVersion # Supported platforms: 201, 202 platformVersion=202 -majorVersion=0.4 -patchVersion=0 # Version of the ide used for the sandbox( possible value are 'idea' or 'pycharmCommunity') @@ -21,5 +19,7 @@ baseIDE=idea # these two variables will be overwrite by the release process (ie the github action) thanks to the env variables: # - ORG_GRADLE_PROJECT_publishToken # - ORG_GRADLE_PROJECT_publishChannel +# - ORG_GRADLE_PROJECT_pluginVersion publishToken=token publishChannel=dev +pluginVersion=nextVersion diff --git a/hack/create_or_update_release_notes_pr.sh b/hack/create_or_update_release_notes_pr.sh new file mode 100755 index 0000000..03b5e66 --- /dev/null +++ b/hack/create_or_update_release_notes_pr.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +######################################################################################################################## +# This script create or update the PR with the next release notes. +# It will generate the next release-notes thanks to script hack/generate_release_notes.sh and update the CHANGELOG.md. +# Then open or update PR. The branch used for the PR is "update-release-notes". +# +# This script is intended to be run in github action but can run in local. +# The following requirements must be satisfied: +# * same requirement as hack/generate_release_notes.sh +# * the github cli: hub must be installed (https://hub.github.com/) +######################################################################################################################## + +set -o errexit +set -o nounset +set -o pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +source "${ROOT}/hack/util.sh" + +util::require-hub + +release_note_branch='update-release-notes' +base_branch='master' +pr_number="$(hub pr list -h update-release-notes --format '%I')" + +if [[ -z "${pr_number}" ]]; then + pr_exist=false + echo "release notes pr does note already exist" + git checkout -b "${release_note_branch}" +else + pr_exist=true + echo "release notes pr already exist (#pr_number)" + hub pr checkout "${pr_number}" + git reset --hard "${base_branch}" +fi + +echo "==================================================================================================================" +echo "generating next release notes" +echo "==================================================================================================================" + +"${ROOT}"/hack/generate_release_notes.sh + +echo "==================================================================================================================" +echo "release notes successfully generated" +echo "merging next release notes with changelog" +echo "==================================================================================================================" + +echo -e "\n" >> "${NEXT_RELEASE_NOTES_FILE}" +cat "${NEXT_RELEASE_NOTES_FILE}" CHANGELOG.md > tmp_changelog.md +mv tmp_changelog.md CHANGELOG.md + + +if ! git config user.name > /dev/null 2>&1; then + # this mean script is run by github action + echo "git user.name is not set. Setting git config user.name and user.email" + git config user.name 'GitHub Action' + git config user.email 'action@github.com' +fi + + +git add CHANGELOG.md +git commit -m "update changelog with new version" +echo "push new changelog on branch ${release_note_branch}" +git push origin "${release_note_branch}" -f + +if [[ "${pr_exist}" == false ]]; then +echo "create release note PR" + hub pull-request --base master --head "${release_note_branch}" --file "${ROOT}/.github/release-notes-pr-description.md" +fi diff --git a/hack/generate_release_notes.sh b/hack/generate_release_notes.sh new file mode 100755 index 0000000..adde244 --- /dev/null +++ b/hack/generate_release_notes.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash + +######################################################################################################################## +# This script generate the release-notes for next version in ${NEXT_RELEASE_NOTES_FILE} ie +# repository_root/next-release-notes.md". It collect release notes from PR description merged into 'master' between the +# last github release and HEAD. +# For more information about the collection please read the documentation: docs/release-notes-generation.md +# +# This script is intended to be run in github action but can run in local. +# +# The following tools must be installed and be in the PATH +# * hub: the github cli (https://hub.github.com/) +# * release-notes: the k8s release-notes-generator tools (https://github.com/kubernetes/release#release-notes) +# can be install thanks to go get command: +# GO111MODULE=on go get k8s.io/release/cmd/release-notes@ +# +# The following environment variables must be set (there are provided by github action context): +# * GITHUB_REPOSITORY: The owner and repository name. For example, octocat/Hello-World +# * GITHUB_TOKEN: github personal token with read right on the repository +# +# Example: +# $ export GITHUB_REPOSITORY='vgramer/release-note-test' +# $ export GITHUB_TOKEN='the-personnal-token' +# $ hack/generate_release_notes.sh +# +# org=vgramer repo=release-note-test +# last release found. it's tag 'v3.0.0' +# tag 'v3.0.0' point on commit '88ab66225555776afdbad09cd8424991852f82ae' +# INFO Using output format: markdown +# INFO Gathering release notes +# INFO Starting to process commit 1 of 4 (25.00%): 7b0505715801ef0c90c0729be1a35fe46482141e +# INFO Starting to process commit 2 of 4 (50.00%): d9489b298d66b6dbf2a97661e1cc847c53216822 +# INFO Starting to process commit 3 of 4 (75.00%): d05bed5ba580ba7e0a7d5fd8f995f4a5c52a0a42 +# INFO Starting to process commit 4 of 4 (100.00%): 88ab66225555776afdbad09cd8424991852f82ae +# INFO No PR found for commit d9489b298d66b6dbf2a97661e1cc847c53216822: no PR IDs found in the commit message +# INFO No PR found for commit 7b0505715801ef0c90c0729be1a35fe46482141e: no PR IDs found in the commit message +# INFO No matches found when parsing PR from commit SHA 7b0505715801ef0c90c0729be1a35fe46482141e +# INFO No matches found when parsing PR from commit SHA d9489b298d66b6dbf2a97661e1cc847c53216822 +# INFO Got PR #8 for commit: 88ab66225555776afdbad09cd8424991852f82ae +# INFO Got PR #10 for commit: d05bed5ba580ba7e0a7d5fd8f995f4a5c52a0a42 +# INFO PR #10 seems to contain a release note +# INFO Got 1 release notes, performing rendering +# INFO Release notes written to file: /Users/vince/workspace/perso/final/release-note-test/next-release-notes.md +######################################################################################################################## + +set -o errexit +set -o nounset +set -o pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +source "${ROOT}/hack/util.sh" + +function check_environment() { + util::require-hub + util::command_exists "release-notes" || util::fatal 'release-notes not found in path. Please install it before running script. "GO111MODULE=on go get k8s.io/release/cmd/release-notes@"' + + set +o nounset + if [[ -z "${GITHUB_TOKEN}" ]]; then + util::fatal "'GITHUB_TOKEN' environment variable is not defined or empty" + fi + + if [[ -z "${GITHUB_REPOSITORY}" ]]; then + util::fatal "'GITHUB_REPOSITORY' environment variable is not defined or empty" + fi + set -o nounset + + [[ ${GITHUB_REPOSITORY} =~ ^[^/]+/[^/]+$ ]] || util::fatal "could not extract organization and repository from GITHUB_REPOSITORY env var. GITHUB_REPOSITORY='${GITHUB_REPOSITORY}'" + org=$(echo "${GITHUB_REPOSITORY}" | cut -d '/' -f 1) + repo=$(echo "${GITHUB_REPOSITORY}" | cut -d '/' -f 2) +} + +check_environment + +echo "org=${org} repo=${repo}" + +# format '%pI %T%n' -> "publish_date_ISO_8601 tag\n". eg:2 021-03-24T20:10:00Z v3.0.0 +last_release_tag="$(hub release -f '%pI %T%n' | sort -nr | head -1 | cut -d ' ' -f 2)" + +if [[ -z "${last_release_tag}" ]]; then + echo "no release found on repository. fallback to first commit" + start_sha="$(git rev-list --max-parents=0 HEAD)" + echo "first commit sha is '${start_sha}'" +else + echo "last release found. it's tag '${last_release_tag}'" + start_sha=$(git rev-parse "${last_release_tag}") + echo "tag '${last_release_tag}' point on commit '${start_sha}'" +fi + +end_sha=$(git rev-parse HEAD) + +# generate release notes: +# * for pr merged in master by any users (--required-author=''). +# * without go dependencies report (--dependencies=false) +release-notes --start-sha "${start_sha}" \ + --end-sha "${end_sha}" \ + --required-author='' \ + --branch master \ + --org "${org}" \ + --repo "${repo}" \ + --go-template=go-template:"${ROOT}/.github/release-notes.tmpl" \ + --output "${NEXT_RELEASE_NOTES_FILE}" \ + --dependencies=false diff --git a/hack/util.sh b/hack/util.sh new file mode 100644 index 0000000..58a6c29 --- /dev/null +++ b/hack/util.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +######################################################################################################################## +# This script contains utility variables and functions for others scripts # +######################################################################################################################## + +set -o errexit +set -o nounset +set -o pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" + + +######################################################################################################################## +# Utility variables # +######################################################################################################################## + +# path to the next release notes file +export NEXT_RELEASE_NOTES_FILE="${ROOT}/next-release-notes.md" + + +######################################################################################################################## +# Utility functions # +######################################################################################################################## + +# Test if a command exist +# example: +# util::command_exists "ls" || util::fatal "ls is not installed" +function util::command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Print an error message and exit with code 1 +# args: the error message +# example: +# $ util::fatal "something wrong happens" +# Error: something wrong happens +function util::fatal() { + echo "Error: $1" + exit 1 +} + +# Check "hub" command exist and exit with error message if does not. +function util::require-hub() { + util::command_exists "hub" || util::fatal 'hub not found in path. please install it before running script. see instruction at https://hub.github.com/' +} diff --git a/plugin/src/main/resources/META-INF/plugin.xml b/plugin/src/main/resources/META-INF/plugin.xml index 8d0858e..376c7c3 100644 --- a/plugin/src/main/resources/META-INF/plugin.xml +++ b/plugin/src/main/resources/META-INF/plugin.xml @@ -6,8 +6,8 @@ org.openpolicyagent.opa-idea-plugin Open Policy Agent - - https://github.com/vgramer/opa-idea-plugin + + https://github.com/open-policy-agent/opa-idea-plugin " | ">=" | "<=" arith-operator ::= "+" | "-" | "*" | "/" | "%" bin-operator ::= "&" | "|" ref ::= ( expr-call | array | object | set | array-compr | object-compr | set-compr |var ) ref-arg* ref-arg ::= ref-arg-dot | ref-arg-brack -ref-arg-brack ::= "[" ( scalar | var | array | object | set | "_" ) "]" +ref-arg-brack ::= "[" ( expr | "_" ) "]" ref-arg-dot ::= "." var var ::= ASCII_LETTER scalar ::= string | NUMBER | TRUE | FALSE | NULL string ::= STRING_TOKEN| RAW_STRING -array ::= '[' term? ( ',' term )* ','? ']' +array ::= '[' expr? ( ',' expr )* ','? ']' object ::= '{' object-item? ( ',' object-item )* ','? '}' -object-item ::= ( scalar | ref | var ) ":" term +object-item ::= ( scalar | ref | var ) ":" expr set ::= empty-set | non-empty-set non-empty-set ::= "{" term ( "," term )* ','? "}" empty-set ::= "set(" ")" diff --git a/src/main/grammar/RegoLexer.flex b/src/main/grammar/RegoLexer.flex index 6dad8b8..92afc19 100644 --- a/src/main/grammar/RegoLexer.flex +++ b/src/main/grammar/RegoLexer.flex @@ -31,7 +31,7 @@ WHITE_SPACE=[ \t\n\x0B\f\r]+ //The closing quote is optional in order to have a valid token, so the quoteHandler can autoclose it //if the user don't close the quote, an error will be reported by the RegoSyntaxErrorAnnotator -STRING_TOKEN=\"([^\r\n\"])*\"? +STRING_TOKEN=\"([^\\\"\r\n]|\\[^\r\n])*\"? RAW_STRING=`[^`]*(`)? COMMENT=[ \t]*#[^\r\n]* diff --git a/src/test/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoSyntaxErrorAnnotatorTest.kt b/src/test/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoSyntaxErrorAnnotatorTest.kt index c8dd5df..739e514 100644 --- a/src/test/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoSyntaxErrorAnnotatorTest.kt +++ b/src/test/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoSyntaxErrorAnnotatorTest.kt @@ -38,7 +38,14 @@ class RegoSyntaxErrorAnnotatorTest : AnnotatorTestBase(RegoSyntaxErrorAnnotator: fun `test no error are reported for valid string containing escape`(){ check_error(""" package main - a:= "hello \”world" + a:= "hello \"world" + """.trimIndent()) + } + + fun `test no error are reported for valid string containing only escape`(){ + check_error(""" + package main + a:= "\”" """.trimIndent()) } diff --git a/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCase.kt b/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCase.kt index da5c583..bce91ec 100644 --- a/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCase.kt +++ b/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCase.kt @@ -52,4 +52,7 @@ class RegoParsingTestCase: RegoParsingTestCaseBase() { fun `test sets`() = doTestNoError() fun `test strings`() = doTestNoError() fun `test variables`() = doTestNoError() + + fun `test ref arg back`() = doTestNoError() + fun `test factor expr`() = doTestNoError() } diff --git a/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCaseBase.kt b/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCaseBase.kt index f975797..46e36f6 100644 --- a/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCaseBase.kt +++ b/src/test/kotlin/org/openpolicyagent/ideaplugin/lang/RegoParsingTestCaseBase.kt @@ -17,7 +17,7 @@ import org.openpolicyagent.ideaplugin.lang.parser.RegoParserDefinition import org.openpolicyagent.ideaplugin.opa.tool.OpaBaseTool.Companion.opaBinary -abstract class RegoParsingTestCaseBase() : ParsingTestCase( +abstract class RegoParsingTestCaseBase : ParsingTestCase( "org/openpolicyagent/ideaplugin/lang/parser/fixtures", "rego", true, diff --git a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/array.rego b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/array.rego index 206ef92..8210573 100644 --- a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/array.rego +++ b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/array.rego @@ -10,3 +10,5 @@ arr5 := [1,2,] arr6 := ["hello", "world"] +# test object value can be complex expression +arr7 := [1 + 2 * 4, count(arr6) / abs(arr5[0]) ] diff --git a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/else_keyword.rego b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/else_keyword.rego index 9cc47b0..dd866ea 100644 --- a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/else_keyword.rego +++ b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/else_keyword.rego @@ -42,4 +42,43 @@ check_object_comprehension_for_else(x) = x { x % 2 == 0 } else = {y : "true" | some y; a[y] } { true -} \ No newline at end of file +} + +check_only_querry_for_else = true { + false +} else { + true +} + +check_only_equal_querry_for_else = true { + false +} else = { + true +} + +# issue 84 +check_empty_query_else = true { + input.x < input.y +} else = false + + +check_empty_query_else_with_number = 3 { + input.x < input.y +} else = 2 + +check_empty_query_else_with_string = "ok" { + input.x < input.y +} else = "ko" + +check_empty_query_else_with_array= ["ok", "yes"] { + input.x < input.y +} else = ["ko", "no"] + +check_empty_query_else_with_set= { 0 ,2 ,3 } { + input.x < input.y +} else = { 4, 5, 6 } + + +check_empty_query_else_with_infix_op= 0 { + input.x < input.y +} else = abs(input.x) + 10 - input.y diff --git a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/factor_expr.rego b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/factor_expr.rego new file mode 100644 index 0000000..6458298 --- /dev/null +++ b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/factor_expr.rego @@ -0,0 +1,24 @@ +package main + +location := [] + + +a1= (1) +a2:= (1) + (2) +a3:= (1 - 3) * 2 +a4:= (1 - 3) * (2 +5) +a5:= ((1 - 3) * 2) / count([1, 2]) + +reverse(l) = [l[j] | _ = l[i]; j := (count(l) - 1) - i] + +c1(l, x) = location[minus(count(location),1) + 2] { + true +} + + +rule1 { + (1 +2 ) * 0 = 0 + + c:= minus(count(location),(1 /2) * 2) + d:= abs((1 - 2) % 4) +} diff --git a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/object.rego b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/object.rego index 23ae94f..07903a2 100644 --- a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/object.rego +++ b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/object.rego @@ -9,3 +9,10 @@ a4 := { "a": 1, "b": c, } a5 := { "a": {"e": 123}, "b": c } +# test object value can be complex expression. Issue #77 +a6 := { + "a": 1 > 2, + "b": { + "c": object.get(a2, "a", "default") + abs(c) - 2 + } +} \ No newline at end of file diff --git a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/ref_arg_back.rego b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/ref_arg_back.rego new file mode 100644 index 0000000..968d110 --- /dev/null +++ b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/ref_arg_back.rego @@ -0,0 +1,117 @@ +package main + +location := [] +index := 0 + +apps = [] +sites = [] +number := [1,2,3] + + +######################################################################################################################## +# test inside rule # +######################################################################################################################## +rule1{ + + # check function call cascade + a1:= location[minus(count(location),1)] + + # infix operation + a2:= location[count(location) - 1 + abs(3)] + + #check array + a3:= location[[1,2,3][1]] + + # check set + a4:= location[{1,2,3}[1]] + + #check object + a5:= location[{"a": 0}["a"]] + + # array comphention + a6:= location[[name | some i; location[i].region == "region"; name := location[i].name][0]] + + # set comphention + a7:= location[{ x | some i; number[i] > 1; x:=number[i]}[0]] + + # obeject comphention + a8:= location[{x:y | some i; number[i] > 2; y := number[i]; x := sprintf("hello%v",[y])}.hello3] + +} + +######################################################################################################################## +# test outside rule # +######################################################################################################################## + +# check function call cascade +b1:= location[minus(count(location),1)] + +# infix operation +b2:= location[count(location) - 1 + abs(3)] + +#check array +b3:= location[[1,2,3][1]] + +# check set +b4:= location[{1,2,3}[1]] + +#check object +b5:= location[{"a": 0}["a"]] + +# array comphention +b6:= location[[name | some i; location[i].region == "region"; name := location[i].name][0]] + +# set comphention +b7:= location[{ x | some i; number[i] > 1; x:=number[i]}[0]] + +# obeject comphention +b8:= location[{x:y | some i; number[i] > 2; y := number[i]; x := sprintf("hello%v",[y])}.hello3] + + +######################################################################################################################## +# test rule head # +######################################################################################################################## +c1(l, x) = location[minus(count(location),1)] { + true +} + + +# check function call cascade +c1(l, x) = location[minus(count(location),1)] { + true +} + +# infix operation +c2(l, x) = location[count(location) - 1 + abs(3)] { + true +} + +#check array +c3(l, x) = location[[1,2,3][1]] { + true +} + +# check set +c4(l, x) = location[{1,2,3}[1]] { + true +} + +#check object +c5(l, x) = location[{"a": 0}["a"]] { + true +} + +# array comphention +c6(l, x) = location[[name | some i; location[i].region == "region"; name := location[i].name][0]] { + true +} + +# set comphention +c7(l, x) = location[{ x | some i; number[i] > 1; x:=number[i]}[0]] { + true +} + +# obeject comphention +c8(l, x) = location[{x:y | some i; number[i] > 2; y := number[i]; x := sprintf("hello%v",[y])}.hello3] { + true +} \ No newline at end of file diff --git a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/strings.rego b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/strings.rego index 6d1b51f..24d3bcd 100644 --- a/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/strings.rego +++ b/src/test/resources/org/openpolicyagent/ideaplugin/lang/parser/fixtures/strings.rego @@ -5,8 +5,13 @@ someRule { someOtherString := "some \\ string" } -someString := `hello\there` - +emptyRawString := `` +rawString := `hello\there` multiLineRawString := `hello world ` +rawStringWithQuote := `"` + +emptyString := "" +stringWithEscapeQuote := "hello \"world" +stringWithOnlyEscapedQuote := "\""