Merge branch 'master' into support-jrt-fs
This commit is contained in:
@ -2153,7 +2153,8 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/11549103?v=4",
|
||||
"profile": "https://github.com/cyw3",
|
||||
"contributions": [
|
||||
"bug"
|
||||
"bug",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -7153,7 +7154,8 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/111259588?v=4",
|
||||
"profile": "https://github.com/nwcm",
|
||||
"contributions": [
|
||||
"doc"
|
||||
"doc",
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -7192,6 +7194,90 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "krdabrowski",
|
||||
"name": "Krystian Dabrowski",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/98942253?v=4",
|
||||
"profile": "https://github.com/krdabrowski",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AndreyBozhko",
|
||||
"name": "Andrey Bozhko",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/22246447?v=4",
|
||||
"profile": "https://github.com/AndreyBozhko",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "rcorfieldffdc",
|
||||
"name": "Richard Corfield",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/42997936?v=4",
|
||||
"profile": "https://github.com/rcorfieldffdc",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "m0rjc",
|
||||
"name": "Richard Corfield",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/994206?v=4",
|
||||
"profile": "https://github.com/m0rjc",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "eant60",
|
||||
"name": "eant60",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/41472980?v=4",
|
||||
"profile": "https://github.com/eant60",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Marcono1234",
|
||||
"name": "Marcono1234",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/11685886?v=4",
|
||||
"profile": "https://github.com/Marcono1234",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "eugenepugach",
|
||||
"name": "eugenepugach",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/133967768?v=4",
|
||||
"profile": "https://github.com/eugenepugach",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "harbulot",
|
||||
"name": "Bruno Harbulot",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/80994?v=4",
|
||||
"profile": "http://blog.distributedmatter.net/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "shai-bennathan",
|
||||
"name": "Shai Bennathan",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/62336907?v=4",
|
||||
"profile": "https://github.com/shai-bennathan",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
103
.ci/build.sh
103
.ci/build.sh
@ -9,7 +9,7 @@ SCRIPT_INCLUDES="log.bash utils.bash setup-secrets.bash openjdk.bash maven.bash
|
||||
source "$(dirname "$0")/inc/fetch_ci_scripts.bash" && fetch_ci_scripts
|
||||
|
||||
function build() {
|
||||
pmd_ci_log_group_start "Prepare Java 8+11+17, Bundler"
|
||||
pmd_ci_log_group_start "Prepare Java 8+11+17+21, Bundler"
|
||||
pmd_ci_openjdk_install_adoptium 11
|
||||
pmd_ci_openjdk_setdefault 11
|
||||
PMD_MAVEN_EXTRA_OPTS=()
|
||||
@ -18,7 +18,13 @@ function build() {
|
||||
pmd_ci_openjdk_install_adoptium 8
|
||||
pmd_ci_log_info "Install openjdk17 for integration tests and pmd-regression-tests"
|
||||
pmd_ci_openjdk_install_adoptium 17
|
||||
PMD_MAVEN_EXTRA_OPTS=(-Djava8.home="${HOME}/openjdk8" -Djava17.home="${HOME}/openjdk17")
|
||||
pmd_ci_log_info "Install openjdk21 for integration tests and pmd-regression-tests"
|
||||
pmd_ci_openjdk_install_adoptium 21
|
||||
PMD_MAVEN_EXTRA_OPTS=(
|
||||
-Djava8.home="${HOME}/openjdk8"
|
||||
-Djava17.home="${HOME}/openjdk17"
|
||||
-Djava21.home="${HOME}/openjdk21"
|
||||
)
|
||||
fi
|
||||
pmd_ci_build_setup_bundler
|
||||
pmd_ci_log_group_end
|
||||
@ -100,7 +106,8 @@ function build() {
|
||||
pmd_ci_build_and_upload_doc
|
||||
pmd_ci_log_group_end
|
||||
|
||||
if pmd_ci_maven_isReleaseBuild; then
|
||||
# release is published only for the case b) pmd-cli/pmd-dist release
|
||||
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" == *-dist ]]; then
|
||||
pmd_ci_log_group_start "Publishing Release"
|
||||
pmd_ci_gh_releases_publishRelease "$GH_RELEASE"
|
||||
pmd_ci_sourceforge_selectDefault "${PMD_CI_MAVEN_PROJECT_VERSION}"
|
||||
@ -108,10 +115,14 @@ function build() {
|
||||
pmd_ci_log_group_end
|
||||
fi
|
||||
|
||||
# create a baseline for snapshot builds (when pmd-dist is built)
|
||||
# or for release builds for case b) when pmd-cli/pmd-dist is released
|
||||
if pmd_ci_maven_isSnapshotBuild || [[ "${PMD_CI_TAG}" == *-dist ]]; then
|
||||
pmd_ci_log_group_start "Creating new baseline for regression tester"
|
||||
regression_tester_setup_ci
|
||||
regression_tester_uploadBaseline
|
||||
pmd_ci_log_group_end
|
||||
fi
|
||||
|
||||
#
|
||||
# everything from here runs only on snapshots, not on release builds
|
||||
@ -130,7 +141,7 @@ function build() {
|
||||
-Dpmd.skip \
|
||||
--show-version --errors --batch-mode \
|
||||
clean package \
|
||||
sonar:sonar -Dsonar.login="${SONAR_TOKEN}" -Psonar
|
||||
sonar:sonar -Dsonar.login="${SONAR_TOKEN}" -Psonar,cli-dist
|
||||
pmd_ci_log_success "New sonar results: https://sonarcloud.io/dashboard?id=net.sourceforge.pmd%3Apmd"
|
||||
pmd_ci_log_group_end
|
||||
|
||||
@ -146,7 +157,7 @@ function build() {
|
||||
-DrepoToken="${COVERALLS_REPO_TOKEN}" \
|
||||
--show-version --errors --batch-mode \
|
||||
clean package jacoco:report \
|
||||
coveralls:report -Pcoveralls
|
||||
coveralls:report -Pcoveralls,cli-dist
|
||||
pmd_ci_log_success "New coveralls result: https://coveralls.io/github/pmd/pmd"
|
||||
pmd_ci_log_group_end
|
||||
fi
|
||||
@ -172,30 +183,58 @@ function pmd_ci_build_run() {
|
||||
if pmd_ci_maven_isReleaseBuild; then
|
||||
pmd_ci_log_info "This is a release build"
|
||||
mvn_profiles="${mvn_profiles},pmd-release"
|
||||
|
||||
# There are two possible (release) builds:
|
||||
if [[ "${PMD_CI_TAG}" != *-dist ]]; then
|
||||
# a) pmd-core and languages modules
|
||||
./mvnw clean deploy -P"${mvn_profiles}",'!cli-dist' --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
|
||||
else
|
||||
# b) pmd-cli and pmd-dist
|
||||
./mvnw clean deploy -P"${mvn_profiles},cli-dist" -pl pmd-cli,pmd-dist --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
|
||||
fi
|
||||
else
|
||||
pmd_ci_log_info "This is a snapshot build"
|
||||
./mvnw clean deploy -P"${mvn_profiles},cli-dist" --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
|
||||
fi
|
||||
|
||||
./mvnw clean deploy -P${mvn_profiles} --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
|
||||
}
|
||||
|
||||
#
|
||||
# Deploys the binary distribution
|
||||
#
|
||||
function pmd_ci_deploy_build_artifacts() {
|
||||
# Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-src.zip"
|
||||
# Deploy SBOM
|
||||
cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
|
||||
cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
|
||||
if pmd_ci_maven_isSnapshotBuild; then
|
||||
# Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-src.zip"
|
||||
# Deploy SBOM
|
||||
cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
|
||||
cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
|
||||
fi
|
||||
|
||||
if pmd_ci_maven_isReleaseBuild; then
|
||||
# release build case a): only pmd-core and language modules released
|
||||
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" != *-dist ]]; then
|
||||
# create a draft github release
|
||||
pmd_ci_gh_releases_createDraftRelease "${PMD_CI_TAG}" "$(git rev-list -n 1 "${PMD_CI_TAG}")"
|
||||
GH_RELEASE="$RESULT"
|
||||
fi
|
||||
|
||||
# release build case b): pmd-cli and pmd-dist are released
|
||||
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" == *-dist ]]; then
|
||||
# Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-src.zip"
|
||||
# Deploy SBOM
|
||||
cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
|
||||
cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
|
||||
|
||||
# draft release has already been created
|
||||
pmd_ci_gh_releases_getLatestDraftRelease
|
||||
GH_RELEASE="$RESULT"
|
||||
|
||||
# Deploy to github releases
|
||||
pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
|
||||
@ -215,7 +254,7 @@ function pmd_ci_build_and_upload_doc() {
|
||||
pmd_doc_create_archive
|
||||
|
||||
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "docs/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-doc.zip"
|
||||
if pmd_ci_maven_isReleaseBuild; then
|
||||
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" != *-dist ]]; then
|
||||
pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "docs/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-doc.zip"
|
||||
fi
|
||||
|
||||
@ -224,19 +263,21 @@ function pmd_ci_build_and_upload_doc() {
|
||||
# Deploy javadoc to https://docs.pmd-code.org/apidocs/*/${PMD_CI_MAVEN_PROJECT_VERSION}/
|
||||
pmd_code_uploadJavadoc "${PMD_CI_MAVEN_PROJECT_VERSION}" "$(pwd)"
|
||||
|
||||
# render release notes
|
||||
# updating github release text
|
||||
rm -f .bundle/config
|
||||
bundle config set --local path vendor/bundle
|
||||
bundle config set --local with release_notes_preprocessing
|
||||
bundle install
|
||||
# renders, and skips the first 6 lines - the Jekyll front-matter
|
||||
local rendered_release_notes
|
||||
rendered_release_notes=$(bundle exec docs/render_release_notes.rb docs/pages/release_notes.md | tail -n +6)
|
||||
local release_name
|
||||
release_name="PMD ${PMD_CI_MAVEN_PROJECT_VERSION} ($(date -u +%d-%B-%Y))"
|
||||
# Upload to https://sourceforge.net/projects/pmd/files/pmd/${PMD_CI_MAVEN_PROJECT_VERSION}/ReadMe.md
|
||||
pmd_ci_sourceforge_uploadReleaseNotes "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "${rendered_release_notes}"
|
||||
if pmd_ci_maven_isSnapshotBuild || [[ "${PMD_CI_TAG}" != *-dist ]]; then
|
||||
# render release notes
|
||||
# updating github release text
|
||||
rm -f .bundle/config
|
||||
bundle config set --local path vendor/bundle
|
||||
bundle config set --local with release_notes_preprocessing
|
||||
bundle install
|
||||
# renders, and skips the first 6 lines - the Jekyll front-matter
|
||||
local rendered_release_notes
|
||||
rendered_release_notes=$(bundle exec docs/render_release_notes.rb docs/pages/release_notes.md | tail -n +6)
|
||||
local release_name
|
||||
release_name="PMD ${PMD_CI_MAVEN_PROJECT_VERSION} ($(date -u +%d-%B-%Y))"
|
||||
# Upload to https://sourceforge.net/projects/pmd/files/pmd/${PMD_CI_MAVEN_PROJECT_VERSION}/ReadMe.md
|
||||
pmd_ci_sourceforge_uploadReleaseNotes "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "${rendered_release_notes}"
|
||||
fi
|
||||
|
||||
if pmd_ci_maven_isSnapshotBuild && [ "${PMD_CI_BRANCH}" = "master" ]; then
|
||||
# only for snapshot builds from branch master: https://docs.pmd-code.org/snapshot -> pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}
|
||||
@ -248,7 +289,7 @@ function pmd_ci_build_and_upload_doc() {
|
||||
pmd_ci_sourceforge_rsyncSnapshotDocumentation "${PMD_CI_MAVEN_PROJECT_VERSION}" "snapshot"
|
||||
fi
|
||||
|
||||
if pmd_ci_maven_isReleaseBuild; then
|
||||
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" != *-dist ]]; then
|
||||
# documentation is already uploaded to https://docs.pmd-code.org/pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}
|
||||
# we only need to setup symlinks for the released version
|
||||
pmd_code_createSymlink "${PMD_CI_MAVEN_PROJECT_VERSION}" "latest"
|
||||
@ -284,7 +325,7 @@ function pmd_ci_dogfood() {
|
||||
sed -i 's/<version>[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}.*<\/version>\( *<!-- pmd.dogfood.version -->\)/<version>'"${PMD_CI_MAVEN_PROJECT_VERSION}"'<\/version>\1/' pom.xml
|
||||
if [ "${PMD_CI_MAVEN_PROJECT_VERSION}" = "7.0.0-SNAPSHOT" ]; then
|
||||
sed -i 's/pmd-dogfood-config\.xml/pmd-dogfood-config7.xml/' pom.xml
|
||||
mpmdVersion=(-Denforcer.skip=true -Dpmd.plugin.version=3.21.1-pmd-7-SNAPSHOT)
|
||||
mpmdVersion=(-Denforcer.skip=true -Dpmd.plugin.version=3.21.1-pmd-7.0.0-SNAPSHOT)
|
||||
fi
|
||||
./mvnw verify --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}" \
|
||||
"${mpmdVersion[@]}" \
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<ruleset name="All Regression Rules"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- uses: actions/cache@v3
|
||||
@ -55,7 +55,7 @@ jobs:
|
||||
run: |
|
||||
echo "LANG=en_US.UTF-8" >> $GITHUB_ENV
|
||||
echo "MAVEN_OPTS=-Daether.connector.http.connectionMaxTtl=180 -DautoReleaseAfterClose=true -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV
|
||||
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/master/scripts" >> $GITHUB_ENV
|
||||
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/22/scripts" >> $GITHUB_ENV
|
||||
- name: Check Environment
|
||||
shell: bash
|
||||
run: |
|
||||
|
4
.github/workflows/git-repo-sync.yml
vendored
4
.github/workflows/git-repo-sync.yml
vendored
@ -17,14 +17,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: false
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 100
|
||||
- name: Setup Environment
|
||||
shell: bash
|
||||
run: |
|
||||
echo "LANG=en_US.UTF-8" >> $GITHUB_ENV
|
||||
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/master/scripts" >> $GITHUB_ENV
|
||||
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/22/scripts" >> $GITHUB_ENV
|
||||
- name: Sync
|
||||
run: .ci/git-repo-sync.sh
|
||||
shell: bash
|
||||
|
4
.github/workflows/troubleshooting.yml
vendored
4
.github/workflows/troubleshooting.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
os: [ ubuntu-latest ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@ -36,7 +36,7 @@ jobs:
|
||||
run: |
|
||||
echo "LANG=en_US.UTF-8" >> $GITHUB_ENV
|
||||
echo "MAVEN_OPTS=-Daether.connector.http.connectionMaxTtl=180 -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV
|
||||
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/master/scripts" >> $GITHUB_ENV
|
||||
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/22/scripts" >> $GITHUB_ENV
|
||||
- name: Check Environment
|
||||
shell: bash
|
||||
run: |
|
||||
|
2
.mvn/wrapper/maven-wrapper.properties
vendored
2
.mvn/wrapper/maven-wrapper.properties
vendored
@ -14,5 +14,5 @@
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
||||
|
32
Dangerfile
32
Dangerfile
@ -51,18 +51,16 @@ def run_pmdtester
|
||||
message2 = create_message
|
||||
end
|
||||
|
||||
report_url = upload_report
|
||||
tar_report
|
||||
|
||||
if report_url
|
||||
message1 += "[Full report](#{report_url}/diff1/index.html)"
|
||||
message1 += "[Download full report as build artifact](#{ENV['PMD_CI_JOB_URL']})"
|
||||
# set value of sticky to true and the message is kept after new commits are submitted to the PR
|
||||
message(message1, sticky: true)
|
||||
|
||||
if message2
|
||||
message2 += "[Download full report as build artifact](#{ENV['PMD_CI_JOB_URL']})"
|
||||
# set value of sticky to true and the message is kept after new commits are submitted to the PR
|
||||
message(message1, sticky: true)
|
||||
|
||||
if message2
|
||||
message2 += "[Full report](#{report_url}/diff2/index.html)"
|
||||
# set value of sticky to true and the message is kept after new commits are submitted to the PR
|
||||
message(message2, sticky: true)
|
||||
end
|
||||
message(message2, sticky: true)
|
||||
end
|
||||
|
||||
rescue StandardError => e
|
||||
@ -84,23 +82,13 @@ def create_message
|
||||
"#{@summary[:configerrors][:removed]} configuration errors.\n"
|
||||
end
|
||||
|
||||
def upload_report
|
||||
def tar_report
|
||||
Dir.chdir('target') do
|
||||
tar_filename = "pr-#{ENV['PMD_CI_PULL_REQUEST_NUMBER']}-diff-report-#{Time.now.strftime("%Y-%m-%dT%H-%M-%SZ")}.tar.gz"
|
||||
|
||||
`tar czf #{tar_filename} diff1/ diff2/`
|
||||
tar_size = (10 * File.size(tar_filename) / 1024 / 1024)/10.0
|
||||
@logger.info "Uploading file #{tar_filename} (#{tar_size}mb) now..."
|
||||
report_url = `curl -u #{ENV['PMD_CI_CHUNK_TOKEN']} -T #{tar_filename} https://chunk.io`
|
||||
if $?.success?
|
||||
report_url.chomp!
|
||||
@logger.info "Successfully uploaded #{tar_filename} to #{report_url}"
|
||||
report_url
|
||||
else
|
||||
@logger.error "Error while uploading #{tar_filename} to chunk.io: #{report_url}"
|
||||
warn("Uploading the diff report failed, this message is mainly used to remind the maintainers of PMD.")
|
||||
nil
|
||||
end
|
||||
@logger.info "Created file #{tar_filename} (#{tar_size}mb)"
|
||||
end
|
||||
end
|
||||
|
||||
|
28
Gemfile.lock
28
Gemfile.lock
@ -1,8 +1,9 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.8.4)
|
||||
addressable (2.8.5)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
base64 (0.1.1)
|
||||
claide (1.1.0)
|
||||
claide-plugins (0.9.2)
|
||||
cork
|
||||
@ -12,23 +13,24 @@ GEM
|
||||
concurrent-ruby (1.2.2)
|
||||
cork (0.3.0)
|
||||
colored2 (~> 3.1)
|
||||
danger (9.2.0)
|
||||
danger (9.3.2)
|
||||
claide (~> 1.0)
|
||||
claide-plugins (>= 0.9.2)
|
||||
colored2 (~> 3.1)
|
||||
cork (~> 0.1)
|
||||
faraday (>= 0.9.0, < 3.0)
|
||||
faraday-http-cache (~> 2.0)
|
||||
git (~> 1.7)
|
||||
git (~> 1.13)
|
||||
kramdown (~> 2.3)
|
||||
kramdown-parser-gfm (~> 1.0)
|
||||
no_proxy_fix
|
||||
octokit (~> 5.0)
|
||||
octokit (~> 6.0)
|
||||
terminal-table (>= 1, < 4)
|
||||
differ (0.1.2)
|
||||
et-orbi (1.2.7)
|
||||
tzinfo
|
||||
faraday (2.7.5)
|
||||
faraday (2.7.11)
|
||||
base64
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-http-cache (2.5.0)
|
||||
@ -46,13 +48,13 @@ GEM
|
||||
kramdown (~> 2.0)
|
||||
liquid (5.4.0)
|
||||
logger-colors (1.0.0)
|
||||
mini_portile2 (2.8.2)
|
||||
mini_portile2 (2.8.4)
|
||||
nap (1.1.0)
|
||||
no_proxy_fix (0.1.2)
|
||||
nokogiri (1.15.2)
|
||||
nokogiri (1.15.4)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
octokit (5.6.1)
|
||||
octokit (6.1.1)
|
||||
faraday (>= 1, < 3)
|
||||
sawyer (~> 0.9)
|
||||
open4 (1.3.4)
|
||||
@ -63,14 +65,14 @@ GEM
|
||||
nokogiri (~> 1.13)
|
||||
rufus-scheduler (~> 3.8)
|
||||
slop (~> 4.9)
|
||||
public_suffix (5.0.1)
|
||||
public_suffix (5.0.3)
|
||||
raabro (1.4.0)
|
||||
racc (1.6.2)
|
||||
racc (1.7.1)
|
||||
rchardet (1.8.0)
|
||||
rexml (3.2.5)
|
||||
rouge (4.1.1)
|
||||
rexml (3.2.6)
|
||||
rouge (4.1.3)
|
||||
ruby2_keywords (0.0.5)
|
||||
rufus-scheduler (3.8.2)
|
||||
rufus-scheduler (3.9.1)
|
||||
fugit (~> 1.1, >= 1.1.6)
|
||||
safe_yaml (1.0.5)
|
||||
sawyer (0.9.2)
|
||||
|
@ -22,7 +22,8 @@ Scala is supported, but there are currently no Scala rules available.
|
||||
|
||||
Additionally, it includes **CPD**, the copy-paste-detector. CPD finds duplicated code in
|
||||
C/C++, C#, Dart, Fortran, Gherkin, Go, Groovy, HTML, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Modelica,
|
||||
Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex and Visualforce, Scala, Swift, T-SQL and XML.
|
||||
Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex and Visualforce, Scala, Swift, T-SQL,
|
||||
Apache Velocity, and XML.
|
||||
|
||||
In the future we hope to add support for data/control flow analysis and automatic (quick) fixes where
|
||||
it makes sense.
|
||||
|
@ -101,8 +101,8 @@ echo " the new release based on the release notes. Also add any deprecated ru
|
||||
echo
|
||||
echo "* Update **../pmd.github.io/_config.yml** to mention the new release"
|
||||
echo
|
||||
echo "* Update property \`pmd-designer.version\` in **pom.xml** to reference the latest pmd-designer release"
|
||||
echo " See <https://search.maven.org/search?q=g:net.sourceforge.pmd%20AND%20a:pmd-ui&core=gav> for the available releases."
|
||||
echo "* Update property \`pmd-designer.version\` in **pom.xml** to reference the version, that will be released"
|
||||
echo " later in this process."
|
||||
echo
|
||||
echo "Press enter to continue..."
|
||||
read -r
|
||||
@ -170,8 +170,8 @@ git commit -a -m "Prepare pmd release ${RELEASE_VERSION}"
|
||||
-DreleaseVersion="${RELEASE_VERSION}" \
|
||||
-DdevelopmentVersion="${DEVELOPMENT_VERSION}" \
|
||||
-DscmCommentPrefix="[release] " \
|
||||
-Pgenerate-rule-docs
|
||||
|
||||
-Darguments='-Pgenerate-rule-docs,!cli-dist' \
|
||||
'-Pgenerate-rule-docs,!cli-dist'
|
||||
|
||||
echo
|
||||
echo "Tag has been pushed.... now check github actions: <https://github.com/pmd/pmd/actions>"
|
||||
@ -235,14 +235,46 @@ EOF
|
||||
git commit -a -m "Prepare next development version [skip ci]"
|
||||
git push origin "${CURRENT_BRANCH}"
|
||||
./mvnw -B release:clean
|
||||
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
echo "* Wait until the new version is synced to maven central and appears as latest version in"
|
||||
echo " <https://repo.maven.apache.org/maven2/net/sourceforge/pmd/pmd/maven-metadata.xml>."
|
||||
echo
|
||||
echo
|
||||
echo "Then proceed with releasing pmd-designer..."
|
||||
echo "<https://github.com/pmd/pmd-designer/blob/master/releasing.md>"
|
||||
echo
|
||||
echo "Press enter to continue when pmd-designer is available in maven-central..."
|
||||
echo "<https://repo.maven.apache.org/maven2/net/sourceforge/pmd/pmd-ui/maven-metadata.xml>."
|
||||
read -r
|
||||
|
||||
echo
|
||||
echo "Continuing with release of pmd-cli and pmd-dist..."
|
||||
git checkout "pmd_releases/${RELEASE_VERSION}"
|
||||
./mvnw versions:update-parent -DparentVersion="${RELEASE_VERSION}" -DskipResolution=true -DgenerateBackupPoms=false -pl pmd-cli,pmd-dist
|
||||
git add pmd-cli/pom.xml pmd-dist/pom.xml
|
||||
git commit -m "[release] prepare release pmd_releases/${RELEASE_VERSION}-dist"
|
||||
git tag -m "[release] copy for tag pmd_releases/${RELEASE_VERSION}-dist" "pmd_releases/${RELEASE_VERSION}-dist"
|
||||
git push origin tag "pmd_releases/${RELEASE_VERSION}-dist"
|
||||
git checkout master
|
||||
# make sure parent reference is correct
|
||||
./mvnw versions:update-parent -DparentVersion="${DEVELOPMENT_VERSION}" -DskipResolution=true -DgenerateBackupPoms=false -pl pmd-cli,pmd-dist
|
||||
git add pmd-cli/pom.xml pmd-dist/pom.xml
|
||||
changes=$(git status --porcelain 2>/dev/null | grep -c -E "^[AMDRC]" || true)
|
||||
if [ "$changes" -gt 0 ]; then
|
||||
git commit -m "Prepare next development version [skip ci]"
|
||||
git push origin "${CURRENT_BRANCH}"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Second tag 'pmd_releases/${RELEASE_VERSION}-dist' has been pushed ... now check github actions: <https://github.com/pmd/pmd/actions>"
|
||||
echo
|
||||
echo
|
||||
echo "Verify the new release on github: <https://github.com/pmd/pmd/releases/tag/pmd_releases/${RELEASE_VERSION}>"
|
||||
echo "and the news entry at <https://sourceforge.net/p/pmd/news/>"
|
||||
echo
|
||||
echo "* Wait until the new version is synced to maven central and appears as latest version in"
|
||||
echo " <https://repo.maven.apache.org/maven2/net/sourceforge/pmd/pmd/maven-metadata.xml>."
|
||||
echo "* Send out an announcement mail to the mailing list:"
|
||||
echo
|
||||
echo "To: PMD Developers List <pmd-devel@lists.sourceforge.net>"
|
||||
|
@ -1,19 +1,20 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (7.0.5)
|
||||
activesupport (7.0.8)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
addressable (2.8.4)
|
||||
addressable (2.8.5)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
base64 (0.1.1)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.11.1)
|
||||
colorator (1.1.0)
|
||||
commonmarker (0.23.9)
|
||||
commonmarker (0.23.10)
|
||||
concurrent-ruby (1.2.2)
|
||||
dnsruby (1.70.0)
|
||||
simpleidn (~> 0.2.1)
|
||||
@ -23,12 +24,13 @@ GEM
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
eventmachine (1.2.7)
|
||||
execjs (2.8.1)
|
||||
faraday (2.7.5)
|
||||
execjs (2.9.1)
|
||||
faraday (2.7.11)
|
||||
base64
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-net_http (3.0.2)
|
||||
ffi (1.15.5)
|
||||
ffi (1.16.2)
|
||||
forwardable-extended (2.6.0)
|
||||
gemoji (3.0.1)
|
||||
github-pages (228)
|
||||
@ -86,7 +88,7 @@ GEM
|
||||
activesupport (>= 2)
|
||||
nokogiri (>= 1.4)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.13.0)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jekyll (3.9.3)
|
||||
addressable (~> 2.4)
|
||||
@ -205,13 +207,13 @@ GEM
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.8.2)
|
||||
mini_portile2 (2.8.4)
|
||||
minima (2.5.1)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-feed (~> 0.9)
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.18.0)
|
||||
nokogiri (1.15.2)
|
||||
minitest (5.20.0)
|
||||
nokogiri (1.15.4)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
octokit (4.25.1)
|
||||
@ -220,11 +222,11 @@ GEM
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (4.0.7)
|
||||
racc (1.6.2)
|
||||
racc (1.7.1)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.2.5)
|
||||
rexml (3.2.6)
|
||||
rouge (3.26.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
|
@ -3,7 +3,7 @@ repository: pmd/pmd
|
||||
pmd:
|
||||
version: 7.0.0-SNAPSHOT
|
||||
previous_version: 6.55.0
|
||||
date: 27-June-2023
|
||||
date: ??-?????-2023
|
||||
release_type: major
|
||||
|
||||
# release types: major, minor, bugfix
|
||||
|
@ -34,6 +34,9 @@ entries:
|
||||
- title: User Documentation
|
||||
output: web, pdf
|
||||
folderitems:
|
||||
- title: Migration Guide for PMD 7
|
||||
url: /pmd_userdocs_migrating_to_pmd7.html
|
||||
output: web, pdf
|
||||
- title: Installation and basic CLI usage
|
||||
url: /pmd_userdocs_installation.html
|
||||
output: web, pdf
|
||||
@ -121,6 +124,9 @@ entries:
|
||||
- title: PMD Java API
|
||||
output: web, pdf
|
||||
url: /pmd_userdocs_tools_java_api.html
|
||||
- title: bld PMD Extension
|
||||
output: web, pdf
|
||||
url: /pmd_userdocs_tools_bld.html
|
||||
- title: CI integrations
|
||||
output: web, pdf
|
||||
url: /pmd_userdocs_tools_ci.html
|
||||
@ -310,7 +316,7 @@ entries:
|
||||
- title: null
|
||||
output: web, pdf
|
||||
subfolders:
|
||||
- title: Salesforce VisualForce Rules
|
||||
- title: Salesforce Visualforce Rules
|
||||
output: web, pdf
|
||||
subfolderitems:
|
||||
- title: Index
|
||||
@ -346,7 +352,7 @@ entries:
|
||||
- title: null
|
||||
output: web, pdf
|
||||
subfolders:
|
||||
- title: VM Rules
|
||||
- title: Velocity Template Language (VTL) Rules
|
||||
output: web, pdf
|
||||
subfolderitems:
|
||||
- title: Index
|
||||
@ -379,6 +385,9 @@ entries:
|
||||
- title: Index
|
||||
output: web, pdf
|
||||
url: /pmd_rules_xml.html
|
||||
- title: Best Practices
|
||||
output: web, pdf
|
||||
url: /pmd_rules_xml_bestpractices.html
|
||||
- title: Error Prone
|
||||
output: web, pdf
|
||||
url: /pmd_rules_xml_errorprone.html
|
||||
@ -400,12 +409,41 @@ entries:
|
||||
- title: Language-Specific Documentation
|
||||
output: web, pdf
|
||||
folderitems:
|
||||
- title: Overview
|
||||
url: /pmd_languages_index.html
|
||||
output: web, pdf
|
||||
- title: Language configuration
|
||||
url: /pmd_languages_configuration.html
|
||||
output: web, pdf
|
||||
- title: Apex
|
||||
url: /pmd_languages_apex.html
|
||||
output: web, pdf
|
||||
- title: C/C++
|
||||
url: /pmd_languages_cpp.html
|
||||
output: web, pdf
|
||||
- title: C#
|
||||
url: /pmd_languages_cs.html
|
||||
output: web, pdf
|
||||
- title: Coco
|
||||
url: /pmd_languages_coco.html
|
||||
output: web, pdf
|
||||
- title: Dart
|
||||
url: /pmd_languages_dart.html
|
||||
output: web, pdf
|
||||
- title: Fortran
|
||||
url: /pmd_languages_fortran.html
|
||||
output: web, pdf
|
||||
- title: Gherkin
|
||||
url: /pmd_languages_gherkin.html
|
||||
output: web, pdf
|
||||
- title: Go
|
||||
url: /pmd_languages_go.html
|
||||
output: web, pdf
|
||||
- title: Groovy
|
||||
url: /pmd_languages_groovy.html
|
||||
- title: HTML
|
||||
url: /pmd_languages_html.html
|
||||
output: web, pdf
|
||||
- title: Java
|
||||
url: /pmd_languages_java.html
|
||||
output: web, pdf
|
||||
@ -415,30 +453,57 @@ entries:
|
||||
- title: JSP
|
||||
url: /pmd_languages_jsp.html
|
||||
output: web, pdf
|
||||
- title: Julia
|
||||
url: /pmd_languages_julia.html
|
||||
output: web, pdf
|
||||
- title: Kotlin
|
||||
url: /pmd_languages_kotlin.html
|
||||
output: web, pdf
|
||||
- title: Lua
|
||||
url: /pmd_languages_lua.html
|
||||
output: web, pdf
|
||||
- title: Matlab
|
||||
url: /pmd_languages_matlab.html
|
||||
output: web, pdf
|
||||
- title: Modelica
|
||||
url: /pmd_languages_modelica.html
|
||||
output: web, pdf
|
||||
- title: Objective-C
|
||||
url: /pmd_languages_objectivec.html
|
||||
output: web, pdf
|
||||
- title: Perl
|
||||
url: /pmd_languages_perl.html
|
||||
output: web, pdf
|
||||
- title: PHP
|
||||
url: /pmd_languages_php.html
|
||||
output: web, pdf
|
||||
- title: PLSQL
|
||||
url: /pmd_languages_plsql.html
|
||||
output: web, pdf
|
||||
- title: Python
|
||||
url: /pmd_languages_python.html
|
||||
output: web, pdf
|
||||
- title: Ruby
|
||||
url: /pmd_languages_ruby.html
|
||||
output: web, pdf
|
||||
- title: Scala
|
||||
url: /pmd_languages_scala.html
|
||||
output: web, pdf
|
||||
- title: Swift
|
||||
url: /pmd_languages_swift.html
|
||||
output: web, pdf
|
||||
- title: T-SQL
|
||||
url: /pmd_languages_tsql.html
|
||||
output: web, pdf
|
||||
- title: Visualforce
|
||||
url: /pmd_languages_visualforce.html
|
||||
output: web, pdf
|
||||
- title: Velocity Template Language (VTL)
|
||||
url: /pmd_languages_vm.html
|
||||
output: web, pdf
|
||||
- title: XML and XML dialects
|
||||
url: /pmd_languages_xml.html
|
||||
output: web, pdf
|
||||
- title: HTML
|
||||
url: /pmd_languages_html.html
|
||||
output: web, pdf
|
||||
- title: Gherkin
|
||||
url: /pmd_languages_gherkin.html
|
||||
output: web, pdf
|
||||
- title: Julia
|
||||
url: /pmd_languages_julia.html
|
||||
output: web, pdf
|
||||
- title: Coco
|
||||
url: /pmd_languages_coco.html
|
||||
output: web, pdf
|
||||
- title: Developer Documentation
|
||||
output: web, pdf
|
||||
folderitems:
|
||||
@ -490,6 +555,9 @@ entries:
|
||||
- title: Creating (XML) dump of the AST
|
||||
url: /pmd_devdocs_experimental_ast_dump.html
|
||||
output: web, pdf
|
||||
- title: List of experimental Features
|
||||
url: /tag_experimental.html
|
||||
output: web, pdf
|
||||
- title: Project documentation
|
||||
output: web, pdf
|
||||
folderitems:
|
||||
|
@ -10,3 +10,6 @@ allowed-tags:
|
||||
- tools # About tools and integrations, Maven, gradle, etc.
|
||||
- devdocs # About PMD internals, contributing, building, projects
|
||||
- languages # Language-specific documentation pages
|
||||
- PmdCapableLanguage
|
||||
- CpdCapableLanguage
|
||||
- experimental
|
||||
|
12
docs/_includes/language_info.html
Normal file
12
docs/_includes/language_info.html
Normal file
@ -0,0 +1,12 @@
|
||||
<details class="language-info">
|
||||
<summary>Language Info for {{include.name}}</summary>
|
||||
<div class="card">
|
||||
<ul class="list-group list-group-flush">
|
||||
{% if include.since %}<li class="list-group-item">Since PMD {{include.since}}</li>{% endif %}
|
||||
<li class="list-group-item">Implementation: {% jdoc include.implementation %}</li>
|
||||
<li class="list-group-item">Id: {{include.id}}</li>
|
||||
<li class="list-group-item">PMD: {% if include.supports_pmd %}✔️{% else %}❌{% endif %}</li>
|
||||
<li class="list-group-item">CPD: {% if include.supports_cpd %}✔️{% else %}❌{% endif %}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
@ -13,7 +13,10 @@ layout: default
|
||||
{% if page.summary %}
|
||||
<div class="summary">{{page.summary}}</div>
|
||||
{% endif %}
|
||||
<div id="inline-toc"><!-- empty, move TOC here when screen size too small --></div>
|
||||
<details id="inline-toc-details">
|
||||
<summary>Table of Contents</summary>
|
||||
<div id="inline-toc"><!-- empty, move TOC here when screen size too small --></div>
|
||||
</details>
|
||||
|
||||
{{content}}
|
||||
|
||||
|
@ -106,16 +106,25 @@ class JavadocTag < Liquid::Tag
|
||||
def initialize(tag_name, doc_ref, tokens)
|
||||
super
|
||||
|
||||
# sanitize a little
|
||||
doc_ref.delete! " \"'"
|
||||
@doc_ref = doc_ref
|
||||
end
|
||||
|
||||
arr = doc_ref.split("#") # split into fqcn + member suffix
|
||||
def render(var_ctx)
|
||||
# maybe the parameter is actually a variable - try to resolve it first
|
||||
if var_ctx.key?(@doc_ref)
|
||||
@doc_ref = var_ctx[@doc_ref]
|
||||
end
|
||||
|
||||
# sanitize a little
|
||||
@doc_ref.delete! " \"'"
|
||||
|
||||
arr = @doc_ref.split("#") # split into fqcn + member suffix
|
||||
|
||||
@type_fqcn = arr[0]
|
||||
@member_suffix = arr[1] || "" # default to empty string
|
||||
|
||||
unless Regexp.new('(!\w*!)?' + Regexp.union(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX, JDocNamespaceDeclaration::SYM_REGEX).source ) =~ @type_fqcn
|
||||
fail "Wrong syntax for type reference, expected eg nspace::a.b.C, !opts!nspace::a.b.C, or :nspace"
|
||||
fail "Wrong syntax for type reference, expected eg nspace::a.b.C, !opts!nspace::a.b.C, or :nspace, but got \'" + @type_fqcn + "\'"
|
||||
end
|
||||
|
||||
# If no options, then split produces [@type_fqcn]
|
||||
@ -130,14 +139,11 @@ class JavadocTag < Liquid::Tag
|
||||
elsif tag_name == "jdoc_old"
|
||||
@use_previous_api_version = true
|
||||
end
|
||||
end
|
||||
|
||||
def render(var_ctx)
|
||||
|
||||
artifact_name, @type_fqcn = JDocNamespaceDeclaration::parse_fqcn(@type_fqcn, var_ctx)
|
||||
resolved_type = JavadocTag::fqcn_type(artifact_name, @type_fqcn)
|
||||
|
||||
JavadocTag::diagnose(artifact_name, @type_fqcn, @is_package_ref, resolved_type)
|
||||
diagnose(var_ctx, artifact_name, @type_fqcn, @is_package_ref, resolved_type)
|
||||
|
||||
# Expand FQCN of arguments
|
||||
@member_suffix.gsub!(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX) {|fqcn| JDocNamespaceDeclaration::parse_fqcn(fqcn, var_ctx)[1]}
|
||||
@ -215,15 +221,18 @@ class JavadocTag < Liquid::Tag
|
||||
|
||||
BASE_PMD_DIR = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..")
|
||||
|
||||
def self.diagnose(artifact_id, fqcn, expect_package, resolved_type)
|
||||
def diagnose(context, artifact_id, fqcn, expect_package, resolved_type)
|
||||
tag_name= expect_package ? "jdoc_package" : "jdoc"
|
||||
# Note: the line numbers don't account for the frontmatter lines
|
||||
# See https://github.com/jekyll/jekyll/issues/7192 and https://github.com/jekyll/jekyll/pull/9385
|
||||
location = "#{context['page']['path']}:#{@line_number}+?"
|
||||
|
||||
if resolved_type == :package && !expect_package
|
||||
warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but it was found to be a package name. Did you mean to use jdoc_package instead of jdoc?\e[0m"
|
||||
warn "\e[33;1m#{location}: #{tag_name} generated link to #{fqcn}, but it was found to be a package name. Did you mean to use jdoc_package instead of jdoc?\e[0m"
|
||||
elsif resolved_type == :file && expect_package
|
||||
warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but it was found to be a java file name. Did you mean to use jdoc instead of jdoc_package?\e[0m"
|
||||
warn "\e[33;1m#{location}: #{tag_name} generated link to #{fqcn}, but it was found to be a java file name. Did you mean to use jdoc instead of jdoc_package?\e[0m"
|
||||
elsif !resolved_type
|
||||
warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but the #{expect_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m"
|
||||
warn "\e[33;1m#{location}: #{tag_name} generated link to #{fqcn}, but the #{expect_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -99,10 +99,11 @@ class JDocNamespaceDeclaration < Liquid::Tag
|
||||
private
|
||||
|
||||
JDOC_NAMESPACE_MAP = "jdoc_nspaces"
|
||||
RESERVED_NSPACES = ['ant', 'apex', 'core', 'cpp', 'cs', 'dart', 'dist', 'doc', 'fortran', 'go', 'groovy', 'java',
|
||||
'javascript', 'jsp',
|
||||
'kotlin', 'lua', 'matlab', 'objectivec', 'perl', 'php', 'plsql', 'python', 'ruby', 'scala', 'swift',
|
||||
'test', 'test-schema', 'ui',
|
||||
RESERVED_NSPACES = ['ant', 'apex', 'cli', 'coco', 'core', 'cpp', 'cs', 'dart', 'dist', 'doc',
|
||||
'fortran', 'gherkin', 'go', 'groovy', 'html', 'java',
|
||||
'javascript', 'jsp', 'julia',
|
||||
'kotlin', 'lang-test', 'lua', 'matlab', 'objectivec', 'perl', 'php', 'plsql', 'python', 'ruby', 'scala', 'swift',
|
||||
'test', 'test-schema', 'tsql', 'ui',
|
||||
'modelica', 'visualforce', 'vm', 'xml'].flat_map {|m| [m, "pmd-" + m]}
|
||||
|
||||
def self.make_base_namespaces
|
||||
|
@ -1007,9 +1007,12 @@ span.soft {
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 990px) {
|
||||
@media (min-height: 600px) and (min-width: 990px) {
|
||||
/* sticky sidebar for big screens */
|
||||
#mysidebar {
|
||||
position: relative;
|
||||
position: fixed !important;
|
||||
overflow: scroll;
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1025,6 +1028,15 @@ span.soft {
|
||||
}
|
||||
}
|
||||
|
||||
#inline-toc-details {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 1350px) {
|
||||
#inline-toc-details {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.col-md-9 img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
@ -1259,3 +1271,7 @@ h4.panel-title {
|
||||
a.edit-header {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.language-info {
|
||||
margin: 2em;
|
||||
}
|
||||
|
@ -87,3 +87,10 @@ li.sidebarTitle {
|
||||
margin-bottom:2.5px;
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 5px solid #01c172;
|
||||
padding: 10px 0 10px 1rem;
|
||||
margin: 1rem 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -17,17 +17,6 @@ $(document).ready(function () {
|
||||
headers: 'h2,h3,h4',
|
||||
});
|
||||
|
||||
$('#mysidebar').height($(".nav").height());
|
||||
|
||||
// this script says, if the height of the viewport is greater than 600px, then insert position-fixed class,
|
||||
// which makes the nav bar float in a fixed position as your scroll. If you have a lot of nav items,
|
||||
// this height may not work for you.
|
||||
var h = $(window).height();
|
||||
//console.log (h);
|
||||
if (h > 600) {
|
||||
$( '#mysidebar' ).attr('class', 'nav position-fixed');
|
||||
}
|
||||
|
||||
// activate tooltips. although this is a bootstrap js function, it must be activated this way in your theme.
|
||||
$('[data-toggle="tooltip"]').tooltip({
|
||||
placement: 'top',
|
||||
|
@ -56,8 +56,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* Make sure to add your new module to PMD's parent pom as `<module>` entry, so that it is built alongside the
|
||||
other languages.
|
||||
* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
|
||||
is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion
|
||||
in the pmd-cli module.
|
||||
is automatically available in the binary distribution (pmd-dist).
|
||||
|
||||
|
||||
## 2. Implement an AST parser for your language
|
||||
@ -120,13 +119,13 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* This is needed to support CPD (copy paste detection)
|
||||
* We provide a default implementation using [`AntlrTokenManager`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java).
|
||||
* You must create your own "AntlrTokenizer" such as we do with
|
||||
[`SwiftTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java).
|
||||
[`SwiftTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/cpd/SwiftTokenizer.java).
|
||||
* If you wish to filter specific tokens (e.g. comments to support CPD suppression via "CPD-OFF" and "CPD-ON")
|
||||
you can create your own implementation of
|
||||
[`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java).
|
||||
[`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenFilter.java).
|
||||
You'll need to override then the protected method `getTokenFilter(AntlrTokenManager)`
|
||||
and return your custom filter. See the tokenizer for C# as an exmaple:
|
||||
[`CsTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java).
|
||||
[`CsTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-cs/src/main/java/net/sourceforge/pmd/lang/cs/cpd/CsTokenizer.java).
|
||||
|
||||
If you don't need a custom token filter, you don't need to override the method. It returns the default
|
||||
`AntlrTokenFilter` which doesn't filter anything.
|
||||
@ -143,7 +142,9 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* For a minimal implementation, it just needs to return a parser *(see step #6)*.
|
||||
* It can be used to provide other features for your language like
|
||||
* violation suppression logic
|
||||
* violation decorators, to add additional language specific information to the created violations
|
||||
* {% jdoc core::reporting::ViolationDecorator %}s, to add additional language specific information to the
|
||||
created violations. The [Java language module](pmd_languages_java.html#violation-decorators) uses this to
|
||||
provide the method name or class name, where the violation occurred.
|
||||
* metrics
|
||||
* custom XPath functions
|
||||
|
||||
@ -169,7 +170,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
## 10. Create an abstract rule class for the language
|
||||
* You need to create your own abstract rule class in order to interface your language with PMD's generic rule
|
||||
execution.
|
||||
* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java) as an example.
|
||||
* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/AbstractSwiftRule.java) as an example.
|
||||
* The rule basically just extends
|
||||
[`AbstractVisitorRule`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractVisitorRule.java)
|
||||
and only redefines the abstract `buildVisitor()` method to return our own type of visitor.
|
||||
@ -229,3 +230,25 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
This will load all rulesets and verify, that all required attributes are provided.
|
||||
|
||||
*Note:* You'll need to add your ruleset to `categories.properties`, so that it can be found.
|
||||
|
||||
### 15. Create documentation page
|
||||
Finishing up your new language module by adding a page in the documentation. Create a new markdown file
|
||||
`<langId>.md` in `docs/pages/pmd/languages/`. This file should have the following frontmatter:
|
||||
|
||||
```
|
||||
---
|
||||
title: <Language Name>
|
||||
permalink: pmd_languages_<langId>.html
|
||||
last_updated: <Month> <Year> (<PMD Version>)
|
||||
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
|
||||
---
|
||||
```
|
||||
|
||||
On this page, language specifics can be documented, e.g. when the language was first supported by PMD.
|
||||
There is also the following Jekyll Include, that creates summary box for the language:
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
{% include language_info.html name='<Language Name>' id='<langId>' implementation='<langId>::lang.<langId>.<langId>LanguageModule' supports_cpd=true supports_pmd=true %}
|
||||
{% endraw %}
|
||||
```
|
||||
|
@ -33,22 +33,22 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
|
||||
" %}
|
||||
|
||||
## Steps
|
||||
|
||||
## 1. Start with a new sub-module
|
||||
### 1. Start with a new sub-module
|
||||
* See pmd-java or pmd-vm for examples.
|
||||
* Make sure to add your new module to PMD's parent pom as `<module>` entry, so that it is built alongside the
|
||||
other languages.
|
||||
* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
|
||||
is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion
|
||||
in the pmd-cli module.
|
||||
is automatically available in the binary distribution (pmd-dist).
|
||||
|
||||
## 2. Implement an AST parser for your language
|
||||
### 2. Implement an AST parser for your language
|
||||
* Ideally an AST parser should be implemented as a JJT file *(see VmParser.jjt or Java.jjt for example)*
|
||||
* There is nothing preventing any other parser implementation, as long as you have some way to convert an input
|
||||
stream into an AST tree. Doing it as a JJT simplifies maintenance down the road.
|
||||
* See this link for reference: [https://javacc.java.net/doc/JJTree.html](https://javacc.java.net/doc/JJTree.html)
|
||||
|
||||
## 3. Create AST node classes
|
||||
### 3. Create AST node classes
|
||||
* For each AST node that your parser can generate, there should be a class
|
||||
* The name of the AST class should be “AST” + “whatever is the name of the node in JJT file”.
|
||||
* For example, if JJT contains a node called “IfStatement”, there should be a class called “ASTIfStatement”
|
||||
@ -57,7 +57,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
creation later. *(see SimpleNode for Velocity and AbstractJavaNode for Java for example)*
|
||||
* Note: These AST node classes are generated usually once by javacc/jjtree and can then be modified as needed.
|
||||
|
||||
## 4. Generate your parser (using JJT)
|
||||
### 4. Generate your parser (using JJT)
|
||||
* An ant script is being used to compile jjt files into classes. This is in `javacc-wrapper.xml` file in the
|
||||
top-level pmd sources.
|
||||
* The ant script is executed via the `maven-antrun-plugin`. Add this plugin to your `pom.xml` file and configure
|
||||
@ -65,7 +65,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* The ant script is called in the phase `generate-sources` whenever the whole project is built. But you can
|
||||
call `./mvnw generate-sources` directly for your module if you want your parser to be generated.
|
||||
|
||||
## 5. Create a PMD parser “adapter”
|
||||
### 5. Create a PMD parser “adapter”
|
||||
* Create a new class that extends `JjtreeParserAdapter`.
|
||||
* This is a generic class, and you need to declare the root AST node.
|
||||
* There are two important methods to implement
|
||||
@ -75,18 +75,20 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* `parseImpl` method should return the root node of the AST tree obtained by parsing the CharStream source
|
||||
* See `VmParser` class as an example
|
||||
|
||||
## 6. Create a language version handler
|
||||
### 6. Create a language version handler
|
||||
* Extend `AbstractPmdLanguageVersionHandler` *(see VmHandler for example)*
|
||||
* This class is sort of a gateway between PMD and all parsing logic specific to your language.
|
||||
* For a minimal implementation, it just needs to return a parser *(see step #5)*.
|
||||
* It can be used to provide other features for your language like
|
||||
* violation suppression logic
|
||||
* violation decorators, to add additional language specific information to the created violations
|
||||
* {% jdoc core::reporting::ViolationDecorator %}s, to add additional language specific information to the
|
||||
created violations. The [Java language module](pmd_languages_java.html#violation-decorators) uses this to
|
||||
provide the method name or class name, where the violation occurred.
|
||||
* metrics (see below "Optional features")
|
||||
* custom XPath functions
|
||||
* See `VmHandler` class as an example
|
||||
|
||||
## 7. Create a base visitor
|
||||
### 7. Create a base visitor
|
||||
* A parser visitor adapter is not needed anymore with PMD 7. The visitor interface now provides a default
|
||||
implementation.
|
||||
* The visitor for JavaCC based AST is generated along the parser from the grammar file. The
|
||||
@ -95,7 +97,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* In order to help use this visitor later on, a base visitor class should be created.
|
||||
See `VmVisitorBase` as an example.
|
||||
|
||||
## 8. Make PMD recognize your language
|
||||
### 8. Make PMD recognize your language
|
||||
* Create your own subclass of `net.sourceforge.pmd.lang.impl.SimpleLanguageModuleBase`. *(see VmLanguageModule or
|
||||
JavaLanguageModule as an example)*
|
||||
* Add for each version of your language a call to `addVersion` in your language module’s constructor.
|
||||
@ -104,7 +106,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
|
||||
* Create the service registration via the text file `src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language`.
|
||||
Add your fully qualified class name as a single line into it.
|
||||
|
||||
## 9. Add AST regression tests
|
||||
### 9. Add AST regression tests
|
||||
|
||||
For languages, that use an external library for parsing, the AST can easily change when upgrading the library.
|
||||
Also for languages, where we have the grammar under our control, it is useful to have such tests.
|
||||
@ -151,19 +153,19 @@ The Scala module also has a test, written in Kotlin instead of Java:
|
||||
`net.sourceforge.pmd.lang.scala.ast.ScalaParserTests`.
|
||||
|
||||
|
||||
## 10. Create an abstract rule class for the language
|
||||
### 10. Create an abstract rule class for the language
|
||||
* Extend `AbstractRule` and implement the parser visitor interface for your language *(see AbstractVmRule for example)*
|
||||
* All other rules for your language should extend this class. The purpose of this class is to implement visit
|
||||
methods for all AST types to simply delegate to default behavior. This is useful because most rules care only
|
||||
about specific AST nodes, but PMD needs to know what to do with each node - so this just lets you use default
|
||||
behavior for nodes you don’t care about.
|
||||
|
||||
## 11. Create rules
|
||||
### 11. Create rules
|
||||
* Rules are created by extending the abstract rule class created in step 9 *(see `EmptyForeachStmtRule` for example)*
|
||||
* Creating rules is already pretty well documented in PMD - and it’s no different for a new language,
|
||||
except you may have different AST nodes.
|
||||
|
||||
## 12. Test the rules
|
||||
### 12. Test the rules
|
||||
* Testing rules is described in depth in [Testing your rules](pmd_userdocs_extending_testing.html).
|
||||
* Each rule has its own test class: Create a test class for your rule extending `PmdRuleTst`
|
||||
*(see AvoidReassigningParametersTest in pmd-vm for example)*
|
||||
@ -181,6 +183,29 @@ The Scala module also has a test, written in Kotlin instead of Java:
|
||||
|
||||
*Note:* You'll need to add your category ruleset to `categories.properties`, so that it can be found.
|
||||
|
||||
### 13. Create documentation page
|
||||
Finishing up your new language module by adding a page in the documentation. Create a new markdown file
|
||||
`<langId>.md` in `docs/pages/pmd/languages/`. This file should have the following frontmatter:
|
||||
|
||||
```
|
||||
---
|
||||
title: <Language Name>
|
||||
permalink: pmd_languages_<langId>.html
|
||||
last_updated: <Month> <Year> (<PMD Version>)
|
||||
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
|
||||
---
|
||||
```
|
||||
|
||||
On this page, language specifics can be documented, e.g. when the language was first supported by PMD.
|
||||
There is also the following Jekyll Include, that creates summary box for the language:
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
{% include language_info.html name='<Language Name>' id='<langId>' implementation='<langId>::lang.<langId>.<langId>LanguageModule' supports_cpd=true supports_pmd=true %}
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
|
||||
## Debugging with Rule Designer
|
||||
|
||||
When implementing your grammar it may be very useful to see how PMD parses your example files.
|
||||
@ -193,9 +218,9 @@ This can be achieved with Rule Designer:
|
||||
* Register it in the `AvailableSyntaxHighlighters` enumeration.
|
||||
* Now build your implementation and place the `target/pmd-ui-<version>-SNAPSHOT.jar` to the `lib` directory inside your `pmd-bin-...` distribution (you have to delete old `pmd-ui-*.jar` from there).
|
||||
|
||||
# Optional features
|
||||
## Optional features
|
||||
|
||||
## Metrics
|
||||
### Metrics
|
||||
|
||||
If you want to add support for computing metrics:
|
||||
* Create a package `lang.<langname>.metrics`
|
||||
|
@ -1,106 +1,133 @@
|
||||
---
|
||||
title: How to add a new CPD language
|
||||
short_title: Add a new CPD language
|
||||
short_title: Adding a new CPD language
|
||||
tags: [devdocs, extending]
|
||||
summary: How to add a new CPD language
|
||||
last_updated: March 18, 2019 (6.13.0)
|
||||
summary: How to add a new language module with CPD support.
|
||||
last_updated: April 2023 (7.0.0)
|
||||
permalink: pmd_devdocs_major_adding_new_cpd_language.html
|
||||
author: Matías Fraga <fragamati@gmail.com>
|
||||
author: Matías Fraga, Clément Fournier
|
||||
---
|
||||
|
||||
First of all, thanks for the contribution!
|
||||
## Adding support for a CPD language
|
||||
|
||||
Happily for you, to add CPD support for a new language is now easier than ever!
|
||||
CPD works generically on the tokens produced by a {% jdoc core::cpd.Tokenizer %}.
|
||||
To add support for a new language, the crucial piece is writing a tokenizer that
|
||||
splits the source file into the tokens specific to your language. Thankfully you
|
||||
can use a stock [Antlr grammar](https://github.com/antlr/grammars-v4) or JavaCC
|
||||
grammar to generate a lexer for you. If you cannot use a lexer generator, for
|
||||
instance because you are wrapping a lexer from another library, it is still relatively
|
||||
easy to implement the Tokenizer interface.
|
||||
|
||||
{% include callout.html content="**Pro Tip**: If you wish to add a new language, there are more than 50 languages you could easily add with just an [Antlr grammar](https://github.com/antlr/grammars-v4)." type="primary" %}
|
||||
Use the following guide to set up a new language module that supports CPD.
|
||||
|
||||
All you need to do is follow this few steps:
|
||||
1. Create a new Maven module for your language. You can take [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go/pom.xml) as an example.
|
||||
- Make sure to add your new module to the parent pom as `<module>` entry, so that it is built alongside the
|
||||
other languages.
|
||||
- Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
|
||||
is automatically available in the binary distribution (pmd-dist).
|
||||
|
||||
1. Create a new module for your language, you can take [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go) as an example
|
||||
* Make sure to add your new module to the parent pom as `<module>` entry, so that it is built alongside the
|
||||
other languages.
|
||||
* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
|
||||
is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion
|
||||
in the pmd-cli module.
|
||||
2. Implement a {% jdoc core::cpd.Tokenizer %}.
|
||||
- For Antlr grammars you can take the grammar from [antlr/grammars-v4](https://github.com/antlr/grammars-v4) and place it in `src/main/antlr4` followed by the package name of the language. You then need to call the appropriate ant wrapper to generate
|
||||
the lexer from the grammar. To do so, edit `pom.xml` (eg like [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go/pom.xml)).
|
||||
Once that is done, `mvn generate-sources` should generate the lexer sources for you.
|
||||
|
||||
2. Create a Tokenizer
|
||||
|
||||
- For Antlr grammars you can take the grammar from [here](https://github.com/antlr/grammars-v4) and
|
||||
extend [AntlrTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java)
|
||||
taking Go as an example
|
||||
|
||||
```java
|
||||
public class GoTokenizer extends AntlrTokenizer {
|
||||
|
||||
@Override protected AntlrTokenManager getLexerForSource(SourceCode sourceCode) {
|
||||
CharStream charStream = AntlrTokenizer.getCharStreamFromSourceCode(sourceCode);
|
||||
return new AntlrTokenManager(new GolangLexer(charStream), sourceCode.getFileName());
|
||||
}
|
||||
}
|
||||
You can now implement a tokenizer, for instance by extending {% jdoc core::cpd.impl.AntlrTokenizer %}. The following reproduces the Go implementation:
|
||||
```java
|
||||
// mind the package convention if you are going to make a PR
|
||||
package net.sourceforge.pmd.lang.go.cpd;
|
||||
|
||||
public class GoTokenizer extends AntlrTokenizer {
|
||||
|
||||
@Override
|
||||
protected Lexer getLexerForSource(CharStream charStream) {
|
||||
return new GolangLexer(charStream);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- For JavaCC grammars you should subclass [JavaCCTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/JavaCCTokenizer.java)
|
||||
which has many examples you could follow, you should also take the
|
||||
[Python implementation](https://github.com/pmd/pmd/blob/master/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java) as reference
|
||||
- For any other scenario you can use [AnyTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AnyTokenizer.java)
|
||||
- For JavaCC grammars, place your grammar in `etc/grammar` and edit the `pom.xml` like the [Python implementation](https://github.com/pmd/pmd/blob/master/pmd-python/pom.xml) does.
|
||||
You can then subclass {% jdoc core::cpd.impl.JavaCCTokenizer %} instead of AntlrTokenizer.
|
||||
- For any other scenario just implement the interface however you can. Look at the Scala or Apex module for existing implementations.
|
||||
|
||||
If you're using Antlr or JavaCC, update the pom.xml of your submodule to use the appropriate ant wrapper. See `pmd-go/pom.xml` and `pmd-python/pom.xml` for examples.
|
||||
|
||||
3. Create your [Language](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AbstractLanguage.java) class
|
||||
3. Create a {% jdoc core::lang.Language %} implementation, and make it implement {% jdoc core::cpd.CpdCapableLanguage %}.
|
||||
If your language only supports CPD, then you can subclass {% jdoc core::lang.impl.CpdOnlyLanguageModuleBase %} to get going:
|
||||
|
||||
```java
|
||||
public class GoLanguage extends AbstractLanguage {
|
||||
```java
|
||||
// mind the package convention if you are going to make a PR
|
||||
package net.sourceforge.pmd.lang.go;
|
||||
|
||||
public class GoLanguageModule extends CpdOnlyLanguageModuleBase {
|
||||
|
||||
public GoLanguage() {
|
||||
super("Go", "go", new GoTokenizer(), ".go");
|
||||
}
|
||||
// A public noarg constructor is required.
|
||||
public GoLanguageModule() {
|
||||
super(LanguageMetadata.withId("go").name("Go").extensions("go"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tokenizer createCpdTokenizer(LanguagePropertyBundle bundle) {
|
||||
// This method should return an instance of the tokenizer you created.
|
||||
return new GoTokenizer();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% include callout.html content="**Pro Tip**: Yes, keep looking at Go!" type="primary" %}
|
||||
|
||||
**You are almost there!**
|
||||
|
||||
4. Update the list of supported languages
|
||||
```
|
||||
|
||||
- Write the fully-qualified name of your Language class to the file `src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language`
|
||||
To make PMD find the language module at runtime, write the fully-qualified name of your language class into the file `src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language`.
|
||||
|
||||
- Update the test that asserts the list of supported languages by updating the `SUPPORTED_LANGUAGES` constant in [BinaryDistributionIT](https://github.com/pmd/pmd/blob/master/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java)
|
||||
At this point the new language module should be available in {% jdoc core::lang.LanguageRegistry#CPD %} and usable by CPD like any other language.
|
||||
|
||||
5. Please don't forget to add some test, you can again.. look at Go implementation ;)
|
||||
|
||||
If you read this far, I'm keen to think you would also love to support some extra CPD configuration (ignore imports or crazy things like that)
|
||||
If that's your case , you came to the right place!
|
||||
|
||||
6. You can add your custom properties using a Token filter
|
||||
|
||||
- For Antlr grammars all you need to do is implement your own [AntlrTokenFilter](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java)
|
||||
|
||||
And by now, I know where you are going to look...
|
||||
|
||||
**WRONG**
|
||||
|
||||
Why do you want GO to solve all your problems?
|
||||
|
||||
You should take a look to [Kotlin token filter implementation](https://github.com/pmd/pmd/blob/master/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java)
|
||||
|
||||
- For non-Antlr grammars you can use [BaseTokenFilter](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java) directly or take a peek to [Java's token filter](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java)
|
||||
4. Update the test that asserts the list of supported languages by updating the `SUPPORTED_LANGUAGES` constant in [BinaryDistributionIT](https://github.com/pmd/pmd/blob/master/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java).
|
||||
|
||||
5. Add some tests for your tokenizer by following the [section below](#testing-your-implementation).
|
||||
|
||||
6. Finishing up your new language module by adding a page in the documentation. Create a new markdown file
|
||||
`<langId>.md` in `docs/pages/pmd/languages/`. This file should have the following frontmatter:
|
||||
|
||||
```
|
||||
---
|
||||
title: <Language Name>
|
||||
permalink: pmd_languages_<langId>.html
|
||||
last_updated: <Month> <Year> (<PMD Version>)
|
||||
tags: [languages, CpdCapableLanguage]
|
||||
---
|
||||
```
|
||||
|
||||
On this page, language specifics can be documented, e.g. when the language was first supported by PMD.
|
||||
There is also the following Jekyll Include, that creates summary box for the language:
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
{% include language_info.html name='<Language Name>' id='<langId>' implementation='<langId>::lang.<langId>.<langId>LanguageModule' supports_cpd=true %}
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
### Declaring tokenizer options
|
||||
|
||||
To make the tokenizer configurable, first define some property descriptors using
|
||||
{% jdoc core::properties.PropertyFactory %}. Look at {% jdoc core::cpd.Tokenizer %}
|
||||
for some predefined ones which you can reuse (prefer reusing property descriptors if you can).
|
||||
You need to override {% jdoc core::Language#newPropertyBundle() %}
|
||||
and call `definePropertyDescriptor` to register the descriptors.
|
||||
After that you can access the values of the properties from the parameter
|
||||
of {% jdoc core::cpd.CpdCapableLanguage#createCpdTokenizer(core::lang.LanguagePropertyBundle) %}.
|
||||
|
||||
To implement simple token filtering, you can use {% jdoc core::cpd.impl.BaseTokenFilter %}
|
||||
as a base class, or another base class in {% jdoc_package core::cpd.impl %}.
|
||||
Take a look at the [Kotlin token filter implementation](https://github.com/pmd/pmd/blob/master/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/cpd/KotlinTokenizer.java), or the [Java one](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/cpd/JavaTokenizer.java).
|
||||
|
||||
|
||||
### Testing your implementation
|
||||
|
||||
Add a Maven dependency on `pmd-lang-test` (scope `test`) in your `pom.xml`.
|
||||
This contains utilities to test your Tokenizer.
|
||||
|
||||
For simple tests, create a test class extending from `CpdTextComparisonTest`.
|
||||
That class is written in Kotlin, but you can extend it in Java as well.
|
||||
This contains utilities to test your tokenizer.
|
||||
|
||||
Create a test class extending from {% jdoc lang-test::cpd.test.CpdTextComparisonTest %}.
|
||||
To add tests, you need to write regular JUnit `@Test`-annotated methods, and
|
||||
call the method `doTest` with the name of the test file.
|
||||
|
||||
For example, for the Dart language:
|
||||
|
||||
```java
|
||||
package net.sourceforge.pmd.lang.dart.cpd;
|
||||
|
||||
public class DartTokenizerTest extends CpdTextComparisonTest {
|
||||
|
||||
@ -110,20 +137,15 @@ public class DartTokenizerTest extends CpdTextComparisonTest {
|
||||
|
||||
|
||||
public DartTokenizerTest() {
|
||||
super(".dart"); // the file extension for the dart language
|
||||
super("dart", ".dart"); // the ID of the language, then the file extension used by test files
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getResourcePrefix() {
|
||||
// If your class is in src/test/java /some/package
|
||||
// you need to place the test files in src/test/resources/some/package/cpdData
|
||||
return "cpdData";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tokenizer newTokenizer() {
|
||||
// Override this abstract method to return the correct tokenizer
|
||||
return new DartTokenizer();
|
||||
// "testdata" is the default value, you don't need to override.
|
||||
// This specifies that you should place the test files in
|
||||
// src/test/resources/net/sourceforge/pmd/lang/dart/cpd/testdata
|
||||
return "testdata";
|
||||
}
|
||||
|
||||
/**************
|
||||
|
@ -1,15 +1,40 @@
|
||||
---
|
||||
title: Apex support
|
||||
permalink: pmd_languages_apex.html
|
||||
last_updated: September 2023 (7.0.0)
|
||||
author: Clément Fournier
|
||||
last_updated: March 2021 (7.0.0)
|
||||
tags: [languages]
|
||||
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
|
||||
summary: "Apex-specific features and guidance"
|
||||
---
|
||||
|
||||
{% include warning.html content="Todo for pmd 7" %}
|
||||
> [Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dev_guide.htm) is a strongly
|
||||
> typed, object-oriented programming language that allows developers to execute flow and
|
||||
> transaction control statements on the Salesforce Platform server, in conjunction with calls to the API.
|
||||
|
||||
### Metrics framework
|
||||
{% include language_info.html name='Apex' id='apex' implementation='apex::lang.apex.ApexLanguageModule' supports_pmd=true supports_cpd=true since='5.5.0' %}
|
||||
|
||||
In order to use code metrics in Java, use the metrics constants in {% jdoc apex::lang.apex.metrics.ApexMetrics %},
|
||||
## Metrics framework
|
||||
|
||||
In order to use code metrics in Apex, use the metrics constants in {% jdoc apex::lang.apex.metrics.ApexMetrics %},
|
||||
together with {% jdoc core::lang.metrics.MetricsUtil %}.
|
||||
|
||||
## Multifile Analysis
|
||||
|
||||
Integration happens in {% jdoc apex::lang.apex.multifile.ApexMultifileAnalysis %}. It uses
|
||||
[ApexLink](https://github.com/nawforce/apex-link). For detailed information, see also [Apexlink POC #2830](https://github.com/pmd/pmd/pull/2830).
|
||||
|
||||
{% include note.html content="ApexLink's new home: <https://github.com/apex-dev-tools>" %}
|
||||
|
||||
Used for rule {% rule apex/design/UnusedMethod %}
|
||||
|
||||
## Language Properties
|
||||
|
||||
See [Apex language properties](pmd_languages_configuration.html#apex-language-properties)
|
||||
|
||||
## Parser
|
||||
|
||||
We use Jorje, the Apex parsers that is shipped within the Apex Language Server. This is part of
|
||||
the [Salesforce Extensions for VS Code](https://github.com/forcedotcom/salesforcedx-vscode).
|
||||
|
||||
We take the binary from <https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/packages/salesforcedx-vscode-apex/out>
|
||||
and provide it as a maven dependency (see [pmd-apex-jorje](https://github.com/pmd/pmd/tree/master/pmd-apex-jorje)).
|
||||
|
@ -1,10 +1,15 @@
|
||||
---
|
||||
title: Coco
|
||||
title: Coco support
|
||||
permalink: pmd_languages_coco.html
|
||||
last_updated: September 2023 (7.0.0)
|
||||
tags: [languages, CpdCapableLanguage]
|
||||
summary: "Coco features and guidance"
|
||||
---
|
||||
|
||||
Coco is a modern programming language designed specifically for building event-driven software.
|
||||
It is part of the Coco Platform from <https://cocotec.io/>.
|
||||
> Coco is a modern programming language designed specifically for building event-driven software.
|
||||
> It is part of the Coco Platform from <https://cocotec.io/>.
|
||||
|
||||
{% include language_info.html name='Coco' id='coco' implementation='coco::lang.coco.CocoLanguageModule' supports_cpd=true since='7.0.0' %}
|
||||
|
||||
## Support in PMD
|
||||
Starting from version 7.0.0, Coco support was added to CPD.
|
||||
|
13
docs/pages/pmd/languages/cpp.md
Normal file
13
docs/pages/pmd/languages/cpp.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: C/C++ support
|
||||
permalink: pmd_languages_cpp.html
|
||||
last_updated: September 2023 (7.0.0)
|
||||
tags: [languages, CpdCapableLanguage]
|
||||
summary: "C/C++ features and guidance"
|
||||
---
|
||||
|
||||
{% include language_info.html name='C++' id='cpp' implementation='cpp::lang.cpp.CppLanguageModule' supports_cpd=true since='3.5' %}
|
||||
|
||||
## Language Properties
|
||||
|
||||
See [Cpp language properties](pmd_languages_configuration.html#cpp-language-properties)
|
9
docs/pages/pmd/languages/cs.md
Normal file
9
docs/pages/pmd/languages/cs.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
title: C# support
|
||||
permalink: pmd_languages_cs.html
|
||||
last_updated: September 2023 (7.0.0)
|
||||
tags: [languages, CpdCapableLanguage]
|
||||
summary: "C#-specific features and guidance"
|
||||
---
|
||||
|
||||
{% include language_info.html name='C#' id='cs' implementation='cs::lang.cs.CsLanguageModule' supports_cpd=true since='4.3' %}
|
11
docs/pages/pmd/languages/dart.md
Normal file
11
docs/pages/pmd/languages/dart.md
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Dart support
|
||||
permalink: pmd_languages_dart.html
|
||||
last_updated: September 2023 (7.0.0)
|
||||
tags: [languages, CpdCapableLanguage]
|
||||
summary: "Dart-specific features and guidance"
|
||||
---
|
||||
|
||||
> [Dart](https://dart.dev/) is a client-optimized language for fast apps on any platform.
|
||||
|
||||
{% include language_info.html name='Dart' id='dart' implementation='dart::lang.dart.DartLanguageModule' supports_cpd=true since='6.14.0' %}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user