diff --git a/.gitattributes b/.gitattributes index aa1753af324bc..63ca2fc710ef2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,8 +15,6 @@ *.json text *.jelly text *.jellytag text -# JENKINS-68887: postcss-less fails to properly parse .less files with Windows line breaks -*.less text eol=lf *.properties text *.rb text *.sh text diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 48c812c7f9109..f26d5d1de3b59 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -40,17 +40,17 @@ For examples, see: https://www.jenkins.io/changelog/ N/A +```[tasklist] ### Submitter checklist - - [ ] The Jira issue, if it exists, is well-described. -- [ ] The changelog entries and upgrade guidelines are appropriate for the audience affected by the change (users or developers, depending on the change) and are in the imperative mood (see [examples](https://github.com/jenkins-infra/jenkins.io/blob/master/content/_data/changelogs/weekly.yml)). - - Fill in the **Proposed upgrade guidelines** section only if there are breaking changes or changes that may require extra steps from users during upgrade. +- [ ] The changelog entries and upgrade guidelines are appropriate for the audience affected by the change (users or developers, depending on the change) and are in the imperative mood (see [examples](https://github.com/jenkins-infra/jenkins.io/blob/master/content/_data/changelogs/weekly.yml)). Fill in the **Proposed upgrade guidelines** section only if there are breaking changes or changes that may require extra steps from users during upgrade. - [ ] There is automated testing or an explanation as to why this change has no tests. - [ ] New public classes, fields, and methods are annotated with `@Restricted` or have `@since TODO` Javadocs, as appropriate. - [ ] New deprecations are annotated with `@Deprecated(since = "TODO")` or `@Deprecated(forRemoval = true, since = "TODO")`, if applicable. - [ ] New or substantially changed JavaScript is not defined inline and does not call `eval` to ease future introduction of Content Security Policy (CSP) directives (see [documentation](https://www.jenkins.io/doc/developer/security/csp/)). - [ ] For dependency updates, there are links to external changelogs and, if possible, full differentials. - [ ] For new APIs and extension points, there is a link to at least one consumer. +``` ### Desired reviewers @@ -60,13 +60,14 @@ N/A If you need an accelerated review process by the community (e.g., for critical bugs), mention @jenkinsci/core-pr-reviewers. --> -### Maintainer checklist - Before the changes are marked as `ready-for-merge`: +```[tasklist] +### Maintainer checklist - [ ] There are at least two (2) approvals for the pull request and no outstanding requests for change. - [ ] Conversations in the pull request are over, or it is explicit that a reviewer is not blocking the change. - [ ] Changelog entries in the pull request title and/or **Proposed changelog entries** are accurate, human-readable, and in the imperative mood. - [ ] Proper changelog labels are set so that the changelog can be generated automatically. - [ ] If the change needs additional upgrade steps from users, the `upgrade-guide-needed` label is set and there is a **Proposed upgrade guidelines** section in the pull request title (see [example](https://github.com/jenkinsci/jenkins/pull/4387)). - [ ] If it would make sense to backport the change to LTS, a Jira issue must exist, be a _Bug_ or _Improvement_, and be labeled as `lts-candidate` to be considered (see [query](https://issues.jenkins.io/issues/?filter=12146)). +``` diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000000000..dd96853821458 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,25 @@ +newPRWelcomeComment: > + Yay, your first pull request towards Jenkins core was created successfully! + Thank you so much! +
+
+ A contributor will provide feedback soon. + Meanwhile, you can join the [chats](https://app.gitter.im/#/room/#jenkins-ci:matrix.org) and [community forums](https://community.jenkins.io/) to connect with other Jenkins users, developers, and maintainers. + +firstPRMergeComment: > + Congratulations on getting your very first Jenkins core pull request merged 🎉🥳 +
+
+ This is a fantastic achievement, and we're thrilled to have you as part of our community! + Thank you for your valuable input, and we look forward to seeing more of your contributions in the future! +
+
+ We would like to invite you to join the [community chats](https://app.gitter.im/#/room/#jenkins-ci:matrix.org) and [forums](https://community.jenkins.io/) to meet other Jenkins contributors 😊 +
+ Don't forget to check out the [participation](https://www.jenkins.io/participate/) page to learn more about how to contribute to Jenkins. + + + + + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d4fc706d89542..6e7d93447f7d9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,7 +17,6 @@ updates: # version of Jetty we deliver. See: # https://github.com/jenkinsci/jenkins/pull/5211 - dependency-name: "jakarta.servlet:jakarta.servlet-api" - - dependency-name: "javax.servlet:javax.servlet-api" # Jetty Maven Plugin and Winstone should be upgraded in lockstep in order # to keep their corresponding Jetty versions aligned. @@ -52,9 +51,14 @@ updates: # Starting with 6.x, Spring Security requires Java 17 at a minimum. - dependency-name: "org.springframework.security:spring-security-bom" versions: [">=6.0.0"] + + # Starting with 7.x, Guice switches from javax.* to jakarta.* bindings. + # See https://github.com/google/guice/wiki/Guice700 + - dependency-name: "com.google.inject:guice-bom" + versions: [">=7.0.0"] - package-ecosystem: "maven" directory: "/" - target-branch: "stable-2.375" + target-branch: "stable-2.414" labels: - "into-lts" - "needs-justification" diff --git a/.github/images/jenkins-welcome.svg b/.github/images/jenkins-welcome.svg new file mode 100644 index 0000000000000..28aa849ebfafe --- /dev/null +++ b/.github/images/jenkins-welcome.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jenkins + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index dea378b71a474..18da01b85864f 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -7,7 +7,7 @@ tag-template: jenkins-$NEXT_MINOR_VERSION template: | _This is an automatically generated changelog draft for Jenkins weekly releases. - See https://www.jenkins.io/changelog/ for the official changelogs._ + See https://www.jenkins.io/changelog/#v$NEXT_MINOR_VERSION for the official changelog for this release, or https://www.jenkins.io/changelog-old/#v$NEXT_MINOR_VERSION for releases older than around 7 months._ $CHANGES diff --git a/.github/renovate.json b/.github/renovate.json index ce2f6a867a861..b6f6d7e650907 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -14,12 +14,6 @@ "stabilityDays": 3, "reviewers": ["team:sig-ux"] }, - { - "matchPackageNames": ["bootstrap"], - "allowedVersions": "<=3.4.1", - "description": "https://issues.jenkins.io/browse/JENKINS-69409", - "enabled": false - }, { "matchPackageNames": ["node"], "allowedVersions": "/18.[0-9]+.[0-9]+(.[0-9]+)?$/" @@ -44,6 +38,24 @@ "matchStrings": ["ARG MAVEN_VERSION=(?.*?)\n"], "depNameTemplate": "org.apache.maven:maven-core", "datasourceTemplate": "maven" + }, + { + "fileMatch": ["core/src/site/site.xml"], + "matchStrings": ["lit@(?.*?)/"], + "depNameTemplate": "lit", + "datasourceTemplate": "npm" + }, + { + "fileMatch": ["core/src/site/site.xml"], + "matchStrings": ["webcomponentsjs@(?.*?)/"], + "depNameTemplate": "@webcomponents/webcomponentsjs", + "datasourceTemplate": "npm" + }, + { + "fileMatch": ["core/src/site/site.xml"], + "matchStrings": ["(?.*?)<\/version>"], + "depNameTemplate": "org.apache.maven.skins:maven-fluido-skin", + "datasourceTemplate": "maven" } ], "labels": ["dependencies", "skip-changelog"], diff --git a/.github/workflows/announce-lts-rc.yml b/.github/workflows/announce-lts-rc.yml new file mode 100644 index 0000000000000..b544abd78f3e8 --- /dev/null +++ b/.github/workflows/announce-lts-rc.yml @@ -0,0 +1,30 @@ +name: Announce LTS RCs + +on: + release: + types: [prereleased] + +jobs: + post: + runs-on: ubuntu-latest + steps: + - name: Post on Discourse + uses: roots/discourse-topic-github-release-action@fc9e50fa1a1ce6255ba4d03f104382845b79ad5f # v1.0.0 + with: + discourse-api-key: ${{ secrets.DISCOURSE_RELEASES_API_KEY }} + discourse-base-url: https://community.jenkins.io/ + discourse-author-username: jenkins-release-bot + discourse-category: 23 + - name: Post on mailing list + uses: dawidd6/action-send-mail@v3 + with: + server_address: smtp.gmail.com + server_port: 465 + username: ${{secrets.MAIL_USERNAME}} + password: ${{secrets.MAIL_PASSWORD}} + secure: true + subject: ${{ github.event.release.tag_name }} has been released + to: jenkinsci-dev@googlegroups.com + from: Jenkins Release Bot + html_body: ${{ github.event.release.body }} + convert_markdown: true diff --git a/.github/workflows/label-lts-prs.yaml b/.github/workflows/label-lts-prs.yaml new file mode 100644 index 0000000000000..e947bd078f0fa --- /dev/null +++ b/.github/workflows/label-lts-prs.yaml @@ -0,0 +1,23 @@ +name: Label PRs targeting LTS branches + +on: [pull_request_target] + +permissions: + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Check if PR targets LTS branch + if: startsWith(github.event.pull_request.base.ref, 'stable-') + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.addLabels({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + issue_number: context.payload.pull_request.number, + labels: ['into-lts'] + }); diff --git a/.gitpod/Dockerfile b/.gitpod/Dockerfile index 83b644700f163..9f5ab9c02d915 100644 --- a/.gitpod/Dockerfile +++ b/.gitpod/Dockerfile @@ -1,6 +1,6 @@ FROM gitpod/workspace-full -ARG MAVEN_VERSION=3.9.1 +ARG MAVEN_VERSION=3.9.4 RUN brew install gh && \ bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && sdk install maven ${MAVEN_VERSION} && sdk default maven ${MAVEN_VERSION}" diff --git a/.idea/encodings.xml b/.idea/encodings.xml index a7f16f208d1df..de5572116383f 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -32,9 +32,6 @@ - - - diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 90787cbb2d51b..1f36364094f1d 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.6 + 1.7 diff --git a/Jenkinsfile b/Jenkinsfile index 1de19cbde01cf..ce0d1f068e388 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -12,12 +12,50 @@ properties([ disableConcurrentBuilds(abortPrevious: true) ]) -def builds = [:] - def axes = [ platforms: ['linux', 'windows'], jdks: [11, 17, 19], ] + +stage('Record build') { + retry(conditions: [kubernetesAgent(handleNonKubernetes: true), nonresumable()], count: 2) { + node('maven-11') { + infra.checkoutSCM() + + /* + * Record the primary build for this CI job. + */ + withCredentials([string(credentialsId: 'launchable-jenkins-jenkins', variable: 'LAUNCHABLE_TOKEN')]) { + /* + * TODO Add the commits of the transitive closure of the Jenkins WAR under test to this build. + */ + sh 'launchable verify && launchable record build --name ${BUILD_TAG} --source jenkinsci/jenkins=.' + axes.values().combinations { + def (platform, jdk) = it + if (platform == 'windows' && jdk != 17) { + return // unnecessary use of hardware + } + def sessionFile = "launchable-session-${platform}-jdk${jdk}.txt" + sh "launchable record session --build ${env.BUILD_TAG} --flavor platform=${platform} --flavor jdk=${jdk} >${sessionFile}" + stash name: sessionFile, includes: sessionFile + } + } + + /* + * Record commits for use in downstream CI jobs that may consume this artifact. + */ + withCredentials([string(credentialsId: 'launchable-jenkins-acceptance-test-harness', variable: 'LAUNCHABLE_TOKEN')]) { + sh 'launchable verify && launchable record commit' + } + withCredentials([string(credentialsId: 'launchable-jenkins-bom', variable: 'LAUNCHABLE_TOKEN')]) { + sh 'launchable verify && launchable record commit' + } + } + } +} + +def builds = [:] + axes.values().combinations { def (platform, jdk) = it if (platform == 'windows' && jdk != 17) { @@ -37,29 +75,50 @@ axes.values().combinations { infra.checkoutSCM() } - def changelistF = "${pwd tmp: true}/changelist" - def m2repo = "${pwd tmp: true}/m2repo" + def tmpDir = pwd(tmp: true) + def changelistF = "${tmpDir}/changelist" + def m2repo = "${tmpDir}/m2repo" + def session // Now run the actual build. stage("${platform.capitalize()} - JDK ${jdk} - Build / Test") { timeout(time: 6, unit: 'HOURS') { + dir(tmpDir) { + def sessionFile = "launchable-session-${platform}-jdk${jdk}.txt" + unstash sessionFile + session = readFile(sessionFile).trim() + } + def mavenOptions = [ + '-Pdebug', + '-Penable-jacoco', + '--update-snapshots', + "-Dmaven.repo.local=$m2repo", + '-Dmaven.test.failure.ignore', + '-DforkCount=2', + '-Dspotbugs.failOnError=false', + '-Dcheckstyle.failOnViolation=false', + '-Dset.changelist', + 'help:evaluate', + '-Dexpression=changelist', + "-Doutput=$changelistF", + 'clean', + 'install', + ] + if (env.CHANGE_ID && !pullRequest.labels.contains('full-test')) { + def excludesFile + def target = platform == 'windows' ? '30%' : '100%' + withCredentials([string(credentialsId: 'launchable-jenkins-jenkins', variable: 'LAUNCHABLE_TOKEN')]) { + if (isUnix()) { + excludesFile = "${tmpDir}/excludes.txt" + sh "launchable verify && launchable subset --session ${session} --target ${target} --get-tests-from-previous-sessions --output-exclusion-rules maven >${excludesFile}" + } else { + excludesFile = "${tmpDir}\\excludes.txt" + bat "launchable verify && launchable subset --session ${session} --target ${target}% --get-tests-from-previous-sessions --output-exclusion-rules maven >${excludesFile}" + } + } + mavenOptions.add(0, "-Dsurefire.excludesFile=${excludesFile}") + } realtimeJUnit(healthScaleFactor: 20.0, testResults: '*/target/surefire-reports/*.xml') { - def mavenOptions = [ - '-Pdebug', - '-Penable-jacoco', - '--update-snapshots', - "-Dmaven.repo.local=$m2repo", - '-Dmaven.test.failure.ignore', - '-DforkCount=2', - '-Dspotbugs.failOnError=false', - '-Dcheckstyle.failOnViolation=false', - '-Dset.changelist', - 'help:evaluate', - '-Dexpression=changelist', - "-Doutput=$changelistF", - 'clean', - 'install', - ] infra.runMaven(mavenOptions, jdk) if (isUnix()) { sh 'git add . && git diff --exit-code HEAD' @@ -71,12 +130,6 @@ axes.values().combinations { // Once we've built, archive the artifacts and the test results. stage("${platform.capitalize()} - JDK ${jdk} - Publish") { archiveArtifacts allowEmptyArchive: true, artifacts: '**/target/surefire-reports/*.dumpstream' - if (!fileExists('core/target/surefire-reports/TEST-jenkins.Junit4TestsRanTest.xml')) { - error 'JUnit 4 tests are no longer being run for the core package' - } - if (!fileExists('test/target/surefire-reports/TEST-jenkins.Junit4TestsRanTest.xml')) { - error 'JUnit 4 tests are no longer being run for the test package' - } // cli and war have been migrated to JUnit 5 if (failFast && currentBuild.result == 'UNSTABLE') { error 'There were test failures; halting early' @@ -86,17 +139,27 @@ axes.values().combinations { if (folders.length > 1) { discoverGitReferenceBuild(scm: folders[1]) } - recordCoverage(tools: [[parser: 'JACOCO', pattern: 'coverage/target/site/jacoco-aggregate/jacoco.xml']], sourceCodeRetention: 'MODIFIED') + recordCoverage(tools: [[parser: 'JACOCO', pattern: 'coverage/target/site/jacoco-aggregate/jacoco.xml']], + sourceCodeRetention: 'MODIFIED', sourceDirectories: [[path: 'core/src/main/java']]) echo "Recording static analysis results for '${platform.capitalize()}'" recordIssues( enabledForFailure: true, - tools: [java(), javaDoc()], + tools: [java()], filters: [excludeFile('.*Assert.java')], sourceCodeEncoding: 'UTF-8', skipBlames: true, trendChartType: 'TOOLS_ONLY' ) + recordIssues( + enabledForFailure: true, + tools: [javaDoc()], + filters: [excludeFile('.*Assert.java')], + sourceCodeEncoding: 'UTF-8', + skipBlames: true, + trendChartType: 'TOOLS_ONLY', + qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]] + ) recordIssues([tool: spotBugs(pattern: '**/target/spotbugsXml.xml'), sourceCodeEncoding: 'UTF-8', skipBlames: true, @@ -117,37 +180,9 @@ axes.values().combinations { skipBlames: true, trendChartType: 'TOOLS_ONLY', qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]]]) - launchable.install() - withCredentials([string(credentialsId: 'launchable-jenkins-jenkins', variable: 'LAUNCHABLE_TOKEN')]) { - launchable('verify') - /* - * TODO Create a Launchable build and session earlier, and replace "--no-build" with - * "--session" to associate these test results with a particular build. The commits - * associated with the Launchable build should be the commits of the transitive - * closure of the Jenkins WAR under test in this build. - */ - launchable("record tests --no-build --flavor platform=${platform} --flavor jdk=${jdk} maven './**/target/surefire-reports'") - } if (failFast && currentBuild.result == 'UNSTABLE') { error 'Static analysis quality gates not passed; halting early' } - /* - * If the current build was successful, we send the commits to Launchable so that - * these commits can be consumed by a build in the Launchable BOM workspace in the - * future. - * - * TODO Move this up to before the present parallel block starts (or move the ATH run - * in this file to after joining on the present parallel block) so that these commits - * can be consumed by a build in the Launchable ATH workspace in this file in the - * future. - */ - if (currentBuild.currentResult == 'SUCCESS') { - withCredentials([string(credentialsId: 'launchable-jenkins-bom', variable: 'LAUNCHABLE_TOKEN')]) { - launchable('verify') - launchable('record commit') - } - } - def changelist = readFile(changelistF) dir(m2repo) { archiveArtifacts( @@ -158,6 +193,13 @@ axes.values().combinations { ) } } + withCredentials([string(credentialsId: 'launchable-jenkins-jenkins', variable: 'LAUNCHABLE_TOKEN')]) { + if (isUnix()) { + sh "launchable verify && launchable record tests --session ${session} --flavor platform=${platform} --flavor jdk=${jdk} maven './**/target/surefire-reports'" + } else { + bat "launchable verify && launchable record tests --session ${session} --flavor platform=${platform} --flavor jdk=${jdk} maven ./**/target/surefire-reports" + } + } } } } @@ -166,7 +208,7 @@ axes.values().combinations { def athAxes = [ platforms: ['linux'], - jdks: [11], + jdks: [17], browsers: ['firefox'], ] athAxes.values().combinations { @@ -178,21 +220,19 @@ athAxes.values().combinations { deleteDir() checkout scm infra.withArtifactCachingProxy { - sh 'bash ath.sh ' + browser + sh "bash ath.sh ${jdk} ${browser}" } junit testResults: 'target/ath-reports/TEST-*.xml', testDataPublishers: [[$class: 'AttachmentPublisher']] - launchable.install() - withCredentials([string(credentialsId: 'launchable-jenkins-acceptance-test-harness', variable: 'LAUNCHABLE_TOKEN')]) { - launchable('verify') - /* - * TODO Create a Launchable build and session earlier, and replace "--no-build" with - * "--session" to associate these test results with a particular build. The commits - * associated with the Launchable build should be the commits of the transitive closure of - * the Jenkins WAR under test in this build as well as the commits of the transitive closure - * of the ATH JAR. - */ - launchable("record tests --no-build --flavor platform=${platform} --flavor jdk=${jdk} --flavor browser=${browser} maven './target/ath-reports'") - } + /* + * Currently disabled, as the fact that this is a manually created subset will confuse Launchable, + * which expects this to be a full build. When we implement subsetting, this can be re-enabled using + * Launchable's subset rather than our own. + */ + /* + withCredentials([string(credentialsId: 'launchable-jenkins-acceptance-test-harness', variable: 'LAUNCHABLE_TOKEN')]) { + sh "launchable verify && launchable record tests --no-build --flavor platform=${platform} --flavor jdk=${jdk} --flavor browser=${browser} maven './target/ath-reports'" + } + */ } } } diff --git a/README.md b/README.md index 529c8234c4583..755a417ea158b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ - - - - + # About diff --git a/ath.sh b/ath.sh index bbb55908f25f0..08009178739ed 100644 --- a/ath.sh +++ b/ath.sh @@ -6,12 +6,14 @@ set -o xtrace cd "$(dirname "$0")" # https://github.com/jenkinsci/acceptance-test-harness/releases -export ATH_VERSION=5545.v924953404220 +export ATH_VERSION=5686.vc3a_26a_d441a_9 if [[ $# -eq 0 ]]; then + export JDK=17 export BROWSER=firefox else - export BROWSER=$1 + export JDK=$1 + export BROWSER=$2 fi MVN='mvn -B -ntp -Pquick-build -am -pl war package' @@ -25,6 +27,7 @@ mkdir -p target/ath-reports chmod a+rwx target/ath-reports exec docker run --rm \ + --env JDK \ --env ATH_VERSION \ --env BROWSER \ --shm-size 2g `# avoid selenium.WebDriverException exceptions like 'Failed to decode response from marionette' and webdriver closed` \ @@ -39,6 +42,7 @@ exec docker run --rm \ set -o pipefail set -o xtrace cd + set-java.sh "${JDK}" # Start the VNC system provided by the image from the default user home directory eval "$(vnc.sh)" env | sort diff --git a/bom/pom.xml b/bom/pom.xml index 10bdab349ce13..9f255a92df246 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -40,7 +40,7 @@ THE SOFTWARE. 9.5 2.0.7 - 1781.v62372c33644e + 1802.v9e2750160d01 2.4.21 @@ -49,14 +49,14 @@ THE SOFTWARE. com.google.inject guice-bom - 5.1.0 + 6.0.0 pom import org.springframework spring-framework-bom - 5.3.27 + 5.3.29 pom import @@ -64,7 +64,7 @@ THE SOFTWARE. org.springframework.security spring-security-bom - 5.8.3 + 5.8.5 pom import @@ -82,7 +82,7 @@ THE SOFTWARE. com.google.guava guava - 31.1-jre + 32.1.1-jre @@ -113,7 +113,7 @@ THE SOFTWARE. commons-codec commons-codec - 1.15 + 1.16.0 commons-collections @@ -128,7 +128,7 @@ THE SOFTWARE. commons-io commons-io - 2.11.0 + 2.13.0 commons-jelly @@ -225,7 +225,7 @@ THE SOFTWARE. org.jenkins-ci crypto-util - 1.8 + 1.9 org.jenkins-ci @@ -260,7 +260,7 @@ THE SOFTWARE. org.jvnet.hudson commons-jelly-tags-define - 1.1-jenkins-20230124 + 1.1-jenkins-20230713 org.jvnet.localizer @@ -295,7 +295,7 @@ THE SOFTWARE. org.kohsuke.metainf-services metainf-services - 1.9 + 1.11 org.kohsuke.stapler diff --git a/changelog.html b/changelog.html deleted file mode 100644 index cf08ed0484d97..0000000000000 --- a/changelog.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/cli/pom.xml b/cli/pom.xml index b6b743cf3f6b4..56560342e5f41 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -15,7 +15,7 @@ https://github.com/jenkinsci/jenkins - 2.9.2 + 2.10.0 @@ -119,7 +119,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.4.1 + 3.5.0 diff --git a/cli/src/main/java/hudson/cli/PlainCLIProtocol.java b/cli/src/main/java/hudson/cli/PlainCLIProtocol.java index 4f4fcfc49a664..e49daa246f889 100644 --- a/cli/src/main/java/hudson/cli/PlainCLIProtocol.java +++ b/cli/src/main/java/hudson/cli/PlainCLIProtocol.java @@ -277,7 +277,7 @@ protected final boolean handle(Op op, DataInputStream dis) throws IOException { onStart(); return true; case STDIN: - onStdin(IOUtils.toByteArray(dis)); + onStdin(dis.readAllBytes()); return true; case END_STDIN: onEndStdin(); @@ -327,10 +327,10 @@ protected boolean handle(Op op, DataInputStream dis) throws IOException { onExit(dis.readInt()); return true; case STDOUT: - onStdout(IOUtils.toByteArray(dis)); + onStdout(dis.readAllBytes()); return true; case STDERR: - onStderr(IOUtils.toByteArray(dis)); + onStderr(dis.readAllBytes()); return true; default: return false; diff --git a/cli/src/main/resources/hudson/cli/client/Messages_ru.properties b/cli/src/main/resources/hudson/cli/client/Messages_ru.properties new file mode 100644 index 0000000000000..ab55c185dc9fc --- /dev/null +++ b/cli/src/main/resources/hudson/cli/client/Messages_ru.properties @@ -0,0 +1,26 @@ +CLI.Usage=Jenkins CLI\n\ + Использование: java -jar jenkins-cli.jar [-s URL] command [opts...] args...\n\ + Параметры:\n\ + \ -s URL : URL сервера (по умолчанию используется переменная окружения JENKINS_URL)\n\ + \ -webSocket : Подключиться с помощью WebSocket (по умолчанию; хорошо работает с большинством обратных прокси-серверов; требует Jetty)\n\ + \ -http : Использовать пару соединений HTTP(S), а не WebSocket\n\ + \ -ssh : Использовать протокол SSH вместо WebSocket (требуется -user; порт SSH должен быть открыт на сервере)\n\ + \ -i KEY : Файл закрытого ключа SSH, используемый для аутентификации (для использования с -ssh)\n\ + \ -noCertificateCheck : Полностью обойти проверку сертификата HTTPS. Используйте с осторожностью\n\ + \ -noKeyAuth : Не пытайтесь загрузить закрытый ключ аутентификации SSH. Конфликты с -i\n\ + \ -user : Указать пользователя (для использования с -ssh; необходимо зарегистрировать открытый ключ)\n\ + \ -strictHostKey : Запрос строгой проверки ключей хоста (для использования с -ssh)\n\ + \ -logger FINE : Включить подробное ведение журнала с клиента\n\ + \ -auth [ USER:SECRET | @FILE ] : Указать имя пользователя и пароль или API-токен (или загрузить оба из файла);\n\ + \ для использования с -http.\n\ + \ Рекомендуется передавать учетные данные по файлам.\n\ + \ Более подробную информацию и варианты смотрите на сайте https://www.jenkins.io/redirect/cli-http-connection-mode.\n\ + \ -bearer [ TOKEN | @FILE ] : Указать аутентификацию с использованием токена (или загрузить токен из файла);\n\ + \ Для использования с -http. Взаимоисключающий вариант с -auth.\n\ + \ Рекомендуется передавать учетные данные через файл.\n\ + \n\ + Доступные команды зависят от сервера. Выполните команду ''help'', чтобы \ + посмотреть список. +CLI.NoURL=Не указаны ни -s, ни переменная окружения JENKINS_URL. +CLI.NoSuchFileExists=Не существует такого файла: {0} +CLI.BadAuth=Параметры окружения JENKINS_USER_ID и JENKINS_API_TOKEN должны быть оба установлены или оставлены пустыми. diff --git a/core/pom.xml b/core/pom.xml index a8045e8029f2e..26f9a102c81ec 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -328,9 +328,10 @@ THE SOFTWARE. websocket-spi ${project.version} + - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api @@ -467,7 +468,7 @@ THE SOFTWARE. org.jenkins-ci core-annotation-processors - 1.0 + 13.v2dcfc22a_a_b_29 provided true @@ -481,7 +482,7 @@ THE SOFTWARE. org.hamcrest - hamcrest-core + hamcrest test @@ -546,6 +547,9 @@ THE SOFTWARE. generate-sources + + ${project.build.directory}/generated-sources/antlr4 ${project.build.directory}/generated-sources/localizer ${project.build.directory}/generated-sources/taglib-interface @@ -650,7 +654,7 @@ THE SOFTWARE. - @{jacocoSurefireArgs} --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.desktop/com.sun.beans.introspect=ALL-UNNAMED + @{jacocoSurefireArgs} --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED false @@ -675,8 +679,8 @@ THE SOFTWARE. - org.kohsuke.stapler - maven-stapler-plugin + io.jenkins.tools.maven + stapler-maven-plugin diff --git a/core/src/main/java/hudson/AbstractMarkupText.java b/core/src/main/java/hudson/AbstractMarkupText.java index b13eeaad3edd0..a05cbb399d81c 100644 --- a/core/src/main/java/hudson/AbstractMarkupText.java +++ b/core/src/main/java/hudson/AbstractMarkupText.java @@ -83,7 +83,7 @@ public final int length() { * @since 1.349 */ public void addHyperlink(int startPos, int endPos, String url) { - addMarkup(startPos, endPos, "", ""); + addMarkup(startPos, endPos, "", ""); } /** @@ -93,7 +93,7 @@ public void addHyperlink(int startPos, int endPos, String url) { * @since 1.395 */ public void addHyperlinkLowKey(int startPos, int endPos, String url) { - addMarkup(startPos, endPos, "", ""); + addMarkup(startPos, endPos, "", ""); } /** diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index bc4b350c0c4ff..c16fc93e1aa91 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -40,6 +40,7 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.nio.file.Files; @@ -59,10 +60,7 @@ import jenkins.ClassLoaderReflectionToolkit; import jenkins.ExtensionFilter; import jenkins.plugins.DetachedPluginsUtil; -import jenkins.util.AntClassLoader; -import jenkins.util.SystemProperties; import jenkins.util.URLClassLoader2; -import org.apache.commons.io.output.NullOutputStream; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Expand; @@ -290,30 +288,17 @@ protected ClassLoader createClassLoader(List paths, ClassLoader parent, At boolean usePluginFirstClassLoader = atts != null && Boolean.parseBoolean(atts.getValue("PluginFirstClassLoader")); - if (useAntClassLoader) { - AntClassLoader classLoader; - if (usePluginFirstClassLoader) { - classLoader = new PluginFirstClassLoader(); - classLoader.setParentFirst(false); - classLoader.setParent(parent); - } else { - classLoader = new AntClassLoader(parent, true); - } - classLoader.addPathFiles(paths); - return classLoader; + List urls = new ArrayList<>(); + for (File path : paths) { + urls.add(path.toURI().toURL()); + } + URLClassLoader2 classLoader; + if (usePluginFirstClassLoader) { + classLoader = new PluginFirstClassLoader2(urls.toArray(new URL[0]), parent); } else { - List urls = new ArrayList<>(); - for (File path : paths) { - urls.add(path.toURI().toURL()); - } - URLClassLoader2 classLoader; - if (usePluginFirstClassLoader) { - classLoader = new PluginFirstClassLoader2(urls.toArray(new URL[0]), parent); - } else { - classLoader = new URLClassLoader2(urls.toArray(new URL[0]), parent); - } - return classLoader; + classLoader = new URLClassLoader2(urls.toArray(new URL[0]), parent); } + return classLoader; } /** @@ -432,17 +417,6 @@ private DependencyClassLoader findAncestorDependencyClassLoader(ClassLoader clas if (classLoader instanceof DependencyClassLoader) { return (DependencyClassLoader) classLoader; } - - if (classLoader instanceof AntClassLoader) { - // AntClassLoaders hold parents not only as AntClassLoader#getParent() - // but also as AntClassLoader#getConfiguredParent() - DependencyClassLoader ret = findAncestorDependencyClassLoader( - ((AntClassLoader) classLoader).getConfiguredParent() - ); - if (ret != null) { - return ret; - } - } } return null; } @@ -529,7 +503,7 @@ private static void createClassJarFromWebInfClasses(File archive, File destDir, final long dirTime = archive.lastModified(); // this ZipOutputStream is reused and not created for each directory - try (ZipOutputStream wrappedZOut = new ZipOutputStream(NullOutputStream.NULL_OUTPUT_STREAM) { + try (OutputStream nos = OutputStream.nullOutputStream(); ZipOutputStream wrappedZOut = new ZipOutputStream(nos) { @Override public void putNextEntry(ZipEntry ze) throws IOException { ze.setTime(dirTime + 1999); // roundup @@ -716,7 +690,4 @@ protected URL findResource(String name) { return null; } } - - @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "Accessible via System Groovy Scripts") - public static /* not final */ boolean useAntClassLoader = SystemProperties.getBoolean(ClassicPluginStrategy.class.getName() + ".useAntClassLoader"); } diff --git a/core/src/main/java/hudson/ExtensionFinder.java b/core/src/main/java/hudson/ExtensionFinder.java index 05ebd3f974187..801735835c0fd 100644 --- a/core/src/main/java/hudson/ExtensionFinder.java +++ b/core/src/main/java/hudson/ExtensionFinder.java @@ -507,6 +507,7 @@ private void resolve(Class c, Set> encountered) { boolean foundInjectableConstructor = false; for (Constructor constructor : cc.getDeclaredConstructors()) { if (constructor.isAnnotationPresent(javax.inject.Inject.class) + || constructor.isAnnotationPresent(jakarta.inject.Inject.class) || constructor.isAnnotationPresent(com.google.inject.Inject.class)) { constructor.getAnnotatedParameterTypes(); constructor.getParameterAnnotations(); @@ -529,6 +530,7 @@ private void resolve(Class c, Set> encountered) { // See com.google.inject.spi.InjectionPoint(TypeLiteral, Method, boolean) for (Method method : cc.getDeclaredMethods()) { if (method.isAnnotationPresent(javax.inject.Inject.class) + || method.isAnnotationPresent(jakarta.inject.Inject.class) || method.isAnnotationPresent(com.google.inject.Inject.class)) { method.getAnnotatedParameterTypes(); method.getParameterAnnotations(); @@ -538,6 +540,7 @@ private void resolve(Class c, Set> encountered) { // See com.google.inject.spi.InjectionPoint(TypeLiteral, Field, boolean) for (Field f : cc.getDeclaredFields()) { if (f.isAnnotationPresent(javax.inject.Inject.class) + || f.isAnnotationPresent(jakarta.inject.Inject.class) || f.isAnnotationPresent(com.google.inject.Inject.class)) { f.getAnnotations(); f.getAnnotatedType().getAnnotations(); diff --git a/core/src/main/java/hudson/Launcher.java b/core/src/main/java/hudson/Launcher.java index 6ea7375ff5a95..e6ba431691fb0 100644 --- a/core/src/main/java/hudson/Launcher.java +++ b/core/src/main/java/hudson/Launcher.java @@ -24,8 +24,6 @@ package hudson; -import static org.apache.commons.io.output.NullOutputStream.NULL_OUTPUT_STREAM; - import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -63,7 +61,6 @@ import jenkins.tasks.filters.EnvVarsFilterRuleWrapper; import jenkins.tasks.filters.EnvVarsFilterableBuilder; import jenkins.util.MemoryReductionUtil; -import org.apache.commons.io.input.NullInputStream; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.Beta; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -192,7 +189,7 @@ public final class ProcStarter { @CheckForNull protected FilePath pwd; @CheckForNull - protected OutputStream stdout = NULL_OUTPUT_STREAM, stderr; + protected OutputStream stdout = OutputStream.nullOutputStream(), stderr; @CheckForNull private TaskListener stdoutListener; @CheckForNull @@ -1512,7 +1509,7 @@ private static EnvVars inherit(@NonNull Map overrides) { @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "for debugging") public static boolean showFullPath = false; - private static final NullInputStream NULL_INPUT_STREAM = new NullInputStream(0); + private static final InputStream NULL_INPUT_STREAM = InputStream.nullInputStream(); private static final Logger LOGGER = Logger.getLogger(Launcher.class.getName()); } diff --git a/core/src/main/java/hudson/PluginFirstClassLoader.java b/core/src/main/java/hudson/PluginFirstClassLoader.java deleted file mode 100644 index f652187a2963e..0000000000000 --- a/core/src/main/java/hudson/PluginFirstClassLoader.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Olivier Lamy - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package hudson; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Collection; -import java.util.Enumeration; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import jenkins.util.AntClassLoader; - -/** - * classLoader which use first /WEB-INF/lib/*.jar and /WEB-INF/classes before core classLoader - * you must use the pluginFirstClassLoader true in the maven-hpi-plugin - * - * @author olamy - * @since 1.371 - * @deprecated use {@link PluginFirstClassLoader2} - */ -@Deprecated -public class PluginFirstClassLoader - extends AntClassLoader -{ - public PluginFirstClassLoader() { - super(null, false); - } - - private List urls = new CopyOnWriteArrayList<>(); - - @Override - public void addPathFiles(Collection paths) - throws IOException - { - for (File f : paths) - { - urls.add(f.toURI().toURL()); - addPathFile(f); - } - } - - /** - * @return List of jar used by the plugin /WEB-INF/lib/*.jar and classes directory /WEB-INF/classes - */ - public List getURLs() - { - return urls; - } - - @Override - protected Enumeration findResources(String name, boolean skipParent) - throws IOException - { - return super.findResources(name, skipParent); - } - - @Override - public Enumeration findResources(String name) - throws IOException - { - return super.findResources(name); - } - - @Override - public URL getResource(String name) - { - return super.getResource(name); - } - - @Override - public InputStream getResourceAsStream(String name) - { - return super.getResourceAsStream(name); - } -} diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 0ea2594fad3ac..5d64485cfa1b8 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -1135,7 +1135,7 @@ protected void copyBundledPlugin(URL src, String fileName) throws IOException { final JarEntry entry = entryName != null && jarFile != null ? jarFile.getJarEntry(entryName) : null; if (entry != null) { try (InputStream i = jarFile.getInputStream(entry)) { - byte[] manifestBytes = IOUtils.toByteArray(i); + byte[] manifestBytes = i.readAllBytes(); in = new ByteArrayInputStream(manifestBytes); } } else { diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index 44956a5b3f8a0..2161e501089f0 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -72,7 +72,6 @@ import jenkins.model.Jenkins; import jenkins.plugins.DetachedPluginsUtil; import jenkins.security.UpdateSiteWarningsMonitor; -import jenkins.util.AntClassLoader; import jenkins.util.URLClassLoader2; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.LogFactory; @@ -414,12 +413,7 @@ public boolean isDeprecated() { */ @Restricted(Beta.class) public void injectJarsToClasspath(File... jars) throws Exception { - if (classLoader instanceof AntClassLoader) { - for (File f : jars) { - LOGGER.log(Level.CONFIG, () -> "Inserting " + f + " into " + shortName + " plugin's classpath"); - ((AntClassLoader) classLoader).addPathComponent(f); - } - } else if (classLoader instanceof URLClassLoader2) { + if (classLoader instanceof URLClassLoader2) { for (File f : jars) { LOGGER.log(Level.CONFIG, () -> "Inserting " + f + " into " + shortName + " plugin's classpath"); ((URLClassLoader2) classLoader).addURL(f.toURI().toURL()); diff --git a/core/src/main/java/hudson/Proc.java b/core/src/main/java/hudson/Proc.java index 61defc264f542..a36ac726ec5cb 100644 --- a/core/src/main/java/hudson/Proc.java +++ b/core/src/main/java/hudson/Proc.java @@ -33,7 +33,6 @@ import hudson.util.DaemonThreadFactory; import hudson.util.ExceptionCatchingThreadFactory; import hudson.util.NamingThreadFactory; -import hudson.util.NullStream; import hudson.util.ProcessTree; import hudson.util.StreamCopyThread; import java.io.File; @@ -52,7 +51,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.commons.io.input.NullInputStream; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -428,8 +426,8 @@ private static String calcName(String[] cmd) { return String.join(" ", cmd); } - public static final InputStream SELFPUMP_INPUT = new NullInputStream(0); - public static final OutputStream SELFPUMP_OUTPUT = new NullStream(); + public static final InputStream SELFPUMP_INPUT = InputStream.nullInputStream(); + public static final OutputStream SELFPUMP_OUTPUT = OutputStream.nullOutputStream(); } /** diff --git a/core/src/main/java/hudson/TcpSlaveAgentListener.java b/core/src/main/java/hudson/TcpSlaveAgentListener.java index 99c83866dff4d..3936071de2efd 100644 --- a/core/src/main/java/hudson/TcpSlaveAgentListener.java +++ b/core/src/main/java/hudson/TcpSlaveAgentListener.java @@ -56,7 +56,6 @@ import jenkins.slaves.RemotingVersionInfo; import jenkins.util.SystemProperties; import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.NullOutputStream; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -315,6 +314,7 @@ private void respondHello(String header, Socket s) throws IOException { if (header.startsWith("GET / ")) { response = "HTTP/1.0 200 OK\r\n" + "Content-Type: text/plain;charset=UTF-8\r\n" + + "X-Content-Type-Options: nosniff\r\n" + "\r\n" + "Jenkins-Agent-Protocols: " + getAgentProtocolNames() + "\r\n" + "Jenkins-Version: " + Jenkins.VERSION + "\r\n" + @@ -330,7 +330,9 @@ private void respondHello(String header, Socket s) throws IOException { s.shutdownOutput(); InputStream i = s.getInputStream(); - IOUtils.copy(i, NullOutputStream.NULL_OUTPUT_STREAM); + try (OutputStream o = OutputStream.nullOutputStream()) { + IOUtils.copy(i, o); + } s.shutdownInput(); } } diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index 07254e2b77e6a..6adba3022f55a 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -32,13 +32,14 @@ import hudson.model.TaskListener; import hudson.util.QuotedStringTokenizer; import hudson.util.VariableResolver; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; @@ -55,7 +56,9 @@ import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.nio.file.CopyOption; import java.nio.file.FileAlreadyExistsException; @@ -64,6 +67,7 @@ import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @@ -108,9 +112,7 @@ import jenkins.util.SystemProperties; import jenkins.util.io.PathRemover; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.NullOutputStream; import org.apache.commons.lang.time.FastDateFormat; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; @@ -247,15 +249,22 @@ public static String loadFile(@NonNull File logfile, @NonNull Charset charset) t // contain unmappable and/or malformed byte sequences. We need to make // sure that in such cases, no CharacterCodingException is thrown. // - // One approach that cannot be used is to call Files.newBufferedReader() - // because there is a difference in how an InputStreamReader constructed - // from a Charset and the reader returned by Files.newBufferedReader() - // handle malformed and unmappable byte sequences for the specified - // encoding; the latter is more picky and will throw an exception. + // One approach that cannot be used is Files.newBufferedReader, which + // creates its CharsetDecoder with the default behavior of reporting + // malformed input and unmappable character errors. The implementation + // of InputStreamReader(InputStream, Charset) has the desired behavior + // of replacing malformed input and unmappable character errors, but + // this implementation is not specified in the API contract. Therefore, + // we explicitly use a decoder with the desired behavior. // See: https://issues.jenkins.io/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989 - try { - return FileUtils.readFileToString(logfile, charset); - } catch (FileNotFoundException e) { + CharsetDecoder decoder = charset.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + try (InputStream is = Files.newInputStream(Util.fileToPath(logfile)); + Reader isr = new InputStreamReader(is, decoder); + Reader br = new BufferedReader(isr)) { + return IOUtils.toString(br); + } catch (NoSuchFileException e) { return ""; } catch (Exception e) { throw new IOException("Failed to fully read " + logfile, e); @@ -627,10 +636,11 @@ public static String ensureEndsWith(@CheckForNull String subject, @CheckForNull public static String getDigestOf(@NonNull InputStream source) throws IOException { try (source) { MessageDigest md5 = getMd5(); - DigestInputStream in = new DigestInputStream(source, md5); - // Note: IOUtils.copy() buffers the input internally, so there is no - // need to use a BufferedInputStream. - IOUtils.copy(in, NullOutputStream.NULL_OUTPUT_STREAM); + try (InputStream in = new DigestInputStream(source, md5); OutputStream out = OutputStream.nullOutputStream()) { + // Note: IOUtils.copy() buffers the input internally, so there is no + // need to use a BufferedInputStream. + IOUtils.copy(in, out); + } return toHexString(md5.digest()); } catch (NoSuchAlgorithmException e) { throw new IOException("MD5 not installed", e); // impossible diff --git a/core/src/main/java/hudson/cli/DisablePluginCommand.java b/core/src/main/java/hudson/cli/DisablePluginCommand.java index 53af28828ddb6..61e378296f457 100644 --- a/core/src/main/java/hudson/cli/DisablePluginCommand.java +++ b/core/src/main/java/hudson/cli/DisablePluginCommand.java @@ -131,7 +131,7 @@ private void printIndented(int indent, String format, String... arguments) { System.arraycopy(arguments, 0, newArgs, 1, arguments.length); String f = "%" + indent + "s" + format + "%n"; - stdout.format(f, newArgs); + stdout.format(f, (Object[]) newArgs); } } diff --git a/core/src/main/java/hudson/console/AnnotatedLargeText.java b/core/src/main/java/hudson/console/AnnotatedLargeText.java index e074044e806da..8e0a59bee2afc 100644 --- a/core/src/main/java/hudson/console/AnnotatedLargeText.java +++ b/core/src/main/java/hudson/console/AnnotatedLargeText.java @@ -34,6 +34,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.remoting.ObjectInputStreamEx; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; @@ -49,7 +50,6 @@ import javax.crypto.CipherOutputStream; import jenkins.model.Jenkins; import jenkins.security.CryptoConfidentialKey; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.jenkinsci.remoting.util.AnonymousClassWarnings; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; diff --git a/core/src/main/java/hudson/console/ConsoleNote.java b/core/src/main/java/hudson/console/ConsoleNote.java index 8183934aedcec..20ded06e98625 100644 --- a/core/src/main/java/hudson/console/ConsoleNote.java +++ b/core/src/main/java/hudson/console/ConsoleNote.java @@ -34,8 +34,8 @@ import hudson.model.Run; import hudson.remoting.ClassFilter; import hudson.remoting.ObjectInputStreamEx; -import hudson.util.IOUtils; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -54,7 +54,7 @@ import jenkins.security.HMACConfidentialKey; import jenkins.util.JenkinsJVM; import jenkins.util.SystemProperties; -import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.commons.io.IOUtils; import org.apache.tools.ant.BuildListener; import org.jenkinsci.remoting.util.AnonymousClassWarnings; import org.kohsuke.accmod.Restricted; @@ -306,12 +306,12 @@ public static void skip(DataInputStream in) throws IOException { DataInputStream decoded = new DataInputStream(Base64.getDecoder().wrap(in)); int macSz = - decoded.readInt(); if (macSz > 0) { // new format - IOUtils.skip(decoded, macSz); + IOUtils.skipFully(decoded, macSz); int sz = decoded.readInt(); - IOUtils.skip(decoded, sz); + IOUtils.skipFully(decoded, sz); } else { // old format int sz = -macSz; - IOUtils.skip(decoded, sz); + IOUtils.skipFully(decoded, sz); } byte[] postamble = new byte[POSTAMBLE.length]; diff --git a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java index acfa1c7867b64..875a3e4ef7e05 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java +++ b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java @@ -35,6 +35,7 @@ import hudson.model.TaskListener; import hudson.util.StreamTaskListener; import hudson.util.jna.DotNet; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URL; @@ -46,7 +47,6 @@ import jenkins.model.Jenkins; import jenkins.util.SystemProperties; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.tools.ant.DefaultLogger; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Move; diff --git a/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java b/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java index 961cf1358b52a..2cf936679a68e 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java +++ b/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java @@ -32,6 +32,7 @@ import hudson.Util; import hudson.util.StreamTaskListener; import hudson.util.jna.Kernel32; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.Writer; @@ -43,7 +44,6 @@ import java.util.logging.Logger; import jenkins.model.Jenkins; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.output.ByteArrayOutputStream; /** * {@link Lifecycle} for Hudson installed as Windows service. diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index 0984690980d1d..92900e678445f 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -940,8 +940,6 @@ public Void call() throws IOException { } }); Jenkins.get().rebuildDependencyGraphAsync(); - - SaveableListener.fireOnChange(this, getConfigFile()); } diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 809c215a61b21..099d0d190ded3 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -953,6 +953,11 @@ public R getNearestOldBuild(int n) { return buildMixIn.getNearestOldBuild(n); } + @Override + protected List getEstimatedDurationCandidates() { + return buildMixIn.getEstimatedDurationCandidates(); + } + /** * Type token for the corresponding build type. * The build class must have two constructors: diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index f44c97dab34ca..31e0c0bc804bd 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -110,6 +110,7 @@ import jenkins.util.ErrorLoggingExecutorService; import jenkins.util.Listeners; import jenkins.util.SystemProperties; +import jenkins.widgets.HasWidgets; import net.jcip.annotations.GuardedBy; import org.apache.commons.lang.StringUtils; import org.jenkins.ui.icon.Icon; @@ -160,7 +161,7 @@ * @author Kohsuke Kawaguchi */ @ExportedBean -public /*transient*/ abstract class Computer extends Actionable implements AccessControlled, ExecutorListener, DescriptorByNameOwner, StaplerProxy { +public /*transient*/ abstract class Computer extends Actionable implements AccessControlled, ExecutorListener, DescriptorByNameOwner, StaplerProxy, HasWidgets { private final CopyOnWriteArrayList executors = new CopyOnWriteArrayList<>(); // TODO: diff --git a/core/src/main/java/hudson/model/ComputerSet.java b/core/src/main/java/hudson/model/ComputerSet.java index 211c795ee95ca..cad9089b776f9 100644 --- a/core/src/main/java/hudson/model/ComputerSet.java +++ b/core/src/main/java/hudson/model/ComputerSet.java @@ -57,6 +57,7 @@ import jenkins.model.ModelObjectWithChildren; import jenkins.model.ModelObjectWithContextMenu.ContextMenu; import jenkins.util.Timer; +import jenkins.widgets.HasWidgets; import net.sf.json.JSONObject; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.QueryParameter; @@ -75,7 +76,7 @@ * @author Kohsuke Kawaguchi */ @ExportedBean -public final class ComputerSet extends AbstractModelObject implements Describable, ModelObjectWithChildren { +public final class ComputerSet extends AbstractModelObject implements Describable, ModelObjectWithChildren, HasWidgets { /** * This is the owner that persists {@link #monitors}. */ diff --git a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java index b88e478740a62..6f8bf2e6ee77f 100644 --- a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java +++ b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java @@ -869,5 +869,5 @@ private static OpenOption[] getOpenOptions() { private static final Logger LOGGER = Logger.getLogger(DirectoryBrowserSupport.class.getName()); @Restricted(NoExternalUse.class) - public static final String DEFAULT_CSP_VALUE = "sandbox; default-src 'none'; img-src 'self'; style-src 'self';"; + public static final String DEFAULT_CSP_VALUE = "sandbox allow-same-origin; default-src 'none'; img-src 'self'; style-src 'self';"; } diff --git a/core/src/main/java/hudson/model/FileParameterValue.java b/core/src/main/java/hudson/model/FileParameterValue.java index e11d31c891fae..e9e30e63463bf 100644 --- a/core/src/main/java/hudson/model/FileParameterValue.java +++ b/core/src/main/java/hudson/model/FileParameterValue.java @@ -46,7 +46,6 @@ import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.fileupload.util.FileItemHeadersImpl; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.DataBoundConstructor; @@ -288,9 +287,7 @@ public long getSize() { @Override public byte[] get() { try { - try (InputStream inputStream = Files.newInputStream(file.toPath())) { - return IOUtils.toByteArray(inputStream); - } + return Files.readAllBytes(file.toPath()); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/core/src/main/java/hudson/model/JDK.java b/core/src/main/java/hudson/model/JDK.java index 50de1401f0299..addb9202f3ce6 100644 --- a/core/src/main/java/hudson/model/JDK.java +++ b/core/src/main/java/hudson/model/JDK.java @@ -34,11 +34,11 @@ import hudson.tools.ToolInstaller; import hudson.tools.ToolProperty; import hudson.util.FormValidation; -import hudson.util.NullStream; import hudson.util.StreamTaskListener; import hudson.util.XStream2; import java.io.File; import java.io.IOException; +import java.io.OutputStream; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.Collections; @@ -164,7 +164,7 @@ public JDK forEnvironment(EnvVars environment) { */ public static boolean isDefaultJDKValid(Node n) { try { - TaskListener listener = new StreamTaskListener(new NullStream()); + TaskListener listener = new StreamTaskListener(OutputStream.nullOutputStream()); Launcher launcher = n.createLauncher(listener); return launcher.launch().cmds("java", "-fullversion").stdout(listener).join() == 0; } catch (IOException | InterruptedException e) { diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index dd9d88ff25c9c..9ae6056092922 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -98,6 +98,7 @@ import jenkins.scm.RunWithSCM; import jenkins.security.HexStringConfidentialKey; import jenkins.triggers.SCMTriggerItem; +import jenkins.widgets.HasWidgets; import net.sf.json.JSONException; import net.sf.json.JSONObject; import org.apache.commons.io.FileUtils; @@ -135,7 +136,7 @@ * @author Kohsuke Kawaguchi */ public abstract class Job, RunT extends Run> - extends AbstractItem implements ExtensionPoint, StaplerOverridable, ModelObjectWithChildren { + extends AbstractItem implements ExtensionPoint, StaplerOverridable, ModelObjectWithChildren, HasWidgets { private static final Logger LOGGER = Logger.getLogger(Job.class.getName()); @@ -611,15 +612,10 @@ public Collection getOverrides() { return r; } - public List getWidgets() { - ArrayList r = new ArrayList<>(); - r.add(createHistoryWidget()); - return r; - } - /** - * @see LazyBuildMixIn#createHistoryWidget + * @deprecated see {@link LazyBuildMixIn#createHistoryWidget()} */ + @Deprecated(forRemoval = true, since = "2.410") protected HistoryWidget createHistoryWidget() { return new HistoryWidget(this, getBuilds(), HISTORY_ADAPTER); } @@ -1013,6 +1009,7 @@ public List getLastBuildsOverThreshold(int numberOfBuilds, Result threshol * Failing to find 3 of those, it will return up to 3 last unsuccessful builds. * * In any case it will not go more than 6 builds into the past to avoid costly build loading. + * @see LazyBuildMixIn#getEstimatedDurationCandidates */ protected List getEstimatedDurationCandidates() { List candidates = new ArrayList<>(3); diff --git a/core/src/main/java/hudson/model/ListView.java b/core/src/main/java/hudson/model/ListView.java index 3476b81cc035b..77852e994ecea 100644 --- a/core/src/main/java/hudson/model/ListView.java +++ b/core/src/main/java/hudson/model/ListView.java @@ -452,7 +452,7 @@ protected void submit(StaplerRequest req) throws ServletException, FormException } for (TopLevelItem item : items) { String relativeNameFrom = item.getRelativeNameFrom(getOwner().getItemGroup()); - if (req.getParameter(relativeNameFrom) != null) { + if (req.getParameter("item_" + relativeNameFrom) != null) { jobNames.add(relativeNameFrom); } } diff --git a/core/src/main/java/hudson/model/ManageJenkinsAction.java b/core/src/main/java/hudson/model/ManageJenkinsAction.java index a0eda48159dbf..c6c37a57662a0 100644 --- a/core/src/main/java/hudson/model/ManageJenkinsAction.java +++ b/core/src/main/java/hudson/model/ManageJenkinsAction.java @@ -79,13 +79,13 @@ public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse respons * menu. */ @Restricted(NoExternalUse.class) - public void addContextMenuItem(ContextMenu menu, String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation, Badge badge) { + public void addContextMenuItem(ContextMenu menu, String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation, Badge badge, String message) { if (Stapler.getCurrentRequest().findAncestorObject(this.getClass()) != null || !Util.isSafeToRedirectTo(url)) { // Default behavior if the URL is absolute or scheme-relative, or the current object is an ancestor (i.e. would resolve correctly) - menu.add(url, icon, iconXml, text, post, requiresConfirmation, badge); + menu.add(url, icon, iconXml, text, post, requiresConfirmation, badge, message); return; } // If neither is the case, rewrite the relative URL to point to inside the /manage/ URL space - menu.add("manage/" + url, icon, iconXml, text, post, requiresConfirmation, badge); + menu.add("manage/" + url, icon, iconXml, text, post, requiresConfirmation, badge, message); } } diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 7a4c7c7a93dd4..910d4637f28fa 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -26,6 +26,7 @@ package hudson.model; import static hudson.init.InitMilestone.JOB_CONFIG_ADAPTED; +import static hudson.model.Item.CANCEL; import static hudson.util.Iterators.reverse; import com.google.common.annotations.VisibleForTesting; @@ -112,6 +113,7 @@ import jenkins.model.Jenkins; import jenkins.model.queue.AsynchronousExecution; import jenkins.model.queue.CompositeCauseOfBlockage; +import jenkins.model.queue.QueueItem; import jenkins.security.QueueItemAuthenticator; import jenkins.security.QueueItemAuthenticatorProvider; import jenkins.security.stapler.StaplerAccessibleType; @@ -1929,25 +1931,34 @@ default CauseOfBlockage getCauseOfBlockage() { * Checks the permission to see if the current user can abort this executable. * Returns normally from this method if it's OK. *

- * NOTE: If you have implemented {@link AccessControlled} this should just be + * NOTE: If you have implemented {@link AccessControlled} this defaults to * {@code checkPermission(hudson.model.Item.CANCEL);} * * @throws AccessDeniedException if the permission is not granted. */ - void checkAbortPermission(); + default void checkAbortPermission() { + if (this instanceof AccessControlled) { + ((AccessControlled) this).checkPermission(CANCEL); + } + } /** * Works just like {@link #checkAbortPermission()} except it indicates the status by a return value, * instead of exception. * Also used by default for {@link hudson.model.Queue.Item#hasCancelPermission}. *

- * NOTE: If you have implemented {@link AccessControlled} this should just be + * NOTE: If you have implemented {@link AccessControlled} this returns by default * {@code return hasPermission(hudson.model.Item.CANCEL);} * * @return false * if the user doesn't have the permission. */ - boolean hasAbortPermission(); + default boolean hasAbortPermission() { + if (this instanceof AccessControlled) { + return ((AccessControlled) this).hasPermission(CANCEL); + } + return true; + } /** * Returns the URL of this task relative to the context root of the application. @@ -2117,7 +2128,7 @@ default long getEstimatedDuration() { * Item in a queue. */ @ExportedBean(defaultVisibility = 999) - public abstract static class Item extends Actionable { + public abstract static class Item extends Actionable implements QueueItem { private final long id; @@ -2128,6 +2139,7 @@ public abstract static class Item extends Actionable { * @since 1.601 */ @Exported + @Override public long getId() { return id; } @@ -2147,12 +2159,19 @@ public int getIdLegacy() { * Project to be built. */ @Exported + @NonNull public final Task task; private /*almost final*/ transient FutureImpl future; private final long inQueueSince; + @Override + @NonNull + public Task getTask() { + return task; + } + /** * Build is blocked because another build is in progress, * required {@link Resource}s are not available, or otherwise blocked @@ -2173,6 +2192,7 @@ public int getIdLegacy() { * True if the item is starving for an executor for too long. */ @Exported + @Override public boolean isStuck() { return false; } /** @@ -2188,6 +2208,7 @@ public long getInQueueSince() { * Returns a human readable presentation of how long this item is already in the queue. * E.g. something like '3 minutes 40 seconds' */ + @Override public String getInQueueForString() { long duration = System.currentTimeMillis() - this.inQueueSince; return Util.getTimeSpanString(duration); @@ -2250,6 +2271,7 @@ public final List getCauses() { } @Restricted(DoNotUse.class) // used from Jelly + @Override public String getCausesDescription() { List causes = getCauses(); StringBuilder s = new StringBuilder(); @@ -2259,15 +2281,11 @@ public String getCausesDescription() { return s.toString(); } - protected Item(Task task, List actions, long id, FutureImpl future) { - this.task = task; - this.id = id; - this.future = future; - this.inQueueSince = System.currentTimeMillis(); - for (Action action : actions) addAction(action); + protected Item(@NonNull Task task, @NonNull List actions, long id, FutureImpl future) { + this(task, actions, id, future, System.currentTimeMillis()); } - protected Item(Task task, List actions, long id, FutureImpl future, long inQueueSince) { + protected Item(@NonNull Task task, @NonNull List actions, long id, FutureImpl future, long inQueueSince) { this.task = task; this.id = id; this.future = future; @@ -2297,6 +2315,7 @@ public String getUrl() { * Gets a human-readable status message describing why it's in the queue. */ @Exported + @Override public final String getWhy() { CauseOfBlockage cob = getCauseOfBlockage(); return cob != null ? cob.getShortDescription() : null; @@ -2312,6 +2331,7 @@ public final String getWhy() { * @return String */ @Exported + @Override public String getParams() { StringBuilder s = new StringBuilder(); for (ParametersAction pa : getActions(ParametersAction.class)) { @@ -2322,19 +2342,6 @@ public String getParams() { return s.toString(); } - /** - * Checks whether a scheduled item may be canceled. - * @return by default, the same as {@link hudson.model.Queue.Task#hasAbortPermission} - */ - public boolean hasCancelPermission() { - return task.hasAbortPermission(); - } - - @Override - public String getDisplayName() { - return null; - } - @Override public String getSearchUrl() { return null; diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index 113b5a742efb5..87644b3aa343b 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -1242,12 +1242,7 @@ private static int addArtifacts(@NonNull VirtualFile dir, /** * Maximum number of artifacts to list before using switching to the tree view. */ - public static final int LIST_CUTOFF = Integer.parseInt(SystemProperties.getString("hudson.model.Run.ArtifactList.listCutoff", "16")); - - /** - * Maximum number of artifacts to show in tree view before just showing a link. - */ - public static final int TREE_CUTOFF = Integer.parseInt(SystemProperties.getString("hudson.model.Run.ArtifactList.treeCutoff", "40")); + public static final int LIST_CUTOFF = Integer.parseInt(SystemProperties.getString("hudson.model.Run.ArtifactList.listCutoff", "20")); // ..and then "too many" diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index d6727ad260587..22eb63cd2fc6f 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -71,7 +71,6 @@ import jenkins.security.MasterToSlaveCallable; import jenkins.slaves.WorkspaceLocator; import jenkins.util.SystemProperties; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.DoNotUse; @@ -470,7 +469,7 @@ public URL getURL() throws IOException { public byte[] readFully() throws IOException { try (InputStream in = connect().getInputStream()) { - return IOUtils.toByteArray(in); + return in.readAllBytes(); } } diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java index b9ca1d2001b8e..7ea06f20191e4 100644 --- a/core/src/main/java/hudson/model/UpdateCenter.java +++ b/core/src/main/java/hudson/model/UpdateCenter.java @@ -1665,7 +1665,7 @@ public void run() { if (e.getMessage().contains("Connection timed out")) { // Google can't be down, so this is probably a proxy issue connectionStates.put(ConnectionStatus.INTERNET, ConnectionStatus.FAILED); - statuses.add(Messages.UpdateCenter_Status_ConnectionFailed(Functions.xmlEscape(connectionCheckUrl))); + statuses.add(Messages.UpdateCenter_Status_ConnectionFailed(Functions.xmlEscape(connectionCheckUrl), Jenkins.get().getRootUrl())); return; } } @@ -1687,7 +1687,7 @@ public void run() { statuses.add(Messages.UpdateCenter_Status_Success()); } catch (UnknownHostException e) { connectionStates.put(ConnectionStatus.UPDATE_SITE, ConnectionStatus.FAILED); - statuses.add(Messages.UpdateCenter_Status_UnknownHostException(Functions.xmlEscape(e.getMessage()))); + statuses.add(Messages.UpdateCenter_Status_UnknownHostException(Functions.xmlEscape(e.getMessage()), Jenkins.get().getRootUrl())); addStatus(e); error = e; } catch (Exception e) { diff --git a/core/src/main/java/hudson/model/UsageStatistics.java b/core/src/main/java/hudson/model/UsageStatistics.java index 0a13c0983b160..cbc356aa3b773 100644 --- a/core/src/main/java/hudson/model/UsageStatistics.java +++ b/core/src/main/java/hudson/model/UsageStatistics.java @@ -35,6 +35,7 @@ import hudson.node_monitors.ArchitectureMonitor; import hudson.security.Permission; import hudson.util.Secret; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.FilterInputStream; import java.io.FilterOutputStream; @@ -65,7 +66,6 @@ import jenkins.model.Jenkins; import jenkins.util.SystemProperties; import net.sf.json.JSONObject; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.kohsuke.stapler.StaplerRequest; /** diff --git a/core/src/main/java/hudson/model/View.java b/core/src/main/java/hudson/model/View.java index 91c34d8c44875..3f9c2765ed896 100644 --- a/core/src/main/java/hudson/model/View.java +++ b/core/src/main/java/hudson/model/View.java @@ -59,7 +59,6 @@ import hudson.util.RunList; import hudson.util.XStream2; import hudson.views.ListViewColumn; -import hudson.widgets.Widget; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -103,6 +102,7 @@ import jenkins.security.stapler.StaplerAccessibleType; import jenkins.util.ProgressiveRendering; import jenkins.util.xml.XMLUtils; +import jenkins.widgets.HasWidgets; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONObject; @@ -147,7 +147,7 @@ * @see ViewGroup */ @ExportedBean -public abstract class View extends AbstractModelObject implements AccessControlled, Describable, ExtensionPoint, Saveable, ModelObjectWithChildren, DescriptorByNameOwner { +public abstract class View extends AbstractModelObject implements AccessControlled, Describable, ExtensionPoint, Saveable, ModelObjectWithChildren, DescriptorByNameOwner, HasWidgets { /** * Container of this view. Set right after the construction @@ -412,16 +412,6 @@ public boolean isFilterQueue() { return filterQueue; } - /** - * Gets the {@link Widget}s registered on this object. - * - *

- * For now, this just returns the widgets registered to Hudson. - */ - public List getWidgets() { - return Collections.unmodifiableList(Jenkins.get().getWidgets()); - } - /** * If this view uses {@code } for rendering, this method returns columns to be displayed. */ diff --git a/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java b/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java index 1ff59f295569c..634fc43b9b660 100644 --- a/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java +++ b/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java @@ -28,9 +28,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.model.Descriptor; +import jakarta.inject.Inject; import java.util.Collections; import java.util.List; -import javax.inject.Inject; import jenkins.model.Jenkins; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; diff --git a/core/src/main/java/hudson/slaves/Cloud.java b/core/src/main/java/hudson/slaves/Cloud.java index 8ab456817a5a1..6ec3ed3b489d5 100644 --- a/core/src/main/java/hudson/slaves/Cloud.java +++ b/core/src/main/java/hudson/slaves/Cloud.java @@ -46,13 +46,24 @@ import hudson.security.PermissionScope; import hudson.slaves.NodeProvisioner.PlannedNode; import hudson.util.DescriptorList; +import hudson.util.FormApply; +import java.io.IOException; import java.util.Collection; import java.util.Objects; import java.util.concurrent.Future; +import javax.servlet.ServletException; import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.apache.commons.lang.Validate; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.DoNotUse; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.HttpRedirect; +import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.interceptor.RequirePOST; +import org.kohsuke.stapler.verb.POST; /** * Creates {@link Node}s to dynamically expand/shrink the agents attached to Hudson. @@ -104,9 +115,10 @@ public abstract class Cloud extends Actionable implements ExtensionPoint, Descri * This is expected to be short ID-like string that does not contain any character unsafe as variable name or * URL path token. */ - public final String name; + public String name; protected Cloud(String name) { + Validate.notEmpty(name, Messages.Cloud_RequiredName()); this.name = name; } @@ -122,7 +134,7 @@ public String getDisplayName() { * @return Jenkins relative URL. */ public @NonNull String getUrl() { - return "cloud/" + Util.rawEncode(name); + return "cloud/" + Util.rawEncode(name) + "/"; } @Override @@ -275,6 +287,58 @@ public static void registerPermissions() { Objects.hash(PERMISSION_SCOPE, PROVISION); } + public String getIcon() { + return "symbol-cloud"; + } + + public String getIconClassName() { + return "symbol-cloud"; + } + + @SuppressWarnings("unused") // stapler + public String getIconAltText() { + return getClass().getSimpleName().replace("Cloud", ""); + } + + /** + * Deletes the cloud. + */ + @RequirePOST + public HttpResponse doDoDelete() throws IOException { + checkPermission(Jenkins.ADMINISTER); + Jenkins.get().clouds.remove(this); + return new HttpRedirect(".."); + } + + /** + * Accepts the update to the node configuration. + */ + @POST + public HttpResponse doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + checkPermission(Jenkins.ADMINISTER); + + Jenkins j = Jenkins.get(); + Cloud cloud = j.getCloud(this.name); + if (cloud == null) { + throw new ServletException("No such cloud " + this.name); + } + Cloud result = cloud.reconfigure(req, req.getSubmittedForm()); + String proposedName = result.name; + if (!proposedName.equals(this.name) + && j.getCloud(proposedName) != null) { + throw new Descriptor.FormException(jenkins.agents.Messages.CloudSet_CloudAlreadyExists(proposedName), "name"); + } + j.clouds.replace(this, result); + j.save(); + // take the user back to the cloud top page. + return FormApply.success("."); + } + + public Cloud reconfigure(@NonNull final StaplerRequest req, JSONObject form) throws Descriptor.FormException { + if (form == null) return null; + return getDescriptor().newInstance(req, form); + } + /** * Parameter object for {@link hudson.slaves.Cloud}. * @since 2.259 diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index ccc90ec0873b2..b7610683be6de 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -56,7 +56,6 @@ import hudson.security.ACLContext; import hudson.slaves.OfflineCause.ChannelTermination; import hudson.util.Futures; -import hudson.util.NullStream; import hudson.util.RingBufferLogHandler; import hudson.util.StreamTaskListener; import hudson.util.VersionNumber; @@ -330,10 +329,11 @@ protected Future _connect(boolean forceReconnect) { @Override public void taskAccepted(Executor executor, Queue.Task task) { + LOGGER.log(Level.FINER, "Accepted {0} on {1}", new Object[] {task.toString(), executor.getOwner().getDisplayName()}); + if (launcher instanceof ExecutorListener) { ((ExecutorListener) launcher).taskAccepted(executor, task); } - //getNode() can return null at indeterminate times when nodes go offline Slave node = getNode(); if (node != null && node.getRetentionStrategy() instanceof ExecutorListener) { @@ -343,6 +343,7 @@ public void taskAccepted(Executor executor, Queue.Task task) { @Override public void taskStarted(Executor executor, Queue.Task task) { + LOGGER.log(Level.FINER, "Started {0} on {1}", new Object[] {task.toString(), executor.getOwner().getDisplayName()}); if (launcher instanceof ExecutorListener) { ((ExecutorListener) launcher).taskStarted(executor, task); } @@ -354,6 +355,7 @@ public void taskStarted(Executor executor, Queue.Task task) { @Override public void taskCompleted(Executor executor, Queue.Task task, long durationMS) { + LOGGER.log(Level.FINE, "Completed {0} on {1}", new Object[] {task.toString(), executor.getOwner().getDisplayName()}); if (launcher instanceof ExecutorListener) { ((ExecutorListener) launcher).taskCompleted(executor, task, durationMS); } @@ -365,6 +367,7 @@ public void taskCompleted(Executor executor, Queue.Task task, long durationMS) { @Override public void taskCompletedWithProblems(Executor executor, Queue.Task task, long durationMS, Throwable problems) { + LOGGER.log(Level.FINE, "Completed with problems {0} on {1}", new Object[] {task.toString(), executor.getOwner().getDisplayName()}); if (launcher instanceof ExecutorListener) { ((ExecutorListener) launcher).taskCompletedWithProblems(executor, task, durationMS, problems); } @@ -386,7 +389,7 @@ public OutputStream openLogFile() { return log; } catch (IOException e) { logger.log(Level.SEVERE, "Failed to create log file " + getLogFile(), e); - return new NullStream(); + return OutputStream.nullOutputStream(); } } diff --git a/core/src/main/java/hudson/tasks/Maven.java b/core/src/main/java/hudson/tasks/Maven.java index db05022bc9b99..4230da15d6f21 100644 --- a/core/src/main/java/hudson/tasks/Maven.java +++ b/core/src/main/java/hudson/tasks/Maven.java @@ -51,7 +51,6 @@ import hudson.tools.ToolProperty; import hudson.util.ArgumentListBuilder; import hudson.util.FormValidation; -import hudson.util.NullStream; import hudson.util.StreamTaskListener; import hudson.util.VariableResolver; import hudson.util.VariableResolver.ByMap; @@ -59,6 +58,7 @@ import hudson.util.XStream2; import java.io.File; import java.io.IOException; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -665,7 +665,7 @@ private static File getExeFile(String execName, String home) { */ public boolean getExists() { try { - return getExecutable(new LocalLauncher(new StreamTaskListener(new NullStream()))) != null; + return getExecutable(new LocalLauncher(new StreamTaskListener(OutputStream.nullOutputStream()))) != null; } catch (IOException | InterruptedException e) { return false; } diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index f7415597d1a72..c5cb6bb751f97 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -91,6 +91,7 @@ public abstract class Trigger implements Describable> * @see Items#currentlyUpdatingByXml */ public void start(J project, boolean newInstance) { + LOGGER.finer(() -> "Starting " + this + " on " + project); this.job = project; try { // reparse the tabs with the job as the hash @@ -206,6 +207,10 @@ protected Object readResolve() throws ObjectStreamException { return this; } + @Override + public String toString() { + return super.toString() + "[" + spec + "]"; + } /** * Runs every minute to check {@link TimerTrigger} and schedules build. @@ -283,7 +288,9 @@ public void run(AbstractProject p) { // Process all triggers, except SCMTriggers when synchronousPolling is set for (TriggeredItem p : inst.allItems(TriggeredItem.class)) { + LOGGER.finer(() -> "considering " + p); for (Trigger t : p.getTriggers().values()) { + LOGGER.finer(() -> "found trigger " + t); if (!(p instanceof AbstractProject && t instanceof SCMTrigger && scmd.synchronousPolling)) { if (t != null && t.spec != null && t.tabs != null) { LOGGER.log(Level.FINE, "cron checking {0} with spec ‘{1}’", new Object[]{p, t.spec.trim()}); @@ -292,6 +299,9 @@ public void run(AbstractProject p) { LOGGER.log(Level.CONFIG, "cron triggered {0}", p); try { long begin_time = System.currentTimeMillis(); + if (t.job == null) { + LOGGER.fine(() -> t + " not yet started on " + p + " but trying to run anyway"); + } t.run(); long end_time = System.currentTimeMillis(); if (end_time - begin_time > CRON_THRESHOLD * 1000) { diff --git a/core/src/main/java/hudson/util/DescribableList.java b/core/src/main/java/hudson/util/DescribableList.java index 0fa5e9fa70f18..a73dac196b2ca 100644 --- a/core/src/main/java/hudson/util/DescribableList.java +++ b/core/src/main/java/hudson/util/DescribableList.java @@ -100,7 +100,11 @@ public void setOwner(Owner owner) { * Removes all instances of the same type, then add the new one. */ public void replace(T item) throws IOException { - removeAll((Class) item.getClass()); + for (T t : data) { + if (t.getClass() == item.getClass()) { + data.remove(t); + } + } data.add(item); onModified(); } diff --git a/core/src/main/java/hudson/util/DoubleLaunchChecker.java b/core/src/main/java/hudson/util/DoubleLaunchChecker.java index d541452ca141d..6fac015c02245 100644 --- a/core/src/main/java/hudson/util/DoubleLaunchChecker.java +++ b/core/src/main/java/hudson/util/DoubleLaunchChecker.java @@ -24,27 +24,22 @@ package hudson.util; -import static hudson.init.InitMilestone.JOB_CONFIG_ADAPTED; -import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.Extension; +import hudson.ExtensionList; +import hudson.Main; import hudson.Util; -import hudson.init.Initializer; -import hudson.triggers.SafeTimerTask; +import hudson.model.AdministrativeMonitor; +import hudson.model.AperiodicWork; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; +import java.time.Duration; import java.util.Random; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; import jenkins.model.Jenkins; -import jenkins.util.Timer; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.interceptor.RequirePOST; /** * Makes sure that no other Hudson uses our {@code JENKINS_HOME} directory, @@ -63,21 +58,15 @@ * @author Kohsuke Kawaguchi * @since 1.178 */ -@SuppressFBWarnings(value = "PREDICTABLE_RANDOM", justification = "The random is just used for load distribution.") -public class DoubleLaunchChecker { +@Extension +public class DoubleLaunchChecker extends AdministrativeMonitor { /** * The timestamp of the owner file when we updated it for the last time. * 0 to indicate that there was no update before. */ private long lastWriteTime = 0L; - /** - * Once the error is reported, the user can choose to ignore and proceed anyway, - * in which case the flag is set to true. - */ - private boolean ignore = false; - - private final Random random = new Random(); + private boolean activated; public final File home; @@ -91,20 +80,29 @@ public DoubleLaunchChecker() { home = Jenkins.get().getRootDir(); } + @Override + public String getDisplayName() { + return Messages.DoubleLaunchChecker_duplicate_jenkins_checker(); + } + + @Override + public boolean isActivated() { + return activated; + } + protected void execute() { + LOGGER.fine("running detector"); File timestampFile = new File(home, ".owner"); long t = timestampFile.lastModified(); - if (t != 0 && lastWriteTime != 0 && t != lastWriteTime && !ignore) { + if (t != 0 && lastWriteTime != 0 && t != lastWriteTime && isEnabled()) { try { collidingId = Files.readString(Util.fileToPath(timestampFile), Charset.defaultCharset()); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Failed to read collision file", e); } // we noticed that someone else have updated this file. - // switch GUI to display this error. - // TODO seems drastic; could this just be switched to an AdministrativeMonitor? - Jenkins.get().servletContext.setAttribute("app", this); + activated = true; LOGGER.severe("Collision detected. timestamp=" + t + ", expected=" + lastWriteTime); // we need to continue updating this file, so that the other Hudson would notice the problem, too. } @@ -113,11 +111,10 @@ protected void execute() { Files.writeString(Util.fileToPath(timestampFile), getId(), Charset.defaultCharset()); lastWriteTime = timestampFile.lastModified(); } catch (IOException e) { + LOGGER.log(Level.FINE, null, e); // if failed to write, err on the safe side and assume things are OK. lastWriteTime = 0; } - - schedule(); } /** @@ -131,44 +128,29 @@ public String getCollidingId() { return collidingId; } - /** - * Schedules the next execution. - */ - public void schedule() { - // randomize the scheduling so that multiple Hudson instances will write at the file at different time - long MINUTE = 1000 * 60; // TODO use TimeUnit.MINUTE.toMillis - - Timer.get() - .schedule(new SafeTimerTask() { - @Override - protected void doRun() { - execute(); - } - }, (random.nextInt(30) + 60) * MINUTE, TimeUnit.MILLISECONDS); - } + @SuppressFBWarnings(value = "PREDICTABLE_RANDOM", justification = "The random is just used for load distribution.") + @Extension + public static final class Schedule extends AperiodicWork { - @Initializer(after = JOB_CONFIG_ADAPTED) - public static void init() { - // TODO AperiodicWork would be more idiomatic - new DoubleLaunchChecker().schedule(); - } + private final Random random = new Random(); - /** - * Serve all URLs with the index view. - */ - public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - rsp.setStatus(SC_INTERNAL_SERVER_ERROR); - req.getView(this, "index.jelly").forward(req, rsp); - } + @Override + public AperiodicWork getNewInstance() { + // Awkward to use DoubleLaunchChecker itself as the AperiodicWork since it is stateful, and we may not return this. + return new Schedule(); + } + + @Override + public long getRecurrencePeriod() { + // randomize the scheduling so that multiple Jenkins instances will write at the file at different time + return (Main.isUnitTest ? Duration.ofSeconds(random.nextInt(10) + 20) : Duration.ofMinutes(random.nextInt(30) + 60)).toMillis(); + } + + @Override + protected void doAperiodicRun() { + ExtensionList.lookupSingleton(DoubleLaunchChecker.class).execute(); + } - /** - * Ignore the problem and go back to using Hudson. - */ - @RequirePOST - public void doIgnore(StaplerRequest req, StaplerResponse rsp) throws IOException { - ignore = true; - Jenkins.get().servletContext.setAttribute("app", Jenkins.get()); - rsp.sendRedirect2(req.getContextPath() + '/'); } private static final Logger LOGGER = Logger.getLogger(DoubleLaunchChecker.class.getName()); diff --git a/core/src/main/java/hudson/util/HeadBufferingStream.java b/core/src/main/java/hudson/util/HeadBufferingStream.java index e5a2de574edc0..491ef6e56b7d8 100644 --- a/core/src/main/java/hudson/util/HeadBufferingStream.java +++ b/core/src/main/java/hudson/util/HeadBufferingStream.java @@ -24,10 +24,10 @@ package hudson.util; +import java.io.ByteArrayOutputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; -import org.apache.commons.io.output.ByteArrayOutputStream; /** * {@link FilterInputStream} that buffers the first N bytes to a byte array on the side. diff --git a/core/src/main/java/hudson/util/HudsonIsRestarting.java b/core/src/main/java/hudson/util/HudsonIsRestarting.java index a0dccc545a713..580a9713a08df 100644 --- a/core/src/main/java/hudson/util/HudsonIsRestarting.java +++ b/core/src/main/java/hudson/util/HudsonIsRestarting.java @@ -41,8 +41,29 @@ * @author Kohsuke Kawaguchi */ public class HudsonIsRestarting { + private boolean safeRestart; + + /** + * @since TODO + */ + public HudsonIsRestarting(boolean safeRestart) { + this.safeRestart = safeRestart; + } + + @Deprecated + public HudsonIsRestarting() { + this.safeRestart = false; + } + public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException { rsp.setStatus(SC_SERVICE_UNAVAILABLE); req.getView(this, "index.jelly").forward(req, rsp); } + + /** + * @since TODO + */ + public boolean isSafeRestart() { + return safeRestart; + } } diff --git a/core/src/main/java/hudson/util/IOUtils.java b/core/src/main/java/hudson/util/IOUtils.java index bf16104d4c451..7bb9121661226 100644 --- a/core/src/main/java/hudson/util/IOUtils.java +++ b/core/src/main/java/hudson/util/IOUtils.java @@ -35,8 +35,9 @@ public class IOUtils { * Drains the input stream and closes it. */ public static void drain(InputStream in) throws IOException { - org.apache.commons.io.IOUtils.copy(in, new NullStream()); - in.close(); + try (in; OutputStream out = OutputStream.nullOutputStream()) { + org.apache.commons.io.IOUtils.copy(in, out); + } } public static void copy(File src, OutputStream out) throws IOException { @@ -81,7 +82,9 @@ public static File mkdirs(File dir) throws IOException { * So to reliably skip just the N bytes, we'll actually read all those bytes. * * @since 1.349 + * @deprecated use {@link org.apache.commons.io.IOUtils#skipFully(InputStream, long)} */ + @Deprecated public static InputStream skip(InputStream in, long size) throws IOException { DataInputStream di = new DataInputStream(in); @@ -149,49 +152,11 @@ public static String readFirstLine(InputStream is, String encoding) throws IOExc } } - - /** - * @deprecated Use instead {@link org.apache.commons.io.IOUtils#DIR_SEPARATOR_UNIX} - */ - @Deprecated - public static final char DIR_SEPARATOR_UNIX = org.apache.commons.io.IOUtils.DIR_SEPARATOR_UNIX; - - /** - * @deprecated Use instead {@link org.apache.commons.io.IOUtils#DIR_SEPARATOR_WINDOWS} - */ - @Deprecated - public static final char DIR_SEPARATOR_WINDOWS = org.apache.commons.io.IOUtils.DIR_SEPARATOR_WINDOWS; - - /** - * @deprecated Use instead {@link org.apache.commons.io.IOUtils#DIR_SEPARATOR} - */ - @Deprecated - public static final char DIR_SEPARATOR = org.apache.commons.io.IOUtils.DIR_SEPARATOR; - - /** - * @deprecated Use instead {@link org.apache.commons.io.IOUtils#LINE_SEPARATOR_UNIX} - */ - @Deprecated - public static final String LINE_SEPARATOR_UNIX = org.apache.commons.io.IOUtils.LINE_SEPARATOR_UNIX; - - /** - * @deprecated Use instead {@link org.apache.commons.io.IOUtils#LINE_SEPARATOR_WINDOWS} - */ - @Deprecated - public static final String LINE_SEPARATOR_WINDOWS = org.apache.commons.io.IOUtils.LINE_SEPARATOR_WINDOWS; - - /** - * @deprecated Use instead {@link org.apache.commons.io.IOUtils#LINE_SEPARATOR} - */ - @Deprecated - public static final String LINE_SEPARATOR; - static { // avoid security issues StringWriter buf = new StringWriter(4); PrintWriter out = new PrintWriter(buf); out.println(); - LINE_SEPARATOR = buf.toString(); } /** diff --git a/core/src/main/java/hudson/util/NullStream.java b/core/src/main/java/hudson/util/NullStream.java index 41ce21803ec47..c6256d5a17bed 100644 --- a/core/src/main/java/hudson/util/NullStream.java +++ b/core/src/main/java/hudson/util/NullStream.java @@ -28,7 +28,9 @@ /** * @author Kohsuke Kawaguchi + * @deprecated use {@link OutputStream#nullOutputStream} */ +@Deprecated public final class NullStream extends OutputStream { public NullStream() {} diff --git a/core/src/main/java/hudson/util/PluginServletFilter.java b/core/src/main/java/hudson/util/PluginServletFilter.java index a7673eaf03d4d..037b7010d51a0 100644 --- a/core/src/main/java/hudson/util/PluginServletFilter.java +++ b/core/src/main/java/hudson/util/PluginServletFilter.java @@ -43,6 +43,7 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import jenkins.model.Jenkins; +import jenkins.util.HttpServletFilter; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -96,6 +97,11 @@ public void init(FilterConfig config) throws ServletException { config.getServletContext().setAttribute(KEY, this); } + /** + * Dynamically register a new filter. + * May be paired with {@link #removeFilter}. + *

For most purposes you can instead use {@link HttpServletFilter}. + */ public static void addFilter(Filter filter) throws ServletException { Jenkins j = Jenkins.getInstanceOrNull(); diff --git a/core/src/main/java/hudson/util/PrettyPrintWriter.java b/core/src/main/java/hudson/util/PrettyPrintWriter.java new file mode 100644 index 0000000000000..4ad71f0f5959b --- /dev/null +++ b/core/src/main/java/hudson/util/PrettyPrintWriter.java @@ -0,0 +1,340 @@ +// TODO adapted from https://github.com/x-stream/xstream/blob/32e52a6519a25366bbb5774bb536b5e290b64a42/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java pending release of https://github.com/jenkinsci/jenkins/pull/7924 + +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 07. March 2004 by Joe Walnes + */ + +package hudson.util; + +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.core.util.QuickWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.AbstractXmlWriter; +import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; +import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer; +import java.io.Writer; + + +/** + * A simple writer that outputs XML in a pretty-printed indented stream. + *

+ * By default, the chars
+ * & < > " ' \r
+ * are escaped and replaced with a suitable XML entity. To alter this behavior, override the + * {@link #writeText(com.thoughtworks.xstream.core.util.QuickWriter, String)} and + * {@link #writeAttributeValue(com.thoughtworks.xstream.core.util.QuickWriter, String)} methods. + *

+ *

+ * The XML specification requires XML parsers to drop CR characters completely. This implementation will therefore use + * only a LF for line endings, never the platform encoding. You can overwrite the {@link #getNewLine()} method for a + * different behavior. + *

+ *

+ * Note: Depending on the XML version some characters cannot be written. Especially a 0 character is never valid in XML, + * neither directly nor as entity nor within CDATA. However, this writer works by default in a quirks mode, where it + * will write any character at least as character entity (even a null character). You may switch into XML_1_1 mode + * (which supports most characters) or XML_1_0 that does only support a very limited number of control characters. See + * XML specification for version 1.0 or 1.1. If a character is not supported, a + * {@link StreamException} is thrown. Select a proper parser implementation that respects the version in the XML header + * (the Xpp3 parser will also read character entities of normally invalid characters). + *

+ * + * @author Joe Walnes + * @author Jörg Schaible + */ +class PrettyPrintWriter extends AbstractXmlWriter { + + public static int XML_QUIRKS = -1; + public static int XML_1_0 = 0; + public static int XML_1_1 = 1; + + private final QuickWriter writer; + private final FastStack elementStack = new FastStack(16); + private final char[] lineIndenter; + private final int mode; + + private boolean tagInProgress; + protected int depth; + private boolean readyForNewLine; + private boolean tagIsEmpty; + + private static final char[] NULL = "�".toCharArray(); + private static final char[] AMP = "&".toCharArray(); + private static final char[] LT = "<".toCharArray(); + private static final char[] GT = ">".toCharArray(); + private static final char[] CR = " ".toCharArray(); + private static final char[] QUOT = """.toCharArray(); + private static final char[] APOS = "'".toCharArray(); + private static final char[] CLOSE = " XML_1_1) { + throw new IllegalArgumentException("Not a valid XML mode"); + } + } + + /** + * @since 1.3 + * @deprecated As of 1.4 use {@link PrettyPrintWriter#PrettyPrintWriter(Writer, int, char[], NameCoder)} instead + */ + @Deprecated + PrettyPrintWriter( + final Writer writer, final int mode, final char[] lineIndenter, final XmlFriendlyReplacer replacer) { + this(writer, mode, lineIndenter, (NameCoder) replacer); + } + + /** + * @since 1.3 + */ + PrettyPrintWriter(final Writer writer, final int mode, final char[] lineIndenter) { + this(writer, mode, lineIndenter, new XmlFriendlyNameCoder()); + } + + PrettyPrintWriter(final Writer writer, final char[] lineIndenter) { + this(writer, XML_QUIRKS, lineIndenter); + } + + /** + * @since 1.3 + */ + PrettyPrintWriter(final Writer writer, final int mode, final String lineIndenter) { + this(writer, mode, lineIndenter.toCharArray()); + } + + PrettyPrintWriter(final Writer writer, final String lineIndenter) { + this(writer, lineIndenter.toCharArray()); + } + + /** + * @since 1.4 + */ + PrettyPrintWriter(final Writer writer, final int mode, final NameCoder nameCoder) { + this(writer, mode, new char[]{' ', ' '}, nameCoder); + } + + /** + * @since 1.3 + * @deprecated As of 1.4 use {@link PrettyPrintWriter#PrettyPrintWriter(Writer, int, NameCoder)} instead + */ + @Deprecated + PrettyPrintWriter(final Writer writer, final int mode, final XmlFriendlyReplacer replacer) { + this(writer, mode, new char[]{' ', ' '}, replacer); + } + + /** + * @since 1.4 + */ + PrettyPrintWriter(final Writer writer, final NameCoder nameCoder) { + this(writer, XML_QUIRKS, new char[]{' ', ' '}, nameCoder); + } + + /** + * @deprecated As of 1.4 use {@link PrettyPrintWriter#PrettyPrintWriter(Writer, NameCoder)} instead. + */ + @Deprecated + PrettyPrintWriter(final Writer writer, final XmlFriendlyReplacer replacer) { + this(writer, XML_QUIRKS, new char[]{' ', ' '}, replacer); + } + + /** + * @since 1.3 + */ + PrettyPrintWriter(final Writer writer, final int mode) { + this(writer, mode, new char[]{' ', ' '}); + } + + PrettyPrintWriter(final Writer writer) { + this(writer, new char[]{' ', ' '}); + } + + @Override + public void startNode(final String name) { + final String escapedName = encodeNode(name); + tagIsEmpty = false; + finishTag(); + writer.write('<'); + writer.write(escapedName); + elementStack.push(escapedName); + tagInProgress = true; + depth++; + readyForNewLine = true; + tagIsEmpty = true; + } + + @Override + public void startNode(final String name, final Class clazz) { + startNode(name); + } + + @Override + public void setValue(final String text) { + readyForNewLine = false; + tagIsEmpty = false; + finishTag(); + + writeText(writer, text); + } + + @Override + public void addAttribute(final String key, final String value) { + writer.write(' '); + writer.write(encodeAttribute(key)); + writer.write('='); + writer.write('\"'); + writeAttributeValue(writer, value); + writer.write('\"'); + } + + protected void writeAttributeValue(final QuickWriter writer, final String text) { + writeText(text, true); + } + + protected void writeText(final QuickWriter writer, final String text) { + writeText(text, false); + } + + private void writeText(final String text, final boolean isAttribute) { + text.codePoints().forEach(c -> { + switch (c) { + case '\0': + if (mode == XML_QUIRKS) { + writer.write(NULL); + } else { + throw new StreamException("Invalid character 0x0 in XML stream"); + } + break; + case '&': + writer.write(AMP); + break; + case '<': + writer.write(LT); + break; + case '>': + writer.write(GT); + break; + case '"': + writer.write(QUOT); + break; + case '\'': + writer.write(APOS); + break; + case '\r': + writer.write(CR); + break; + case '\t': + case '\n': + if (!isAttribute) { + writer.write(Character.toChars(c)); + break; + } + //$FALL-THROUGH$ + default: + if (Character.isDefined(c) && !Character.isISOControl(c)) { + if (mode != XML_QUIRKS) { + if (c > '\ud7ff' && c < '\ue000') { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML stream"); + } + } + writer.write(Character.toChars(c)); + } else { + if (mode == XML_1_0) { + if (c < 9 || c == '\u000b' || c == '\u000c' || c == '\u000e' || c >= '\u000f' && c <= '\u001f') { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML 1.0 stream"); + } + } + if (mode != XML_QUIRKS) { + if (c == '\ufffe' || c == '\uffff') { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML stream"); + } + } + writer.write("&#x"); + writer.write(Integer.toHexString(c)); + writer.write(';'); + } + } + }); + } + + @Override + public void endNode() { + depth--; + if (tagIsEmpty) { + writer.write('/'); + readyForNewLine = false; + finishTag(); + elementStack.popSilently(); + } else { + finishTag(); + writer.write(CLOSE); + writer.write((String) elementStack.pop()); + writer.write('>'); + } + readyForNewLine = true; + if (depth == 0) { + writer.flush(); + } + } + + private void finishTag() { + if (tagInProgress) { + writer.write('>'); + } + tagInProgress = false; + if (readyForNewLine) { + endOfLine(); + } + readyForNewLine = false; + tagIsEmpty = false; + } + + protected void endOfLine() { + writer.write(getNewLine()); + for (int i = 0; i < depth; i++) { + writer.write(lineIndenter); + } + } + + @Override + public void flush() { + writer.flush(); + } + + @Override + public void close() { + writer.close(); + } + + /** + * Retrieve the line terminator. This method returns always a line feed, since according the XML specification any + * parser must ignore a carriage return. Overload this method, if you need different behavior. + * + * @return the line terminator + * @since 1.3 + */ + protected String getNewLine() { + return "\n"; + } +} diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index e9689bde2f178..8f995738683bc 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -53,7 +53,6 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.ObjectStreamException; import java.io.RandomAccessFile; import java.io.Serializable; @@ -75,7 +74,6 @@ import jenkins.agents.AgentComputerUtil; import jenkins.security.SlaveToMasterCallable; import jenkins.util.SystemProperties; -import org.apache.commons.io.FileUtils; import org.jenkinsci.remoting.SerializableOnlyOverRemoting; import org.jvnet.winp.WinProcess; import org.jvnet.winp.WinpException; @@ -914,7 +912,7 @@ public synchronized List getArguments() { return arguments; arguments = new ArrayList<>(); try { - byte[] cmdline = readFileToByteArray(getFile("cmdline")); + byte[] cmdline = Files.readAllBytes(Util.fileToPath(getFile("cmdline"))); int pos = 0; for (int i = 0; i < cmdline.length; i++) { byte b = cmdline[i]; @@ -938,7 +936,7 @@ public synchronized EnvVars getEnvironmentVariables() { return envVars; envVars = new EnvVars(); try { - byte[] environ = readFileToByteArray(getFile("environ")); + byte[] environ = Files.readAllBytes(Util.fileToPath(getFile("environ"))); int pos = 0; for (int i = 0; i < environ.length; i++) { byte b = environ[i]; @@ -954,12 +952,6 @@ public synchronized EnvVars getEnvironmentVariables() { return envVars; } } - - public byte[] readFileToByteArray(File file) throws IOException { - try (InputStream in = FileUtils.openInputStream(file)) { - return org.apache.commons.io.IOUtils.toByteArray(in); - } - } } /** diff --git a/core/src/main/java/hudson/util/StreamTaskListener.java b/core/src/main/java/hudson/util/StreamTaskListener.java index 4abe31d3ec512..389a57c724de3 100644 --- a/core/src/main/java/hudson/util/StreamTaskListener.java +++ b/core/src/main/java/hudson/util/StreamTaskListener.java @@ -149,7 +149,7 @@ public StreamTaskListener(@NonNull Writer w) throws IOException { */ @Deprecated public StreamTaskListener() throws IOException { - this(new NullStream()); + this(OutputStream.nullOutputStream()); } public static StreamTaskListener fromStdout() { diff --git a/core/src/main/java/hudson/util/XStream2.java b/core/src/main/java/hudson/util/XStream2.java index 98c1934c4127f..5c6ebc566731d 100644 --- a/core/src/main/java/hudson/util/XStream2.java +++ b/core/src/main/java/hudson/util/XStream2.java @@ -46,7 +46,6 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.ReaderWrapper; -import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; import com.thoughtworks.xstream.io.xml.StandardStaxDriver; import com.thoughtworks.xstream.mapper.CannotResolveClassException; import com.thoughtworks.xstream.mapper.Mapper; @@ -138,7 +137,7 @@ private static class StaxDriver extends StandardStaxDriver { @Override public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out, getNameCoder()); + return new PrettyPrintWriter(out, PrettyPrintWriter.XML_1_1, getNameCoder()); } @Override @@ -470,8 +469,18 @@ public Class realClass(String elementName) { */ private static final class AssociatedConverterImpl implements Converter { private final XStream xstream; - private final ConcurrentHashMap, Converter> cache = - new ConcurrentHashMap<>(); + private static final ClassValue> classCache = new ClassValue>() { + @Override + protected Class computeValue(Class type) { + return computeConverterClass(type); + } + }; + private final ClassValue cache = new ClassValue() { + @Override + protected Converter computeValue(Class type) { + return computeConverter(type); + } + }; private AssociatedConverterImpl(XStream xstream) { this.xstream = xstream; @@ -482,17 +491,33 @@ private Converter findConverter(@CheckForNull Class t) { if (t == null) { return null; } + return cache.get(t); + } - Converter result = cache.get(t); - if (result != null) - // ConcurrentHashMap does not allow null, so use this object to represent null - return result == this ? null : result; + @CheckForNull + private static Class computeConverterClass(@NonNull Class t) { try { final ClassLoader classLoader = t.getClassLoader(); if (classLoader == null) { return null; } - Class cl = classLoader.loadClass(t.getName() + "$ConverterImpl"); + String name = t.getName() + "$ConverterImpl"; + if (classLoader.getResource(name.replace('.', '/') + ".class") == null) { + return null; + } + return classLoader.loadClass(name).asSubclass(ConverterMatcher.class); + } catch (ClassNotFoundException e) { + return null; + } + } + + @CheckForNull + private Converter computeConverter(@NonNull Class t) { + Class cl = classCache.get(t); + if (cl == null) { + return null; + } + try { Constructor c = cl.getConstructors()[0]; Class[] p = c.getParameterTypes(); @@ -507,14 +532,9 @@ else if (p[i] == Mapper.class) } ConverterMatcher cm = (ConverterMatcher) c.newInstance(args); - result = cm instanceof SingleValueConverter + return cm instanceof SingleValueConverter ? new SingleValueConverterWrapper((SingleValueConverter) cm) : (Converter) cm; - cache.put(t, result); - return result; - } catch (ClassNotFoundException e) { - cache.put(t, this); // See above.. this object in cache represents null - return null; } catch (IllegalAccessException e) { IllegalAccessError x = new IllegalAccessError(); x.initCause(e); diff --git a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java index da3576771416f..2c171b594f5a3 100644 --- a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java +++ b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java @@ -24,12 +24,22 @@ package hudson.widgets; -import hudson.model.Queue.Item; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.Job; +import hudson.model.Queue; import hudson.model.Queue.Task; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import jenkins.model.Jenkins; +import jenkins.model.queue.QueueItem; import jenkins.widgets.HistoryPageFilter; +import jenkins.widgets.WidgetFactory; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; /** * Displays the build history on the side panel. @@ -52,17 +62,17 @@ public BuildHistoryWidget(Task owner, Iterable baseList, Adapter a /** * Returns the first queue item if the owner is scheduled for execution in the queue. */ - public Item getQueuedItem() { + public QueueItem getQueuedItem() { return Jenkins.get().getQueue().getItem(owner); } /** * Returns the queue item if the owner is scheduled for execution in the queue, in REVERSE ORDER */ - public List getQueuedItems() { - LinkedList list = new LinkedList<>(); - for (Item item : Jenkins.get().getQueue().getItems()) { - if (item.task == owner) { + public List getQueuedItems() { + LinkedList list = new LinkedList<>(); + for (QueueItem item : Jenkins.get().getQueue().getItems()) { + if (item.getTask() == owner) { list.addFirst(item); } } @@ -78,4 +88,28 @@ public HistoryPageFilter getHistoryPageFilter() { return updateFirstTransientBuildKey(historyPageFilter); } + + @Extension + @Restricted(DoNotUse.class) + @Symbol("buildHistory") + public static final class FactoryImpl extends WidgetFactory { + @Override + public Class type() { + return Job.class; + } + + @Override + public Class widgetType() { + return BuildHistoryWidget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull Job target) { + if (target instanceof Queue.Task) { + return List.of(new BuildHistoryWidget<>((Queue.Task) target, target.getBuilds(), Job.HISTORY_ADAPTER)); + } + return Collections.emptySet(); + } + } } diff --git a/core/src/main/java/hudson/widgets/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java index aba195ab7c744..c7a7f12a1d76f 100644 --- a/core/src/main/java/hudson/widgets/HistoryWidget.java +++ b/core/src/main/java/hudson/widgets/HistoryWidget.java @@ -25,11 +25,16 @@ package hudson.widgets; import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; import hudson.Functions; +import hudson.model.Job; import hudson.model.ModelObject; +import hudson.model.Queue; import hudson.model.Run; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -37,6 +42,10 @@ import jenkins.util.SystemProperties; import jenkins.widgets.HistoryPageEntry; import jenkins.widgets.HistoryPageFilter; +import jenkins.widgets.WidgetFactory; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; import org.kohsuke.stapler.Header; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; @@ -97,6 +106,11 @@ public HistoryWidget(O owner, Iterable baseList, Adapter adapter) this.searchString = currentRequest.getParameter("search"); } + @Override + protected String getOwnerUrl() { + return baseUrl; + } + /** * Title of the widget. */ @@ -292,4 +306,29 @@ private Long getPagingParam(@CheckForNull StaplerRequest currentRequest, @CheckF return null; } } + + @Extension + @Restricted(DoNotUse.class) + @Symbol("history") + public static final class FactoryImpl extends WidgetFactory { + @Override + public Class type() { + return Job.class; + } + + @Override + public Class widgetType() { + return HistoryWidget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull Job target) { + // e.g. hudson.model.ExternalJob + if (!(target instanceof Queue.Task)) { + return List.of(new HistoryWidget<>(target, target.getBuilds(), Job.HISTORY_ADAPTER)); + } + return Collections.emptySet(); + } + } } diff --git a/core/src/main/java/hudson/widgets/Widget.java b/core/src/main/java/hudson/widgets/Widget.java index 81bc9e4e4cac8..a26d904cbe572 100644 --- a/core/src/main/java/hudson/widgets/Widget.java +++ b/core/src/main/java/hudson/widgets/Widget.java @@ -24,7 +24,7 @@ package hudson.widgets; -import hudson.ExtensionPoint; +import edu.umd.cs.findbugs.annotations.CheckForNull; import hudson.model.View; /** @@ -47,14 +47,14 @@ * @since 1.146 * @see jenkins.model.Jenkins#getWidgets() */ -public abstract class Widget implements ExtensionPoint { +public abstract class Widget { /** * Gets the URL path name. * *

* For example, if this method returns "xyz", and if the parent object * (that this widget is associated with) is bound to /foo/bar/zot, - * then this widget object will be exposed to /foo/bar/zot/xyz. + * then this widget object will be exposed to /foo/bar/zot/widget/xyz. * *

* This method is useful when the widget needs to expose additional URLs, @@ -67,4 +67,21 @@ public abstract class Widget implements ExtensionPoint { public String getUrlName() { return getClass().getSimpleName(); } + + /** + * @return The URL of the owner of this widget relative to context path. Always ends with a trailing slash. + * Can be null for backward compatibility with widgets annotated with @Extension. + */ + @CheckForNull + protected String getOwnerUrl() { + return null; + } + + /** + * @return the URL relative to the context path. Always ends with a trailing '/'. + */ + public String getUrl() { + String ownerUrl = getOwnerUrl(); + return (ownerUrl == null ? "" : ownerUrl) + "widget/" + getUrlName() + '/'; + } } diff --git a/core/src/main/java/jenkins/agents/CloudSet.java b/core/src/main/java/jenkins/agents/CloudSet.java new file mode 100644 index 0000000000000..5229dd06f18b4 --- /dev/null +++ b/core/src/main/java/jenkins/agents/CloudSet.java @@ -0,0 +1,272 @@ +/* + * The MIT License + * + * Copyright (c) 2023, CloudBees Inc, and other contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.agents; + +import hudson.Extension; +import hudson.Functions; +import hudson.Util; +import hudson.model.AbstractModelObject; +import hudson.model.AutoCompletionCandidates; +import hudson.model.Describable; +import hudson.model.Descriptor; +import hudson.model.Failure; +import hudson.model.RootAction; +import hudson.model.UpdateCenter; +import hudson.slaves.Cloud; +import hudson.util.FormValidation; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.servlet.ServletException; +import jenkins.model.Jenkins; +import jenkins.model.ModelObjectWithChildren; +import jenkins.model.ModelObjectWithContextMenu; +import net.sf.json.JSONObject; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.StaplerProxy; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.interceptor.RequirePOST; +import org.kohsuke.stapler.verb.POST; + +@Restricted(NoExternalUse.class) +public class CloudSet extends AbstractModelObject implements Describable, ModelObjectWithChildren, RootAction, StaplerProxy { + private static final Logger LOGGER = Logger.getLogger(CloudSet.class.getName()); + + @Override + public Descriptor getDescriptor() { + return Jenkins.get().getDescriptorOrDie(CloudSet.class); + } + + public Cloud getDynamic(String token) { + return Jenkins.get().getCloud(token); + } + + @Override + @Restricted(NoExternalUse.class) + public Object getTarget() { + Jenkins.get().checkPermission(Jenkins.SYSTEM_READ); + return this; + } + + @Override + public String getIconFileName() { + return null; + } + + @Override + public String getDisplayName() { + return Messages.CloudSet_DisplayName(); + } + + @Override + public String getUrlName() { + return "cloud"; + } + + @Override + public String getSearchUrl() { + return "/cloud/"; + } + + @SuppressWarnings("unused") // stapler + @Restricted(DoNotUse.class) // stapler + public String getCloudUrl(StaplerRequest request, Jenkins jenkins, Cloud cloud) { + String context = Functions.getNearestAncestorUrl(request, jenkins); + if (Jenkins.get().getCloud(cloud.name) != cloud) { // this cloud is not the first occurrence with this name + return context + "/cloud/cloudByIndex/" + getClouds().indexOf(cloud) + "/"; + } else { + return context + "/" + cloud.getUrl(); + } + } + + @SuppressWarnings("unused") // stapler + @Restricted(DoNotUse.class) // stapler + public Cloud getCloudByIndex(int index) { + return Jenkins.get().clouds.get(index); + } + + @SuppressWarnings("unused") // stapler + public boolean isCloudAvailable() { + return !Cloud.all().isEmpty(); + } + + @SuppressWarnings("unused") // stapler + public String getCloudUpdateCenterCategoryLabel() { + return URLEncoder.encode(UpdateCenter.getCategoryDisplayName("cloud"), StandardCharsets.UTF_8); + } + + @Override + public ModelObjectWithContextMenu.ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception { + ModelObjectWithContextMenu.ContextMenu m = new ModelObjectWithContextMenu.ContextMenu(); + Jenkins.get().clouds.stream().forEach(c -> m.add(c)); + return m; + } + + public Cloud getDynamic(String name, StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + return Jenkins.get().clouds.getByName(name); + } + + @SuppressWarnings("unused") // stapler + @Restricted(DoNotUse.class) // stapler + public Jenkins.CloudList getClouds() { + return Jenkins.get().clouds; + } + + @SuppressWarnings("unused") // stapler + @Restricted(DoNotUse.class) // stapler + public boolean hasClouds() { + return !Jenkins.get().clouds.isEmpty(); + } + + /** + * Makes sure that the given name is good as an agent name. + * @return trimmed name if valid; throws ParseException if not + */ + public String checkName(String name) throws Failure { + if (name == null) + throw new Failure("Query parameter 'name' is required"); + + name = name.trim(); + Jenkins.checkGoodName(name); + + if (Jenkins.get().getCloud(name) != null) + throw new Failure(Messages.CloudSet_CloudAlreadyExists(name)); + + // looks good + return name; + } + + @SuppressWarnings("unused") // stapler + public FormValidation doCheckName(@QueryParameter String value) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + if (Util.fixEmpty(value) == null) { + return FormValidation.ok(); + } + try { + checkName(value); + return FormValidation.ok(); + } catch (Failure e) { + return FormValidation.error(e.getMessage()); + } + } + + /** + * First check point in creating a new cloud. + */ + @RequirePOST + public synchronized void doCreate(StaplerRequest req, StaplerResponse rsp, + @QueryParameter String name, @QueryParameter String mode, + @QueryParameter String from) throws IOException, ServletException, Descriptor.FormException { + final Jenkins jenkins = Jenkins.get(); + jenkins.checkPermission(Jenkins.ADMINISTER); + + if (mode != null && mode.equals("copy")) { + name = checkName(name); + + Cloud src = jenkins.getCloud(from); + if (src == null) { + if (Util.fixEmpty(from) == null) { + throw new Failure(Messages.CloudSet_SpecifyCloudToCopy()); + } else { + throw new Failure(Messages.CloudSet_NoSuchCloud(from)); + } + } + + // copy through XStream + String xml = Jenkins.XSTREAM.toXML(src); + // Not great, but cloud name is final + xml = xml.replace("" + src.name + "", "" + name + ""); + Cloud result = (Cloud) Jenkins.XSTREAM.fromXML(xml); + jenkins.clouds.add(result); + // send the browser to the config page + rsp.sendRedirect2(Functions.getNearestAncestorUrl(req, jenkins) + "/" + result.getUrl() + "configure"); + } else { + // proceed to step 2 + if (mode == null) { + throw new Failure("No mode given"); + } + + Descriptor d = Cloud.all().findByName(mode); + if (d == null) { + throw new Failure("No node type ‘" + mode + "’ is known"); + } + handleNewCloudPage(d, name, req, rsp); + } + } + + private void handleNewCloudPage(Descriptor descriptor, String name, StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException { + checkName(name); + JSONObject formData = req.getSubmittedForm(); + formData.put("name", name); + formData.put("cloudName", name); // ec2 uses that field name + formData.remove("mode"); // Cloud descriptors won't have this field. + req.setAttribute("instance", formData); + req.setAttribute("descriptor", descriptor); + req.getView(this, "_new.jelly").forward(req, rsp); + } + + /** + * Really creates a new agent. + */ + @POST + public synchronized void doDoCreate(StaplerRequest req, StaplerResponse rsp, + @QueryParameter String type) throws IOException, ServletException, Descriptor.FormException { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + Cloud cloud = Cloud.all().find(type).newInstance(req, req.getSubmittedForm()); + if (!Jenkins.get().clouds.add(cloud)) { + LOGGER.log(Level.WARNING, () -> "Creating duplicate cloud name " + cloud.name + ". Plugin " + Jenkins.get().getPluginManager().whichPlugin(cloud.getClass()) + " should be updated to support user provided name."); + } + // take the user back to the cloud list top page + rsp.sendRedirect2("."); + } + + @Extension + public static class DescriptorImpl extends Descriptor implements StaplerProxy { + + /** + * Auto-completion for the "copy from" field in the new cloud page. + */ + @SuppressWarnings("unused") // stapler + public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value) { + final AutoCompletionCandidates r = new AutoCompletionCandidates(); + Jenkins.get().clouds.stream() + .filter(c -> c.name.startsWith(value)) + .forEach(c -> r.add(c.name)); + return r; + } + + @Override + public Object getTarget() { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + return this; + } + } +} diff --git a/core/src/main/java/jenkins/agents/CloudsLink.java b/core/src/main/java/jenkins/agents/CloudsLink.java new file mode 100644 index 0000000000000..38293b0ba3aef --- /dev/null +++ b/core/src/main/java/jenkins/agents/CloudsLink.java @@ -0,0 +1,69 @@ +/* + * The MIT License + * + * Copyright (c) 2023, CloudBees Inc, and other contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.agents; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.ManagementLink; +import hudson.security.Permission; +import jenkins.model.Jenkins; +import org.jenkinsci.Symbol; + +@Extension +@Symbol("clouds") +public class CloudsLink extends ManagementLink { + + @Override + public String getDisplayName() { + return Messages.CloudsLink_DisplayName(); + } + + @Override + public String getDescription() { + return Messages.CloudsLink_Description(); + } + + @Override + public String getIconFileName() { + return "symbol-cloud"; + } + + @Override + public String getUrlName() { + return "cloud"; + } + + @NonNull + @Override + public Category getCategory() { + return Category.CONFIGURATION; + } + + @NonNull + @Override + public Permission getRequiredPermission() { + return Jenkins.SYSTEM_READ; + } +} diff --git a/core/src/main/java/jenkins/cli/SafeRestartCommand.java b/core/src/main/java/jenkins/cli/SafeRestartCommand.java new file mode 100644 index 0000000000000..9f83627ba844c --- /dev/null +++ b/core/src/main/java/jenkins/cli/SafeRestartCommand.java @@ -0,0 +1,59 @@ +/* + * The MIT License + * + * Copyright (c) 2023, Jan Meiswinkel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.cli; + +import hudson.Extension; +import hudson.cli.CLICommand; +import hudson.cli.Messages; +import java.util.logging.Logger; +import jenkins.model.Jenkins; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.args4j.Option; + +/** + * Safe Restart Jenkins - do not accept any new jobs and try to pause existing. + * + * @since TODO + */ +@Extension +@Restricted(NoExternalUse.class) +public class SafeRestartCommand extends CLICommand { + private static final Logger LOGGER = Logger.getLogger(SafeRestartCommand.class.getName()); + + @Option(name = "-message", usage = "Message for safe restart that will be visible to users") + public String message = null; + + @Override + public String getShortDescription() { + return Messages.SafeRestartCommand_ShortDescription(); + } + + @Override + protected int run() throws Exception { + Jenkins.get().doSafeRestart(null, message); + return 0; + } +} diff --git a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java index 5170d60327391..d06c3c7bff69a 100644 --- a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java +++ b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java @@ -57,7 +57,7 @@ public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException { disable(true); rsp.sendRedirect(req.getContextPath() + "/manage"); } else if (req.hasParameter("cloud")) { - rsp.sendRedirect(req.getContextPath() + "/configureClouds"); + rsp.sendRedirect(req.getContextPath() + "/manage/cloud/"); } else if (req.hasParameter("agent")) { rsp.sendRedirect(req.getContextPath() + "/computer/new"); } diff --git a/core/src/main/java/jenkins/install/InstallStateFilter.java b/core/src/main/java/jenkins/install/InstallStateFilter.java index af34991aa163a..f5114717d0eec 100644 --- a/core/src/main/java/jenkins/install/InstallStateFilter.java +++ b/core/src/main/java/jenkins/install/InstallStateFilter.java @@ -2,8 +2,8 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; +import jakarta.inject.Provider; import java.util.List; -import javax.inject.Provider; /** * Allows plugging in to the lifecycle when determining InstallState diff --git a/core/src/main/java/jenkins/install/InstallUtil.java b/core/src/main/java/jenkins/install/InstallUtil.java index 0572d48a5209c..ff6949eaefd8c 100644 --- a/core/src/main/java/jenkins/install/InstallUtil.java +++ b/core/src/main/java/jenkins/install/InstallUtil.java @@ -37,6 +37,7 @@ import hudson.model.UpdateCenter.InstallationJob; import hudson.model.UpdateCenter.UpdateCenterJob; import hudson.util.VersionNumber; +import jakarta.inject.Provider; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; @@ -51,7 +52,6 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; -import javax.inject.Provider; import jenkins.model.Jenkins; import jenkins.util.SystemProperties; import jenkins.util.xml.XMLUtils; diff --git a/core/src/main/java/jenkins/management/NodesLink.java b/core/src/main/java/jenkins/management/NodesLink.java index e0058a24304bc..7a6f73f205f83 100644 --- a/core/src/main/java/jenkins/management/NodesLink.java +++ b/core/src/main/java/jenkins/management/NodesLink.java @@ -39,7 +39,7 @@ public class NodesLink extends ManagementLink { @Override public String getIconFileName() { - return "symbol-cloud"; + return "symbol-computer"; } @Override diff --git a/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java b/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java index 2731e12649e51..022474b496ba9 100644 --- a/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java @@ -3,29 +3,21 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import hudson.Extension; import hudson.RestrictedSince; -import hudson.model.Descriptor; import hudson.model.RootAction; -import hudson.slaves.Cloud; -import hudson.util.FormApply; -import java.io.IOException; -import javax.servlet.ServletException; -import net.sf.json.JSONObject; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.verb.POST; /** - * Provides a configuration form for {@link Jenkins#clouds}. - * - * Has been overhauled in Jenkins 2.XXX to no longer contribute to Configure System, but be a standalone form. + * Redirects from /configureClouds to /cloud/. + * Previously was the form for clouds. + * @deprecated Replaced by {@link jenkins.agents.CloudsLink} and {@link jenkins.agents.CloudSet}. */ @Extension @Symbol("cloud") @Restricted(NoExternalUse.class) @RestrictedSince("2.205") +@Deprecated public class GlobalCloudConfiguration implements RootAction { @CheckForNull @@ -44,12 +36,4 @@ public String getDisplayName() { public String getUrlName() { return "configureClouds"; } - - @POST - public void doConfigure(StaplerRequest req, StaplerResponse rsp) throws Descriptor.FormException, IOException, ServletException { - Jenkins.get().checkPermission(Jenkins.ADMINISTER); - JSONObject json = req.getSubmittedForm(); - Jenkins.get().clouds.rebuildHetero(req, json, Cloud.all(), "cloud"); - FormApply.success(req.getContextPath() + "/manage").generateResponse(req, rsp, null); - } } diff --git a/core/src/main/java/jenkins/model/GlobalConfiguration.java b/core/src/main/java/jenkins/model/GlobalConfiguration.java index a1eb2523c7743..4a5aa76ba1178 100644 --- a/core/src/main/java/jenkins/model/GlobalConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalConfiguration.java @@ -22,7 +22,7 @@ * An option to present a single section for your plugin in the Jenkins global configuration page is * to use this class to manage the configuration for your plugin and its extension points. To access * properties defined in your GlobalConfiguration subclass, here are two possibilities: - *

  • @{@link javax.inject.Inject} into your other {@link hudson.Extension}s (so this does not work + *
    • @{@link jakarta.inject.Inject} into your other {@link hudson.Extension}s (so this does not work * for classes not annotated with {@link hudson.Extension})
    • *
    • access it via a call to {@code ExtensionList.lookupSingleton(.class)}
    * diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index dda1ef9d81f5c..9bf94cf9389a5 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -225,6 +225,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -264,6 +265,7 @@ import jenkins.ExtensionComponentSet; import jenkins.ExtensionRefreshException; import jenkins.InitReactorRunner; +import jenkins.agents.CloudSet; import jenkins.diagnostics.URICheckEncodingMonitor; import jenkins.install.InstallState; import jenkins.install.SetupWizard; @@ -481,6 +483,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve @CheckForNull private transient volatile QuietDownInfo quietDownInfo; + private transient volatile boolean terminating; @GuardedBy("Jenkins.class") private transient boolean cleanUpStarted; @@ -1575,6 +1578,14 @@ public ComputerSet getComputer() { return new ComputerSet(); } + /** + * Only there to bind to /cloud/ URL. Otherwise /cloud/new gets resolved to getCloud("new") by stapler which is not what we want. + */ + @Restricted(DoNotUse.class) + public CloudSet getCloud() { + return new CloudSet(); + } + /** * Exposes {@link Descriptor} by its name to URL. * @@ -2039,13 +2050,7 @@ public boolean isUpgradedFromBefore(VersionNumber v) { * Gets the read-only list of all {@link Computer}s. */ public Computer[] getComputers() { - Computer[] r = computers.values().toArray(new Computer[0]); - Arrays.sort(r, (lhs, rhs) -> { - if (lhs.getNode() == Jenkins.this) return -1; - if (rhs.getNode() == Jenkins.this) return 1; - return lhs.getName().compareTo(rhs.getName()); - }); - return r; + return computers.values().stream().sorted(Comparator.comparing(Computer::getName)).toArray(Computer[]::new); } @CLIResolver @@ -2934,6 +2939,20 @@ public boolean isQuietingDown() { return quietDownInfo != null; } + /** + * Returns if the quietingDown is a safe restart. + * @since TODO + */ + @Restricted(NoExternalUse.class) + @NonNull + public boolean isPreparingSafeRestart() { + QuietDownInfo quietDownInfo = this.quietDownInfo; + if (quietDownInfo != null) { + return quietDownInfo.isSafeRestart(); + } + return false; + } + /** * Returns quiet down reason if it was indicated. * @return @@ -2944,7 +2963,7 @@ public boolean isQuietingDown() { @CheckForNull public String getQuietDownReason() { final QuietDownInfo info = quietDownInfo; - return info != null ? info.reason : null; + return info != null ? info.message : null; } /** @@ -4084,7 +4103,7 @@ public synchronized HttpRedirect doQuietDown() { * * @param block Block until the system really quiets down and no builds are running * @param timeout If non-zero, only block up to the specified number of milliseconds - * @deprecated since 2.267; use {@link #doQuietDown(boolean, int, String)} instead. + * @deprecated since 2.267; use {@link #doQuietDown(boolean, int, String, boolean)} instead. */ @Deprecated public synchronized HttpRedirect doQuietDown(boolean block, int timeout) { @@ -4100,16 +4119,34 @@ public synchronized HttpRedirect doQuietDown(boolean block, int timeout) { * * @param block Block until the system really quiets down and no builds are running * @param timeout If non-zero, only block up to the specified number of milliseconds - * @param reason Quiet reason that will be visible to user - * @since 2.267 + * @param message Quiet reason that will be visible to user + * @deprecated use {@link #doQuietDown(boolean, int, String, boolean)} instead. + */ + @Deprecated(since = "TODO") + public HttpRedirect doQuietDown(boolean block, + int timeout, + @CheckForNull String message) throws InterruptedException, IOException { + + return doQuietDown(block, timeout, message, false); + } + + /** + * Quiet down Jenkins - preparation for a restart + * + * @param block Block until the system really quiets down and no builds are running + * @param timeout If non-zero, only block up to the specified number of milliseconds + * @param message Quiet reason that will be visible to user + * @param safeRestart If the quietDown is for a safeRestart + * @since TODO */ @RequirePOST public HttpRedirect doQuietDown(@QueryParameter boolean block, @QueryParameter int timeout, - @QueryParameter @CheckForNull String reason) throws InterruptedException, IOException { + @QueryParameter @CheckForNull String message, + @QueryParameter boolean safeRestart) throws InterruptedException, IOException { synchronized (this) { checkPermission(MANAGE); - quietDownInfo = new QuietDownInfo(reason); + quietDownInfo = new QuietDownInfo(message, safeRestart); } if (block) { long waitUntil = timeout; @@ -4504,20 +4541,35 @@ public void doRestart(StaplerRequest req, StaplerResponse rsp) throws IOExceptio } /** - * Queues up a restart of Jenkins for when there are no builds running, if we can. + * Queues up a safe restart of Jenkins. + * Builds that cannot continue while the controller is not running have to finish or pause before it can proceed. + * No new builds will be started. No new jobs are accepted. * - * This first replaces "app" to {@link HudsonIsRestarting} + * @deprecated use {@link #doSafeRestart(StaplerRequest, String)} instead. * - * @since 1.332 */ - @CLIMethod(name = "safe-restart") + @Deprecated(since = "TODO") public HttpResponse doSafeRestart(StaplerRequest req) throws IOException, ServletException, RestartNotSupportedException { + return doSafeRestart(req, null); + } + + /** + * Queues up a safe restart of Jenkins. Jobs have to finish or pause before it can proceed. No new jobs are accepted. + * + * @since TODO + */ + public HttpResponse doSafeRestart(StaplerRequest req, @QueryParameter("message") String message) throws IOException, ServletException, RestartNotSupportedException { checkPermission(MANAGE); - if (req != null && req.getMethod().equals("GET")) + if (req != null && req.getMethod().equals("GET")) { return HttpResponses.forwardToView(this, "_safeRestart.jelly"); + } + + if (req != null && req.getParameter("cancel") != null) { + return doCancelQuietDown(); + } if (req == null || req.getMethod().equals("POST")) { - safeRestart(); + safeRestart(message); } return HttpResponses.redirectToDot(); @@ -4563,11 +4615,22 @@ public void run() { /** * Queues up a restart to be performed once there are no builds currently running. * @since 1.332 + * @deprecated use {@link #safeRestart(String)} instead. */ + @Deprecated(since = "TODO") public void safeRestart() throws RestartNotSupportedException { + safeRestart(null); + } + + /** + * Queues up a restart to be performed once there are no builds currently running. + * @param message the message to show to users in the shutdown banner. + * @since TODO + */ + public void safeRestart(String message) throws RestartNotSupportedException { final Lifecycle lifecycle = restartableLifecycle(); // Quiet down so that we won't launch new builds. - quietDownInfo = new QuietDownInfo(); + quietDownInfo = new QuietDownInfo(message, true); new Thread("safe-restart thread") { final String exitUser = getAuthentication2().getName(); @@ -4576,11 +4639,10 @@ public void run() { try (ACLContext ctx = ACL.as2(ACL.SYSTEM2)) { // Wait 'til we have no active executors. - doQuietDown(true, 0, null); - + doQuietDown(true, 0, message, true); // Make sure isQuietingDown is still true. if (isQuietingDown()) { - servletContext.setAttribute("app", new HudsonIsRestarting()); + servletContext.setAttribute("app", new HudsonIsRestarting(true)); // give some time for the browser to load the "reloading" page lifecycle.onStatusUpdate("Restart in 10 seconds"); Thread.sleep(TimeUnit.SECONDS.toMillis(10)); @@ -5752,16 +5814,31 @@ private static void _setJenkinsJVM(boolean jenkinsJVM) { } private static final class QuietDownInfo { - @CheckForNull - final String reason; + final String message; + + private boolean safeRestart; QuietDownInfo() { - this(null); + this(null, false); + } + + QuietDownInfo(final String message) { + this(message, false); + } + + QuietDownInfo(final String message, final boolean safeRestart) { + this.message = message; + this.safeRestart = safeRestart; + } + + + boolean isSafeRestart() { + return safeRestart; } - QuietDownInfo(final String reason) { - this.reason = reason; + void setSafeRestart(boolean safeRestart) { + this.safeRestart = safeRestart; } } } diff --git a/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java b/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java index 52b49131ad792..01ac4ca37242c 100644 --- a/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java +++ b/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java @@ -2,7 +2,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Functions; -import hudson.Util; import hudson.model.Action; import hudson.model.Actionable; import hudson.model.BallColor; @@ -10,6 +9,7 @@ import hudson.model.Job; import hudson.model.ModelObject; import hudson.model.Node; +import hudson.slaves.Cloud; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -150,7 +150,7 @@ public ContextMenu add(String url, String icon, String iconXml, String text, boo return this; } - /** @since TODO */ + /** @since 2.401 */ public ContextMenu add(String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation, Badge badge) { if (text != null && icon != null && url != null) { MenuItem item = new MenuItem(url, icon, text); @@ -163,6 +163,20 @@ public ContextMenu add(String url, String icon, String iconXml, String text, boo return this; } + /** @since TODO */ + public ContextMenu add(String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation, Badge badge, String message) { + if (text != null && icon != null && url != null) { + MenuItem item = new MenuItem(url, icon, text); + item.iconXml = iconXml; + item.post = post; + item.requiresConfirmation = requiresConfirmation; + item.badge = badge; + item.message = message; + items.add(item); + } + return this; + } + /** * Add a header row (no icon, no URL, rendered in header style). * @@ -221,6 +235,13 @@ public ContextMenu add(Computer c) { .withContextRelativeUrl(c.getUrl())); } + public ContextMenu add(Cloud c) { + return add(new MenuItem() + .withDisplayName(c.getDisplayName()) + .withIconClass(c.getIconClassName()) + .withContextRelativeUrl(c.getUrl())); + } + /** * Adds a child item when rendering context menu of its parent. * @@ -333,6 +354,8 @@ class MenuItem { private Badge badge; + private String message; + /** * The type of menu item * @since 2.340 @@ -355,13 +378,18 @@ public String getIconXml() { /** * The badge to display for the context menu item - * @since TODO + * @since 2.401 */ @Exported public Badge getBadge() { return badge; } + @Exported + public String getMessage() { + return message; + } + public MenuItem(String url, String icon, String displayName) { withUrl(url).withIcon(icon).withDisplayName(displayName); } @@ -414,7 +442,7 @@ public MenuItem withIconClass(String iconClass) { } public MenuItem withDisplayName(String displayName) { - this.displayName = Util.escape(displayName); + this.displayName = displayName; return this; } diff --git a/core/src/main/java/jenkins/model/TransientActionFactory.java b/core/src/main/java/jenkins/model/TransientActionFactory.java index 73b211751cb91..6eb1ed52692f2 100644 --- a/core/src/main/java/jenkins/model/TransientActionFactory.java +++ b/core/src/main/java/jenkins/model/TransientActionFactory.java @@ -24,10 +24,8 @@ package jenkins.model; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionListListener; import hudson.ExtensionPoint; @@ -80,59 +78,53 @@ public abstract class TransientActionFactory implements ExtensionPoint { */ public abstract @NonNull Collection createFor(@NonNull T target); - /** @see no pairs/tuples in Java */ - private static class CacheKey { - private final Class type; - private final Class actionType; + @Restricted(NoExternalUse.class) + @Extension + public static final class Cache extends ExtensionListListener { - CacheKey(Class type, Class actionType) { - this.type = type; - this.actionType = actionType; - } + @SuppressWarnings("rawtypes") + private ExtensionList allFactories; - @Override - public boolean equals(Object obj) { - return obj instanceof CacheKey && type == ((CacheKey) obj).type && actionType == ((CacheKey) obj).actionType; - } + private ClassValue>>> cache; - @Override - public int hashCode() { - return type.hashCode() ^ actionType.hashCode(); + private synchronized ClassValue>>> cache() { + if (allFactories == null) { + allFactories = ExtensionList.lookup(TransientActionFactory.class); + allFactories.addListener(this); + } + if (cache == null) { + cache = new ClassValue<>() { + @Override + protected ClassValue>> computeValue(Class type) { + return new ClassValue<>() { + @Override + protected List> computeValue(Class actionType) { + List> factories = new ArrayList<>(); + for (TransientActionFactory taf : allFactories) { + if (taf.type().isAssignableFrom(type) && (actionType.isAssignableFrom(taf.actionType()) || taf.actionType().isAssignableFrom(actionType))) { + factories.add(taf); + } + } + return factories; + } + }; + } + }; + } + return cache; } - } - @SuppressWarnings("rawtypes") - private static final LoadingCache, LoadingCache>>> cache = - CacheBuilder.newBuilder().weakKeys().build(new CacheLoader<>() { + @Override - public LoadingCache>> load(final ExtensionList allFactories) throws Exception { - final LoadingCache>> perJenkinsCache = - CacheBuilder.newBuilder().build(new CacheLoader<>() { - @Override - public List> load(CacheKey key) throws Exception { - List> factories = new ArrayList<>(); - for (TransientActionFactory taf : allFactories) { - Class actionType = taf.actionType(); - if (taf.type().isAssignableFrom(key.type) && (key.actionType.isAssignableFrom(actionType) || actionType.isAssignableFrom(key.actionType))) { - factories.add(taf); - } - } - return factories; - } - }); - allFactories.addListener(new ExtensionListListener() { - @Override - public void onChange() { - perJenkinsCache.invalidateAll(); - } - }); - return perJenkinsCache; + public synchronized void onChange() { + cache = null; } - }); + + } @Restricted(NoExternalUse.class) // pending a need for it outside Actionable public static Iterable> factoriesFor(Class type, Class actionType) { - return cache.getUnchecked(ExtensionList.lookup(TransientActionFactory.class)).getUnchecked(new CacheKey(type, actionType)); + return ExtensionList.lookupSingleton(Cache.class).cache().get(type).get(actionType); } } diff --git a/test/src/test/java/jenkins/util/AntClassLoaderTest.java b/core/src/main/java/jenkins/model/experimentalflags/RemovePrototypeUserExperimentalFlag.java similarity index 58% rename from test/src/test/java/jenkins/util/AntClassLoaderTest.java rename to core/src/main/java/jenkins/model/experimentalflags/RemovePrototypeUserExperimentalFlag.java index c8c882ed81ac1..a2773986cfda8 100644 --- a/test/src/test/java/jenkins/util/AntClassLoaderTest.java +++ b/core/src/main/java/jenkins/model/experimentalflags/RemovePrototypeUserExperimentalFlag.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright 2020 CloudBees, Inc. + * Copyright (c) 2023, CloudBees, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,26 +22,33 @@ * THE SOFTWARE. */ -package jenkins.util; +package jenkins.model.experimentalflags; -import static org.junit.Assert.assertNotNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import hudson.Extension; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.recipes.WithPlugin; +@Extension +public final class RemovePrototypeUserExperimentalFlag extends BooleanUserExperimentalFlag { -public class AntClassLoaderTest { + public RemovePrototypeUserExperimentalFlag() { + super("remove-prototype.flag"); + } - @Rule - public JenkinsRule r = new JenkinsRule(); + @NonNull + @Override + public Boolean getDefaultValue() { + return false; + } - @Issue("JENKINS-60644") - @WithPlugin("loads-resource.jpi") - @Test - public void loadsResource() throws Exception { - assertNotNull(r.jenkins.pluginManager.getPlugin("loads-resource").classLoader.getResourceAsStream("io/jenkins/plugins/loads_resource/stuff")); + @Override + public String getDisplayName() { + return "Remove Prototype.js"; } + @Nullable + @Override + public String getShortDescription() { + return "Remove Prototype.js from all Jenkins UI pages. This will break anything that depends on Prototype.js."; + } } diff --git a/core/src/main/java/jenkins/model/lazy/BuildReferenceMapAdapter.java b/core/src/main/java/jenkins/model/lazy/BuildReferenceMapAdapter.java index 79984477a02aa..d9771de36576a 100644 --- a/core/src/main/java/jenkins/model/lazy/BuildReferenceMapAdapter.java +++ b/core/src/main/java/jenkins/model/lazy/BuildReferenceMapAdapter.java @@ -3,7 +3,6 @@ import edu.umd.cs.findbugs.annotations.Nullable; import hudson.util.AdaptedIterator; import hudson.util.Iterators; -import java.lang.reflect.Array; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; @@ -192,25 +191,16 @@ protected R adapt(BuildReference ref) { @Override public Object[] toArray() { - List list = new ArrayList<>(this); + List list = new ArrayList<>(size()); + for (var e : this) { + list.add(e); + } return list.toArray(); } @Override public T[] toArray(T[] a) { - int size = size(); - T[] r = a; - if (r.length > size) - r = (T[]) Array.newInstance(a.getClass().getComponentType(), size); - - Iterator itr = iterator(); - int i = 0; - - while (itr.hasNext()) { - r[i++] = (T) itr.next(); - } - - return r; + return new ArrayList<>(this).toArray(a); } @Override @@ -309,25 +299,16 @@ protected Entry adapt(Entry> e) { @Override public Object[] toArray() { - List list = new ArrayList<>(this); + List list = new ArrayList<>(size()); + for (var e : this) { + list.add(e); + } return list.toArray(); } @Override public T[] toArray(T[] a) { - int size = size(); - T[] r = a; - if (r.length > size) - r = (T[]) Array.newInstance(a.getClass().getComponentType(), size); - - Iterator> itr = iterator(); - int i = 0; - - while (itr.hasNext()) { - r[i++] = (T) itr.next(); - } - - return r; + return new ArrayList<>(this).toArray(a); } @Override diff --git a/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java b/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java index e6e2b51906f2f..3b6309eef7b02 100644 --- a/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java +++ b/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java @@ -34,6 +34,7 @@ import hudson.model.ItemGroup; import hudson.model.Job; import hudson.model.Queue; +import hudson.model.Result; import hudson.model.Run; import hudson.model.RunMap; import hudson.model.listeners.ItemListener; @@ -44,6 +45,8 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; @@ -265,6 +268,34 @@ public final RunT getNearestOldBuild(int n) { return builds.search(n, AbstractLazyLoadRunMap.Direction.DESC); } + /** + * Suitable for {@link Job#getEstimatedDurationCandidates}. + * @since 2.407 + */ + public List getEstimatedDurationCandidates() { + var loadedBuilds = builds.getLoadedBuilds().values(); // reverse chronological order + List candidates = new ArrayList<>(3); + for (Result threshold : List.of(Result.UNSTABLE, Result.FAILURE)) { + for (RunT build : loadedBuilds) { + if (candidates.contains(build)) { + continue; + } + if (!build.isBuilding()) { + Result result = build.getResult(); + if (result != null && result.isBetterOrEqualTo(threshold)) { + candidates.add(build); + if (candidates.size() == 3) { + LOGGER.fine(() -> "Candidates: " + candidates); + return candidates; + } + } + } + } + } + LOGGER.fine(() -> "Candidates: " + candidates); + return candidates; + } + /** * Suitable for {@link Job#createHistoryWidget}. */ diff --git a/core/src/main/java/jenkins/model/queue/QueueItem.java b/core/src/main/java/jenkins/model/queue/QueueItem.java new file mode 100644 index 0000000000000..7ee696b13e91c --- /dev/null +++ b/core/src/main/java/jenkins/model/queue/QueueItem.java @@ -0,0 +1,78 @@ +package jenkins.model.queue; + +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.model.Cause; +import hudson.model.ModelObject; +import hudson.model.Queue; +import hudson.model.Run; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; + +/** + * Interface used by Jelly views to render a queue item through {@code }. + * @since 2.405 + */ +@Restricted(Beta.class) +public interface QueueItem extends ModelObject { + /** + * @return true if the item is starving for an executor for too long. + */ + boolean isStuck(); + + /** + * @return The underlying {@link Queue.Task} currently in queue. + */ + @NonNull + Queue.Task getTask(); + + /** + * Checks whether a scheduled item may be canceled. + * @return by default, the same as {@link Queue.Task#hasAbortPermission} + */ + default boolean hasCancelPermission() { + return getTask().hasAbortPermission(); + } + + /** + * Unique ID (per controller) that tracks the {@link Queue.Task} as it moves through different stages + * in the queue (each represented by different implementations of {@link QueueItem} and into any subsequent + * {@link Run} instance (see {@link Run#getQueueId()}). + */ + long getId(); + + /** + * Convenience method that returns a read only view of the {@link Cause}s associated with this item in the queue as a single string. + */ + @NonNull + String getCausesDescription(); + + /** + * Gets a human-readable status message describing why it's in the queue. + * May return null if there is no cause of blockage. + */ + @CheckForNull + String getWhy(); + + /** + * Gets a human-readable message about the parameters of this item + */ + @NonNull + String getParams(); + + /** + * Returns a human readable presentation of how long this item is already in the queue. + * E.g. something like '3 minutes 40 seconds' + */ + @NonNull + String getInQueueForString(); + + /** + * @return a display name for this queue item; by default, {@link Queue.Task#getFullDisplayName()} + */ + @CheckForNull + @Override + default String getDisplayName() { + return getTask().getFullDisplayName(); + } +} diff --git a/core/src/main/java/jenkins/monitor/OperatingSystemEndOfLifeAdminMonitor.java b/core/src/main/java/jenkins/monitor/OperatingSystemEndOfLifeAdminMonitor.java new file mode 100644 index 0000000000000..df93685debcd8 --- /dev/null +++ b/core/src/main/java/jenkins/monitor/OperatingSystemEndOfLifeAdminMonitor.java @@ -0,0 +1,292 @@ +/* + * The MIT License + * + * Copyright 2023 Mark Waite. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.monitor; + +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.Extension; +import hudson.model.AdministrativeMonitor; +import hudson.security.Permission; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import jenkins.model.Jenkins; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.apache.commons.io.IOUtils; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.HttpRedirect; +import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.HttpResponses; +import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.interceptor.RequirePOST; + +@Extension +@Restricted(NoExternalUse.class) +@Symbol("operatingSystemEndOfLife") +public class OperatingSystemEndOfLifeAdminMonitor extends AdministrativeMonitor { + + static final Logger LOGGER = Logger.getLogger(OperatingSystemEndOfLifeAdminMonitor.class.getName()); + + /** + * Allow tests to disable the end of life monitor without a JenkinsRule. + */ + boolean ignoreEndOfLife = false; + + private LocalDate warningsStartDate = LocalDate.now().plusYears(10); + private boolean afterEndOfLifeDate = false; + private String operatingSystemName = System.getProperty("os.name", "Unknown"); + private String endOfLifeDate = "2099-12-31"; + private String documentationUrl = "https://www.jenkins.io/redirect/operating-system-end-of-life"; + + /* Remember the last dataFile to avoid reading it again */ + private File lastDataFile = null; + /* Remember the lines of the last dataFile */ + private List lastLines = null; + + public OperatingSystemEndOfLifeAdminMonitor(String id) throws IOException { + super(id); + fillOperatingSystemList(); + } + + public OperatingSystemEndOfLifeAdminMonitor() throws IOException { + fillOperatingSystemList(); + } + + private void fillOperatingSystemList() throws IOException { + if (Jenkins.getInstanceOrNull() != null && !isEnabled()) { + /* If not enabled, do not read the data files or perform any checks */ + LOGGER.log(Level.FINEST, "Operating system end of life monitor is not enabled, reading no data"); + return; + } + ClassLoader cl = getClass().getClassLoader(); + URL localOperatingSystemData = cl.getResource("jenkins/monitor/OperatingSystemEndOfLifeAdminMonitor/end-of-life-data.json"); + String initialOperatingSystemJson = IOUtils.toString(localOperatingSystemData.openStream(), StandardCharsets.UTF_8); + readOperatingSystemList(initialOperatingSystemJson); + } + + /* Package protected for testing */ + void readOperatingSystemList(String initialOperatingSystemJson) throws IOException { + JSONArray systems = JSONArray.fromObject(initialOperatingSystemJson); + if (systems.isEmpty()) { + throw new IOException("Empty data set"); + } + for (Object systemObj : systems) { + if (!(systemObj instanceof JSONObject)) { + throw new IOException("Wrong object type in data file"); + } + JSONObject system = (JSONObject) systemObj; + + if (!system.has("pattern")) { + throw new IOException("Missing pattern in definition file"); + } + String pattern = system.getString("pattern"); + + if (!system.has("endOfLife")) { + throw new IOException("No end of life date for " + pattern); + } + LocalDate endOfLife = LocalDate.parse(system.getString("endOfLife")); + + /* Start date defaults to 6 months before end of life */ + LocalDate startDate = system.has("start") ? LocalDate.parse(system.getString("start")) : endOfLife.minusMonths(6); + + File dataFile = getDataFile(system); + + LOGGER.log(Level.FINEST, "Pattern {0} starts {1} and reaches end of life {2} from file {3}", + new Object[]{pattern, startDate, endOfLife, dataFile}); + + String name = readOperatingSystemName(dataFile, pattern); + if (name.isEmpty()) { + LOGGER.log(Level.FINE, "Pattern {0} did not match from file {1}", + new Object[]{pattern, dataFile}); + continue; + } + + if (startDate.isBefore(warningsStartDate)) { + warningsStartDate = startDate; + LOGGER.log(Level.FINE, "Warnings start date is now {0}", warningsStartDate); + } + + LOGGER.log(Level.FINE, "Matched operating system {0}", name); + if (startDate.isBefore(LocalDate.now())) { + this.operatingSystemName = name; + this.documentationUrl = buildDocumentationUrl(this.operatingSystemName); + this.endOfLifeDate = endOfLife.toString(); + if (endOfLife.isBefore(LocalDate.now())) { + LOGGER.log(Level.FINE, "Operating system {0} is after end of life {1}", + new Object[]{name, endOfLife}); + afterEndOfLifeDate = true; + } else { + LOGGER.log(Level.FINE, "Operating system {0} started warnings {1} and reaches end of life {2}", + new Object[]{name, startDate, endOfLife}); + } + } + } + if (lastLines != null) { + // Discard the cached contents of the last read file + lastLines.clear(); + } + } + + @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", + justification = "File path defined in war file, not by user") + @CheckForNull + private File getDataFile(@NonNull JSONObject system) { + /* dataFile defaults to /etc/os-release */ + String fileName = "/etc/os-release"; + if (system.has("file")) { + fileName = system.getString("file"); + } + File dataFile = new File(fileName); + return dataFile; + } + + /* Package protected for testing */ + @NonNull + String readOperatingSystemName(File dataFile, @NonNull String patternStr) { + if (dataFile == null || !dataFile.exists()) { + return ""; + } + Pattern pattern = Pattern.compile("^PRETTY_NAME=[\"](" + patternStr + ".*)[\"]"); + String name = ""; + try { + List lines = dataFile.equals(lastDataFile) ? lastLines : Files.readAllLines(dataFile.toPath()); + for (String line : lines) { + Matcher matcher = pattern.matcher(line); + if (matcher.matches()) { + name = matcher.group(1); + } + } + if (!dataFile.equals(lastDataFile)) { + lastDataFile = dataFile; + lastLines = new ArrayList<>(lines); + } + } catch (IOException ioe) { + LOGGER.log(Level.SEVERE, "File read exception", ioe); + } + return name; + } + + @NonNull + public String getOperatingSystemName() { + return operatingSystemName; + } + + @NonNull + public String getEndOfLifeDate() { + return endOfLifeDate; + } + + public boolean getAfterEndOfLifeDate() { + return afterEndOfLifeDate; + } + + @NonNull + public String getDocumentationUrl() { + return documentationUrl; + } + + /* Package protected for tests */ + @NonNull + String readDocumentationUrl(File dataFile, @NonNull String patternStr) { + if (dataFile == null || !dataFile.exists()) { + return ""; + } + String operatingSystemName = readOperatingSystemName(dataFile, patternStr); + return buildDocumentationUrl(operatingSystemName); + } + + private String buildDocumentationUrl(String operatingSystemName) { + String scheme = "https"; + String hostName = "www.jenkins.io"; + String path = "/redirect/operating-system-end-of-life"; + String query = "q=" + operatingSystemName.replace(" ", "-").replace("/", "-").replace("(", "").replace(")", ""); + + String url = documentationUrl; + try { + URI documentationURI = new URI(scheme, hostName, path, query, null); + url = documentationURI.toString(); + } catch (URISyntaxException e) { + url = scheme + "://" + hostName + path; + } + return url; + } + + /* + * Send user to the right place depending on "yes" or "no". + */ + @Restricted(DoNotUse.class) // WebOnly + @RequirePOST + public HttpResponse doAct(@QueryParameter String no) throws IOException { + if (no != null) { // dismiss + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + disable(true); + LOGGER.log(Level.FINE, "Disabled operating system end of life monitor"); + return HttpResponses.forwardToPreviousPage(); + } else { + LOGGER.log(Level.FINE, "Enabled operating system end of life monitor"); + return new HttpRedirect(documentationUrl); + } + } + + @Override + public boolean isActivated() { + if (ignoreEndOfLife) { + LOGGER.log(Level.FINE, "Not activated because ignoring end of life monitor"); + return false; + } + if (LocalDate.now().isBefore(warningsStartDate)) { + LOGGER.log(Level.FINE, "Not activated because it is before the start date {0}", warningsStartDate); + return false; + } + LOGGER.log(Level.FINEST, "Activated because it is after the warnings start date {0}", warningsStartDate); + return true; + } + + @Override + public Permission getRequiredPermission() { + return Jenkins.SYSTEM_READ; + } + + @Override + public String getDisplayName() { + return "Operating system end of life monitor"; + } +} diff --git a/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java b/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java index efd9eecffdf71..b1d3a42e9f5c2 100644 --- a/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java +++ b/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java @@ -2049,11 +2049,11 @@ private String chompLeadingDot(String str) { * @since 1.5.1 made public and added read-only array references */ public enum ArrayType { - /** Update (or get a copy of) the GENERIC_TLDS_PLUS table containing additonal generic TLDs */ + /** Update (or get a copy of) the GENERIC_TLDS_PLUS table containing additional generic TLDs */ GENERIC_PLUS, /** Update (or get a copy of) the GENERIC_TLDS_MINUS table containing deleted generic TLDs */ GENERIC_MINUS, - /** Update (or get a copy of) the COUNTRY_CODE_TLDS_PLUS table containing additonal country code TLDs */ + /** Update (or get a copy of) the COUNTRY_CODE_TLDS_PLUS table containing additional country code TLDs */ COUNTRY_CODE_PLUS, /** Update (or get a copy of) the COUNTRY_CODE_TLDS_MINUS table containing deleted country code TLDs */ COUNTRY_CODE_MINUS, diff --git a/core/src/main/java/jenkins/security/ConfidentialStore.java b/core/src/main/java/jenkins/security/ConfidentialStore.java index a0d4ce6b9e6fd..61b279a4a43d5 100644 --- a/core/src/main/java/jenkins/security/ConfidentialStore.java +++ b/core/src/main/java/jenkins/security/ConfidentialStore.java @@ -68,8 +68,6 @@ public abstract class ConfidentialStore { * Retrieves the currently active singleton instance of {@link ConfidentialStore}. */ public static @NonNull ConfidentialStore get() { - if (TEST != null) return TEST.get(); - Jenkins j = Jenkins.getInstanceOrNull(); if (j == null) { return Mock.INSTANCE; @@ -100,12 +98,6 @@ public abstract class ConfidentialStore { return cs; } - /** - * @deprecated No longer needed. - */ - @Deprecated - /*package*/ static ThreadLocal TEST = null; - static final class Mock extends ConfidentialStore { static final Mock INSTANCE = new Mock(); diff --git a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java index aff89bc1e456c..9c97c9ae3bbc1 100644 --- a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java +++ b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java @@ -19,7 +19,6 @@ import javax.crypto.CipherOutputStream; import javax.crypto.SecretKey; import jenkins.model.Jenkins; -import org.apache.commons.io.IOUtils; /** * Default portable implementation of {@link ConfidentialStore} that uses @@ -104,7 +103,7 @@ protected byte[] load(ConfidentialKey key) throws IOException { sym.init(Cipher.DECRYPT_MODE, masterKey); try (InputStream fis = Files.newInputStream(f.toPath()); CipherInputStream cis = new CipherInputStream(fis, sym)) { - byte[] bytes = IOUtils.toByteArray(cis); + byte[] bytes = cis.readAllBytes(); return verifyMagic(bytes); } } catch (GeneralSecurityException e) { diff --git a/core/src/main/java/jenkins/security/ResourceDomainFilter.java b/core/src/main/java/jenkins/security/ResourceDomainFilter.java index e5669c893c0e8..eda15fe3e7c94 100644 --- a/core/src/main/java/jenkins/security/ResourceDomainFilter.java +++ b/core/src/main/java/jenkins/security/ResourceDomainFilter.java @@ -24,22 +24,16 @@ package jenkins.security; -import hudson.init.InitMilestone; -import hudson.init.Initializer; -import hudson.util.PluginServletFilter; +import hudson.Extension; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.logging.Logger; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import jenkins.util.HttpServletFilter; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -49,45 +43,27 @@ * * @since 2.200 */ +@Extension @Restricted(NoExternalUse.class) -public class ResourceDomainFilter implements Filter { +public class ResourceDomainFilter implements HttpServletFilter { private static final Logger LOGGER = Logger.getLogger(ResourceDomainFilter.class.getName()); private static final Set ALLOWED_PATHS = new HashSet<>(Arrays.asList("/" + ResourceDomainRootAction.URL, "/favicon.ico", "/favicon.svg", "/robots.txt")); public static final String ERROR_RESPONSE = "Jenkins serves only static files on this domain."; - @Initializer(after = InitMilestone.EXTENSIONS_AUGMENTED) - public static void init() throws ServletException { - PluginServletFilter.addFilter(new ResourceDomainFilter()); - } - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - if (servletRequest instanceof HttpServletRequest) { - HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; - HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; - if (ResourceDomainConfiguration.isResourceRequest(httpServletRequest)) { - String path = httpServletRequest.getPathInfo(); - if (!path.startsWith("/" + ResourceDomainRootAction.URL + "/") && !ALLOWED_PATHS.contains(path)) { - LOGGER.fine(() -> "Rejecting request to " + httpServletRequest.getRequestURL() + " from " + httpServletRequest.getRemoteAddr() + " on resource domain"); - httpServletResponse.sendError(404, ERROR_RESPONSE); - return; - } - LOGGER.finer(() -> "Accepting request to " + httpServletRequest.getRequestURL() + " from " + httpServletRequest.getRemoteAddr() + " on resource domain"); + public boolean handle(HttpServletRequest req, HttpServletResponse rsp) throws IOException, ServletException { + if (ResourceDomainConfiguration.isResourceRequest(req)) { + String path = req.getPathInfo(); + if (!path.startsWith("/" + ResourceDomainRootAction.URL + "/") && !ALLOWED_PATHS.contains(path)) { + LOGGER.fine(() -> "Rejecting request to " + req.getRequestURL() + " from " + req.getRemoteAddr() + " on resource domain"); + rsp.sendError(404, ERROR_RESPONSE); + return true; } + LOGGER.finer(() -> "Accepting request to " + req.getRequestURL() + " from " + req.getRemoteAddr() + " on resource domain"); } - filterChain.doFilter(servletRequest, servletResponse); + return false; } - @Override - public void init(FilterConfig filterConfig) throws ServletException { - - } - - @Override - public void destroy() { - - } } diff --git a/core/src/main/java/jenkins/security/seed/UserSeedChangeListener.java b/core/src/main/java/jenkins/security/seed/UserSeedChangeListener.java index 417aee07650fc..02753addb79d9 100644 --- a/core/src/main/java/jenkins/security/seed/UserSeedChangeListener.java +++ b/core/src/main/java/jenkins/security/seed/UserSeedChangeListener.java @@ -32,14 +32,11 @@ import java.util.logging.Logger; import jenkins.security.SecurityListener; import jenkins.util.Listeners; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Listener notified when a user was requested to changed their seed + * @since 2.160 and 2.150.2, but restricted (unavailable to plugins) before TODO */ -//TODO remove restriction on the weekly after the security fix -@Restricted(NoExternalUse.class) public abstract class UserSeedChangeListener implements ExtensionPoint { private static final Logger LOGGER = Logger.getLogger(SecurityListener.class.getName()); diff --git a/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java b/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java index 3b99f708abfa8..8bf24d1b01a9d 100644 --- a/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java +++ b/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java @@ -26,25 +26,18 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; -import hudson.init.InitMilestone; -import hudson.init.Initializer; -import hudson.util.PluginServletFilter; import java.io.IOException; import java.time.LocalDate; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import jenkins.telemetry.Telemetry; +import jenkins.util.HttpServletFilter; import net.sf.json.JSONObject; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -95,30 +88,13 @@ public JSONObject createContent() { return payload; } - @Initializer(after = InitMilestone.EXTENSIONS_AUGMENTED) - public static void setUpFilter() { - Filter filter = new AcceptLanguageFilter(); - if (!PluginServletFilter.hasFilter(filter)) { - try { - PluginServletFilter.addFilter(filter); - } catch (ServletException ex) { - LOGGER.log(Level.WARNING, "Failed to set up languages servlet filter", ex); - } - } - } - - public static final class AcceptLanguageFilter implements Filter { + @Extension + public static final class AcceptLanguageFilter implements HttpServletFilter { @Override - public void init(FilterConfig filterConfig) { - - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - if (request instanceof HttpServletRequest && !Telemetry.isDisabled()) { - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - String language = httpServletRequest.getHeader("Accept-Language"); + public boolean handle(HttpServletRequest req, HttpServletResponse rsp) throws IOException, ServletException { + if (!Telemetry.isDisabled()) { + String language = req.getHeader("Accept-Language"); if (language != null) { if (!requestsByLanguage.containsKey(language)) { requestsByLanguage.put(language, new AtomicLong(0)); @@ -126,23 +102,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha requestsByLanguage.get(language).incrementAndGet(); } } - chain.doFilter(request, response); + return false; } - @Override - public void destroy() { - - } - - @Override - public boolean equals(Object obj) { // support PluginServletFilter#hasFilter - return obj != null && obj.getClass() == AcceptLanguageFilter.class; - } - - // findbugs - @Override - public int hashCode() { - return 42; - } } } diff --git a/core/src/main/java/jenkins/util/AntClassLoader.java b/core/src/main/java/jenkins/util/AntClassLoader.java deleted file mode 100644 index 1b2685f98446f..0000000000000 --- a/core/src/main/java/jenkins/util/AntClassLoader.java +++ /dev/null @@ -1,73 +0,0 @@ -package jenkins.util; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Collection; -import java.util.Enumeration; -import jenkins.ClassLoaderReflectionToolkit; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.types.Path; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; - -/** - * {@link org.apache.tools.ant.AntClassLoader} with loosened visibility for use with {@link - * ClassLoaderReflectionToolkit}. - * - * @deprecated use {@link URLClassLoader2} - */ -@Deprecated -@Restricted(NoExternalUse.class) -public class AntClassLoader extends org.apache.tools.ant.AntClassLoader implements JenkinsClassLoader { - - public AntClassLoader(final ClassLoader parent, final Project project, final Path classpath) { - super(parent, project, classpath); - } - - public AntClassLoader() {} - - public AntClassLoader(final Project project, final Path classpath) { - super(project, classpath); - } - - public AntClassLoader(final ClassLoader parent, final Project project, - final Path classpath, final boolean parentFirst) { - super(parent, project, classpath, parentFirst); - } - - public AntClassLoader(final Project project, final Path classpath, - final boolean parentFirst) { - super(project, classpath, parentFirst); - } - - public AntClassLoader(final ClassLoader parent, final boolean parentFirst) { - super(parent, parentFirst); - } - - public void addPathFiles(Collection paths) throws IOException { - for (File f : paths) { - addPathFile(f); - } - } - - @Override - public URL findResource(final String name) { - return super.findResource(name); - } - - @Override - public Enumeration findResources(final String name) throws IOException { - return super.findResources(name); - } - - @Override - public Class findLoadedClass2(String name) { - return super.findLoadedClass(name); - } - - @Override - public Object getClassLoadingLock(String className) { - return super.getClassLoadingLock(className); - } -} diff --git a/core/src/main/java/jenkins/util/HttpServletFilter.java b/core/src/main/java/jenkins/util/HttpServletFilter.java new file mode 100644 index 0000000000000..b83b37d1174de --- /dev/null +++ b/core/src/main/java/jenkins/util/HttpServletFilter.java @@ -0,0 +1,89 @@ +/* + * The MIT License + * + * Copyright 2023 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.util; + +import hudson.ExtensionList; +import hudson.ExtensionPoint; +import hudson.init.Initializer; +import hudson.security.csrf.CrumbExclusion; +import hudson.util.PluginServletFilter; +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; + +/** + * More convenient and declarative way to use {@link PluginServletFilter}. + * Register an implementation if you wish to intercept certain HTTP requests. + * Typical implementations will inspect {@link HttpServletRequest#getPathInfo} to determine if they should be active. + * @since 2.406 + * @see CrumbExclusion + */ +public interface HttpServletFilter extends ExtensionPoint { + + /** + * Potentially intercepts or otherwise modifies an HTTP request. + * @param req as in {@link Filter#doFilter} + * @param rsp as in {@link Filter#doFilter} + * @return true if this request was handled; false to proceed with other handlers ({@link FilterChain}) + * @throws IOException as in {@link Filter#doFilter} + * @throws ServletException as in {@link Filter#doFilter} + */ + boolean handle(HttpServletRequest req, HttpServletResponse rsp) throws IOException, ServletException; + + @Restricted(DoNotUse.class) + @Initializer + static void register() throws ServletException { + PluginServletFilter.addFilter(new Filter() { + @Override + public void doFilter(ServletRequest req, ServletResponse rsp, FilterChain chain) throws IOException, ServletException { + if (req instanceof HttpServletRequest && rsp instanceof HttpServletResponse) { + for (HttpServletFilter filter : ExtensionList.lookup(HttpServletFilter.class)) { + if (filter.handle((HttpServletRequest) req, (HttpServletResponse) rsp)) { + return; + } + } + } + chain.doFilter(req, rsp); + } + + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void destroy() { + } + }); + } + +} diff --git a/core/src/main/java/jenkins/util/JSONSignatureValidator.java b/core/src/main/java/jenkins/util/JSONSignatureValidator.java index 955c89168a1c3..3cc10ebd40385 100644 --- a/core/src/main/java/jenkins/util/JSONSignatureValidator.java +++ b/core/src/main/java/jenkins/util/JSONSignatureValidator.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -34,7 +35,6 @@ import net.sf.json.JSONObject; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; -import org.apache.commons.io.output.NullOutputStream; import org.apache.commons.io.output.TeeOutputStream; import org.jvnet.hudson.crypto.CertificateUtil; import org.jvnet.hudson.crypto.SignatureOutputStream; @@ -159,7 +159,8 @@ public FormValidation verifySignature(JSONObject o) throws IOException { */ private FormValidation checkSpecificSignature(JSONObject json, JSONObject signatureJson, MessageDigest digest, String digestEntry, Signature signature, String signatureEntry, String digestName) throws IOException { // this is for computing a digest to check sanity - DigestOutputStream dos = new DigestOutputStream(NullOutputStream.NULL_OUTPUT_STREAM, digest); + OutputStream nos = OutputStream.nullOutputStream(); + DigestOutputStream dos = new DigestOutputStream(nos, digest); SignatureOutputStream sos = new SignatureOutputStream(signature); String providedDigest = signatureJson.optString(digestEntry, null); diff --git a/core/src/main/java/jenkins/websocket/WebSocketSession.java b/core/src/main/java/jenkins/websocket/WebSocketSession.java index 43c4bba482e6a..0160985b7b02a 100644 --- a/core/src/main/java/jenkins/websocket/WebSocketSession.java +++ b/core/src/main/java/jenkins/websocket/WebSocketSession.java @@ -69,7 +69,8 @@ void startPings() { if (PING_INTERVAL_SECONDS != 0) { pings = Timer.get().scheduleAtFixedRate(() -> { try { - handler.sendPing(ByteBuffer.wrap(new byte[0])); + Future f = handler.sendPing(ByteBuffer.wrap(new byte[0])); + // TODO do something interesting with the future } catch (Exception x) { error(x); pings.cancel(true); diff --git a/core/src/main/java/jenkins/widgets/BuildQueueWidget.java b/core/src/main/java/jenkins/widgets/BuildQueueWidget.java index c55c221578f5b..44aca9afaf83a 100644 --- a/core/src/main/java/jenkins/widgets/BuildQueueWidget.java +++ b/core/src/main/java/jenkins/widgets/BuildQueueWidget.java @@ -1,8 +1,39 @@ +/* + * The MIT License + * + * Copyright 2023, CloudBees Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package jenkins.widgets; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; +import hudson.model.ComputerSet; +import hudson.model.View; import hudson.widgets.Widget; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import jenkins.model.Jenkins; +import jenkins.model.queue.QueueItem; import org.jenkinsci.Symbol; /** @@ -13,7 +44,75 @@ * @author Kohsuke Kawaguchi * @since 1.514 */ -@Extension(ordinal = 200) @Symbol("buildQueue") // historically this was the top most widget public class BuildQueueWidget extends Widget { + @NonNull + private String ownerUrl; + @NonNull + private List queueItems; + + private boolean filtered; + + public BuildQueueWidget(@NonNull String ownerUrl, @NonNull List queueItems) { + this(ownerUrl, queueItems, false); + } + + public BuildQueueWidget(@NonNull String ownerUrl, @NonNull List queueItems, boolean filtered) { + this.ownerUrl = ownerUrl; + this.queueItems = new ArrayList<>(queueItems); + this.filtered = filtered; + } + + @Override + public String getOwnerUrl() { + return ownerUrl; + } + + @NonNull + @SuppressWarnings("unused") // stapler + public List getQueueItems() { + return queueItems; + } + + @SuppressWarnings("unused") // stapler + public boolean isFiltered() { + return filtered; + } + + @Extension(ordinal = 200) @Symbol("buildQueueView") // historically this was the top most widget + public static final class ViewFactoryImpl extends WidgetFactory { + @Override + public Class type() { + return View.class; + } + + @Override + public Class widgetType() { + return BuildQueueWidget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull View target) { + return List.of(new BuildQueueWidget(target.getUrl(), new ArrayList<>(target.getQueueItems()), target.isFilterQueue())); + } + } + + @Extension(ordinal = 200) @Symbol("buildQueueComputer") // historically this was the top most widget + public static final class ComputerSetFactoryImpl extends WidgetFactory { + @Override + public Class type() { + return ComputerSet.class; + } + + @Override + public Class widgetType() { + return BuildQueueWidget.class; + } + @NonNull + @Override + public Collection createFor(@NonNull ComputerSet target) { + return List.of(new BuildQueueWidget("computer/", List.of(Jenkins.get().getQueue().getItems()))); + } + } } diff --git a/core/src/main/java/jenkins/widgets/ExecutorsWidget.java b/core/src/main/java/jenkins/widgets/ExecutorsWidget.java index 235c1844761c4..c660d4e039114 100644 --- a/core/src/main/java/jenkins/widgets/ExecutorsWidget.java +++ b/core/src/main/java/jenkins/widgets/ExecutorsWidget.java @@ -1,7 +1,15 @@ package jenkins.widgets; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; +import hudson.model.Computer; +import hudson.model.ComputerSet; +import hudson.model.View; import hudson.widgets.Widget; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import jenkins.model.Jenkins; import org.jenkinsci.Symbol; @@ -13,6 +21,78 @@ * @author Kohsuke Kawaguchi * @since 1.514 */ -@Extension(ordinal = 100) @Symbol("executors") // historically this was above normal widgets and below BuildQueueWidget public class ExecutorsWidget extends Widget { + private final String ownerUrl; + private final List computers; + + public ExecutorsWidget(@NonNull String ownerUrl, @NonNull List computers) { + this.ownerUrl = ownerUrl; + this.computers = new ArrayList<>(computers); + } + + @Override + protected String getOwnerUrl() { + return ownerUrl; + } + + public List getComputers() { + return Collections.unmodifiableList(computers); + } + + @Extension(ordinal = 100) @Symbol("executors") // historically this was above normal widgets and below BuildQueueWidget + public static final class ViewFactoryImpl extends WidgetFactory { + @Override + public Class type() { + return View.class; + } + + @Override + public Class widgetType() { + return ExecutorsWidget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull View target) { + return List.of(new ExecutorsWidget(target.getUrl(), target.getComputers())); + } + } + + @Extension(ordinal = 100) @Symbol("executorsComputer") // historically this was above normal widgets and below BuildQueueWidget + public static final class ComputerFactoryImpl extends WidgetFactory { + @Override + public Class type() { + return Computer.class; + } + + @Override + public Class widgetType() { + return ExecutorsWidget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull Computer target) { + return List.of(new ExecutorsWidget(target.getUrl(), List.of(target))); + } + } + + @Extension(ordinal = 100) @Symbol("executorsComputerSet") // historically this was above normal widgets and below BuildQueueWidget + public static final class ComputerSetFactoryImpl extends WidgetFactory { + @Override + public Class type() { + return ComputerSet.class; + } + + @Override + public Class widgetType() { + return ExecutorsWidget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull ComputerSet target) { + return List.of(new ExecutorsWidget("computer/", List.of(target.get_all()))); + } + } } diff --git a/core/src/main/java/jenkins/widgets/HasWidgets.java b/core/src/main/java/jenkins/widgets/HasWidgets.java new file mode 100644 index 0000000000000..5fcb35416b323 --- /dev/null +++ b/core/src/main/java/jenkins/widgets/HasWidgets.java @@ -0,0 +1,85 @@ +/* + * The MIT License + * + * Copyright 2023, CloudBees Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.widgets; + +import edu.umd.cs.findbugs.annotations.CheckForNull; +import hudson.widgets.Widget; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import jenkins.security.stapler.StaplerAccessibleType; +import jenkins.security.stapler.StaplerDispatchable; + +/** + * Classes implementing this interface can have widgets, and they can be accessed using relative urls "widget/widgetName" + * @since 2.410 + */ +@StaplerAccessibleType +public interface HasWidgets { + Logger LOGGER = Logger.getLogger(HasWidgets.class.getName()); + + /** + * @return the list of widgets attached to the object. + */ + default List getWidgets() { + List result = new ArrayList<>(); + WidgetFactory + .factoriesFor(getClass(), Widget.class) + .forEach(wf -> { + try { + Collection wfResult = wf.createFor(wf.type().cast(this)); + for (Widget w : wfResult) { + if (wf.widgetType().isInstance(w)) { + result.add(w); + } else { + LOGGER.log(Level.WARNING, "Widget from {0} for {1} included {2} not assignable to {3}", new Object[] {wf, this, w, wf.widgetType()}); + } + } + } catch (RuntimeException e) { + LOGGER.log(Level.WARNING, "Could not load all widgets from " + wf + " for " + this, e); + } + }); + return Collections.unmodifiableList(result); + } + + /** + * Returns the named widget, or null if it does not exist. + * Defaults to iterating on widgets and filtering based on the defined urlName. + * + * @param name the name of the widget within the current context. + * @return the named widget, or null if it does not exist. + */ + @CheckForNull + @StaplerDispatchable + default Widget getWidget(String name) { + if (name == null) { + return null; + } + return getWidgets().stream().filter(w -> name.equals(w.getUrlName())).findFirst().orElse(null); + } +} diff --git a/core/src/main/java/jenkins/widgets/HistoryPageEntry.java b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java index 5028fbcf0a146..ac5e0a772692e 100644 --- a/core/src/main/java/jenkins/widgets/HistoryPageEntry.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java @@ -25,14 +25,14 @@ package jenkins.widgets; import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.model.Queue; import hudson.model.Run; +import jenkins.model.queue.QueueItem; /** * Represents an entry used by the {@link HistoryPageFilter}. * *

    - * Wraps {@link Queue.Item} and {@link Run} instances from the build queue, normalizing + * Wraps {@link QueueItem} and {@link Run} instances from the build queue, normalizing * access to the info required for pagination. * * @@ -55,8 +55,8 @@ public long getEntryId() { } protected static long getEntryId(@NonNull Object entry) { - if (entry instanceof Queue.Item) { - return ((Queue.Item) entry).getId(); + if (entry instanceof QueueItem) { + return ((QueueItem) entry).getId(); } else if (entry instanceof Run) { Run run = (Run) entry; return Long.MIN_VALUE + run.getNumber(); diff --git a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java index d289db70a746e..adc09b12f22db 100644 --- a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java @@ -42,6 +42,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import jenkins.model.queue.QueueItem; /** * History page filter. @@ -55,9 +56,9 @@ public class HistoryPageFilter { private Long olderThan; private String searchString; - // Need to use different Lists for Queue.Items and Runs because + // Need to use different Lists for QueueItem and Runs because // we need access to them separately in the jelly files for rendering. - public final List> queueItems = new ArrayList<>(); + public final List> queueItems = new ArrayList<>(); public final List> runs = new ArrayList<>(); @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "read by Stapler") @@ -128,7 +129,7 @@ public void add(@NonNull Iterable runItems) { * @param queueItems The queue items to be added. Queue items do not need to be sorted. * @since 2.17 */ - public void add(@NonNull Iterable runItems, @NonNull List queueItems) { + public void add(@NonNull Iterable runItems, @NonNull List queueItems) { sort(queueItems); addInternal(Iterables.concat(queueItems, runItems)); } @@ -136,7 +137,7 @@ public void add(@NonNull Iterable runItems, @NonNull List queueIt /** * Add items to the History page, internal implementation. * @param items The items to be added. - * @param The type of items should either be T or Queue.Item. + * @param The type of items should either be T or {@link QueueItem}. */ private void addInternal(@NonNull Iterable items) { // Note that items can be a large lazily evaluated collection, @@ -240,8 +241,8 @@ public int compare(Object o1, Object o2) { } private long getNextBuildNumber(@NonNull Object entry) { - if (entry instanceof Queue.Item) { - Queue.Task task = ((Queue.Item) entry).task; + if (entry instanceof QueueItem) { + Queue.Task task = ((QueueItem) entry).getTask(); if (task instanceof Job) { return ((Job) task).getNextBuildNumber(); } @@ -253,8 +254,8 @@ private long getNextBuildNumber(@NonNull Object entry) { return HistoryPageEntry.getEntryId(entry) + 1; } - private void addQueueItem(Queue.Item item) { - HistoryPageEntry entry = new HistoryPageEntry<>(item); + private void addQueueItem(QueueItem item) { + HistoryPageEntry entry = new HistoryPageEntry<>(item); queueItems.add(entry); updateNewestOldest(entry.getEntryId()); } @@ -279,8 +280,8 @@ private void updateNewestOldest(long entryId) { private boolean add(Object entry) { // Purposely not calling isFull(). May need to add a greater number of entries // to the page initially, newerThan then cutting it back down to size using cutLeading() - if (entry instanceof Queue.Item) { - Queue.Item item = (Queue.Item) entry; + if (entry instanceof QueueItem) { + QueueItem item = (QueueItem) entry; if (searchString != null && !fitsSearchParams(item)) { return false; } @@ -310,7 +311,7 @@ private int getFillCount() { return Math.max(0, maxEntries - size()); } - private boolean fitsSearchParams(@NonNull Queue.Item item) { + private boolean fitsSearchParams(@NonNull QueueItem item) { if (fitsSearchString(item.getDisplayName())) { return true; } else if (fitsSearchString(item.getId())) { diff --git a/core/src/main/java/jenkins/widgets/JenkinsWidgetFactory.java b/core/src/main/java/jenkins/widgets/JenkinsWidgetFactory.java new file mode 100644 index 0000000000000..d4c1441147b9a --- /dev/null +++ b/core/src/main/java/jenkins/widgets/JenkinsWidgetFactory.java @@ -0,0 +1,62 @@ +/* + * The MIT License + * + * Copyright 2023, CloudBees Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.widgets; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.View; +import hudson.widgets.Widget; +import java.util.Collection; +import jenkins.model.Jenkins; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; + +/** + * Add widgets annotated with @Extension, or added manually to Jenkins via Jenkins.get().getWidgets().add(...) + * + * @deprecated New widgets should provide a {@link WidgetFactory} instead of relying on this legacy lookup. + */ +@Extension +@Restricted(DoNotUse.class) +@Deprecated +@Symbol("jenkins") +public final class JenkinsWidgetFactory extends WidgetFactory { + @Override + public Class type() { + return View.class; + } + + @Override + public Class widgetType() { + return Widget.class; + } + + @NonNull + @Override + public Collection createFor(@NonNull View target) { + return Jenkins.get().getWidgets(); + } +} diff --git a/core/src/main/java/jenkins/widgets/WidgetFactory.java b/core/src/main/java/jenkins/widgets/WidgetFactory.java new file mode 100644 index 0000000000000..35039c0655c2c --- /dev/null +++ b/core/src/main/java/jenkins/widgets/WidgetFactory.java @@ -0,0 +1,82 @@ +/* + * The MIT License + * + * Copyright 2023, CloudBees Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.widgets; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.ExtensionList; +import hudson.ExtensionPoint; +import hudson.widgets.Widget; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +/** + * Allows you to add new widgets to various kind of objects whose class implements {@link HasWidgets}. + * @param The type of object to add widgets to. + * @param The subtype of {@link Widget} the factory contributes. + * @since 2.410 + */ +public abstract class WidgetFactory implements ExtensionPoint { + /** + * The type of object this factory cares about. + * Declared separately, rather than by having {@link #createFor} do a check-cast, + * so that method bodies are not loaded until actually needed. + * @return the type of {@link T} + */ + public abstract Class type(); + + /** + * A supertype of any widgets this factory might produce. + * Defined so that factories which produce irrelevant widgets need not be consulted. + * If your implementation was returning multiple disparate kinds of widgets, it is best to split it into two factories. + *

    If an API defines an abstract {@link Widget} subtype, and you are providing a concrete implementation, + * you may return the API type here to delay class loading. + * @return a bound for the result of {@link #createFor} + */ + public abstract Class widgetType(); + + /** + * Creates widgets for a given object. + * This may be called frequently for the same object, so if your implementation is expensive, do your own caching. + * @param target a widgetable object + * @return a possible empty set of widgets (typically either using {@link Set#of}). + */ + public abstract @NonNull Collection createFor(@NonNull T target); + + @Restricted(NoExternalUse.class) // pending a need for it outside HasWidgets + public static Iterable> factoriesFor(Class type, Class widgetType) { + List> result = new ArrayList<>(); + for (WidgetFactory wf : ExtensionList.lookup(WidgetFactory.class)) { + if (wf.type().isAssignableFrom(type) && widgetType.isAssignableFrom(wf.widgetType())) { + result.add(wf); + } + } + return result; + } + +} diff --git a/core/src/main/java/org/jenkins/ui/icon/IconSet.java b/core/src/main/java/org/jenkins/ui/icon/IconSet.java index e607a696125d5..53dbc74c33802 100644 --- a/core/src/main/java/org/jenkins/ui/icon/IconSet.java +++ b/core/src/main/java/org/jenkins/ui/icon/IconSet.java @@ -530,6 +530,7 @@ private static void initializeSVGs() { translations.put("icon-user", "symbol-people"); translations.put("icon-undo", "symbol-undo"); translations.put("icon-redo", "symbol-redo"); + translations.put("icon-hourglass", "symbol-hourglass"); ICON_TO_SYMBOL_TRANSLATIONS = translations; } diff --git a/core/src/main/resources/META-INF/upgrade/IOUtils.hint b/core/src/main/resources/META-INF/upgrade/IOUtils.hint index bfbaf27a94681..bc995ed09acbe 100644 --- a/core/src/main/resources/META-INF/upgrade/IOUtils.hint +++ b/core/src/main/resources/META-INF/upgrade/IOUtils.hint @@ -1,10 +1,4 @@ -hudson.util.IOUtils.DIR_SEPARATOR_UNIX => org.apache.commons.io.IOUtils.DIR_SEPARATOR_UNIX;; -hudson.util.IOUtils.DIR_SEPARATOR_WINDOWS => org.apache.commons.io.IOUtils.DIR_SEPARATOR_WINDOWS;; -hudson.util.IOUtils.DIR_SEPARATOR => org.apache.commons.io.IOUtils.DIR_SEPARATOR;; -hudson.util.IOUtils.LINE_SEPARATOR_UNIX => org.apache.commons.io.IOUtils.LINE_SEPARATOR_UNIX;; -hudson.util.IOUtils.LINE_SEPARATOR_WINDOWS => org.apache.commons.io.IOUtils.LINE_SEPARATOR_WINDOWS;; -hudson.util.IOUtils.LINE_SEPARATOR => org.apache.commons.io.IOUtils.LINE_SEPARATOR;; hudson.util.IOUtils.closeQuietly($args$) => org.apache.commons.io.IOUtils.closeQuietly($args$);; hudson.util.IOUtils.toByteArray($args$) => org.apache.commons.io.IOUtils.toByteArray($args$);; hudson.util.IOUtils.toCharArray($args$) => org.apache.commons.io.IOUtils.toCharArray($args$);; diff --git a/core/src/main/resources/META-INF/upgrade/README.md b/core/src/main/resources/META-INF/upgrade/README.md new file mode 100644 index 0000000000000..a2797b1bebd5a --- /dev/null +++ b/core/src/main/resources/META-INF/upgrade/README.md @@ -0,0 +1,2 @@ +Contains [Jackpot](https://netbeans.apache.org/jackpot/index.html)-based refactoring rules offered when plugins are open in NetBeans IDE. +Could be [converted to a more general tool](https://github.com/openrewrite/rewrite-jenkins/issues/6). diff --git a/core/src/main/resources/hudson/AboutJenkins/index.jelly b/core/src/main/resources/hudson/AboutJenkins/index.jelly index 5a31c6b9690ed..6d589663f576d 100644 --- a/core/src/main/resources/hudson/AboutJenkins/index.jelly +++ b/core/src/main/resources/hudson/AboutJenkins/index.jelly @@ -79,34 +79,6 @@ THE SOFTWARE. - - - Font Awesome - - - Dave Gandy - - - SIL OFL 1.1 License - and - MIT License - - - - - Google Fonts: - Roboto - - - - Christian Robertson - - - Apache - License, version 2.0 - - - diff --git a/core/src/main/resources/hudson/Messages_fr.properties b/core/src/main/resources/hudson/Messages_fr.properties index 700ecb7b1d226..1c948734def79 100644 --- a/core/src/main/resources/hudson/Messages_fr.properties +++ b/core/src/main/resources/hudson/Messages_fr.properties @@ -20,6 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +AbstractItem.NewNameInUse=Le nom "{0}" est déjà utilisé. +AbstractItem.NewNameUnchanged=Le nouveau nom est identique au nom actuel. + FilePath.did_not_manage_to_validate_may_be_too_sl=Impossible de valider {0} (peut-être est-ce trop lent) FilePath.validateAntFileMask.whitespaceSeprator=\ Les espaces ne peuvent plus être utilisés comme séparateurs. Merci d''utiliser maintenant '','' comme séparateur à la place. diff --git a/core/src/main/resources/hudson/PluginManager/_installed.js b/core/src/main/resources/hudson/PluginManager/_installed.js new file mode 100644 index 0000000000000..e3712b850818b --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/_installed.js @@ -0,0 +1,55 @@ +(function () { + const restartRequired = document + .getElementById("is-restart-required-for-completion") + .getAttribute("data-is-restart-required"); + + document.addEventListener("DOMContentLoaded", function () { + document + .querySelectorAll(".plugin-manager-toggle-switch") + .forEach(function (toggle) { + toggle.addEventListener("click", flip); + }); + }); + + function flip(event) { + let btn = event.target; + + // trigger + fetch( + btn.getAttribute("url") + + "/make" + + (btn.checked ? "Enabled" : "Disabled"), + { + method: "post", + headers: crumb.wrap({}), + }, + ).then((rsp) => { + if (!rsp.ok) { + rsp.text().then((responseText) => { + document.getElementById("needRestart").innerHTML = responseText; + }); + } + updateMsg(); + }); + } + + function updateMsg() { + // has anything changed since its original state? + let e = Array.from( + document + .getElementById("plugins") + .querySelectorAll("input[type='checkbox']"), + ).find(function (e) { + return String(e.checked) !== e.getAttribute("original"); + }); + + if (restartRequired === "true") { + e = true; + } + + document.getElementById("needRestart").style.display = + e != null ? "block" : "none"; + } + + updateMsg(); // set the initial state +})(); diff --git a/core/src/main/resources/hudson/PluginManager/_table.js b/core/src/main/resources/hudson/PluginManager/_table.js index 4ce767a27931e..8174fa1e833dd 100644 --- a/core/src/main/resources/hudson/PluginManager/_table.js +++ b/core/src/main/resources/hudson/PluginManager/_table.js @@ -11,9 +11,9 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { for (var i = 0; i < items.length; i++) { if ( (filterParts.length < 1 || filter.length < 2) && - items[i].hasClassName("hidden-by-default") + items[i].classList.contains("hidden-by-default") ) { - items[i].addClassName("jenkins-hidden"); + items[i].classList.add("jenkins-hidden"); continue; } var makeVisible = true; @@ -41,7 +41,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { } } var instructions = document.getElementById( - "hidden-by-default-instructions" + "hidden-by-default-instructions", ); if (instructions) { instructions.style.display = anyVisible ? "none" : ""; @@ -53,7 +53,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { (function () { var instructionsTd = document.getElementById( - "hidden-by-default-instructions-td" + "hidden-by-default-instructions-td", ); if (instructionsTd) { // only on Available tab @@ -71,9 +71,9 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { (function () { function selectAll(selector, element) { if (element) { - return $(element).select(selector); + return element.querySelectorAll(selector); } else { - return Element.select(undefined, selector); + return document.querySelectorAll(selector); } } function select(selector, element) { @@ -88,7 +88,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { /** * Wait for document onload. */ - Element.observe(window, "load", function () { + window.addEventListener("load", function () { var pluginsTable = select("#plugins"); var pluginTRs = selectAll(".plugin", pluginsTable); @@ -96,11 +96,6 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { return; } - var pluginI18n = select(".plugins.i18n"); - function i18n(messageId) { - return pluginI18n.getAttribute("data-" + messageId); - } - // Create a map of the plugin rows, making it easy to index them. var plugins = {}; for (var i = 0; i < pluginTRs.length; i++) { @@ -129,7 +124,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { var pluginId = span.getAttribute("data-plugin-id"); var pluginName = getPluginName(pluginId); - span.update(pluginName); + span.textContent = pluginName; ids.push(pluginId); } return ids; @@ -145,7 +140,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { // dependent plugins in this case. // Note: This does not cover "implied" dependencies ala detached plugins. See https://goo.gl/lQHrUh if (dependentIds.length === 1 && dependentIds[0] === "jenkins-core") { - pluginTR.addClassName("all-dependents-disabled"); + pluginTR.classList.add("all-dependents-disabled"); return; } @@ -155,7 +150,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { if (dependentId === "jenkins-core") { // Jenkins core is always enabled. So, make sure it's not possible to disable/uninstall // any plugins that it "depends" on. (we sill have bundled plugins) - pluginTR.removeClassName("all-dependents-disabled"); + pluginTR.classList.remove("all-dependents-disabled"); return; } @@ -166,13 +161,13 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { dependentPluginTr.jenkinsPluginMetadata.enableInput.checked ) { // One of the plugins that depend on this plugin, is marked as enabled. - pluginTR.removeClassName("all-dependents-disabled"); + pluginTR.classList.remove("all-dependents-disabled"); return; } } } - pluginTR.addClassName("all-dependents-disabled"); + pluginTR.classList.add("all-dependents-disabled"); } function markHasDisabledDependencies(pluginTR) { @@ -187,21 +182,21 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { !dependencyPluginTr.jenkinsPluginMetadata.enableInput.checked ) { // One of the plugins that this plugin depend on, is marked as disabled. - pluginTR.addClassName("has-disabled-dependency"); + pluginTR.classList.add("has-disabled-dependency"); return; } } } - pluginTR.removeClassName("has-disabled-dependency"); + pluginTR.classList.remove("has-disabled-dependency"); } function setEnableWidgetStates() { for (var i = 0; i < pluginTRs.length; i++) { var pluginMetadata = pluginTRs[i].jenkinsPluginMetadata; - if (pluginTRs[i].hasClassName("has-dependents-but-disabled")) { + if (pluginTRs[i].classList.contains("has-dependents-but-disabled")) { if (pluginMetadata.enableInput.checked) { - pluginTRs[i].removeClassName("has-dependents-but-disabled"); + pluginTRs[i].classList.remove("has-dependents-but-disabled"); } } markAllDependentsDisabled(pluginTRs[i]); @@ -210,18 +205,13 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { } function addDependencyInfoRow(pluginTR, infoTR) { - infoTR.addClassName("plugin-dependency-info"); - pluginTR.insert({ - after: infoTR, - }); + infoTR.classList.add("plugin-dependency-info"); + pluginTR.parentNode.insertBefore(infoTR, pluginTR.nextElementSibling); } function removeDependencyInfoRow(pluginTR) { - var nextRows = pluginTR.nextSiblings(); - if (nextRows && nextRows.length > 0) { - var nextRow = nextRows[0]; - if (nextRow.hasClassName("plugin-dependency-info")) { - nextRow.remove(); - } + var nextRow = pluginTR.nextElementSibling; + if (nextRow && nextRow.classList.contains("plugin-dependency-info")) { + nextRow.remove(); } } @@ -230,19 +220,18 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { // Remove all existing class info infoContainer.removeAttribute("class"); - infoContainer.addClassName("enable-state-info"); + infoContainer.classList.add("enable-state-info"); - if (pluginTR.hasClassName("has-disabled-dependency")) { + if (pluginTR.classList.contains("has-disabled-dependency")) { var dependenciesDiv = pluginMetadata.dependenciesDiv; var dependencySpans = pluginMetadata.dependencies; - infoContainer.update( + infoContainer.innerHTML = '

    " - ); + i18n("cannot-enable") + + '
    ' + + i18n("disabled-dependencies") + + ".
    "; // Go through each dependency element. Show the spans where the dependency is // disabled. Hide the others. @@ -257,20 +246,20 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { } if (enabled) { // It's enabled ... hide the span - dependencySpan.setStyle({ display: "none" }); + dependencySpan.style.display = "none"; } else { // It's disabled ... show the span - dependencySpan.setStyle({ display: "inline-block" }); + dependencySpan.style.display = "inline-block"; } } - dependenciesDiv.setStyle({ display: "inherit" }); + dependenciesDiv.style.display = "inherit"; infoContainer.appendChild(dependenciesDiv); return true; } - if (pluginTR.hasClassName("has-dependents")) { - if (!pluginTR.hasClassName("all-dependents-disabled")) { + if (pluginTR.classList.contains("has-dependents")) { + if (!pluginTR.classList.contains("all-dependents-disabled")) { var dependentIds = pluginMetadata.dependentIds; // If the only dependent is jenkins-core (it's a bundle plugin), then lets @@ -278,30 +267,28 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { // dependent plugins in this case. // Note: This does not cover "implied" dependencies ala detached plugins. See https://goo.gl/lQHrUh if (dependentIds.length === 1 && dependentIds[0] === "jenkins-core") { - pluginTR.addClassName("all-dependents-disabled"); + pluginTR.classList.add("all-dependents-disabled"); return false; } - infoContainer.update( + infoContainer.innerHTML = '
    ' + - i18n("cannot-disable") + - '
    ' + - i18n("enabled-dependents") + - ".
    " - ); + i18n("cannot-disable") + + '
    ' + + i18n("enabled-dependents") + + ".
    "; infoContainer.appendChild(getDependentsDiv(pluginTR, true)); return true; } } - if (pluginTR.hasClassName("possibly-has-implied-dependents")) { - infoContainer.update( + if (pluginTR.classList.contains("possibly-has-implied-dependents")) { + infoContainer.innerHTML = '
    ' + - i18n("detached-disable") + - '
    ' + - i18n("detached-possible-dependents") + - "
    " - ); + i18n("detached-disable") + + '
    ' + + i18n("detached-possible-dependents") + + "
    "; infoContainer.appendChild(getDependentsDiv(pluginTR, true)); return true; } @@ -312,28 +299,26 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { function populateUninstallInfo(pluginTR, infoContainer) { // Remove all existing class info infoContainer.removeAttribute("class"); - infoContainer.addClassName("uninstall-state-info"); + infoContainer.classList.add("uninstall-state-info"); - if (pluginTR.hasClassName("has-dependents")) { - infoContainer.update( + if (pluginTR.classList.contains("has-dependents")) { + infoContainer.innerHTML = '
    ' + - i18n("cannot-uninstall") + - '
    ' + - i18n("installed-dependents") + - ".
    " - ); + i18n("cannot-uninstall") + + '
    ' + + i18n("installed-dependents") + + ".
    "; infoContainer.appendChild(getDependentsDiv(pluginTR, false)); return true; } - if (pluginTR.hasClassName("possibly-has-implied-dependents")) { - infoContainer.update( + if (pluginTR.classList.contains("possibly-has-implied-dependents")) { + infoContainer.innerHTML = '
    ' + - i18n("detached-uninstall") + - '
    ' + - i18n("detached-possible-dependents") + - "
    " - ); + i18n("detached-uninstall") + + '
    ' + + i18n("detached-possible-dependents") + + "
    "; infoContainer.appendChild(getDependentsDiv(pluginTR, false)); return true; } @@ -353,21 +338,21 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { var dependentId = dependentSpan.getAttribute("data-plugin-id"); if (!hideDisabled || dependentId === "jenkins-core") { - dependentSpan.setStyle({ display: "inline-block" }); + dependentSpan.style.display = "inline-block"; } else { var depPluginTR = getPluginTR(dependentId); var depPluginMetadata = depPluginTR.jenkinsPluginMetadata; if (depPluginMetadata.enableInput.checked) { // It's enabled ... show the span - dependentSpan.setStyle({ display: "inline-block" }); + dependentSpan.style.display = "inline-block"; } else { // It's disabled ... hide the span - dependentSpan.setStyle({ display: "none" }); + dependentSpan.style.display = "none"; } } } - dependentsDiv.setStyle({ display: "inherit" }); + dependentsDiv.style.display = "inherit"; return dependentsDiv; } @@ -387,19 +372,19 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { if (dependenciesDiv) { pluginTR.jenkinsPluginMetadata.dependencies = selectAll( "span", - dependenciesDiv + dependenciesDiv, ); pluginTR.jenkinsPluginMetadata.dependencyIds = processSpanSet( - pluginTR.jenkinsPluginMetadata.dependencies + pluginTR.jenkinsPluginMetadata.dependencies, ); } if (dependentsDiv) { pluginTR.jenkinsPluginMetadata.dependents = selectAll( "span", - dependentsDiv + dependentsDiv, ); pluginTR.jenkinsPluginMetadata.dependentIds = processSpanSet( - pluginTR.jenkinsPluginMetadata.dependents + pluginTR.jenkinsPluginMetadata.dependents, ); } @@ -407,7 +392,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { if (enableInput) { // Toggling of the enable/disable checkbox requires a check and possible // change of visibility on the same checkbox on other plugins. - Element.observe(enableInput, "click", function () { + enableInput.addEventListener("click", function () { setEnableWidgetStates(); }); } @@ -419,7 +404,7 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { infoTR.appendChild(infoTD); infoTD.appendChild(infoDiv); infoTD.setAttribute("colspan", "6"); // This is the cell that all info will be added to. - infoDiv.setStyle({ display: "inherit" }); + infoDiv.style.display = "inherit"; // We don't want the info row to appear immediately. We wait for e.g. 1 second and if the mouse // is still in there (hasn't left the cell) then we show. The following code is for clearing the @@ -434,16 +419,16 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { // Handle mouse in/out of the enable/disable cell (left most cell). if (enableTD) { - Element.observe(enableTD, "mouseenter", function () { + enableTD.addEventListener("mouseenter", function () { showInfoTimeout = setTimeout(function () { showInfoTimeout = undefined; - infoDiv.update(""); + infoDiv.textContent = ""; if (populateEnableDisableInfo(pluginTR, infoDiv)) { addDependencyInfoRow(pluginTR, infoTR); } }, 1000); }); - Element.observe(enableTD, "mouseleave", function () { + enableTD.addEventListener("mouseleave", function () { clearShowInfoTimeout(); removeDependencyInfoRow(pluginTR); }); @@ -451,16 +436,16 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { // Handle mouse in/out of the uninstall cell (right most cell). if (uninstallTD) { - Element.observe(uninstallTD, "mouseenter", function () { + uninstallTD.addEventListener("mouseenter", function () { showInfoTimeout = setTimeout(function () { showInfoTimeout = undefined; - infoDiv.update(""); + infoDiv.textContent = ""; if (populateUninstallInfo(pluginTR, infoDiv)) { addDependencyInfoRow(pluginTR, infoTR); } }, 1000); }); - Element.observe(uninstallTD, "mouseleave", function () { + uninstallTD.addEventListener("mouseleave", function () { clearShowInfoTimeout(); removeDependencyInfoRow(pluginTR); }); @@ -475,9 +460,9 @@ Behaviour.specify("#filter-box", "_table", 0, function (e) { }); })(); -Element.observe(window, "load", function () { +window.addEventListener("load", function () { const compatibleCheckbox = document.querySelector( - "[data-select='compatible']" + "[data-select='compatible']", ); if (compatibleCheckbox) { compatibleCheckbox.addEventListener("click", () => { @@ -491,4 +476,63 @@ Element.observe(window, "load", function () { window.updateTableHeaderCheckbox(); }); } + + const uninstallButtons = document.querySelectorAll( + "[data-action='uninstall']", + ); + uninstallButtons.forEach((uninstallButton) => { + uninstallButton.addEventListener("click", () => { + const title = uninstallButton.dataset.message; + const href = uninstallButton.dataset.href; + + const options = { + message: i18n("uninstall-description"), + type: "destructive", + }; + + dialog.confirm(title, options).then( + () => { + var form = document.createElement("form"); + form.setAttribute("method", "POST"); + form.setAttribute("action", href); + crumb.appendToForm(form); + document.body.appendChild(form); + form.submit(); + }, + () => {}, + ); + }); + }); + + // Enable/disable the 'Update' button depending on if any updates are checked + const anyCheckboxesSelected = () => { + return ( + document.querySelectorAll("input[type='checkbox']:checked:not(:disabled)") + .length > 0 + ); + }; + const updateButton = document.querySelector("#button-update"); + const checkboxes = document.querySelectorAll( + "input[type='checkbox'], [data-select], .jenkins-table__checkbox", + ); + checkboxes.forEach((checkbox) => { + checkbox.addEventListener("click", () => { + setTimeout(() => { + updateButton.disabled = !anyCheckboxesSelected(); + }); + }); + }); + + // Show update center error if element exists + const updateCenterError = document.querySelector("#update-center-error"); + if (updateCenterError) { + notificationBar.show( + updateCenterError.content.textContent, + notificationBar.ERROR, + ); + } }); + +function i18n(messageId) { + return document.querySelector("#i18n").getAttribute("data-" + messageId); +} diff --git a/core/src/main/resources/hudson/PluginManager/advanced_fr.properties b/core/src/main/resources/hudson/PluginManager/advanced_fr.properties index 40cc50a775eb7..70e4bf603a440 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_fr.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_fr.properties @@ -20,8 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +Advanced\ settings=Paramètres avancés HTTP\ Proxy\ Configuration=Configuration du proxy HTTP -Upload\ Plugin=Soumettre un plugin +Deploy\ Plugin=Déployer le plugin +Deploy=Déployer File=Fichier Update\ Site=Site de mise à jour Upload=Soumettre diff --git a/core/src/main/resources/hudson/PluginManager/available.jelly b/core/src/main/resources/hudson/PluginManager/available.jelly index bc17fb21ebcd9..212deb4935677 100644 --- a/core/src/main/resources/hudson/PluginManager/available.jelly +++ b/core/src/main/resources/hudson/PluginManager/available.jelly @@ -42,11 +42,35 @@ THE SOFTWARE. autofocus="true" value="${request.getParameter('filter')}" /> +
    + +
    + + + + +
    +
    + +
    + diff --git a/core/src/main/resources/hudson/PluginManager/installed.properties b/core/src/main/resources/hudson/PluginManager/installed.properties index fa5ecc5526a94..e08e426afc183 100644 --- a/core/src/main/resources/hudson/PluginManager/installed.properties +++ b/core/src/main/resources/hudson/PluginManager/installed.properties @@ -32,3 +32,5 @@ adoptThisPlugin=\ This plugin is up for adoption! We are looking for new maintainers. \ Visit our
    Adopt a Plugin initiative for more information. reportIssue=Report an issue with this plugin +uninstall-title=Are you sure you want to uninstall {0}? +uninstall-description=This will remove the plugin binary from your $JENKINS_HOME, but it will leave the configuration files of the plugin untouched diff --git a/core/src/main/resources/hudson/PluginManager/installed_de.properties b/core/src/main/resources/hudson/PluginManager/installed_de.properties index 2745acb84a343..29dec97f28beb 100644 --- a/core/src/main/resources/hudson/PluginManager/installed_de.properties +++ b/core/src/main/resources/hudson/PluginManager/installed_de.properties @@ -42,3 +42,5 @@ It\ has\ one\ or\ more\ disabled\ dependencies=Mindestens eine Abhängigkeit ist This\ plugin\ cannot\ be\ uninstalled=Dieses Plugin kann nicht deinstalliert werden. No\ description\ available.=Keine Beschreibung verfügbar. This\ plugin\ cannot\ be\ enabled=Dieses Plugin kann nicht aktiviert werden. +uninstall-title=Sind sie sicher dass sie {0} deinstallieren wollen? +uninstall-description=Dadurch wird die Plugin-Binärdatei aus $JENKINS_HOME entfernt, aber die Konfigurationsdateien des Plugins bleiben erhalten diff --git a/core/src/main/resources/hudson/PluginManager/table.jelly b/core/src/main/resources/hudson/PluginManager/updates.jelly similarity index 80% rename from core/src/main/resources/hudson/PluginManager/table.jelly rename to core/src/main/resources/hudson/PluginManager/updates.jelly index eeb3d83e11768..1cd688864eb25 100644 --- a/core/src/main/resources/hudson/PluginManager/table.jelly +++ b/core/src/main/resources/hudson/PluginManager/updates.jelly @@ -23,20 +23,10 @@ THE SOFTWARE. --> - - - - - Variable to contain List of Plugin - - - Page name to be passed to local:tabBar; 'updates' or 'available'. - - - If true, will hide all rows by default, and only the filter field will show them. - - + + + @@ -55,13 +45,22 @@ THE SOFTWARE. autofocus="true" value="${request.getParameter('filter')}" /> +
    + + + + + + +
    -
    - - + @@ -81,29 +80,19 @@ THE SOFTWARE. - + - - - + - - - - - - + @@ -225,20 +214,18 @@ THE SOFTWARE. - - - + @@ -253,21 +240,6 @@ THE SOFTWARE.
    ${%Name}${%Name} ${%Released}${%Installed}${%Installed}
    - ${%loading} -
    - - - - - - - () - - - - + + + + + + + () + + + +
    - -
    -
    - - - - - - - - - - -
    -
    diff --git a/core/src/main/resources/hudson/PluginManager/table.properties b/core/src/main/resources/hudson/PluginManager/updates.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table.properties rename to core/src/main/resources/hudson/PluginManager/updates.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_bg.properties b/core/src/main/resources/hudson/PluginManager/updates_bg.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_bg.properties rename to core/src/main/resources/hudson/PluginManager/updates_bg.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_ca.properties b/core/src/main/resources/hudson/PluginManager/updates_ca.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_ca.properties rename to core/src/main/resources/hudson/PluginManager/updates_ca.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_cs.properties b/core/src/main/resources/hudson/PluginManager/updates_cs.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_cs.properties rename to core/src/main/resources/hudson/PluginManager/updates_cs.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_da.properties b/core/src/main/resources/hudson/PluginManager/updates_da.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_da.properties rename to core/src/main/resources/hudson/PluginManager/updates_da.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_de.properties b/core/src/main/resources/hudson/PluginManager/updates_de.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_de.properties rename to core/src/main/resources/hudson/PluginManager/updates_de.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_es.properties b/core/src/main/resources/hudson/PluginManager/updates_es.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_es.properties rename to core/src/main/resources/hudson/PluginManager/updates_es.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_es_AR.properties b/core/src/main/resources/hudson/PluginManager/updates_es_AR.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_es_AR.properties rename to core/src/main/resources/hudson/PluginManager/updates_es_AR.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_et.properties b/core/src/main/resources/hudson/PluginManager/updates_et.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_et.properties rename to core/src/main/resources/hudson/PluginManager/updates_et.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_fi.properties b/core/src/main/resources/hudson/PluginManager/updates_fi.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_fi.properties rename to core/src/main/resources/hudson/PluginManager/updates_fi.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_fr.properties b/core/src/main/resources/hudson/PluginManager/updates_fr.properties similarity index 80% rename from core/src/main/resources/hudson/PluginManager/table_fr.properties rename to core/src/main/resources/hudson/PluginManager/updates_fr.properties index bf16337fdb8fa..4b7ac87894aab 100644 --- a/core/src/main/resources/hudson/PluginManager/table_fr.properties +++ b/core/src/main/resources/hudson/PluginManager/updates_fr.properties @@ -20,16 +20,15 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ to\ install\ the\ plugin=Cocher pour installer le plugin -Click\ this\ heading\ to\ sort\ by\ category=Cliquez sur l''en-tête pour classer par catégorie -Download\ now\ and\ install\ after\ restart=Télécharger maintenant et installer après redémarrage -Filter=Filtre -Inactive=Inactif -Install=Installer -Install\ without\ restart=Installer sans redémarrer -Installed=Installé +Updates=Mises à jour +Search\ plugin\ updates=Rechercher les mises à jour du plugin +Update=Mettre à jour Name=Nom +Released=Publié(e) +Installed=Installé +Applying\ this\ update\ will\ address\ security\ vulnerabilities\ in\ the\ currently\ installed\ version.=L'application de cette mise à jour corrigera les failles de sécurité de la version actuellement installée. +No\ updates=Aucunes mises à jour +Inactive=Inactif Version=Version -No\ updates=Pas de mises à jour compatWarning=Avertissement: Cette nouvelle version n''est pas compatible avec la version installée. Il peut être nécessaire de reconfigurer les tâches utilisant ce plugin. coreWarning=Ce plugin est conçu pour Jenkins {0} ou une version plus récente. Il pourrait ne pas fonctionner avec votre version de Jenkins. diff --git a/core/src/main/resources/hudson/PluginManager/table_he.properties b/core/src/main/resources/hudson/PluginManager/updates_he.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_he.properties rename to core/src/main/resources/hudson/PluginManager/updates_he.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_hu.properties b/core/src/main/resources/hudson/PluginManager/updates_hu.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_hu.properties rename to core/src/main/resources/hudson/PluginManager/updates_hu.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_it.properties b/core/src/main/resources/hudson/PluginManager/updates_it.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_it.properties rename to core/src/main/resources/hudson/PluginManager/updates_it.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_ja.properties b/core/src/main/resources/hudson/PluginManager/updates_ja.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_ja.properties rename to core/src/main/resources/hudson/PluginManager/updates_ja.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_ko.properties b/core/src/main/resources/hudson/PluginManager/updates_ko.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_ko.properties rename to core/src/main/resources/hudson/PluginManager/updates_ko.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_lt.properties b/core/src/main/resources/hudson/PluginManager/updates_lt.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_lt.properties rename to core/src/main/resources/hudson/PluginManager/updates_lt.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_lv.properties b/core/src/main/resources/hudson/PluginManager/updates_lv.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_lv.properties rename to core/src/main/resources/hudson/PluginManager/updates_lv.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_nb_NO.properties b/core/src/main/resources/hudson/PluginManager/updates_nb_NO.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_nb_NO.properties rename to core/src/main/resources/hudson/PluginManager/updates_nb_NO.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_nl.properties b/core/src/main/resources/hudson/PluginManager/updates_nl.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_nl.properties rename to core/src/main/resources/hudson/PluginManager/updates_nl.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_pl.properties b/core/src/main/resources/hudson/PluginManager/updates_pl.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_pl.properties rename to core/src/main/resources/hudson/PluginManager/updates_pl.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_pt_BR.properties b/core/src/main/resources/hudson/PluginManager/updates_pt_BR.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_pt_BR.properties rename to core/src/main/resources/hudson/PluginManager/updates_pt_BR.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_pt_PT.properties b/core/src/main/resources/hudson/PluginManager/updates_pt_PT.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_pt_PT.properties rename to core/src/main/resources/hudson/PluginManager/updates_pt_PT.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_ro.properties b/core/src/main/resources/hudson/PluginManager/updates_ro.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_ro.properties rename to core/src/main/resources/hudson/PluginManager/updates_ro.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_ru.properties b/core/src/main/resources/hudson/PluginManager/updates_ru.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_ru.properties rename to core/src/main/resources/hudson/PluginManager/updates_ru.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_sk.properties b/core/src/main/resources/hudson/PluginManager/updates_sk.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_sk.properties rename to core/src/main/resources/hudson/PluginManager/updates_sk.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_sr.properties b/core/src/main/resources/hudson/PluginManager/updates_sr.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_sr.properties rename to core/src/main/resources/hudson/PluginManager/updates_sr.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_sv_SE.properties b/core/src/main/resources/hudson/PluginManager/updates_sv_SE.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_sv_SE.properties rename to core/src/main/resources/hudson/PluginManager/updates_sv_SE.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_tr.properties b/core/src/main/resources/hudson/PluginManager/updates_tr.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_tr.properties rename to core/src/main/resources/hudson/PluginManager/updates_tr.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_uk.properties b/core/src/main/resources/hudson/PluginManager/updates_uk.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_uk.properties rename to core/src/main/resources/hudson/PluginManager/updates_uk.properties diff --git a/core/src/main/resources/hudson/PluginManager/table_zh_TW.properties b/core/src/main/resources/hudson/PluginManager/updates_zh_TW.properties similarity index 100% rename from core/src/main/resources/hudson/PluginManager/table_zh_TW.properties rename to core/src/main/resources/hudson/PluginManager/updates_zh_TW.properties diff --git a/core/src/main/resources/hudson/cli/Messages.properties b/core/src/main/resources/hudson/cli/Messages.properties index bc6068df321ac..15d27a2433b27 100644 --- a/core/src/main/resources/hudson/cli/Messages.properties +++ b/core/src/main/resources/hudson/cli/Messages.properties @@ -84,6 +84,7 @@ ReloadConfigurationCommand.ShortDescription=Discard all the loaded data in memor ConnectNodeCommand.ShortDescription=Reconnect to a node(s) DisconnectNodeCommand.ShortDescription=Disconnects from a node. QuietDownCommand.ShortDescription=Quiet down Jenkins, in preparation for a restart. Don’t start any builds. +SafeRestartCommand.ShortDescription=Safe Restart Jenkins. Don’t start any builds. CancelQuietDownCommand.ShortDescription=Cancel the effect of the "quiet-down" command. OfflineNodeCommand.ShortDescription=Stop using a node for performing builds temporarily, until the next "online-node" command. WaitNodeOnlineCommand.ShortDescription=Wait for a node to become online. diff --git a/core/src/main/resources/hudson/cli/Messages_de.properties b/core/src/main/resources/hudson/cli/Messages_de.properties index 1a390a6d1ecb8..eef93169fc1af 100644 --- a/core/src/main/resources/hudson/cli/Messages_de.properties +++ b/core/src/main/resources/hudson/cli/Messages_de.properties @@ -39,6 +39,7 @@ ListPluginsCommand.ShortDescription=Gibt eine Liste installierter Plugins aus. OfflineNodeCommand.ShortDescription=Knoten wird bis zum nächsten "online-node"-Kommando für keine neuen Builds verwendet. OnlineNodeCommand.ShortDescription=Knoten wird wieder für neue Builds verwendet. Hebt ein vorausgegangenes "offline-node"-Kommando auf. QuietDownCommand.ShortDescription=Keine neuen Builds mehr starten, z.B. zur Vorbereitung eines Neustarts. +SafeRestartCommand.ShortDescription=Sicheren Neustart einleiten. Keine neuen Builds mehr starten und versuchen, laufende zu pausieren. ReloadConfigurationCommand.ShortDescription=Alle Daten im Speicher verwerfen und Konfiguration neu von Festplatte laden. Dies ist nützlich, wenn Sie Änderungen direkt im Dateisystem vorgenommen haben. ReloadJobCommand.ShortDescription=Lädt ein Element neu. RemoveJobFromViewCommand.ShortDescription=Entfernt Elemente aus einer Ansicht diff --git a/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js b/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js index edccad221f515..bd71b5fec8078 100644 --- a/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js +++ b/core/src/main/resources/hudson/console/ExpandableDetailsNote/script.js @@ -9,6 +9,6 @@ detail.style.display = detail.style.display == "block" ? "none" : "block"; }); - } + }, ); })(); diff --git a/core/src/main/resources/hudson/diagnosis/ReverseProxySetupMonitor/resources.js b/core/src/main/resources/hudson/diagnosis/ReverseProxySetupMonitor/resources.js index fa020b9eb6e6a..baf1a0654c774 100644 --- a/core/src/main/resources/hudson/diagnosis/ReverseProxySetupMonitor/resources.js +++ b/core/src/main/resources/hudson/diagnosis/ReverseProxySetupMonitor/resources.js @@ -2,20 +2,23 @@ var redirectForm = document.getElementById("redirect-error"); if (!redirectForm) { console.warn( - 'This script expects to have an element with id="redirect-error" to be working.' + 'This script expects to have an element with id="redirect-error" to be working.', ); return; } var urlToTest = redirectForm.getAttribute("data-url"); var callUrlToTest = function (testWithContext, callback) { + var headers = {}; var body = null; if (testWithContext === true) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; body = new URLSearchParams({ testWithContext: "true" }); } fetch(urlToTest, { + method: "POST", cache: "no-cache", - headers: crumb.wrap({}), + headers: crumb.wrap(headers), body, }) .then((rsp) => callback(rsp)) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly b/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly index d16bdb1bd651c..aba5588ccd135 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly @@ -27,8 +27,7 @@ THE SOFTWARE. --> - - + @@ -68,9 +67,9 @@ THE SOFTWARE. - + - + diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete.properties deleted file mode 100644 index 3d1cebc58572b..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete.properties +++ /dev/null @@ -1 +0,0 @@ -delete.logrecorder=Are you sure you want to delete the log recorder ‘{0}’? diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_bg.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_bg.properties deleted file mode 100644 index b9327a1025769..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_bg.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, Alexander Shopov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=\ - Сигурни ли сте, че искате да премахнете това записване на журнали? -Yes=\ - Да diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_da.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_da.properties deleted file mode 100644 index be43db31bca87..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_da.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Ja -delete.logrecorder=Er du sikker på at du vil slette denne logopsamler? ({0}) - diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_de.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_de.properties deleted file mode 100644 index d7864e0855553..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_de.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=Möchten Sie diesen Log-Rekorder wirklich löschen? ({0}) - -Yes=Ja diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_fr.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_fr.properties deleted file mode 100644 index 75fcc51afb35d..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_fr.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=Etes-vous certain de vouloir effacer cet enregistreur de log? ({0}) - -Yes=Oui diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_it.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_it.properties deleted file mode 100644 index d29e75678d76a..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=Eliminare il registratore log "{0}"? -Yes=Sì diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_ja.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_ja.properties deleted file mode 100644 index 4c576da6f0d72..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_ja.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=このログレコーダーを削除してもよろしいですか? ({0}) - -Yes=はい diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_nl.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_nl.properties deleted file mode 100644 index e14d82beefbdc..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_nl.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Wim Rosseel -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=Weet U zeker dat U deze logger wenst te verwijderen? ({0}) - -Yes=Ja diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_pl.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_pl.properties deleted file mode 100644 index 736502ff8814f..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_pl.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017, Damian Szczepanik -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -delete.logrecorder=Czy na pewno chcesz usunąć tego rejestratora logów? ({0}) - -Yes=Tak diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_pt_BR.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_pt_BR.properties deleted file mode 100644 index a1e827d322b1e..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_pt_BR.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva, Fernando Boaglio -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Sim -delete.logrecorder=Deseja realmente remover o gravador de registro de atividades? ({0}) -Delete\ log\ recorder=Remover o gravador de registro de atividades diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_ru.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_ru.properties deleted file mode 100644 index 4600f2e54e7e5..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_ru.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=Вы действительно хотите удалить этот журнал? ({0}) - -Yes=Да diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_sr.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_sr.properties deleted file mode 100644 index 4e75c5e45ec92..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_sr.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This file is under the MIT License by authors - -delete.logrecorder=Дали желите да уклоните овог преписивача? ({0}) - -Yes=Да diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_zh_TW.properties b/core/src/main/resources/hudson/logging/LogRecorder/delete_zh_TW.properties deleted file mode 100644 index 28b4a64a47bcc..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_zh_TW.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.logrecorder=您確定要刪除這個記錄錄製器嗎? ({0}) - -Yes=是 diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index.jelly b/core/src/main/resources/hudson/logging/LogRecorder/index.jelly index 1188c2c7e425d..b0f3d8cd09dc5 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorder/index.jelly @@ -27,24 +27,51 @@ THE SOFTWARE. --> - - + -

    ${it.displayName}

    + + + + + +
    + + +
    + + Configure + +
    + + ${%Atom feed} + + +
    + +
    + +
    + ${%Delete log recorder} +
    +
    +
    +
    + + + + +

    ${entry.key.displayName}

    - - -
    - - -
    - -
    diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete_es.properties b/core/src/main/resources/hudson/logging/LogRecorder/index.properties similarity index 87% rename from core/src/main/resources/hudson/logging/LogRecorder/delete_es.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index.properties index 363e1044de173..bf51ec370ca92 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete_es.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2022 Jenkins contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -delete.logrecorder=Estas seguro de querer borrar este registro de ''logs'' -Yes=Sí +Clear\ This\ Log=Clear this log +delete.logrecorder=Are you sure you want to delete the log recorder ‘{0}’? diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_bg.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_bg.properties index 9073cd6dff10c..c7d4a49f0bb15 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_bg.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_bg.properties @@ -22,3 +22,13 @@ Clear\ This\ Log=\ Изчистване на този журнал +Delete=\ + Изтриване +Back\ to\ Loggers=\ + Към журналите +Log\ records=\ + Журнални записи +Configure=\ + Настройки +delete.logrecorder=\ + Сигурни ли сте, че искате да премахнете това записване на журнали? diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_da.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_da.properties similarity index 94% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_da.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_da.properties index a9bcf21b76c49..033b843130fa9 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_da.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_da.properties @@ -24,3 +24,4 @@ Configure=Konfigurer Delete=Slet Back\ to\ Loggers=Tilbage til loggere Log\ records=Logopsamlere +delete.logrecorder=Er du sikker p at du vil slette denne logopsamler? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_de.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_de.properties index bdf762c55c18f..8c4f622cfdae4 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_de.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_de.properties @@ -21,3 +21,8 @@ # THE SOFTWARE. Clear\ This\ Log=Dieses Log zurücksetzen +Back\ to\ Loggers=Zurück zu den Loggern +Log\ records=Log-Aufzeichnungen +Configure=Konfigurieren +Delete=Löschen +delete.logrecorder=Möchten Sie diesen Log-Rekorder wirklich löschen? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_es.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_es.properties similarity index 94% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_es.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_es.properties index 613aef96bfe34..8ca60b38eb629 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_es.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_es.properties @@ -24,3 +24,4 @@ Back\ to\ Loggers=Volver Log\ records=Líneas de ''log'' Configure=Configurar Delete=Borrar +delete.logrecorder=Estas seguro de querer borrar este registro de ''logs'' diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_fr.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_fr.properties similarity index 93% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_fr.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_fr.properties index 7951daf47478c..2ca043a8a8cc5 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_fr.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_fr.properties @@ -24,3 +24,4 @@ Back\ to\ Loggers=Retourner aux loggers Log\ records=Enregistrements de log Configure=Configurer Delete=Supprimer +delete.logrecorder=Etes-vous certain de vouloir effacer cet enregistreur de log? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_it.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_it.properties index b81333fcc6542..1c16203cf4220 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_it.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_it.properties @@ -22,3 +22,8 @@ # THE SOFTWARE. Clear\ This\ Log=Pulisci questo log +Back\ to\ Loggers=Torna alle definizioni dei registratori log +Configure=Configura +Delete=Elimina +Log\ records=Voci dei log +delete.logrecorder=Eliminare il registratore log "{0}"? diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties index d406d296df6af..dfd570649fe04 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties @@ -21,3 +21,8 @@ # THE SOFTWARE. Clear\ This\ Log=クリア +Back\ to\ Loggers=ロガーへ戻る +Log\ records=ログレコード +Configure=設定 +Delete=削除 +delete.logrecorder=このログレコーダーを削除してもよろしいですか? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_lv.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_lv.properties similarity index 100% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_lv.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_lv.properties diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_nl.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_nl.properties similarity index 94% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_nl.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_nl.properties index 670efe80080cd..83d13ea009308 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_nl.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_nl.properties @@ -24,3 +24,4 @@ Back\ to\ Loggers=Terug naar de loggers Log\ records=Logboek Configure=Configureer Delete=Verwijder +delete.logrecorder=Weet U zeker dat U deze logger wenst te verwijderen? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_pl.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_pl.properties index 5e652b0bab6e1..58fae9a0484a0 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_pl.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_pl.properties @@ -20,3 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. Clear\ This\ Log=Usuń logi +Back\ to\ Loggers=Powrót do rejestratorów logów +Delete=Usuń +Log\ records=Zawartość rejestratora logów +Configure=Skonfiguruj +delete.logrecorder=Czy na pewno chcesz usunąć tego rejestratora logów? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_pt_BR.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_pt_BR.properties index 26fc194464eb4..196580ea81537 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_pt_BR.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_pt_BR.properties @@ -21,3 +21,7 @@ # THE SOFTWARE. Clear\ This\ Log=Limpar este log +Configure=Configurar +Delete=Excluir +Log\ records=Registros de log +delete.logrecorder=Deseja realmente remover o gravador de registro de atividades? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_ru.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_ru.properties similarity index 92% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_ru.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_ru.properties index 91d14e709dab1..2da776c007984 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_ru.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_ru.properties @@ -24,3 +24,4 @@ Back\ to\ Loggers=Вернуться к журналам Configure=Настроить Delete=Удалить Log\ records=Записи журнала +delete.logrecorder=Вы действительно хотите удалить этот журнал? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_sr.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_sr.properties index b1fef4f7c1aac..662bae8a133de 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/index_sr.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_sr.properties @@ -1,3 +1,8 @@ # This file is under the MIT License by authors Clear\ This\ Log=Пребриши журнал +Back\ to\ Loggers=Назад на преписиваче +Log\ records=Нивои за писање у журнал +Configure=Конфигуриши +Delete=Уклони +delete.logrecorder=Дали желите да уклоните овог преписивача? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_zh_TW.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_zh_TW.properties similarity index 94% rename from core/src/main/resources/hudson/logging/LogRecorder/sidepanel_zh_TW.properties rename to core/src/main/resources/hudson/logging/LogRecorder/index_zh_TW.properties index ac89f02074bff..d0f08393e0cc9 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_zh_TW.properties +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_zh_TW.properties @@ -24,3 +24,4 @@ Log\ records=記錄內容 Configure=設定 Back\ to\ Loggers=回到日誌記錄 Delete=刪除 +delete.logrecorder=您確定要刪除這個記錄錄製器嗎? ({0}) diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel.jelly b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel.jelly index 8e088f4bd80a7..9aa04af840d0f 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel.jelly @@ -33,7 +33,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_bg.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_bg.properties deleted file mode 100644 index 6bfd7999e7949..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_bg.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, Alexander Shopov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Delete=\ - Изтриване -Back\ to\ Loggers=\ - Към журналите -Log\ records=\ - Журнални записи -Configure=\ - Настройки diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_de.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_de.properties deleted file mode 100644 index da24af33f9130..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_de.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Loggers=Zurück zu den Loggern -Log\ records=Log-Aufzeichnungen -Configure=Konfigurieren -Delete=Löschen diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_it.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_it.properties deleted file mode 100644 index c820d76427c7a..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_it.properties +++ /dev/null @@ -1,27 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Loggers=Torna alle definizioni dei registratori log -Configure=Configura -Delete=Elimina -Log\ records=Voci dei log diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_ja.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_ja.properties deleted file mode 100644 index 7544cf386a896..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_ja.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Loggers=ロガーへ戻る -Log\ records=ログレコード -Configure=設定 -Delete=削除 diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_pl.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_pl.properties deleted file mode 100644 index f3c8624c39e17..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_pl.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017, Damian Szczepanik -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -Back\ to\ Loggers=Powrót do rejestratorów logów -Delete=Usuń -Log\ records=Zawartość rejestratora logów -Configure=Skonfiguruj diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_pt_BR.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_pt_BR.properties deleted file mode 100644 index 688384bce6b6a..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_pt_BR.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number -# of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Configure=Configurar -Delete=Excluir -Log\ records=Registros de log diff --git a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_sr.properties b/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_sr.properties deleted file mode 100644 index 4fa36bf1afb32..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorder/sidepanel_sr.properties +++ /dev/null @@ -1,6 +0,0 @@ -# This file is under the MIT License by authors - -Back\ to\ Loggers=Назад на преписиваче -Log\ records=Нивои за писање у журнал -Configure=Конфигуриши -Delete=Уклони diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/all.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/all.jelly index ed8ddacce6b65..476209c54113c 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/all.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/all.jelly @@ -30,13 +30,17 @@ THE SOFTWARE. -

    ${%All Jenkins Logs}

    + + + + + +
    Log messages at a level lower than INFO are never recorded in the Jenkins log. Use log recorders to record these log messages.
    - - +
    diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly index 4e856c478e481..7b0fe2e910491 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly @@ -24,19 +24,23 @@ THE SOFTWARE. - - + ${%SEVERE} + diff --git a/core/src/main/resources/hudson/model/Computer/delete_ru.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.properties similarity index 93% rename from core/src/main/resources/hudson/model/Computer/delete_ru.properties rename to core/src/main/resources/hudson/logging/LogRecorderManager/feeds.properties index e1f83648e330c..c5e64b7c59433 100644 --- a/core/src/main/resources/hudson/model/Computer/delete_ru.properties +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2022 Jenkins contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Yes=Да +WARNING=Warning +SEVERE=Severe diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly index 037780cf7c88a..35e166f4784b0 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly @@ -27,27 +27,29 @@ THE SOFTWARE. --> - - + - ${%Add new log recorder} + ${%Add recorder} + + ${%Log levels} + + ${name} - ${name} @@ -55,8 +57,8 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly index 508610695d136..db697a1a145b7 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly @@ -27,8 +27,7 @@ THE SOFTWARE. --> - - + diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/new.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/new.jelly index b278b783178ea..25680c9e8c1cd 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/new.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/new.jelly @@ -26,9 +26,8 @@ THE SOFTWARE. Create a new LogRecorder --> - - - + + diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_bg.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_bg.properties deleted file mode 100644 index 16f1c974835d4..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_bg.properties +++ /dev/null @@ -1,34 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, Alexander Shopov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Dashboard=\ - Към командния панел -Logger\ List=\ - Списък с журналите -Manage\ Jenkins=\ - Управление на Jenkins -New\ Log\ Recorder=\ - Нов журнал -All\ Logs=\ - Всички журнали -Log\ Levels=\ - Ниво на журналните записи diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_da.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_da.properties deleted file mode 100644 index 942a5a1849e11..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_da.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Logs=Alle logs -New\ Log\ Recorder=Ny logopsamler -Back\ to\ Dashboard=Tilbage til oversigtssiden -Logger\ List=Loggerliste -Log\ Levels=Logningsniveauer -Manage\ Jenkins=Bestyr Jenkins diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_de.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_de.properties deleted file mode 100644 index 315e2425b78ec..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_de.properties +++ /dev/null @@ -1,6 +0,0 @@ -Back\ to\ Dashboard=Zurück zur Übersicht -Logger\ List=Logger-Liste -All\ Logs=Alle Logs -New\ Log\ Recorder=Neuer Log-Rekorder -Log\ Levels=Log-Prioritäten (Levels) -Manage\ Jenkins=Jenkins verwalten diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_es.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_es.properties deleted file mode 100644 index 9d93ab0551a15..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_es.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Dashboard=Volver al Panel de Control -Manage\ Jenkins=Administrar Jenkins -Logger\ List=Lista de Loggers -All\ Logs=Todos los Logs -New\ Log\ Recorder=Nuevo registro de Logs -Log\ Levels=Niveles de Log diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_fr.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_fr.properties deleted file mode 100644 index a7c3cc7c48875..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_fr.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Dashboard=Retour au tableau de bord -Manage\ Jenkins=Administrer Jenkins -Log\ Levels=Niveaux des logs -Logger\ List=Liste des loggers -All\ Logs=Tous les logs -New\ Log\ Recorder=Nouveau enregistreur de log diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_hu.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_hu.properties deleted file mode 100644 index c738571673718..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_hu.properties +++ /dev/null @@ -1,8 +0,0 @@ -# This file is under the MIT License by authors - -All\ Logs=Összes Log -Back\ to\ Dashboard=Vissza a Dashboard-ra -Log\ Levels=Log Szintek -Logger\ List=Loggolók Listája -Manage\ Jenkins=Jenkins Kezelése -New\ Log\ Recorder=Új Log Felvevő diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_it.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_it.properties deleted file mode 100644 index e79a4980230b1..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_it.properties +++ /dev/null @@ -1,29 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Log\ Messages=Tutti i messaggi di log -Back\ to\ Dashboard=Torna al cruscotto -Log\ Levels=Livelli log -Log\ Recorders=Registratori log -Manage\ Jenkins=Gestisci Jenkins -New\ Log\ Recorder=Nuovo registratore log diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ja.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ja.properties deleted file mode 100644 index f01d675575fe2..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ja.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Dashboard=ダッシュボードへ戻る -Manage\ Jenkins=Jenkinsの管理 -Logger\ List=ロガーリスト -All\ Logs=すべてのログ -New\ Log\ Recorder=新規レコーダー登録 -Log\ Levels=ログレベル diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ko.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ko.properties deleted file mode 100644 index ba9e06991a187..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ko.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Logs=모든 로그 -Manage\ Jenkins=Jenkins 관리 -Back\ to\ Dashboard=대시보드로 돌아감 -Log\ Levels=로그 레벨 -Logger\ List=로그 목록 -New\ Log\ Recorder=새 로그 기록기 diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_lt.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_lt.properties deleted file mode 100644 index 4e8a37047877f..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_lt.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This file is under the MIT License by authors - -All\ Logs=Visi žurnalai -Log\ Levels=Žurnalų lygiai -Manage\ Jenkins=Valdyti Jenkins diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_lv.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_lv.properties deleted file mode 100644 index 7c53c42d7e812..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_lv.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Logs=Visi žurnāli -Back\ to\ Dashboard=Atpakaļ uz Uzdevumdēli -Log\ Levels=Žurnāla līmeņi -Logger\ List=Iežurnalētāja saraksts -Manage\ Jenkins=Pārvaldīt Jenkins -New\ Log\ Recorder=Jauns žurnāla ieraksts diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_nl.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_nl.properties deleted file mode 100644 index dc5b3cc0553b9..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_nl.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Logs=Alle Logs -Back\ to\ Dashboard=Terug naar Dashboard -Manage\ Jenkins=Beheer Jenkins -Log\ Levels=Logniveaus -Logger\ List=Lijst Loggers -New\ Log\ Recorder=Nieuw Logrecord diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pl.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pl.properties deleted file mode 100644 index a62eaa6321ca1..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pl.properties +++ /dev/null @@ -1,27 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013-2017, Kohsuke Kawaguchi, Damian Szczepanik -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -All\ Logs=Wszystkie Logi -Back\ to\ Dashboard=Powrót do tablicy -Log\ Levels=Poziom logowania -Logger\ List=Lista rejestratorów logów -Manage\ Jenkins=Zarządzaj Jenkinsem -New\ Log\ Recorder=Dodaj rejestratora logów diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pt_BR.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pt_BR.properties deleted file mode 100644 index bfd8600a3479f..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pt_BR.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number -# of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Log\ Levels=Níveis de registro de atividade -Log\ Recorders=Gravadores de registro de atividade diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pt_PT.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pt_PT.properties deleted file mode 100644 index f90277997c870..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_pt_PT.properties +++ /dev/null @@ -1,8 +0,0 @@ -# This file is under the MIT License by authors - -All\ Logs=Todos os Logs -Back\ to\ Dashboard=Voltar ao Painel -Log\ Levels=Níveis de Log -Logger\ List=Lista de Loggers -Manage\ Jenkins=Gerir o Jenkins -New\ Log\ Recorder=Novo Gravador de Log diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ru.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ru.properties deleted file mode 100644 index 8fd19b24a872a..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_ru.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Logs=Все журналы -Back\ to\ Dashboard=Домой -Manage\ Jenkins=Настроить Jenkins -Log\ Levels=Уровни журналирования -Logger\ List=Список журналов -New\ Log\ Recorder=Новый журнал diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_sr.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_sr.properties deleted file mode 100644 index 27cc591ea0f4b..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_sr.properties +++ /dev/null @@ -1,8 +0,0 @@ -# This file is under the MIT License by authors - -Back\ to\ Dashboard=Назад на контролну панелу -Manage\ Jenkins=Управљање Jenkins-ом -Logger\ List=Преписивачи -New\ Log\ Recorder=Нови преписивач -Log\ Levels=Нивои журнала -All\ Logs=Сви журнали diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_sv_SE.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_sv_SE.properties deleted file mode 100644 index 1f496cedc47c3..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_sv_SE.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Back\ to\ Dashboard=Tillbaka till instrumentpanel -Log\ Levels=Loggningsnivåer -Manage\ Jenkins=Hantera Jenkins diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_zh_TW.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_zh_TW.properties deleted file mode 100644 index cf180e5f34bb2..0000000000000 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel_zh_TW.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -All\ Logs=所有記錄 -Log\ Levels=記錄等級 -Logger\ List=記錄器清單 -Manage\ Jenkins=管理 Jenkins -New\ Log\ Recorder=新增記錄錄製器 -Back\ to\ Dashboard=返回資訊主頁 diff --git a/core/src/main/resources/hudson/model/AbstractBuild/index.jelly b/core/src/main/resources/hudson/model/AbstractBuild/index.jelly index 58864689d56ab..2d35a86710edb 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/index.jelly +++ b/core/src/main/resources/hudson/model/AbstractBuild/index.jelly @@ -48,7 +48,7 @@ THE SOFTWARE. - ${%Build} ${it.displayName} () + ${it.displayName} ()
    diff --git a/core/src/main/resources/hudson/model/AbstractItem/confirm-rename_fr.properties b/core/src/main/resources/hudson/model/AbstractItem/confirm-rename_fr.properties new file mode 100644 index 0000000000000..85badf43445c1 --- /dev/null +++ b/core/src/main/resources/hudson/model/AbstractItem/confirm-rename_fr.properties @@ -0,0 +1 @@ +Rename=Renommer diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace.jelly b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace.jelly index 1c29fc0d72278..5b46f654a5e12 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace.jelly +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace.jelly @@ -30,7 +30,7 @@ THE SOFTWARE. -

    ${%Error: no workspace}

    +

    ${%Error: no workspace}

    diff --git a/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked.jelly b/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked.jelly index ea15447875051..f8e5696ef260e 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked.jelly +++ b/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error: Wipe Out Workspace blocked by SCM}

    +

    ${%Error: Wipe Out Workspace blocked by SCM}

    ${%The SCM for this project has blocked this attempt to wipe out the project's workspace.}

    diff --git a/core/src/main/resources/hudson/model/AllView/noJob.groovy b/core/src/main/resources/hudson/model/AllView/noJob.groovy index 414c3753fda90..6f5a7adeab68b 100644 --- a/core/src/main/resources/hudson/model/AllView/noJob.groovy +++ b/core/src/main/resources/hudson/model/AllView/noJob.groovy @@ -57,7 +57,7 @@ div { if (hasAdministerJenkinsPermission) { li(class: "content-block") { - a(href: "configureClouds", class: "content-block__link") { + a(href: "cloud/", class: "content-block__link") { span(_("setUpCloud")) span(class: "trailing-icon") { l.icon( diff --git a/core/src/main/resources/hudson/model/BuildTimelineWidget/build-timeline-widget.js b/core/src/main/resources/hudson/model/BuildTimelineWidget/build-timeline-widget.js index 4437c99d13dc4..eb7c1fa2cc88b 100644 --- a/core/src/main/resources/hudson/model/BuildTimelineWidget/build-timeline-widget.js +++ b/core/src/main/resources/hudson/model/BuildTimelineWidget/build-timeline-widget.js @@ -11,17 +11,16 @@ function getData(eventSource1, current, min, max) { } if (!eventSource1.loaded[current]) { eventSource1.loaded[current] = true; - fetch( - "timeline/data/?" + - new URLSearchParams({ - min: current * interval, - max: (current + 1) * interval, - }), - { - method: "POST", - headers: crumb.wrap({}), - } - ).then((t) => { + fetch("timeline/data", { + method: "POST", + headers: crumb.wrap({ + "Content-Type": "application/x-www-form-urlencoded", + }), + body: new URLSearchParams({ + min: current * interval, + max: (current + 1) * interval, + }), + }).then((t) => { if (t.ok) { t.json() .then((json) => { @@ -129,6 +128,6 @@ if (window.addEventListener) { tl.layout(); }, null, - true + true, ); })(); diff --git a/core/src/main/resources/hudson/model/Computer/delete.properties b/core/src/main/resources/hudson/model/Computer/delete.properties deleted file mode 100644 index 3e3f7b4af26b7..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete.properties +++ /dev/null @@ -1 +0,0 @@ -delete.agent=Delete the agent ‘{0}’? diff --git a/core/src/main/resources/hudson/model/Computer/delete_bg.properties b/core/src/main/resources/hudson/model/Computer/delete_bg.properties deleted file mode 100644 index c5ee918a67f7e..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_bg.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2015, 2016, Alexander Shopov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ slave?=\ - Сигурни ли сте, че искате да премахнете този компютър? -Yes=\ - Да -Are\ you\ sure\ about\ deleting\ the\ agent?=\ - Сигурни ли сте, че искате да премахнете този компютър? diff --git a/core/src/main/resources/hudson/model/Computer/delete_da.properties b/core/src/main/resources/hudson/model/Computer/delete_da.properties deleted file mode 100644 index 1d3dcce7bd165..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_da.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Ja diff --git a/core/src/main/resources/hudson/model/Computer/delete_de.properties b/core/src/main/resources/hudson/model/Computer/delete_de.properties deleted file mode 100644 index 36fe894a14835..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_de.properties +++ /dev/null @@ -1,2 +0,0 @@ -Yes=Ja -Are\ you\ sure\ about\ deleting\ the\ agent?=Möchten Sie diesen Agenten wirklich entfernen? diff --git a/core/src/main/resources/hudson/model/Computer/delete_es.properties b/core/src/main/resources/hudson/model/Computer/delete_es.properties deleted file mode 100644 index cfa2048c7944b..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_es.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ agent?=¿Estás seguro de querer borrar este agente? -Yes=Sí diff --git a/core/src/main/resources/hudson/model/Computer/delete_fr.properties b/core/src/main/resources/hudson/model/Computer/delete_fr.properties deleted file mode 100644 index 50339e156c295..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_fr.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Oui diff --git a/core/src/main/resources/hudson/model/Computer/delete_it.properties b/core/src/main/resources/hudson/model/Computer/delete_it.properties deleted file mode 100644 index c75d81ab961dd..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.agent=Eliminare l''agente "{0}"? -Yes=Sì diff --git a/core/src/main/resources/hudson/model/Computer/delete_ja.properties b/core/src/main/resources/hudson/model/Computer/delete_ja.properties deleted file mode 100644 index 5c9309d2906ea..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_ja.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=はい diff --git a/core/src/main/resources/hudson/model/Computer/delete_lv.properties b/core/src/main/resources/hudson/model/Computer/delete_lv.properties deleted file mode 100644 index 36cff5933bcaf..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_lv.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -Yes=Jā diff --git a/core/src/main/resources/hudson/model/Computer/delete_pt_BR.properties b/core/src/main/resources/hudson/model/Computer/delete_pt_BR.properties deleted file mode 100644 index a6342e7d754ce..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_pt_BR.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva, Fernando Boaglio -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Sim -delete.agent=Remover o agente ‘{0}’? diff --git a/core/src/main/resources/hudson/model/Computer/delete_sr.properties b/core/src/main/resources/hudson/model/Computer/delete_sr.properties deleted file mode 100644 index 92cac21eb6a64..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_sr.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This file is under the MIT License by authors - -Are\ you\ sure\ about\ deleting\ the\ agent?=Да ли сте сигурни да желите да уклоните агента? -Yes=Да -Are\ you\ sure\ about\ deleting\ the\ slave?=Да ли сте сигурни да желите да уклоните помоћника? diff --git a/core/src/main/resources/hudson/model/Computer/delete_zh_TW.properties b/core/src/main/resources/hudson/model/Computer/delete_zh_TW.properties deleted file mode 100644 index 91fda1edf9324..0000000000000 --- a/core/src/main/resources/hudson/model/Computer/delete_zh_TW.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=是 diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel.jelly b/core/src/main/resources/hudson/model/Computer/sidepanel.jelly index 1d01f9468d7cb..25361242a80a3 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/Computer/sidepanel.jelly @@ -31,7 +31,7 @@ THE SOFTWARE. - + @@ -45,6 +45,8 @@ THE SOFTWARE. - + + + diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel.properties b/core/src/main/resources/hudson/model/Computer/sidepanel.properties new file mode 100644 index 0000000000000..45c837030322b --- /dev/null +++ b/core/src/main/resources/hudson/model/Computer/sidepanel.properties @@ -0,0 +1 @@ +delete.confirm=Delete the agent ‘{0}’? diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel_bg.properties b/core/src/main/resources/hudson/model/Computer/sidepanel_bg.properties index 176f68568519a..4ce72bf8b824f 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel_bg.properties +++ b/core/src/main/resources/hudson/model/Computer/sidepanel_bg.properties @@ -26,8 +26,6 @@ Build\ History=\ История на изграждането Configure=\ Настройки -Delete\ Slave=\ - Изтриване на машина Load\ Statistics=\ Статистика на натоварването Script\ Console=\ diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel_de.properties b/core/src/main/resources/hudson/model/Computer/sidepanel_de.properties index 6a44be12eab73..0dacc069729e2 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel_de.properties +++ b/core/src/main/resources/hudson/model/Computer/sidepanel_de.properties @@ -27,3 +27,4 @@ Status=Status Configure=Konfigurieren Load\ Statistics=Auslastung Delete\ Agent=Agent entfernen +delete.confirm=Agent ‘{0}’ wirklich entfernen? diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel_pt_BR.properties b/core/src/main/resources/hudson/model/Computer/sidepanel_pt_BR.properties index 1e69d185b4048..995b4d3f4e083 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Computer/sidepanel_pt_BR.properties @@ -27,3 +27,4 @@ Status=Situação Load\ Statistics=Estatísticas de carga Script\ Console=Terminal de script Delete\ Agent=Remover o agente +delete.confirm=Remover o agente ‘{0}’? diff --git a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly index 8deed1af27022..e3fe848311ecc 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly @@ -30,11 +30,14 @@ THE SOFTWARE. - + - - + + + diff --git a/core/src/main/resources/hudson/model/DirectoryBrowserSupport/dir.jelly b/core/src/main/resources/hudson/model/DirectoryBrowserSupport/dir.jelly index 1b379a30d53d6..73a64d61acde4 100644 --- a/core/src/main/resources/hudson/model/DirectoryBrowserSupport/dir.jelly +++ b/core/src/main/resources/hudson/model/DirectoryBrowserSupport/dir.jelly @@ -56,7 +56,7 @@ THE SOFTWARE.

    - + ${%Tmp directories are hidden}

    @@ -130,7 +130,7 @@ THE SOFTWARE.

    - + ${%Tmp directories are hidden}

    diff --git a/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js b/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js index 19513361e7744..7fcfa705ff738 100644 --- a/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js +++ b/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js @@ -9,42 +9,56 @@ window.buildTimeTrend_displayBuilds = function (data) { for (var x = 0; data.length > x; x++) { var e = data[x]; - var tr = new Element("tr"); - tr.insert( - new Element("td", { data: e.iconColorOrdinal }).insert( - new Element("a", { - class: "build-status-link", - href: e.number + "/console", - }).insert(generateSVGIcon(e.iconName)) - ) - ); - tr.insert( - new Element("td", { data: e.number }).insert( - new Element("a", { - href: e.number + "/", - class: "model-link inside", - }).update(e.displayName.escapeHTML()) - ) - ); - tr.insert( - new Element("td", { data: e.duration }).update( - e.durationString.escapeHTML() - ) - ); + var tr = document.createElement("tr"); + + let td = document.createElement("td"); + td.setAttribute("data", e.iconColorOrdinal); + + let link = document.createElement("a"); + link.classList.add("build-status-link"); + link.href = e.number + "/console"; + td.appendChild(link); + let svg = generateSVGIcon(e.iconName); + link.appendChild(svg); + tr.appendChild(td); + + td = document.createElement("td"); + td.setAttribute("data", e.number); + + link = document.createElement("a"); + link.href = e.number + "/"; + link.classList.add("model-link", "inside"); + link.innerText = escapeHTML(e.displayName); + + td.appendChild(link); + tr.appendChild(td); + + td = document.createElement("td"); + td.setAttribute("data", e.duration); + + td.innerText = escapeHTML(e.durationString); + + tr.appendChild(td); if (isDistributedBuildsEnabled) { var buildInfo = null; - var buildInfoStr = (e.builtOnStr || "").escapeHTML(); + var buildInfoStr = escapeHTML(e.builtOnStr || ""); if (e.builtOn) { - buildInfo = new Element("a", { - href: rootURL + "/computer/" + e.builtOn, - class: "model-link inside", - }).update(buildInfoStr); + buildInfo = document.createElement("a"); + buildInfo.href = rootURL + "/computer/" + e.builtOn; + buildInfo.classList.add("model-link", "inside"); + buildInfo.innerText = buildInfoStr; } else { buildInfo = buildInfoStr; } - tr.insert(new Element("td").update(buildInfo)); + td = document.createElement("td"); + if (buildInfo instanceof Node) { + td.appendChild(buildInfo); + } else { + td.innerText = buildInfo; + } + tr.appendChild(td); } - p.insert(tr); + p.appendChild(tr); Behaviour.applySubtree(tr); } ts_refresh(p); @@ -95,30 +109,32 @@ function generateSVGIcon(iconName, iconSizeClass) { "href", imagesURL + "/build-status/build-status-sprite.svg#build-status-" + - (isInProgress ? "in-progress" : "static") + (isInProgress ? "in-progress" : "static"), ); svg1.appendChild(use1); const svg2 = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg2.setAttribute( "class", - "svg-icon icon-" + iconName + " " + (iconSizeClass || "icon-sm") + "svg-icon icon-" + iconName + " " + (iconSizeClass || "icon-sm"), ); svg2.setAttribute("viewBox", "0 0 24 24"); const use2 = document.createElementNS("http://www.w3.org/2000/svg", "use"); use2.setAttribute( "href", - imagesURL + "/build-status/build-status-sprite.svg#" + buildStatus + imagesURL + "/build-status/build-status-sprite.svg#" + buildStatus, ); svg2.appendChild(use2); - const span = new Element("span", { - class: "build-status-icon__wrapper icon-" + iconName, - }) - .insert( - new Element("span", { class: "build-status-icon__outer" }).insert(svg1) - ) - .insert(svg2); + const span = document.createElement("span"); + span.classList.add("build-status-icon__wrapper", "icon-" + iconName); + + let span2 = document.createElement("span"); + span2.classList.add("build-status-icon__outer"); + span2.appendChild(svg1); + + span.appendChild(span2); + span.appendChild(svg2); return span; } @@ -158,7 +174,7 @@ window.displayBuilds = function (data) { "jenkins-table__link", "jenkins-table__badge", "model-link", - "inside" + "inside", ); a2.href = rootUrl + "/" + e.url; a2.textContent = e.displayName; @@ -174,7 +190,7 @@ window.displayBuilds = function (data) { "onclick", 'javascript:tl.getBand(0).scrollToCenter(Timeline.DateTime.parseGregorianDateTime("' + e.timestampString3 + - '"))' + '"))', ); button.textContent = e.timestampString; td3.appendChild(button); diff --git a/core/src/main/resources/hudson/model/Job/configure_ja.properties b/core/src/main/resources/hudson/model/Job/configure_ja.properties index 8873b4c101277..e0854b35c3ab9 100644 --- a/core/src/main/resources/hudson/model/Job/configure_ja.properties +++ b/core/src/main/resources/hudson/model/Job/configure_ja.properties @@ -1,6 +1,7 @@ # The MIT License # # Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:cactusman +# Copyright (c) 2023 Takashi Harano # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -23,5 +24,6 @@ name={0}名 Description=説明 Save=保存 +Apply=適用 LOADING=ロード中... Strategy=方針 diff --git a/core/src/main/resources/hudson/model/Job/index.jelly b/core/src/main/resources/hudson/model/Job/index.jelly index 686bb59d66410..23a454b4d52e2 100644 --- a/core/src/main/resources/hudson/model/Job/index.jelly +++ b/core/src/main/resources/hudson/model/Job/index.jelly @@ -28,7 +28,20 @@ THE SOFTWARE. -

    ${it.pronoun}

    +
    +
    + + + + + + +

    + +

    +
    +
    + diff --git a/core/src/main/resources/hudson/model/ListView/configure-entries.jelly b/core/src/main/resources/hudson/model/ListView/configure-entries.jelly index fe7be59bb14be..5cffab5e11ee0 100644 --- a/core/src/main/resources/hudson/model/ListView/configure-entries.jelly +++ b/core/src/main/resources/hudson/model/ListView/configure-entries.jelly @@ -44,7 +44,7 @@ THE SOFTWARE. - +
    diff --git a/core/src/main/resources/hudson/model/LoadStatistics/resources.js b/core/src/main/resources/hudson/model/LoadStatistics/resources.js index e53560a45245b..2ffbf37ed892e 100644 --- a/core/src/main/resources/hudson/model/LoadStatistics/resources.js +++ b/core/src/main/resources/hudson/model/LoadStatistics/resources.js @@ -29,7 +29,7 @@ if (graphLocation) { const type = timespanSelect.value; const parentSelector = graphLocation.getAttribute( - "data-graph-parent-selector" + "data-graph-parent-selector", ); const baseUrl = graphLocation.getAttribute("data-graph-base-url"); const graphAlt = graphLocation.getAttribute("data-graph-alt"); diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly b/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly index 79cadc127ca90..a345052bc588a 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly @@ -57,13 +57,14 @@ THE SOFTWARE.
    + - ${taskTags!=null and attrs.contextMenu!='false' ? it.addContextMenuItem(taskTags, m.urlName, iconSrc, iconXml, m.displayName, m.requiresPOST, m.requiresConfirmation, m.badge) : null} + ${taskTags!=null and attrs.contextMenu!='false' ? it.addContextMenuItem(taskTags, m.urlName, iconSrc, iconXml, m.displayName, m.requiresPOST, m.requiresConfirmation, m.badge, sure) : null} - + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index.properties index ffd34b83006a3..824ce770d5832 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -are.you.sure={0}: are you sure? +sure=Are you sure? diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_bg.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_bg.properties index 30dd0a083f822..a307b9924b38c 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_bg.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_bg.properties @@ -34,8 +34,6 @@ JenkinsCliText=\ Manage\ Jenkins=\ Управление на Jenkins # {0}: are you sure? -are.you.sure=\ - {0}: сигурни ли сте? Script\ Console=\ Конзола за скриптове Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut\ down\ safely.=\ diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_cs.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_cs.properties index 905a895ed63f2..9c92f62ed8a4a 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_cs.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_cs.properties @@ -42,4 +42,4 @@ System\ Information=Systém - Informace System\ Log=Systém - Log SystemLogText=Loggovací soubor systému zachycuje výstup z java.util.logging výstupu vztahujícímu se k Jenkins-u. Useful\ when\ you\ modified\ config\ files\ directly\ on\ disk.=Potřebné, pokud modifikujete konfigurační soubory přímo na disku. -are.you.sure={0}: opravdu to chcete? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_da.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_da.properties index 9a63b4bc56eab..28948380a6e18 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_da.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_da.properties @@ -25,4 +25,4 @@ Jenkins\ CLI=Jenkins CLI (kommandolinie) Manage\ Jenkins=Administrér Jenkins Manage\ Nodes=Bestyr noder Prepare\ for\ Shutdown=Forbered nedlukning -are.you.sure={0}: er du sikker? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_de.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_de.properties index 25d8abb8c42f4..5e1cebb9b5c70 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_de.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_de.properties @@ -22,4 +22,4 @@ Manage\ Jenkins=Jenkins verwalten -are.you.sure={0}: sind Sie sicher? +sure=Sind Sie sicher? diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_es.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_es.properties index 1c924cec9d436..cd300cd96f1eb 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_es.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_es.properties @@ -27,4 +27,4 @@ Manage\ Jenkins=Administrar Jenkins Reload\ Configuration\ from\ Disk=Recargar configuración desde el disco duro. Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut\ down\ safely.=Detener la ejecución de nuevas construcciones para que el sistema pueda apagarse de manera segura. SystemLogText=El log del sistema captura la salida de la clase java.util.logging en todo lo relacionado con Jenkins. -are.you.sure=estás seguro? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_et.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_et.properties index 42604525f183a..938447cc15713 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_et.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_et.properties @@ -15,4 +15,4 @@ Script\ Console=Skriptide Konsool Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut\ down\ safely.=Lõpetab uute järkude ehitamise selleks et süsteemi võiks ilma probleemideta sulgeda. System\ Information=Süsteemi informatsioon System\ Log=Süsteemi logid -are.you.sure={0}: oled kindel? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_fr.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_fr.properties index f70cc363deaae..9877014bea231 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_fr.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_fr.properties @@ -26,4 +26,4 @@ Load\ Statistics=Statistiques d’utilisation LoadStatisticsText=Vérifiez l’utilisation des ressources et décidez si vous avez besoin d’ordinateurs supplémentaires pour vos constructions. Manage\ Jenkins=Administrer Jenkins Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut\ down\ safely.=Cesser d''exécuter de nouveaux builds, afin que le système puisse se fermer. -are.you.sure={0} : êtes-vous sûr ? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_he.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_he.properties index e514992fdc83a..da17e69481470 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_he.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_he.properties @@ -34,4 +34,4 @@ Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut System\ Log=לוגים של המערכת SystemLogText=לוגים של המערכת לוכדים פלט מ-java.util.logging שקשור לג׳נקינס. Useful\ when\ you\ modified\ config\ files\ directly\ on\ disk.=שימושי כאשר עדכנת קבצי מערכת ישירות על הדיסק -are.you.sure={0}: האם אתה בטוח? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_it.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_it.properties index a6d78e32c0a38..5ab07a5298322 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_it.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_it.properties @@ -21,6 +21,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -are.you.sure={0}: procedere? alt=Testo alternativo Manage\ Jenkins=Gestisci Jenkins diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ja.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ja.properties index 5055849217f3d..0bd16c2907603 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ja.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ja.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Manage\ Jenkins=Jenkinsの管理 -are.you.sure={0}: よろしいですか? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ko.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ko.properties index 8b8335ea63e15..919addc549333 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ko.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ko.properties @@ -33,4 +33,4 @@ Script\ Console=스크립트 콘솔 Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut\ down\ safely.=새로운 빌드 SystemLogText=java.util.loggin에서 출력된 젠킨스와 롼견된 시스템 로그 Useful\ when\ you\ modified\ config\ files\ directly\ on\ disk.=디스크의 파일을 직접 변경했을 때 유용합니다. -are.you.sure=확실 합니까? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_lt.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_lt.properties index 763fa1b2e4e61..bd2167c0c592a 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_lt.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_lt.properties @@ -1,2 +1,2 @@ Manage\ Jenkins=Tvarkyti Jenkins -are.you.sure={0}: ar jūs tikri? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_nl.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_nl.properties index 39c2ffbcf19f9..19cee3dda2b8d 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_nl.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_nl.properties @@ -39,4 +39,4 @@ Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut System\ Log=Systeemlogboek SystemLogText=De uitvoer van java.util.logging voor Jenkins wordt geregistreerd. Useful\ when\ you\ modified\ config\ files\ directly\ on\ disk.=Dit is nuttig wanneer u configuratiebestanden buiten Jenkins om heeft bewerkt. -are.you.sure={0}: weet u het zeker? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pl.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pl.properties index 66669fa38818b..7dd9ec5a92823 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pl.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pl.properties @@ -21,5 +21,4 @@ # THE SOFTWARE. Manage\ Jenkins=Zarządzaj Jenkinsem -are.you.sure={0}: czy jesteś pewien? Search\ settings=Szukaj ustawień diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pt_BR.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pt_BR.properties index e264c8e7a0f1f..7ef6501d4487f 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pt_BR.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_pt_BR.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Manage\ Jenkins=Gerenciar o Jenkins -are.you.sure={0}: tem certeza? +sure=Tem certeza? diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ru.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ru.properties index e25f6847fc701..daa0c47755ea7 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ru.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_ru.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Manage\ Jenkins=Настройка Jenkins -are.you.sure={0}: вы уверены? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sk.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sk.properties index ab9750511ff5f..d917ba47ad630 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sk.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sk.properties @@ -23,4 +23,4 @@ Load\ Statistics=Štatistiky zaťaženia Manage\ Jenkins=Spravovať Jenkins Manage\ Nodes=Spravovať uzly -are.you.sure={0}: si si istý? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sr.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sr.properties index 31ace6e8ca9b2..dccaeed249d2a 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sr.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sr.properties @@ -2,7 +2,6 @@ Configure\ System=Постави системска подешавања Manage\ Jenkins=Управљање Jenkins-ом -are.you.sure={0}: дали сте сигурни? Add,\ remove,\ control\ and\ monitor\ the\ various\ nodes\ that\ Jenkins\ runs\ jobs\ on.=Додајте, уклоните, и наджиравај машинама Jenkins\ CLI=Jenkins са командне линије Cancel\ Shutdown=Откажи гашење diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sv_SE.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sv_SE.properties index b9838d5642e4b..d98edf9466f60 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sv_SE.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_sv_SE.properties @@ -26,4 +26,4 @@ Configure\ System=Konfigurera Systemet Jenkins\ CLI=Jenkins Kommandsradstolk Manage\ Jenkins=Hantera Jenkins Stops\ executing\ new\ builds,\ so\ that\ the\ system\ can\ be\ eventually\ shut\ down\ safely.=Sluta starta nya byggen, så att systemet sedan kan stängas säkert. -are.you.sure={0}: är du säker? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_tr.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_tr.properties index 8ce1897f763a9..6b1e4c494f2e5 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_tr.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_tr.properties @@ -22,4 +22,4 @@ Manage\ Jenkins=Jenkins''i Yönet Search\ settings=Ayarlar içinde ara -are.you.sure={0}: emin misin? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_uk.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_uk.properties index 36f156bb79f4c..21599a7071ed3 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_uk.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_uk.properties @@ -38,4 +38,4 @@ System\ Information=Відомості про систему System\ Log=Системний лог SystemLogText=Системний журнал фіксує вивід даних з java.util.logging пов''язаних з Дженкінс. Useful\ when\ you\ modified\ config\ files\ directly\ on\ disk.=Корисно якщо ви модифікуєте конфігураційні файли прямо на диску -are.you.sure={0}: Ви впевнені? + diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_zh_TW.properties b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_zh_TW.properties index 14e9fb141560b..9ccaf5fc7e9ec 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index_zh_TW.properties +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index_zh_TW.properties @@ -20,7 +20,6 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -are.you.sure={0}\: 您確定嗎? Manage\ Jenkins=管理 Jenkins Configure\ System=設定系統 Configure\ global\ settings\ and\ paths.=設定全域設定值及路徑。 diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index a14216ffe0f8c..ebe77e965edce 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -288,10 +288,10 @@ UpdateCenter.Status.CheckingJavaNet=Checking update center connectivity UpdateCenter.Status.Success=Success UpdateCenter.Status.UnknownHostException=\ Failed to resolve host name {0}. \ - Perhaps you need to configure HTTP proxy? + Perhaps you need to configure HTTP proxy? UpdateCenter.Status.ConnectionFailed=\ Failed to connect to {0}. \ - Perhaps you need to configure HTTP proxy? + Perhaps you need to configure HTTP proxy? UpdateCenter.init=Initialing update center UpdateCenter.CoreUpdateMonitor.DisplayName=Jenkins Update Notification @@ -407,7 +407,7 @@ Jenkins.IsRestarting=Jenkins is restarting User.IllegalUsername="{0}" is prohibited as a username for security reasons. User.IllegalFullname="{0}" is prohibited as a full name for security reasons. -TimeZoneProperty.DisplayName=User Defined Time Zone +TimeZoneProperty.DisplayName=User Defined Time Zone TimeZoneProperty.DisplayDefaultTimeZone=Default TimeZoneProperty.current_time_in_=Current time in {0}: {1} TimeZoneProperty.current_time_on_server_in_in_proposed_di=Current time on server in {0}: {1}; in proposed display zone: {2} diff --git a/core/src/main/resources/hudson/model/Messages_bg.properties b/core/src/main/resources/hudson/model/Messages_bg.properties index 89de5dfca1a76..9e1eb7b0b9681 100644 --- a/core/src/main/resources/hudson/model/Messages_bg.properties +++ b/core/src/main/resources/hudson/model/Messages_bg.properties @@ -400,10 +400,10 @@ UpdateCenter.Status.Success=\ Успех UpdateCenter.Status.UnknownHostException=\ Неуспешна проверка на адреса „{0}“.\ - Вероятно трябва да настроите\ + Вероятно трябва да настроите\ сървър-посредник за HTTP. UpdateCenter.Status.ConnectionFailed=\ - Вероятно трябва да настроите\ + Вероятно трябва да настроите\ сървър-посредник за HTTP. UpdateCenter.init=\ Инициализиране на центъра за обновяване diff --git a/core/src/main/resources/hudson/model/Messages_de.properties b/core/src/main/resources/hudson/model/Messages_de.properties index 886cc0dce8a56..1a413b4822bb7 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -291,10 +291,10 @@ UpdateCenter.Status.CheckingJavaNet=Überprüfe Zugang zu jenkins-ci.org-Server UpdateCenter.Status.Success=Erfolgreich UpdateCenter.Status.UnknownHostException=\ Hostname {0} konnte nicht aufgelöst werden. \ - Eventuell sollten Sie einen HTTP-Proxy konfigurieren? + Eventuell sollten Sie einen HTTP-Proxy konfigurieren? UpdateCenter.Status.ConnectionFailed=\ Es konnte keine Verbindung zu {0} aufgebaut werden. \ - Eventuell sollten Sie einen HTTP-Proxy konfigurieren? + Eventuell sollten Sie einen HTTP-Proxy konfigurieren? UpdateCenter.init=Initialisiere das Update Center UpdateCenter.CoreUpdateMonitor.DisplayName=Jenkins-Update-Benachrichtigungen UpdateCenter.DisplayName=Update-Center diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index c9e17aa5e7574..3037740893a2f 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -176,10 +176,10 @@ UpdateCenter.Status.CheckingJavaNet=Probando conectividad con jenkins-ci.org UpdateCenter.Status.Success=Correcto UpdateCenter.Status.UnknownHostException=\ Nombre de servidor imposible de resolver {0}. \ - Quizás tengas que configurar to proxy + Quizás tengas que configurar to proxy UpdateCenter.Status.ConnectionFailed=\ Imposible de conectar con {0}. \ - Quizás tengas que configurar to proxy + Quizás tengas que configurar to proxy UpdateCenter.init=Inicializando centro de actualizaciones UpdateCenter.PluginCategory.builder=Plugins relacionados con la forma de ejecutar trabajos UpdateCenter.PluginCategory.buildwrapper=Plugins que añaden tareas relacionadas con la ejecución diff --git a/core/src/main/resources/hudson/model/Messages_fr.properties b/core/src/main/resources/hudson/model/Messages_fr.properties index fb3765371852c..14600f22b3f7f 100644 --- a/core/src/main/resources/hudson/model/Messages_fr.properties +++ b/core/src/main/resources/hudson/model/Messages_fr.properties @@ -135,10 +135,10 @@ UpdateCenter.Status.CheckingJavaNet=Vérification de la connexion à jenkins-ci. UpdateCenter.Status.Success=Succès UpdateCenter.Status.UnknownHostException=\ Impossible de résoudre le nom de host {0}. \ - Peut-être devez-vous configurer un proxy HTTP? + Peut-être devez-vous configurer un proxy HTTP? UpdateCenter.Status.ConnectionFailed=\ Echec lors de la connexion à {0}. \ - Peut-être devez-vous configurer le proxy HTTP. + Peut-être devez-vous configurer le proxy HTTP. Permalink.LastBuild=Dernier build Permalink.LastStableBuild=Dernier build stable diff --git a/core/src/main/resources/hudson/model/Messages_it.properties b/core/src/main/resources/hudson/model/Messages_it.properties index cf9432db79b95..63a9962e8ec90 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -437,11 +437,11 @@ UpdateCenter.Status.CheckingJavaNet=Controllo connettività al Centro \ aggiornamenti in corso UpdateCenter.Status.ConnectionFailed=Impossibile \ connettersi a {0}. Forse è necessario \ - configurare il proxy HTTP? + configurare il proxy HTTP? UpdateCenter.Status.Success=Operazione completata UpdateCenter.Status.UnknownHostException=Impossibile \ risolvere il nome host {0}. Forse è necessario \ - configurare il proxy HTTP? + configurare il proxy HTTP? User.IllegalFullname="{0}" è vietato come nome completo per motivi di sicurezza. User.IllegalUsername="{0}" è vietato come nome utente per motivi di sicurezza. View.ConfigurePermission.Description=Questo permesso consente agli utenti di \ diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index fd1b28f90cee9..709195b8df238 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -215,10 +215,10 @@ UpdateCenter.Status.CheckingJavaNet=jenkins-ci.orgとの接続をチェックし UpdateCenter.Status.Success=成功 UpdateCenter.Status.UnknownHostException=\ ホスト名 {0}の解決に失敗しました。 \ - たぶん、HTTPプロクシーを設定する必要があります。 + たぶん、HTTPプロクシーを設定する必要があります。 UpdateCenter.Status.ConnectionFailed=\ {0} との接続に失敗しました。 \ - たぶん、HTTPプロクシーを設定する必要があります。 + たぶん、HTTPプロクシーを設定する必要があります。 UpdateCenter.init=アップデートセンターの初期化中 UpdateCenter.PluginCategory.builder=ビルドツール UpdateCenter.PluginCategory.buildwrapper=ビルドラッパー diff --git a/core/src/main/resources/hudson/model/Messages_lt.properties b/core/src/main/resources/hudson/model/Messages_lt.properties index 93bcd224d29c4..60ff2702330d7 100644 --- a/core/src/main/resources/hudson/model/Messages_lt.properties +++ b/core/src/main/resources/hudson/model/Messages_lt.properties @@ -234,10 +234,10 @@ UpdateCenter.Status.CheckingJavaNet=Tikrinamas prisijungimas prie atnaujinimų c UpdateCenter.Status.Success=Sėkmė UpdateCenter.Status.UnknownHostException=\ Nepavyko išspręsti stoties pavadinimo {0}. \ - Gal jums reikia sukonfigūruoti HTTP šliuzą? + Gal jums reikia sukonfigūruoti HTTP šliuzą? UpdateCenter.Status.ConnectionFailed=\ Nepavyko prisijungti prie {0}. \ - Gal jums reikia sukonfigūruoti HTTP šliuzą? + Gal jums reikia sukonfigūruoti HTTP šliuzą? UpdateCenter.init=Inicializuojamas atnaujinimų centras UpdateCenter.PluginCategory.android=Android kūrimas UpdateCenter.PluginCategory.builder=Kūrimo įrankiai diff --git a/core/src/main/resources/hudson/model/Messages_pt_BR.properties b/core/src/main/resources/hudson/model/Messages_pt_BR.properties index 335e1d298f716..70f756a9a09df 100644 --- a/core/src/main/resources/hudson/model/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Messages_pt_BR.properties @@ -132,7 +132,7 @@ Slave.Remote.Director.Mandatory=Diretório remoto é obrigatório Run.InProgressDuration={0} e contando UpdateCenter.Status.UnknownHostException=\ Erro ao resolver o nome do hospedeiro {0}. \ - Talvez você precise configurar um proxy HTTP? + Talvez você precise configurar um proxy HTTP? Hudson.NotUsesUTF8ToDecodeURL=não use caracteres UTF-8 nas URLs UpdateCenter.Status.CheckingInternet=Checando conexão com a Internet View.DeletePermission.Description=\ @@ -203,7 +203,7 @@ Hudson.NotANegativeNumber=Número não negativo UpdateCenter.PluginCategory.misc=Diversos UpdateCenter.Status.ConnectionFailed=\ Erro ao conectar em {0}. \ - Talvez voê precise configurar um proxy HTTP? + Talvez voê precise configurar um proxy HTTP? UpdateCenter.PluginCategory.maven=Maven UpdateCenter.PluginCategory.upload=Carregadores de artefatos Permalink.LastUnstableBuild=Última construção instável diff --git a/core/src/main/resources/hudson/model/Messages_sr.properties b/core/src/main/resources/hudson/model/Messages_sr.properties index 5afaf342d29f1..31b872a8ccf09 100644 --- a/core/src/main/resources/hudson/model/Messages_sr.properties +++ b/core/src/main/resources/hudson/model/Messages_sr.properties @@ -201,9 +201,9 @@ UpdateCenter.Status.CheckingInternet=Провера везом са интерн UpdateCenter.Status.CheckingJavaNet=Провера везом са центар за aжурирање UpdateCenter.Status.Success=Успех UpdateCenter.Status.UnknownHostException=Неуспешна провера адресе {0}. \ -Можда морате поставити HTTP proxy? +Можда морате поставити HTTP proxy? UpdateCenter.Status.ConnectionFailed=Неуспешно повезивање са {0}. \ -Можда морате поставити HTTP proxy? +Можда морате поставити HTTP proxy? UpdateCenter.init=Инициализација центра за ажурирање UpdateCenter.PluginCategory.builder=Алати за изградњу UpdateCenter.PluginCategory.buildwrapper=Скрипт омотачи за изградњу diff --git a/core/src/main/resources/hudson/model/Messages_zh_TW.properties b/core/src/main/resources/hudson/model/Messages_zh_TW.properties index ee910ee054794..a87d2b59afb5a 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_TW.properties @@ -214,10 +214,10 @@ UpdateCenter.Status.CheckingJavaNet=檢查是否能連到更新中心 UpdateCenter.Status.Success=成功 UpdateCenter.Status.UnknownHostException=\ 無法解析主機名稱 {0}。\ - 說不定您應該要設定 HTTP 代理伺服器? + 說不定您應該要設定 HTTP 代理伺服器? UpdateCenter.Status.ConnectionFailed=\ 無法連線到{0}。\ - 說不定您應該要設定 HTTP 代理伺服器? + 說不定您應該要設定 HTTP 代理伺服器? UpdateCenter.init=初始化更新中心 UpdateCenter.PluginCategory.builder=建置工具 UpdateCenter.PluginCategory.buildwrapper=建置包裝程式 diff --git a/core/src/main/resources/hudson/model/ParametersAction/index.jelly b/core/src/main/resources/hudson/model/ParametersAction/index.jelly index ae4fadf983b0a..a035793cfab3e 100644 --- a/core/src/main/resources/hudson/model/ParametersAction/index.jelly +++ b/core/src/main/resources/hudson/model/ParametersAction/index.jelly @@ -23,34 +23,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> - - + + + - + - - -

    ${%Build} ${build.displayName}

    -
    -
    -
    ${%Parameters}
    -
    -
    ${%Name}
    - - - - - - -
    - - - -
    + + + ${title} + + + + +
    diff --git a/core/src/main/resources/hudson/model/Run/_delete-retry.js b/core/src/main/resources/hudson/model/Run/_delete-retry.js new file mode 100644 index 0000000000000..3bf44a7b047d5 --- /dev/null +++ b/core/src/main/resources/hudson/model/Run/_delete-retry.js @@ -0,0 +1,6 @@ +document + .getElementById("delete-retry-show-error") + .addEventListener("click", function (e) { + e.preventDefault(); + document.getElementById("delete-error").style.display = "block"; + }); diff --git a/core/src/main/resources/hudson/model/Run/delete-retry.jelly b/core/src/main/resources/hudson/model/Run/delete-retry.jelly index ee45ea3219801..79dfa6beedf3b 100644 --- a/core/src/main/resources/hudson/model/Run/delete-retry.jelly +++ b/core/src/main/resources/hudson/model/Run/delete-retry.jelly @@ -14,7 +14,8 @@ - ${%Show reason} + ${%Show reason} + -

    - + +

    - -

    +

    + diff --git a/core/src/main/resources/hudson/model/UpdateCenter/index.jelly b/core/src/main/resources/hudson/model/UpdateCenter/index.jelly index 2a37c46143eef..feffecd43ae48 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/index.jelly +++ b/core/src/main/resources/hudson/model/UpdateCenter/index.jelly @@ -30,6 +30,7 @@ THE SOFTWARE. +

    ${%Download progress}

    diff --git a/core/src/main/resources/hudson/model/UpdateCenter/update-center.js b/core/src/main/resources/hudson/model/UpdateCenter/update-center.js index 9f086aca848c3..aa426cb9adfaa 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/update-center.js +++ b/core/src/main/resources/hudson/model/UpdateCenter/update-center.js @@ -9,38 +9,46 @@ Behaviour.specify( crumb.appendToForm(form); form.submit(); }); - } + }, ); function refresh() { window.setTimeout(function () { - new Ajax.Request("./body", { - onSuccess: function (rsp) { - var div = document.createElement("div"); - div.innerHTML = rsp.responseText; + fetch("./body", { + method: "post", + headers: crumb.wrap({}), + }).then((rsp) => { + if (rsp.ok) { + rsp.text().then((responseText) => { + var div = document.createElement("div"); + div.innerHTML = responseText; - var rows = div.children[0].rows; - for (var i = 0; i < rows.length; i++) { - var row = rows[i]; - var target = document.getElementById(row.id); - if (target == null) { - document.getElementById("log").appendChild(row); - } else { - var tcell = target.cells[1]; - var scell = row.cells[1]; - if (scell.id != tcell.id) { - tcell.innerHTML = scell.innerHTML; - tcell.id = scell.id; + var rows = div.children[0].rows; + for (var i = 0; i < rows.length; i++) { + var row = rows[i]; + var target = document.getElementById(row.id); + if (target == null) { + document.getElementById("log").appendChild(row); + } else { + var tcell = target.cells[1]; + var scell = row.cells[1]; + if (scell.id !== tcell.id) { + tcell.innerHTML = scell.innerHTML; + tcell.id = scell.id; + } } } - } - var scheduleDiv = document.getElementById("scheduleRestartBlock"); - scheduleDiv.innerHTML = div.lastElementChild.innerHTML; - Behaviour.applySubtree(scheduleDiv); - refresh(); - }, + var scheduleDiv = document.getElementById("scheduleRestartBlock"); + scheduleDiv.innerHTML = div.lastElementChild.innerHTML; + // we need to call applySubtree for parentNode so that click listeners for "Details" + // button in Failure/status.jelly are added as buttons get rendered + Behaviour.applySubtree(scheduleDiv.parentNode); + refresh(); + }); + } }); }, 5000); } + window.scrollTo(0, 10000); refresh(); diff --git a/core/src/main/resources/hudson/model/User/delete.properties b/core/src/main/resources/hudson/model/User/delete.properties deleted file mode 100644 index bbfbbddef3d96..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete.properties +++ /dev/null @@ -1 +0,0 @@ -delete.user=Delete Jenkins user ‘{0}’? diff --git a/core/src/main/resources/hudson/model/User/delete_bg.properties b/core/src/main/resources/hudson/model/User/delete_bg.properties deleted file mode 100644 index b013dc42154f9..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_bg.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2015, 2016, Alexander Shopov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ user\ from\ Jenkins?=\ - Сигурни ли сте, че искате да изтриете потребителя от Jenkins? -Yes=\ - Да diff --git a/core/src/main/resources/hudson/model/User/delete_da.properties b/core/src/main/resources/hudson/model/User/delete_da.properties deleted file mode 100644 index 20aeedde18da9..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_da.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Ja -delete.user=Er du sikker på at du vil slette brugeren fra Jenkins? ({0}) - diff --git a/core/src/main/resources/hudson/model/User/delete_de.properties b/core/src/main/resources/hudson/model/User/delete_de.properties deleted file mode 100644 index d4c26fcb79520..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_de.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ user\ from\ Jenkins?=\ - Möchten Sie den Benutzer wirklich löschen? -Yes=Ja diff --git a/core/src/main/resources/hudson/model/User/delete_es.properties b/core/src/main/resources/hudson/model/User/delete_es.properties deleted file mode 100644 index 8d148da53bcbd..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_es.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.user=¿Estás seguro de querer borrar el usuario de Jenkins? ({0}) - -Yes=Sí diff --git a/core/src/main/resources/hudson/model/User/delete_fr.properties b/core/src/main/resources/hudson/model/User/delete_fr.properties deleted file mode 100644 index 7e7f6b1f302a8..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_fr.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.user=Êtes-vous sûr de vouloir supprimer cet utilisateur de Jenkins? ({0}) - -Yes=Oui diff --git a/core/src/main/resources/hudson/model/User/delete_it.properties b/core/src/main/resources/hudson/model/User/delete_it.properties deleted file mode 100644 index 9be78c0d0e6c5..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.user=Eliminare l''utente Jenkins "{0}"? -Yes=Sì diff --git a/core/src/main/resources/hudson/model/User/delete_ja.properties b/core/src/main/resources/hudson/model/User/delete_ja.properties deleted file mode 100644 index 9a68545e6d735..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_ja.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ user\ from\ Jenkins?=\ - Jenkinsからユーザーを削除してもよろしいですか。 -Yes=はい diff --git a/core/src/main/resources/hudson/model/User/delete_pt_BR.properties b/core/src/main/resources/hudson/model/User/delete_pt_BR.properties deleted file mode 100644 index 7d7462470144c..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_pt_BR.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva, Fernando Boaglio -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Sim -delete.user=Tem certeza que deseja excluir esse usuário do Jenkins? ({0}) - diff --git a/core/src/main/resources/hudson/model/User/delete_ru.properties b/core/src/main/resources/hudson/model/User/delete_ru.properties deleted file mode 100644 index 4a62b5e816286..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_ru.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017, Ilia Zasimov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Да -delete.user=Вы уверены, что хотите удалить пользователя из Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/delete_sk.properties b/core/src/main/resources/hudson/model/User/delete_sk.properties deleted file mode 100644 index e7aa2a9344ed8..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_sk.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This file is under the MIT License by authors - -delete.user=Ste si istý vymazaním používateľa z Jenkins? ({0}) - -Yes=Áno diff --git a/core/src/main/resources/hudson/model/User/delete_sr.properties b/core/src/main/resources/hudson/model/User/delete_sr.properties deleted file mode 100644 index 1ff93ad49a105..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_sr.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This file is under the MIT License by authors - -delete.user=Да ли желите да уклоните корисника са Jenkins? ({0}) - -Yes=Да diff --git a/core/src/main/resources/hudson/model/User/delete_zh_TW.properties b/core/src/main/resources/hudson/model/User/delete_zh_TW.properties deleted file mode 100644 index 8d5ee52abea90..0000000000000 --- a/core/src/main/resources/hudson/model/User/delete_zh_TW.properties +++ /dev/null @@ -1,2 +0,0 @@ -delete.user=您確定要刪除 Jenkins 使用者「{0}」嗎? -Yes=是 diff --git a/core/src/main/resources/hudson/model/User/sidepanel.jelly b/core/src/main/resources/hudson/model/User/sidepanel.jelly index c92a0f5f228c5..ecc6ff014cbe1 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/User/sidepanel.jelly @@ -38,7 +38,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/User/sidepanel.properties b/core/src/main/resources/hudson/model/User/sidepanel.properties new file mode 100644 index 0000000000000..f0b727d659603 --- /dev/null +++ b/core/src/main/resources/hudson/model/User/sidepanel.properties @@ -0,0 +1 @@ +delete.user=Delete Jenkins user ‘{0}’? \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/User/sidepanel_da.properties b/core/src/main/resources/hudson/model/User/sidepanel_da.properties index 113a436aac166..078bfa8b51194 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_da.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_da.properties @@ -26,3 +26,4 @@ Delete=Slet People=Personer Builds=Byg My\ Views=Mine Views +delete.user=Er du sikker p at du vil slette brugeren fra Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_de.properties b/core/src/main/resources/hudson/model/User/sidepanel_de.properties index d8655d23594a9..77dd23c9c29c6 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_de.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_de.properties @@ -25,3 +25,4 @@ Status=Status Builds=Builds Configure=Einstellungen Delete=Löschen +delete.user=Möchten Sie den Benutzer ‘{0}’ wirklich löschen? diff --git a/core/src/main/resources/hudson/model/User/sidepanel_es.properties b/core/src/main/resources/hudson/model/User/sidepanel_es.properties index b5102edbaf843..0ce0a5059ba46 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_es.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_es.properties @@ -26,3 +26,4 @@ Builds=Ejecuciones My\ Views=Mi vista Configure=Configurar Delete=Borrar +delete.user=Ests seguro de querer borrar el usuario de Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_fr.properties b/core/src/main/resources/hudson/model/User/sidepanel_fr.properties index 26fd838834dd8..0f8d3ec6f5da0 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_fr.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_fr.properties @@ -26,3 +26,4 @@ My\ Views=Mes Vues Status=Statut Builds=Constructions Configure=Configurer +delete.user=tes-vous sr de vouloir supprimer cet utilisateur de Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_it.properties b/core/src/main/resources/hudson/model/User/sidepanel_it.properties index b6d4a45a871c1..a7bf9d514f505 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_it.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_it.properties @@ -26,3 +26,4 @@ Configure=Configura Delete=Elimina People=Persone Status=Stato +delete.user=Eliminare l''utente Jenkins "{0}"? diff --git a/core/src/main/resources/hudson/model/User/sidepanel_pt_BR.properties b/core/src/main/resources/hudson/model/User/sidepanel_pt_BR.properties index ad414f437ad2a..fcf5495ebe6b9 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_pt_BR.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_pt_BR.properties @@ -25,3 +25,4 @@ Status=Estado Builds=construções Configure=Configurar Delete=Remover +delete.user=Tem certeza que deseja excluir esse usuário do Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_ru.properties b/core/src/main/resources/hudson/model/User/sidepanel_ru.properties index 526dedc7d5eff..f8cda092d51d8 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_ru.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_ru.properties @@ -26,3 +26,4 @@ People=Пользователи Status=Статус Builds=Сборки Configure=Настроить +delete.user=Вы уверены, что хотите удалить пользователя из Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_sk.properties b/core/src/main/resources/hudson/model/User/sidepanel_sk.properties index db5f959537823..ef26159cf25db 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_sk.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_sk.properties @@ -6,3 +6,4 @@ Delete=Vymaž My\ Views=Moje Pohľadz People=Ľudia Status=Stav +delete.user=Ste si istý vymazaním používateľa z Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_sr.properties b/core/src/main/resources/hudson/model/User/sidepanel_sr.properties index d53625459d15d..184959ac80f0f 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_sr.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_sr.properties @@ -6,3 +6,4 @@ Builds=Изградњe Configure=Подешавања Delete=Уклони My\ Views=Моји прегледи +delete.user=Да ли желите да уклоните корисника са Jenkins? ({0}) diff --git a/core/src/main/resources/hudson/model/User/sidepanel_zh_TW.properties b/core/src/main/resources/hudson/model/User/sidepanel_zh_TW.properties index acbd355b89602..caf5130089974 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel_zh_TW.properties +++ b/core/src/main/resources/hudson/model/User/sidepanel_zh_TW.properties @@ -26,3 +26,4 @@ Status=狀態 Builds=建置 Configure=設定 Delete=刪除 +delete.user=您確定要刪除 Jenkins 使用者「{0}」嗎? diff --git a/core/src/main/resources/hudson/model/View/AsynchPeople/people-resources.js b/core/src/main/resources/hudson/model/View/AsynchPeople/people-resources.js index 3083edccb6f40..05a000cb037e7 100644 --- a/core/src/main/resources/hudson/model/View/AsynchPeople/people-resources.js +++ b/core/src/main/resources/hudson/model/View/AsynchPeople/people-resources.js @@ -1,6 +1,6 @@ window.display = function (data) { var p = document.getElementById("people"); - p.show(); + p.style.display = ""; var rootURL = document.head.getAttribute("data-rooturl"); for (var x = 0; data.length > x; x++) { var e = data[x]; diff --git a/core/src/main/resources/hudson/model/View/delete.jelly b/core/src/main/resources/hudson/model/View/delete.jelly deleted file mode 100644 index 81d3e71b5ec24..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete.jelly +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - -
    - ${%delete.view(it.displayName)} - - -
    -
    -
    diff --git a/core/src/main/resources/hudson/model/View/delete.properties b/core/src/main/resources/hudson/model/View/delete.properties deleted file mode 100644 index 391657e424073..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete.properties +++ /dev/null @@ -1 +0,0 @@ -delete.view=Delete the view ‘{0}’? diff --git a/core/src/main/resources/hudson/model/View/delete_bg.properties b/core/src/main/resources/hudson/model/View/delete_bg.properties deleted file mode 100644 index d84ed30e8f81a..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_bg.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, Alexander Shopov -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=\ - Да -Are\ you\ sure\ about\ deleting\ the\ view?=\ - Сигурни ли сте, че искате да изтриете изгледа? diff --git a/core/src/main/resources/hudson/model/View/delete_cs.properties b/core/src/main/resources/hudson/model/View/delete_cs.properties deleted file mode 100644 index 1107fa0d094b6..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_cs.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=Opravdu chcete smazat pohled? -Yes=Ano diff --git a/core/src/main/resources/hudson/model/View/delete_da.properties b/core/src/main/resources/hudson/model/View/delete_da.properties deleted file mode 100644 index f8719812b5aa7..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_da.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Ja -Are\ you\ sure\ about\ deleting\ the\ view?=Er du sikker pa at du vil slette visningen? diff --git a/core/src/main/resources/hudson/model/View/delete_de.properties b/core/src/main/resources/hudson/model/View/delete_de.properties deleted file mode 100644 index 2f6681e7fb5a4..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_de.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=Soll die Ansicht wirklich gelöscht werden? -Yes=Ja diff --git a/core/src/main/resources/hudson/model/View/delete_es.properties b/core/src/main/resources/hudson/model/View/delete_es.properties deleted file mode 100644 index c868f671fe16a..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_es.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=¿Estás seguro de querer borrar esta vista? -Yes=Sí diff --git a/core/src/main/resources/hudson/model/View/delete_fr.properties b/core/src/main/resources/hudson/model/View/delete_fr.properties deleted file mode 100644 index 5aa6d45f7a330..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_fr.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Oui -delete.view=Supprimer la vue ‘{0}’ ? diff --git a/core/src/main/resources/hudson/model/View/delete_it.properties b/core/src/main/resources/hudson/model/View/delete_it.properties deleted file mode 100644 index 6f969071fdea0..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.view=Eliminare la vista "{0}"? -Yes=Sì diff --git a/core/src/main/resources/hudson/model/View/delete_ja.properties b/core/src/main/resources/hudson/model/View/delete_ja.properties deleted file mode 100644 index 9b628ce34162f..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_ja.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2021, Sun Microsystems, Inc., Kohsuke Kawaguchi, Takashi Harano -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=このビューを削除しますか? -Yes=はい -delete.view=ビュー ‘{0}’ を削除しますか? diff --git a/core/src/main/resources/hudson/model/View/delete_lt.properties b/core/src/main/resources/hudson/model/View/delete_lt.properties deleted file mode 100644 index f204695efef16..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_lt.properties +++ /dev/null @@ -1,4 +0,0 @@ -# /jenkins-core/src/main/resources/hudson/model/View/delete_lt.properties - -Are\ you\ sure\ about\ deleting\ the\ view?=Ar tikrai norite ištrinti šią skiltį? -Yes=Taip diff --git a/core/src/main/resources/hudson/model/View/delete_nl.properties b/core/src/main/resources/hudson/model/View/delete_nl.properties deleted file mode 100644 index baa4c0b2fb1e5..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_nl.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=Weet u zeker dat u deze overzichtstab wilt verwijderen? -Yes=Ja diff --git a/core/src/main/resources/hudson/model/View/delete_pl.properties b/core/src/main/resources/hudson/model/View/delete_pl.properties deleted file mode 100644 index 0013a02eaaca7..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_pl.properties +++ /dev/null @@ -1,4 +0,0 @@ -# This file is under the MIT License by authors - -Are\ you\ sure\ about\ deleting\ the\ view?=Czy na pewno chcesz usunąć ten widok? -Yes=Tak diff --git a/core/src/main/resources/hudson/model/View/delete_pt_BR.properties b/core/src/main/resources/hudson/model/View/delete_pt_BR.properties deleted file mode 100644 index 7f3c9502e7cc6..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_pt_BR.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Cleiber Silva, Fernando Boaglio -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Yes=Sim -delete.view=Apagar a visão '{0}'? diff --git a/core/src/main/resources/hudson/model/View/delete_ru.properties b/core/src/main/resources/hudson/model/View/delete_ru.properties deleted file mode 100644 index f608ec34de882..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_ru.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=Вы уверены, что хотите удалить этот вид? -Yes=Да diff --git a/core/src/main/resources/hudson/model/View/delete_sr.properties b/core/src/main/resources/hudson/model/View/delete_sr.properties deleted file mode 100644 index 8735d3614f8f5..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_sr.properties +++ /dev/null @@ -1,4 +0,0 @@ -# This file is under the MIT License by authors - -Yes=Да -Are\ you\ sure\ about\ deleting\ the\ view?=Да ли желите да уклоните преглед? diff --git a/core/src/main/resources/hudson/model/View/delete_sv_SE.properties b/core/src/main/resources/hudson/model/View/delete_sv_SE.properties deleted file mode 100644 index ff647127d5422..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_sv_SE.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=Är du säker på att du vill ta bort vyn? -Yes=Ja diff --git a/core/src/main/resources/hudson/model/View/delete_tr.properties b/core/src/main/resources/hudson/model/View/delete_tr.properties deleted file mode 100644 index 703cbdea87dbe..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_tr.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -Are\ you\ sure\ about\ deleting\ the\ view?=Görüntüyü silmek istediğinize emin misiniz? -Yes=Evet diff --git a/core/src/main/resources/hudson/model/View/delete_zh_TW.properties b/core/src/main/resources/hudson/model/View/delete_zh_TW.properties deleted file mode 100644 index 66fd3c8ee3472..0000000000000 --- a/core/src/main/resources/hudson/model/View/delete_zh_TW.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -delete.view=確定要刪除視景「{0}」嗎? -Are\ you\ sure\ about\ deleting\ the\ view?=您確定要刪除這個視景嗎? -Yes=是 diff --git a/core/src/main/resources/hudson/model/View/newJob.jelly b/core/src/main/resources/hudson/model/View/newJob.jelly index 0e42579655736..fa7f08da60556 100644 --- a/core/src/main/resources/hudson/model/View/newJob.jelly +++ b/core/src/main/resources/hudson/model/View/newJob.jelly @@ -33,9 +33,7 @@ THE SOFTWARE. - + +
    diff --git a/core/src/main/resources/hudson/slaves/Cloud/configure.jelly b/core/src/main/resources/hudson/slaves/Cloud/configure.jelly new file mode 100644 index 0000000000000..3e122734d601f --- /dev/null +++ b/core/src/main/resources/hudson/slaves/Cloud/configure.jelly @@ -0,0 +1,52 @@ + + + + + + + + + +

    ${%title(it.name)}

    + + + + + + + + + + + + + + + + + +
    +
    +
    diff --git a/core/src/main/resources/hudson/slaves/Cloud/configure.properties b/core/src/main/resources/hudson/slaves/Cloud/configure.properties new file mode 100644 index 0000000000000..ab2ee7c16cc6a --- /dev/null +++ b/core/src/main/resources/hudson/slaves/Cloud/configure.properties @@ -0,0 +1 @@ +title=Cloud {0} Configuration diff --git a/core/src/main/resources/hudson/slaves/Cloud/help-name.html b/core/src/main/resources/hudson/slaves/Cloud/help-name.html new file mode 100644 index 0000000000000..53a09519ddb56 --- /dev/null +++ b/core/src/main/resources/hudson/slaves/Cloud/help-name.html @@ -0,0 +1,5 @@ +
    + Uniquely identifies this Cloud instance among other instances in Jenkins + Clouds. This is expected to be short ID-like string that does not contain any + character unsafe as variable name or URL path token. +
    diff --git a/core/src/main/resources/hudson/slaves/Cloud/index.jelly b/core/src/main/resources/hudson/slaves/Cloud/index.jelly index da3478f2e0389..84dc3a9a95629 100644 --- a/core/src/main/resources/hudson/slaves/Cloud/index.jelly +++ b/core/src/main/resources/hudson/slaves/Cloud/index.jelly @@ -25,11 +25,11 @@ THE SOFTWARE. - + -

    ${%Cloud} ${it.name}

    +

    ${%Cloud(it.name)}

    diff --git a/core/src/main/resources/hudson/slaves/Cloud/index.properties b/core/src/main/resources/hudson/slaves/Cloud/index.properties new file mode 100644 index 0000000000000..444ee764d9a37 --- /dev/null +++ b/core/src/main/resources/hudson/slaves/Cloud/index.properties @@ -0,0 +1 @@ +Cloud=Cloud {0} diff --git a/core/src/main/resources/hudson/slaves/Cloud/sidepanel.jelly b/core/src/main/resources/hudson/slaves/Cloud/sidepanel.jelly index 7a47b57953c70..551560f93d3e9 100644 --- a/core/src/main/resources/hudson/slaves/Cloud/sidepanel.jelly +++ b/core/src/main/resources/hudson/slaves/Cloud/sidepanel.jelly @@ -27,6 +27,10 @@ THE SOFTWARE. + + + diff --git a/core/src/main/resources/hudson/slaves/Cloud/sidepanel.properties b/core/src/main/resources/hudson/slaves/Cloud/sidepanel.properties new file mode 100644 index 0000000000000..146ec63bc95ae --- /dev/null +++ b/core/src/main/resources/hudson/slaves/Cloud/sidepanel.properties @@ -0,0 +1 @@ +delete.cloud=Delete the cloud ‘{0}’? diff --git a/core/src/main/resources/hudson/slaves/Cloud/sidepanel_de.properties b/core/src/main/resources/hudson/slaves/Cloud/sidepanel_de.properties new file mode 100644 index 0000000000000..b96cfa6e198f0 --- /dev/null +++ b/core/src/main/resources/hudson/slaves/Cloud/sidepanel_de.properties @@ -0,0 +1,4 @@ +Configure=Konfigurieren +View\ Configuration=Konfiguration ansehen +delete.cloud=Soll die Cloud ‘{0}’ wirklich gelöscht werden? +Delete\ Cloud=Cloud löschen diff --git a/core/src/main/resources/hudson/slaves/Messages.properties b/core/src/main/resources/hudson/slaves/Messages.properties index 5d60fadf50f9b..c25afc9473434 100644 --- a/core/src/main/resources/hudson/slaves/Messages.properties +++ b/core/src/main/resources/hudson/slaves/Messages.properties @@ -41,7 +41,8 @@ ComputerLauncher.NoJavaFound=Java version {0} was found but 1.8 or later is need ComputerLauncher.JavaVersionResult={0} -version returned {1}. ComputerLauncher.UnknownJavaVersion=Couldn’t figure out the Java version of {0} Cloud.ProvisionPermission.Description=Provision new nodes +Cloud.RequiredName=Cloud must have a unique non-empty name. JNLPLauncher.TCPPortDisabled=Either WebSocket mode is selected, or the TCP port for inbound agents must be enabled JNLPLauncher.InstanceIdentityRequired=You must install the instance-identity plugin to use inbound agents in TCP mode JNLPLauncher.WebsocketNotEnabled=WebSocket support is not enabled in this Jenkins installation -JNLPLauncher.TunnelingNotSupported=Tunneling is not supported in WebSocket mode \ No newline at end of file +JNLPLauncher.TunnelingNotSupported=Tunneling is not supported in WebSocket mode diff --git a/core/src/main/resources/hudson/slaves/SlaveComputer/sidepanel2.jelly b/core/src/main/resources/hudson/slaves/SlaveComputer/sidepanel2.jelly index 27608c2bb2da3..6d5e310952407 100644 --- a/core/src/main/resources/hudson/slaves/SlaveComputer/sidepanel2.jelly +++ b/core/src/main/resources/hudson/slaves/SlaveComputer/sidepanel2.jelly @@ -26,8 +26,8 @@ THE SOFTWARE. - - + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/tasks/BuildTrigger/config.jelly b/core/src/main/resources/hudson/tasks/BuildTrigger/config.jelly index c1b5ed907ee9c..ba23628f01863 100644 --- a/core/src/main/resources/hudson/tasks/BuildTrigger/config.jelly +++ b/core/src/main/resources/hudson/tasks/BuildTrigger/config.jelly @@ -26,7 +26,8 @@ THE SOFTWARE. diff --git a/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index.jelly b/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index.jelly index 72d28f5ceaf09..ae0175e73ed59 100644 --- a/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index.jelly +++ b/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index.jelly @@ -33,7 +33,6 @@ THE SOFTWARE.

    - ${%Recorded Fingerprints}

    diff --git a/core/src/main/resources/hudson/util/AWTProblem/index.jelly b/core/src/main/resources/hudson/util/AWTProblem/index.jelly index ec8df8e3292a3..40dcc52cde9c7 100644 --- a/core/src/main/resources/hudson/util/AWTProblem/index.jelly +++ b/core/src/main/resources/hudson/util/AWTProblem/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%errorMessage}

    diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/description.jelly b/core/src/main/resources/hudson/util/DoubleLaunchChecker/description.jelly new file mode 100644 index 0000000000000..bb405e931933b --- /dev/null +++ b/core/src/main/resources/hudson/util/DoubleLaunchChecker/description.jelly @@ -0,0 +1,4 @@ + + + ${%blurb} + diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/description.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/description.properties new file mode 100644 index 0000000000000..ee54268d61092 --- /dev/null +++ b/core/src/main/resources/hudson/util/DoubleLaunchChecker/description.properties @@ -0,0 +1 @@ +blurb = Detects if more than one Jenkins process is attempting to run in the same $JENKINS_HOME directory simultaneously. diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index.jelly b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message.jelly similarity index 86% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index.jelly rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message.jelly index cfbbda0abd359..9f7354230dbcb 100644 --- a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index.jelly +++ b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message.jelly @@ -24,13 +24,7 @@ THE SOFTWARE. - - - - - - -

    ${%Error}

    +

    ${%message(it.home)}

    @@ -45,10 +39,9 @@ THE SOFTWARE.
    -
    +
    -
    -
    +
    \ No newline at end of file diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_bg.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_bg.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_bg.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_bg.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_da.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_da.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_da.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_da.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_de.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_de.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_de.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_de.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_es.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_es.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_es.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_es.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_fr.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_fr.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_fr.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_fr.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_it.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_it.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_it.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_it.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_ja.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_ja.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_ja.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_ja.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_nl.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_nl.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_nl.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_nl.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_pt_BR.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_pt_BR.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_pt_BR.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_pt_BR.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_ru.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_ru.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_ru.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_ru.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_sr.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_sr.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_sr.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_sr.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_tr.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_tr.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_tr.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_tr.properties diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_zh_TW.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/message_zh_TW.properties similarity index 100% rename from core/src/main/resources/hudson/util/DoubleLaunchChecker/index_zh_TW.properties rename to core/src/main/resources/hudson/util/DoubleLaunchChecker/message_zh_TW.properties diff --git a/core/src/main/resources/hudson/util/HudsonFailedToLoad/index.jelly b/core/src/main/resources/hudson/util/HudsonFailedToLoad/index.jelly index 3c868da831464..8d1722acf3c44 100644 --- a/core/src/main/resources/hudson/util/HudsonFailedToLoad/index.jelly +++ b/core/src/main/resources/hudson/util/HudsonFailedToLoad/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${it.stackTraceString}
    diff --git a/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly b/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly index 63c501a8426e9..c51e37e67687a 100644 --- a/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly +++ b/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly @@ -56,6 +56,17 @@ THE SOFTWARE.

    ${%Your browser will reload automatically when Jenkins is ready.}

    + +
    +

    + ${%Safe Restart} +

    +

    + ${%Builds on agents can usually continue.} +

    +
    +
    + diff --git a/core/src/main/resources/hudson/util/HudsonIsRestarting/index_de.properties b/core/src/main/resources/hudson/util/HudsonIsRestarting/index_de.properties index 16b1bacda1f87..1750883d183d6 100644 --- a/core/src/main/resources/hudson/util/HudsonIsRestarting/index_de.properties +++ b/core/src/main/resources/hudson/util/HudsonIsRestarting/index_de.properties @@ -1,2 +1,6 @@ -Please\ wait\ while\ Jenkins\ is\ restarting=Jenkins wird neu gestartet. Bitte warten +Please\ wait\ while\ Jenkins\ is\ restarting=Jenkins wird neu gestartet. Bitte warten. Your\ browser\ will\ reload\ automatically\ when\ Jenkins\ is\ ready.=Der Webbrowser wird diese Seite automatisch neu laden, sobald Jenkins hochgefahren ist. +Safe\ Restart=Sicherer Neustart +Builds\ on\ agents\ can\ usually\ continue.=Builds auf Agenten laufen in der Regel weiter. +Restart=Neustarten +Cancel=Abbrechen \ No newline at end of file diff --git a/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index.jelly b/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index.jelly index e516ea80253c6..860dfcdecd33a 100644 --- a/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index.jelly +++ b/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%errorMessage(it.whereAntIsLoaded)}

    diff --git a/core/src/main/resources/hudson/util/IncompatibleServletVersionDetected/index.jelly b/core/src/main/resources/hudson/util/IncompatibleServletVersionDetected/index.jelly index 926a5cfd795e7..4b2a2ab7dfc6a 100644 --- a/core/src/main/resources/hudson/util/IncompatibleServletVersionDetected/index.jelly +++ b/core/src/main/resources/hudson/util/IncompatibleServletVersionDetected/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%errorMessage(it.whereServletIsLoaded)}

    diff --git a/core/src/main/resources/hudson/util/IncompatibleVMDetected/index.jelly b/core/src/main/resources/hudson/util/IncompatibleVMDetected/index.jelly index c9baaa5ce2854..d16e14c216e38 100644 --- a/core/src/main/resources/hudson/util/IncompatibleVMDetected/index.jelly +++ b/core/src/main/resources/hudson/util/IncompatibleVMDetected/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%errorMessage}

    diff --git a/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index.jelly b/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index.jelly index 0dc65cfc2836b..535f0c8ba6471 100644 --- a/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index.jelly +++ b/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%errorMessage.1}

    diff --git a/core/src/main/resources/hudson/util/Messages.properties b/core/src/main/resources/hudson/util/Messages.properties index b4c8f3325ab2b..a44fcfd5b3559 100644 --- a/core/src/main/resources/hudson/util/Messages.properties +++ b/core/src/main/resources/hudson/util/Messages.properties @@ -24,6 +24,7 @@ ClockDifference.InSync=In sync ClockDifference.Ahead={0} ahead ClockDifference.Behind={0} behind ClockDifference.Failed=Failed to check +DoubleLaunchChecker.duplicate_jenkins_checker=Duplicate Jenkins checker FormFieldValidator.did_not_manage_to_validate_may_be_too_sl=Did not manage to validate {0} (may be too slow) FormValidation.ValidateRequired=Required FormValidation.Error.Details=(show details) diff --git a/core/src/main/resources/hudson/util/NoHomeDir/index.jelly b/core/src/main/resources/hudson/util/NoHomeDir/index.jelly index 0476004a78585..d173ce128febb 100644 --- a/core/src/main/resources/hudson/util/NoHomeDir/index.jelly +++ b/core/src/main/resources/hudson/util/NoHomeDir/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%errorMessage.1(it.home)}

    diff --git a/core/src/main/resources/hudson/util/NoTempDir/index.jelly b/core/src/main/resources/hudson/util/NoTempDir/index.jelly index f6b27dcef0c3d..c8788ee5b0b45 100644 --- a/core/src/main/resources/hudson/util/NoTempDir/index.jelly +++ b/core/src/main/resources/hudson/util/NoTempDir/index.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. -

    ${%Error}

    +

    ${%Error}

    ${%description(it.tempDir)}

    ${it.stackTraceString}
    diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/icon.js b/core/src/main/resources/hudson/views/BuildButtonColumn/icon.js index 6f776158644ad..80977933eaaa8 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/icon.js +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/icon.js @@ -9,9 +9,12 @@ Behaviour.specify( var icon = document.getElementById(id); icon.onclick = function () { - new Ajax.Request(url); + fetch(url, { + method: "post", + headers: crumb.wrap({}), + }); hoverNotification(message, this, -100); return false; }; - } + }, ); diff --git a/core/src/main/resources/hudson/model/User/delete.jelly b/core/src/main/resources/jenkins/agents/CloudSet/_new.jelly similarity index 56% rename from core/src/main/resources/hudson/model/User/delete.jelly rename to core/src/main/resources/jenkins/agents/CloudSet/_new.jelly index ea3cab8ccfc6e..3ea4d00d6accf 100644 --- a/core/src/main/resources/hudson/model/User/delete.jelly +++ b/core/src/main/resources/jenkins/agents/CloudSet/_new.jelly @@ -1,7 +1,7 @@ + - - - - + + + -
    - ${%delete.user(it.displayName)} - - + +

    ${%New cloud}

    + + + + + + + + +
    +
    diff --git a/core/src/main/resources/jenkins/agents/CloudSet/index.jelly b/core/src/main/resources/jenkins/agents/CloudSet/index.jelly new file mode 100644 index 0000000000000..7678b5251326c --- /dev/null +++ b/core/src/main/resources/jenkins/agents/CloudSet/index.jelly @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + ${%newCloud} + + + + + + + + + + + + + + + + + + +
    + ${%Name} +
    +
    + +
    +
    + ${cloud.name} + +
    + + + +
    +
    +
    + +
    + + +
    + + +

    ${%noCloudAvailable}

    +
    + +

    ${%noCloudPlugin}

    +
    +
    + +
    +
    +
    +
    +
    +
    +
    diff --git a/core/src/main/resources/jenkins/agents/CloudSet/index.properties b/core/src/main/resources/jenkins/agents/CloudSet/index.properties new file mode 100644 index 0000000000000..83ebb39111e27 --- /dev/null +++ b/core/src/main/resources/jenkins/agents/CloudSet/index.properties @@ -0,0 +1,5 @@ +learnMoreDistributedBuilds=Learn more about distributed builds +noCloudAvailable=There are no clouds currently setup, create one or install a plugin for more cloud options. +noCloudPlugin=There are no cloud implementations for dynamically allocated agents installed. +newCloud=New cloud +installCloudPlugin=Install a plugin diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete.jelly b/core/src/main/resources/jenkins/agents/CloudSet/new.jelly similarity index 64% rename from core/src/main/resources/hudson/logging/LogRecorder/delete.jelly rename to core/src/main/resources/jenkins/agents/CloudSet/new.jelly index dc26149907b4c..982b500e1f490 100644 --- a/core/src/main/resources/hudson/logging/LogRecorder/delete.jelly +++ b/core/src/main/resources/jenkins/agents/CloudSet/new.jelly @@ -1,7 +1,7 @@ - - - - + + + + - -
    -

    ${%delete.logrecorder(it.displayName)}

    -
    - -
    -
    + +
    diff --git a/core/src/main/resources/jenkins/agents/Messages.properties b/core/src/main/resources/jenkins/agents/Messages.properties new file mode 100644 index 0000000000000..11a27f40642ca --- /dev/null +++ b/core/src/main/resources/jenkins/agents/Messages.properties @@ -0,0 +1,6 @@ +CloudSet.DisplayName=Clouds +CloudSet.CloudAlreadyExists=Cloud called ‘{0}’ already exists +CloudSet.SpecifyCloudToCopy=Specify which cloud to copy +CloudSet.NoSuchCloud=No such cloud: {0} +CloudsLink.DisplayName=Clouds +CloudsLink.Description=Add, remove, and configure cloud instances to provision agents on-demand. diff --git a/core/src/main/resources/jenkins/diagnostics/URICheckEncodingMonitor/adjunct.js b/core/src/main/resources/jenkins/diagnostics/URICheckEncodingMonitor/adjunct.js index 6066d3a13cc62..fda1897c03b11 100644 --- a/core/src/main/resources/jenkins/diagnostics/URICheckEncodingMonitor/adjunct.js +++ b/core/src/main/resources/jenkins/diagnostics/URICheckEncodingMonitor/adjunct.js @@ -4,10 +4,14 @@ Behaviour.specify( 0, function (element) { var url = element.getAttribute("data-url"); - var params = { value: "\u57f7\u4e8b" }; - new Ajax.Updater("URICheckEncodingMonitor-message", url, { - method: "get", - parameters: params, + var params = new URLSearchParams({ value: "\u57f7\u4e8b" }); + fetch(url + "?" + params).then((rsp) => { + rsp.text().then((responseText) => { + var message = document.getElementById( + "URICheckEncodingMonitor-message", + ); + message.innerHTML = responseText; + }); }); - } + }, ); diff --git a/core/src/main/resources/jenkins/dialogs.properties b/core/src/main/resources/jenkins/dialogs.properties new file mode 100644 index 0000000000000..b56a2bde0ea92 --- /dev/null +++ b/core/src/main/resources/jenkins/dialogs.properties @@ -0,0 +1,8 @@ +cancel=Cancel +yes=Yes +submit=Submit +no=No +add=Add +save=Save +ok=OK +apply=Apply \ No newline at end of file diff --git a/core/src/main/resources/jenkins/dialogs_de.properties b/core/src/main/resources/jenkins/dialogs_de.properties new file mode 100644 index 0000000000000..b8f79fa440b00 --- /dev/null +++ b/core/src/main/resources/jenkins/dialogs_de.properties @@ -0,0 +1,8 @@ +cancel=Abbrechen +yes=Ja +submit=Absenden +no=Nein +add=Hinzufügen +save=Speichern +ok=OK +apply=Übernehmen \ No newline at end of file diff --git a/core/src/main/resources/jenkins/install/SetupWizard/_wizard-ui.js b/core/src/main/resources/jenkins/install/SetupWizard/_wizard-ui.js new file mode 100644 index 0000000000000..d4f79462c47e5 --- /dev/null +++ b/core/src/main/resources/jenkins/install/SetupWizard/_wizard-ui.js @@ -0,0 +1,12 @@ +// all variables declared here have to be in global scope +window.defaultUpdateSiteId = (function () { + var defaultSiteId = document + .querySelector("#default-site-id") + .getAttribute("data-default-update-site-id"); + return defaultSiteId ? defaultSiteId.replace("'", "") : "default"; +})(); + +window.setupWizardExtensions = []; +window.onSetupWizardInitialized = function (extension) { + setupWizardExtensions.push(extension); +}; diff --git a/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly b/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly index 8ca66093b0e9c..8c290f10261c2 100644 --- a/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly +++ b/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token.jelly @@ -14,7 +14,6 @@ diff --git a/core/src/main/resources/lib/form/secretTextarea/secret.css b/core/src/main/resources/lib/form/secretTextarea/secret.css index cf657bab4b2a4..39d98e0bfcf75 100644 --- a/core/src/main/resources/lib/form/secretTextarea/secret.css +++ b/core/src/main/resources/lib/form/secretTextarea/secret.css @@ -65,18 +65,3 @@ border: none; padding: 1em; } - -.secret input[type="button"] { - background: #4b99d0; - background: var(--btn-primary-bg); - color: #fff; - color: var(--btn-text-color); - border-radius: 4px; - border: none; - padding: 1em 2em; -} - -.secret input[type="button"]:hover { - background: #5092be; - cursor: pointer; -} diff --git a/core/src/main/resources/lib/form/section.jelly b/core/src/main/resources/lib/form/section.jelly index 7a4383f27ef19..706920ad6ecc3 100644 --- a/core/src/main/resources/lib/form/section.jelly +++ b/core/src/main/resources/lib/form/section.jelly @@ -40,8 +40,6 @@ THE SOFTWARE. - -
    diff --git a/core/src/main/resources/lib/form/section_.js b/core/src/main/resources/lib/form/section_.js deleted file mode 100644 index 60e344fc5f09e..0000000000000 --- a/core/src/main/resources/lib/form/section_.js +++ /dev/null @@ -1,77 +0,0 @@ -window.section = (function () { - var SectionNode = function (e) { - this.section = e; - this.children = []; - }; - SectionNode.prototype = { - /** - * Points to the DIV node of the section header. - * @type {HTMLElement} - */ - section: null, - - /** - * Child sections. - * - * @type {Array} - */ - children: null, - - getHTML: function () { - return this.section.innerHTML; - }, - }; - - return { - SectionNode: SectionNode, - /** - * Builds the tree of SectionNode that represents the section hierarchy. - * - * @param {HTMLElement|string} root - * The root DOM node or its ID from which we build the tree model. - * @return {SectionNode} - * Tree structure that represents the nesting of sections. - * For root node, the 'section' property refers to null. - */ - buildTree: function (root) { - root = $(root || document.body); - - /** - * Recursively visit elements and find all visible section headers that are not inside f:repeatable elements. - * - * @param {HTMLElement} dom - * Parent element - * @param {SectionNode} parent - * Function that returns the array to which discovered section headers and child elements are added. - */ - function visitor(dom, parent) { - function isVisible(elem) { - return !!( - elem.offsetWidth || - elem.offsetHeight || - (elem.getClientRects && elem.getClientRects().length) - ); - } - - for (var e = dom.firstChild; e != null; e = e.nextSibling) { - if (e.nodeType == 1) { - if (e.className == "jenkins-section__title" && isVisible(e)) { - var child = new SectionNode(e); - - parent.children.push(child); - // The next line seems to be unnecessary, as there are no children inside the section header itself. - // So this code will always returns a flat list of section headers. - visitor(e, child); - } else if (!e.classList.contains("repeated-container")) { - visitor(e, parent); - } - } - } - } - - var top = new SectionNode(null); - visitor(root, top); - return top; - }, - }; -})(); diff --git a/core/src/main/resources/lib/form/select/select.js b/core/src/main/resources/lib/form/select/select.js index f6e96c642e7ff..3aa7e3ecc7cf9 100644 --- a/core/src/main/resources/lib/form/select/select.js +++ b/core/src/main/resources/lib/form/select/select.js @@ -4,7 +4,7 @@ function updateListBox(listBox, url, config) { config = config || {}; config = object(config); var originalOnSuccess = config.onSuccess; - var l = $(listBox); + var l = listBox; // Hacky function to retrofit compatibility with tables-to-divs // If the `); + this.dialog.appendChild(inputDiv); + this.input = inputDiv.querySelector("[data-id=input]"); + if (!this.options.allowEmpty) { + this.input.addEventListener("input", () => this.checkInput()); + } + } + + this.appendButtons(); + + this.dialog.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + e.preventDefault(); + if (this.ok.disabled == false) { + this.ok.dispatchEvent(new Event("click")); + } + } + if (e.key === "Escape") { + e.preventDefault(); + this.dialog.dispatchEvent(new Event("cancel")); + } + }); + } +}; + +Dialog.prototype.checkInput = function () { + if (this.input.value.trim()) { + this.ok.disabled = false; + } else { + this.ok.disabled = true; + } +}; + +Dialog.prototype.appendButtons = function () { + const buttons = createElementFromHtml(`
    + + +
    `); + + this.dialog.appendChild(buttons); + + this.ok = buttons.querySelector("[data-id=ok]"); + this.cancel = buttons.querySelector("[data-id=cancel]"); + if (!this.options.cancel) { + this.cancel.style.display = "none"; + } else { + this.cancel.addEventListener("click", (e) => { + e.preventDefault(); + this.dialog.dispatchEvent(new Event("cancel")); + }); + } + if (this.dialogType === "prompt" && !this.options.allowEmpty) { + this.ok.disabled = true; + } +}; + +Dialog.prototype.show = function () { + return new Promise((resolve, cancel) => { + this.dialog.showModal(); + this.dialog.addEventListener( + "cancel", + (e) => { + e.preventDefault(); + this.dialog.remove(); + cancel(); + }, + { once: true }, + ); + this.dialog.focus(); + if (this.input != null) { + this.input.focus(); + } + if (this.ok != null) { + this.ok.addEventListener( + "click", + (e) => { + if (this.dialogType === "form" && this.options.submitButton) { + this.form.submit(); + } else { + e.preventDefault(); + + let value = true; + if (this.dialogType === "prompt") { + value = this.input.value; + } + if (this.dialogType === "form") { + value = new FormData(this.form); + } + this.dialog.remove(); + resolve(value); + } + }, + { once: true }, + ); + } + }); +}; + +function init() { + window.dialog = { + modal: function (content, options) { + const defaults = { + content: content, + }; + options = Object.assign({}, defaults, options); + let dialog = new Dialog("modal", options); + dialog + .show() + .then() + .catch(() => {}); + }, + + alert: function (title, options) { + const defaults = { + title: title, + cancel: false, + }; + options = Object.assign({}, defaults, options); + let dialog = new Dialog("alert", options); + dialog + .show() + .then() + .catch(() => {}); + }, + + confirm: function (title, options) { + const defaults = { + title: title, + okText: window.dialog.translations.yes, + }; + options = Object.assign({}, defaults, options); + let dialog = new Dialog("confirm", options); + return dialog.show(); + }, + + prompt: function (title, options) { + const defaults = { + title: title, + }; + options = Object.assign({}, defaults, options); + let dialog = new Dialog("prompt", options); + return dialog.show(); + }, + + form: function (form, options) { + const defaults = { + form: form, + minWidth: "600px", + maxWidth: "900px", + submitButton: true, + okText: window.dialog.translations.submit, + }; + options = Object.assign({}, defaults, options); + let dialog = new Dialog("form", options); + return dialog.show(); + }, + }; +} + +export default { init }; diff --git a/war/src/main/js/components/dropdowns/index.js b/war/src/main/js/components/dropdowns/index.js new file mode 100644 index 0000000000000..c01fe1dc62a03 --- /dev/null +++ b/war/src/main/js/components/dropdowns/index.js @@ -0,0 +1,11 @@ +import Jumplists from "@/components/dropdowns/jumplists"; +import InpageJumplist from "@/components/dropdowns/inpage-jumplist"; +import OverflowButton from "@/components/dropdowns/overflow-button"; + +function init() { + Jumplists.init(); + InpageJumplist.init(); + OverflowButton.init(); +} + +export default { init }; diff --git a/war/src/main/js/components/dropdowns/inpage-jumplist.js b/war/src/main/js/components/dropdowns/inpage-jumplist.js new file mode 100644 index 0000000000000..d912b77330a2a --- /dev/null +++ b/war/src/main/js/components/dropdowns/inpage-jumplist.js @@ -0,0 +1,26 @@ +import { toId } from "@/util/dom"; + +/* + * Generates a jump list for the active breadcrumb to jump to + * sections on the page (if using ) + */ +function init() { + const inpageNavigationBreadcrumb = document.querySelector("#inpage-nav"); + + if (inpageNavigationBreadcrumb) { + const chevron = document.createElement("li"); + chevron.classList.add("children"); + chevron.items = Array.from( + document.querySelectorAll( + "form > div > .jenkins-section > .jenkins-section__title", + ), + ).map((section) => { + section.id = toId(section.textContent); + return { label: section.textContent, url: "#" + section.id }; + }); + + inpageNavigationBreadcrumb.after(chevron); + } +} + +export default { init }; diff --git a/war/src/main/js/components/dropdowns/jumplists.js b/war/src/main/js/components/dropdowns/jumplists.js new file mode 100644 index 0000000000000..474fe0bfde4c7 --- /dev/null +++ b/war/src/main/js/components/dropdowns/jumplists.js @@ -0,0 +1,124 @@ +import Path from "@/util/path"; +import behaviorShim from "@/util/behavior-shim"; +import Utils from "@/components/dropdowns/utils"; + +function init() { + generateJumplistAccessors(); + generateDropdowns(); +} + +/* + * Appends a ⌄ button at the end of links which support jump lists + */ +function generateJumplistAccessors() { + document.querySelectorAll("A.model-link").forEach((link) => { + const isFirefox = navigator.userAgent.indexOf("Firefox") !== -1; + // Firefox adds unwanted lines when copying buttons in text, so use a span instead + const dropdownChevron = document.createElement( + isFirefox ? "span" : "button", + ); + dropdownChevron.className = "jenkins-menu-dropdown-chevron"; + dropdownChevron.dataset.href = link.href; + dropdownChevron.addEventListener("click", (event) => { + event.preventDefault(); + }); + link.appendChild(dropdownChevron); + }); +} + +/* + * Generates the dropdowns for the jump lists + */ +function generateDropdowns() { + behaviorShim.specify( + "li.children, #menuSelector, .jenkins-menu-dropdown-chevron", + "-dropdown-", + 1000, + (element) => + Utils.generateDropdown(element, (instance) => { + const href = element.dataset.href; + const jumplistType = !element.classList.contains("children") + ? "contextMenu" + : "childrenContextMenu"; + + if (element.items) { + instance.setContent(Utils.generateDropdownItems(element.items)); + return; + } + + fetch(Path.combinePath(href, jumplistType)) + .then((response) => response.json()) + .then((json) => + instance.setContent( + Utils.generateDropdownItems( + mapChildrenItemsToDropdownItems(json.items), + ), + ), + ) + .catch((error) => console.log(`Jumplist request failed: ${error}`)) + .finally(() => (instance.loaded = true)); + }), + ); +} + +/* + * Generates the contents for the dropdown + */ +function mapChildrenItemsToDropdownItems(items) { + return items.map((item) => { + if (item.type === "HEADER") { + return { + type: "HEADER", + label: item.displayName, + }; + } + + if (item.type === "SEPARATOR") { + return { + type: "SEPARATOR", + }; + } + + return { + icon: item.icon, + iconXml: item.iconXml, + label: item.displayName, + url: item.url, + type: item.post || item.requiresConfirmation ? "button" : "link", + badge: item.badge, + onClick: () => { + if (item.post || item.requiresConfirmation) { + if (item.requiresConfirmation) { + dialog + .confirm(item.displayName, { message: item.message }) + .then(() => { + const form = document.createElement("form"); + form.setAttribute("method", item.post ? "POST" : "GET"); + form.setAttribute("action", item.url); + if (item.post) { + crumb.appendToForm(form); + } + document.body.appendChild(form); + form.submit(); + }); + } else { + fetch(item.url, { + method: "post", + headers: crumb.wrap({}), + }); + if (event.length === 1 && event[0].target != null) { + hoverNotification("Done.", event[0].target); + } + } + } + }, + subMenu: item.subMenu + ? () => { + return mapChildrenItemsToDropdownItems(item.subMenu.items); + } + : null, + }; + }); +} + +export default { init }; diff --git a/war/src/main/js/components/dropdowns/overflow-button.js b/war/src/main/js/components/dropdowns/overflow-button.js new file mode 100644 index 0000000000000..55edc6e0de221 --- /dev/null +++ b/war/src/main/js/components/dropdowns/overflow-button.js @@ -0,0 +1,20 @@ +import Utils from "@/components/dropdowns/utils"; +import behaviorShim from "@/util/behavior-shim"; + +/** + * Creates a new dropdown based on the element's next sibling + */ +function init() { + behaviorShim.specify( + "[data-dropdown='true']", + "-dropdown-", + 1000, + (element) => { + Utils.generateDropdown(element, (instance) => { + instance.setContent(element.nextElementSibling.content); + }); + }, + ); +} + +export default { init }; diff --git a/war/src/main/js/components/dropdowns/templates.js b/war/src/main/js/components/dropdowns/templates.js new file mode 100644 index 0000000000000..d20ae72674a09 --- /dev/null +++ b/war/src/main/js/components/dropdowns/templates.js @@ -0,0 +1,103 @@ +import { createElementFromHtml } from "@/util/dom"; +import { xmlEscape } from "@/util/security"; + +function dropdown() { + return { + content: "

    ", + interactive: true, + trigger: "click", + allowHTML: true, + placement: "bottom-start", + arrow: false, + theme: "dropdown", + appendTo: document.body, + offset: [0, 0], + animation: "dropdown", + onShow: (instance) => { + const referenceParent = instance.reference.parentNode; + + if (referenceParent.classList.contains("model-link")) { + referenceParent.classList.add("model-link--open"); + } + }, + onHide: (instance) => { + const referenceParent = instance.reference.parentNode; + referenceParent.classList.remove("model-link--open"); + }, + }; +} + +function menuItem(options) { + const itemOptions = Object.assign( + { + type: "link", + }, + options, + ); + + const label = xmlEscape(itemOptions.label); + let badgeText; + let badgeTooltip; + if (itemOptions.badge) { + badgeText = xmlEscape(itemOptions.badge.text); + badgeTooltip = xmlEscape(itemOptions.badge.tooltip); + } + const tag = itemOptions.type === "link" ? "a" : "button"; + + const item = createElementFromHtml(` + <${tag} class="jenkins-dropdown__item" href="${itemOptions.url}"> + ${ + itemOptions.icon + ? `
    ${ + itemOptions.iconXml + ? itemOptions.iconXml + : `${label}` + }
    ` + : `` + } + ${label} + ${ + itemOptions.badge != null + ? `${badgeText}` + : `` + } + ${ + itemOptions.subMenu != null + ? `` + : `` + } + + `); + + if (options.onClick) { + item.addEventListener("click", () => options.onClick()); + } + + return item; +} + +function heading(label) { + return createElementFromHtml( + `

    ${label}

    `, + ); +} + +function separator() { + return createElementFromHtml( + `
    `, + ); +} + +function placeholder(label) { + return createElementFromHtml( + `

    ${label}

    `, + ); +} + +export default { + dropdown, + menuItem, + heading, + separator, + placeholder, +}; diff --git a/war/src/main/js/components/dropdowns/utils.js b/war/src/main/js/components/dropdowns/utils.js new file mode 100644 index 0000000000000..8636d82befbda --- /dev/null +++ b/war/src/main/js/components/dropdowns/utils.js @@ -0,0 +1,138 @@ +import Templates from "@/components/dropdowns/templates"; +import makeKeyboardNavigable from "@/util/keyboard"; +import tippy from "tippy.js"; +import behaviorShim from "@/util/behavior-shim"; + +const SELECTED_ITEM_CLASS = "jenkins-dropdown__item--selected"; + +/* + * Generates the dropdowns for the given element + * Preloads the data on hover for speed + * @param element - the element to generate the dropdown for + * @param callback - called to retrieve the list of dropdown items + */ +function generateDropdown(element, callback) { + tippy( + element, + Object.assign({}, Templates.dropdown(), { + onCreate(instance) { + instance.reference.addEventListener("mouseenter", () => { + if (instance.loaded) { + return; + } + + instance.popper.addEventListener("click", () => { + instance.hide(); + }); + + callback(instance); + }); + }, + onShown(instance) { + behaviorShim.applySubtree(instance.popper); + }, + }), + ); +} + +/* + * Generates the contents for the dropdown + */ +function generateDropdownItems(items) { + const menuItems = document.createElement("div"); + menuItems.classList.add("jenkins-dropdown"); + + items + .map((item) => { + if (item.type === "HEADER") { + return Templates.heading(item.label); + } + + if (item.type === "SEPARATOR") { + return Templates.separator(); + } + + const menuItem = Templates.menuItem(item); + + if (item.subMenu != null) { + tippy( + menuItem, + Object.assign({}, Templates.dropdown(), { + content: generateDropdownItems(item.subMenu()), + trigger: "mouseenter", + placement: "right-start", + offset: [-8, 0], + }), + ); + } + + return menuItem; + }) + .forEach((item) => menuItems.appendChild(item)); + + if (items.length === 0) { + menuItems.appendChild(Templates.placeholder("No items")); + } + + makeKeyboardNavigable( + menuItems, + () => menuItems.querySelectorAll(".jenkins-dropdown__item"), + SELECTED_ITEM_CLASS, + (selectedItem, key) => { + switch (key) { + case "ArrowLeft": { + const root = selectedItem.closest("[data-tippy-root]"); + if (root) { + const tippyReference = root._tippy; + if (tippyReference) { + tippyReference.hide(); + } + } + break; + } + case "ArrowRight": { + const tippyRef = selectedItem._tippy; + if (!tippyRef) { + break; + } + + tippyRef.show(); + tippyRef.props.content + .querySelector(".jenkins-dropdown__item") + .classList.add(SELECTED_ITEM_CLASS); + break; + } + } + }, + (container) => { + const isVisible = + window.getComputedStyle(container).visibility === "visible"; + const isLastDropdown = Array.from( + document.querySelectorAll(".jenkins-dropdown"), + ) + .filter((dropdown) => container !== dropdown) + .filter( + (dropdown) => + window.getComputedStyle(dropdown).visibility === "visible", + ) + .every( + (dropdown) => + !( + container.compareDocumentPosition(dropdown) & + Node.DOCUMENT_POSITION_FOLLOWING + ), + ); + + return isVisible && isLastDropdown; + }, + ); + + behaviorShim.applySubtree(menuItems); + + return menuItems; +} + +export default { + generateDropdown, + generateDropdownItems, +}; diff --git a/war/src/main/js/components/modals/index.js b/war/src/main/js/components/modals/index.js deleted file mode 100644 index e8bbea2742a43..0000000000000 --- a/war/src/main/js/components/modals/index.js +++ /dev/null @@ -1,61 +0,0 @@ -import { createElementFromHtml } from "@/util/dom"; -import { CLOSE } from "@/util/symbols"; - -const defaults = { - maxWidth: undefined, - hideCloseButton: false, -}; - -export function showModal(contents, options = {}) { - options = Object.assign({}, defaults, options); - const modal = createElementFromHtml( - ` -
    -
    ` - ); - modal.style.maxWidth = options.maxWidth; - - let closeButton; - if (options.hideCloseButton !== true) { - closeButton = createElementFromHtml(` - - `); - modal.appendChild(closeButton); - closeButton.addEventListener("click", () => closeModal()); - } - - modal.querySelector("div").appendChild(contents); - - document.querySelector("body").appendChild(modal); - - modal.addEventListener("cancel", (e) => { - e.preventDefault(); - - closeModal(); - }); - - modal.addEventListener("click", function (e) { - if (e.target !== e.currentTarget) { - return; - } - - closeModal(); - }); - - function closeModal() { - modal.classList.add("jenkins-modal--hidden"); - - modal.addEventListener("webkitAnimationEnd", () => { - modal.remove(); - }); - } - - modal.showModal(); - - if (closeButton !== null) { - closeButton.blur(); - } -} diff --git a/war/src/main/js/components/notifications/index.js b/war/src/main/js/components/notifications/index.js index 8c5f784006224..eb670da192907 100644 --- a/war/src/main/js/components/notifications/index.js +++ b/war/src/main/js/components/notifications/index.js @@ -56,7 +56,7 @@ function init() { this.init(); this.div.appendChild( - createElementFromHtml(options.icon || this.defaultIcon) + createElementFromHtml(options.icon || this.defaultIcon), ); const message = this.div.appendChild(document.createElement("span")); message.appendChild(document.createTextNode(text)); diff --git a/war/src/main/js/components/row-selection-controller/index.js b/war/src/main/js/components/row-selection-controller/index.js index 395619847bbac..d4de91b89de46 100644 --- a/war/src/main/js/components/row-selection-controller/index.js +++ b/war/src/main/js/components/row-selection-controller/index.js @@ -1,15 +1,15 @@ const rowSelectionControllers = document.querySelectorAll( - ".jenkins-table__checkbox" + ".jenkins-table__checkbox", ); rowSelectionControllers.forEach((headerCheckbox) => { const table = headerCheckbox.closest(".jenkins-table"); const tableCheckboxes = table.querySelectorAll("input[type='checkbox']"); const moreOptionsButton = table.querySelector( - ".jenkins-table__checkbox-options" + ".jenkins-table__checkbox-options", ); const moreOptionsDropdown = table.querySelector( - ".jenkins-table__checkbox-dropdown" + ".jenkins-table__checkbox-dropdown", ); const moreOptionsAllButton = table.querySelector("[data-select='all']"); const moreOptionsNoneButton = table.querySelector("[data-select='none']"); @@ -23,14 +23,14 @@ rowSelectionControllers.forEach((headerCheckbox) => { const allCheckboxesSelected = () => { const selectedCheckboxes = Array.from(tableCheckboxes).filter( - (e) => e.checked + (e) => e.checked, ); return tableCheckboxes.length === selectedCheckboxes.length; }; const anyCheckboxesSelected = () => { const selectedCheckboxes = Array.from(tableCheckboxes).filter( - (e) => e.checked + (e) => e.checked, ); return selectedCheckboxes.length > 0; }; @@ -66,7 +66,7 @@ rowSelectionControllers.forEach((headerCheckbox) => { headerCheckbox.classList.remove("jenkins-table__checkbox--indeterminate"); if (moreOptionsDropdown !== null) { moreOptionsDropdown.classList.remove( - "jenkins-table__checkbox-dropdown--visible" + "jenkins-table__checkbox-dropdown--visible", ); } @@ -89,7 +89,7 @@ rowSelectionControllers.forEach((headerCheckbox) => { return; } moreOptionsDropdown.classList.remove( - "jenkins-table__checkbox-dropdown--visible" + "jenkins-table__checkbox-dropdown--visible", ); } }); @@ -97,7 +97,7 @@ rowSelectionControllers.forEach((headerCheckbox) => { if (moreOptionsButton !== null) { moreOptionsButton.addEventListener("click", () => { moreOptionsDropdown.classList.toggle( - "jenkins-table__checkbox-dropdown--visible" + "jenkins-table__checkbox-dropdown--visible", ); }); } diff --git a/war/src/main/js/components/search-bar/index.js b/war/src/main/js/components/search-bar/index.js index 3b5c89de2e98e..7b8ede4dc7045 100644 --- a/war/src/main/js/components/search-bar/index.js +++ b/war/src/main/js/components/search-bar/index.js @@ -12,11 +12,11 @@ function init() { .forEach((searchBar) => { const searchWrapper = searchBar.parentElement.parentElement; const searchResultsContainer = createElementFromHtml( - `
    ` + `
    `, ); searchWrapper.appendChild(searchResultsContainer); const searchResults = createElementFromHtml( - `
    ` + `
    `, ); searchResultsContainer.appendChild(searchResults); @@ -37,16 +37,16 @@ function init() { createElementFromHtml( `
    ${item.icon}
    ${xmlEscape(item.label)}
    ` - ) + }">
    ${item.icon}
    ${xmlEscape(item.label)}`, + ), ); }); if (results.length === 0 && container === searchResults) { container.appendChild( createElementFromHtml( - `

    No results

    ` - ) + `

    No results

    `, + ), ); } } @@ -64,13 +64,13 @@ function init() { function showResultsContainer() { searchResultsContainer.classList.add( - "jenkins-search__results-container--visible" + "jenkins-search__results-container--visible", ); } function hideResultsContainer() { searchResultsContainer.classList.remove( - "jenkins-search__results-container--visible" + "jenkins-search__results-container--visible", ); searchResultsContainer.style.height = "1px"; } @@ -84,7 +84,7 @@ function init() { makeKeyboardNavigable( searchResultsContainer, () => searchResults.querySelectorAll("a"), - SELECTED_CLASS + SELECTED_CLASS, ); // Workaround: Firefox doesn't update the dropdown height correctly so diff --git a/war/src/main/js/components/stop-button-link/index.js b/war/src/main/js/components/stop-button-link/index.js new file mode 100644 index 0000000000000..1bb34088dd997 --- /dev/null +++ b/war/src/main/js/components/stop-button-link/index.js @@ -0,0 +1,35 @@ +import behaviorShim from "@/util/behavior-shim"; + +function registerStopButton(link) { + let question = link.getAttribute("data-confirm"); + let url = link.getAttribute("href"); + link.addEventListener("click", function (e) { + e.preventDefault(); + var execute = function () { + fetch(url, { + method: "post", + headers: crumb.wrap({}), + }); + }; + if (question != null) { + dialog.confirm(question).then(() => { + execute(); + }); + } else { + execute(); + } + }); +} + +function init() { + behaviorShim.specify( + ".stop-button-link", + "stop-button-link", + 0, + (element) => { + registerStopButton(element); + }, + ); +} + +export default { init }; diff --git a/war/src/main/js/components/tooltips/index.js b/war/src/main/js/components/tooltips/index.js index 90792b240a30b..6b28e3e7f52b2 100644 --- a/war/src/main/js/components/tooltips/index.js +++ b/war/src/main/js/components/tooltips/index.js @@ -15,7 +15,7 @@ const TOOLTIP_BASE = { * @param {HTMLElement} element - Registers the tooltips for the given element */ function registerTooltip(element) { - if (element._tippy) { + if (element._tippy && element._tippy.props.theme === "tooltip") { element._tippy.destroy(); } @@ -39,8 +39,8 @@ function registerTooltip(element) { instance.reference.setAttribute("title", instance.props.content); }, }, - TOOLTIP_BASE - ) + TOOLTIP_BASE, + ), ); } @@ -57,8 +57,8 @@ function registerTooltip(element) { "true"; }, }, - TOOLTIP_BASE - ) + TOOLTIP_BASE, + ), ); } } @@ -82,8 +82,8 @@ function hoverNotification(text, element) { }, 3000); }, }, - TOOLTIP_BASE - ) + TOOLTIP_BASE, + ), ); tooltip.show(); } @@ -95,7 +95,7 @@ function init() { 1000, (element) => { registerTooltip(element); - } + }, ); window.hoverNotification = hoverNotification; diff --git a/war/src/main/js/filter-build-history.js b/war/src/main/js/filter-build-history.js index b0f4f99176b7a..05fa29d05fae0 100644 --- a/war/src/main/js/filter-build-history.js +++ b/war/src/main/js/filter-build-history.js @@ -2,10 +2,10 @@ import debounce from "lodash/debounce"; const buildHistoryContainer = document.getElementById("buildHistory"); const pageSearchInputContainer = buildHistoryContainer.querySelector( - ".build-search-row .jenkins-search" + ".build-search-row .jenkins-search", ); const pageSearchInput = buildHistoryContainer.querySelector( - ".build-search-row input" + ".build-search-row input", ); const buildHistoryPage = document.getElementById("buildHistoryPage"); const properties = document.getElementById("properties"); @@ -16,9 +16,9 @@ const noBuildsBanner = document.getElementById("no-builds"); const sidePanel = document.getElementById("side-panel"); const buildHistoryPageNav = document.getElementById("buildHistoryPageNav"); -const pageOne = buildHistoryPageNav.querySelectorAll(".pageOne")[0]; -const pageUp = buildHistoryPageNav.querySelectorAll(".pageUp")[0]; -const pageDown = buildHistoryPageNav.querySelectorAll(".pageDown")[0]; +const pageOne = buildHistoryPageNav.querySelector(".pageOne"); +const pageUp = buildHistoryPageNav.querySelector(".pageUp"); +const pageDown = buildHistoryPageNav.querySelector(".pageDown"); const leftRightPadding = 4; const updateBuildsRefreshInterval = 5000; @@ -91,7 +91,7 @@ function updateBuilds(params) { if (newDataTable.classList.contains("hasPageData")) { buildHistoryPage.setAttribute( "page-entry-newest", - newDataTable.getAttribute("page-entry-newest") + newDataTable.getAttribute("page-entry-newest"), ); } @@ -112,7 +112,7 @@ function createRefreshTimeout(params) { cancelRefreshTimeout(); buildRefreshTimeout = window.setTimeout( () => updateBuilds(params), - updateBuildsRefreshInterval + updateBuildsRefreshInterval, ); } @@ -137,25 +137,25 @@ function getOldestEntryId() { } function getDataTable(buildHistoryDiv) { - return $(buildHistoryDiv).getElementsBySelector("table.pane")[0]; + return buildHistoryDiv.querySelector("table.pane"); } function updatePageParams(dataTable) { buildHistoryPage.setAttribute( "page-has-up", - dataTable.getAttribute("page-has-up") + dataTable.getAttribute("page-has-up"), ); buildHistoryPage.setAttribute( "page-has-down", - dataTable.getAttribute("page-has-down") + dataTable.getAttribute("page-has-down"), ); buildHistoryPage.setAttribute( "page-entry-newest", - dataTable.getAttribute("page-entry-newest") + dataTable.getAttribute("page-entry-newest"), ); buildHistoryPage.setAttribute( "page-entry-oldest", - dataTable.getAttribute("page-entry-oldest") + dataTable.getAttribute("page-entry-oldest"), ); } function togglePageUpDown() { @@ -208,39 +208,31 @@ function checkRowCellOverflows(row) { return div; } function blockUnwrap(element) { - var wrapped = $(element).getElementsBySelector(".wrapped"); - for (var i = 0; i < wrapped.length; i++) { - var wrappedEl = wrapped[i]; + element.querySelectorAll(".wrapped").forEach(function (wrappedEl) { wrappedEl.parentNode.removeChild(wrappedEl); element.parentNode.insertBefore(wrappedEl, element); wrappedEl.classList.remove("wrapped"); - } + }); element.parentNode.removeChild(element); } - var buildName = $(row).getElementsBySelector(".build-name")[0]; - var buildDetails = $(row).getElementsBySelector(".build-details")[0]; + var buildName = row.querySelector(".build-name"); + var buildDetails = row.querySelector(".build-details"); if (!buildName || !buildDetails) { return; } - var buildControls = $(row).getElementsBySelector(".build-controls")[0]; - var desc; - - var descElements = $(row).getElementsBySelector(".desc"); - if (descElements.length > 0) { - desc = descElements[0]; - } + var buildControls = row.querySelector(".build-controls"); + var desc = row.querySelector(".desc"); function resetCellOverflows() { markSingleline(); // undo block wraps - var blockWraps = $(row).getElementsBySelector(".block.wrap"); - for (var i = 0; i < blockWraps.length; i++) { - blockUnwrap(blockWraps[i]); - } + row.querySelectorAll(".block.wrap").forEach(function (blockWrap) { + blockUnwrap(blockWrap); + }); buildName.classList.remove("block"); buildName.removeAttribute("style"); @@ -273,35 +265,31 @@ function checkRowCellOverflows(row) { function fitToControlsHeight(element) { if (buildControls) { if (element.clientHeight < buildControls.clientHeight) { - $(element).setStyle({ - height: buildControls.clientHeight.toString() + "px", - }); + element.style.height = buildControls.clientHeight.toString() + "px"; } } } function setBuildControlWidths() { if (buildControls) { - var buildBadge = - $(buildControls).getElementsBySelector(".build-badge")[0]; + var buildBadge = buildControls.querySelector(".build-badge"); if (buildBadge) { var buildControlsWidth = buildControls.clientWidth; var buildBadgeWidth; - var buildStop = - $(buildControls).getElementsBySelector(".build-stop")[0]; + var buildStop = buildControls.querySelector(".build-stop"); if (buildStop) { - $(buildStop).setStyle({ width: "24px" }); + buildStop.style.width = "24px"; // Minus 24 for the buildStop width, // minus 4 for left+right padding in the controls container buildBadgeWidth = buildControlsWidth - 24 - leftRightPadding; if (buildControls.classList.contains("indent-multiline")) { buildBadgeWidth = buildBadgeWidth - 20; } - $(buildBadge).setStyle({ width: buildBadgeWidth + "px" }); + buildBadge.style.width = buildBadgeWidth + "px"; } else { - $(buildBadge).setStyle({ width: "100%" }); + buildBadge.style.width = "100%"; } } controlsOverflowParams = getElementOverflowParams(buildControls); @@ -323,8 +311,7 @@ function checkRowCellOverflows(row) { var badgesOverflowing = false; var nameLessThanHalf = true; var detailsLessThanHalf = true; - var buildBadge = - $(buildControls).getElementsBySelector(".build-badge")[0]; + var buildBadge = buildControls.querySelector(".build-badge"); if (buildBadge) { var badgeOverflowParams = getElementOverflowParams(buildBadge); @@ -343,11 +330,11 @@ function checkRowCellOverflows(row) { // eslint-disable-next-line no-inner-declarations function expandLeftWithRight( leftCellOverFlowParams, - rightCellOverflowParams + rightCellOverflowParams, ) { // Float them left and right... - $(leftCellOverFlowParams.element).setStyle({ float: "left" }); - $(rightCellOverflowParams.element).setStyle({ float: "right" }); + leftCellOverFlowParams.element.style.float = "left"; + rightCellOverflowParams.element.style.float = "right"; if ( !leftCellOverFlowParams.isOverflowed && @@ -360,18 +347,16 @@ function checkRowCellOverflows(row) { leftCellOverFlowParams.isOverflowed && !rightCellOverflowParams.isOverflowed ) { - $(leftCellOverFlowParams.element).setStyle({ - width: leftCellOverFlowParams.scrollWidth + "px", - }); + leftCellOverFlowParams.element.style.width = + leftCellOverFlowParams.scrollWidth + "px"; return; } if ( !leftCellOverFlowParams.isOverflowed && rightCellOverflowParams.isOverflowed ) { - $(rightCellOverflowParams.element).setStyle({ - width: rightCellOverflowParams.scrollWidth + "px", - }); + rightCellOverflowParams.element.style.width = + rightCellOverflowParams.scrollWidth + "px"; return; } } @@ -432,7 +417,7 @@ function checkRowCellOverflows(row) { } if (buildControls && !controlsRepositioned) { - buildBadge = $(buildControls).getElementsBySelector(".build-badge")[0]; + buildBadge = buildControls.querySelector(".build-badge"); if (buildBadge) { badgeOverflowParams = getElementOverflowParams(buildBadge); @@ -563,7 +548,7 @@ document.addEventListener("DOMContentLoaded", function () { // If the build history pane is collapsed, just return immediately and don't set up // the build history refresh. - if (buildHistoryContainer.hasClassName("collapsed")) { + if (buildHistoryContainer.classList.contains("collapsed")) { return; } @@ -573,26 +558,26 @@ document.addEventListener("DOMContentLoaded", function () { checkAllRowCellOverflows(); // Show/hide the nav as the mouse moves into the sidepanel and build history. - sidePanel.observe("mouseover", function () { + sidePanel.addEventListener("mouseover", function () { buildHistoryPageNav.classList.add("mouseOverSidePanel"); }); - sidePanel.observe("mouseout", function () { + sidePanel.addEventListener("mouseout", function () { buildHistoryPageNav.classList.remove("mouseOverSidePanel"); }); - buildHistoryContainer.observe("mouseover", function () { + buildHistoryContainer.addEventListener("mouseover", function () { buildHistoryPageNav.classList.add("mouseOverSidePanelBuildHistory"); }); - buildHistoryContainer.observe("mouseout", function () { + buildHistoryContainer.addEventListener("mouseout", function () { buildHistoryPageNav.classList.remove("mouseOverSidePanelBuildHistory"); }); - pageOne.observe("click", function () { + pageOne.addEventListener("click", function () { loadPage(); }); - pageUp.observe("click", function () { + pageUp.addEventListener("click", function () { loadPage({ "newer-than": getNewestEntryId() }); }); - pageDown.observe("click", function () { + pageDown.addEventListener("click", function () { if (hasPageDown()) { cancelRefreshTimeout(); loadPage({ "older-than": getOldestEntryId() }); diff --git a/war/src/main/js/pages/dashboard/index.js b/war/src/main/js/pages/dashboard/index.js index 5fa64f489c4ca..0ead233a0f63f 100644 --- a/war/src/main/js/pages/dashboard/index.js +++ b/war/src/main/js/pages/dashboard/index.js @@ -1,14 +1,14 @@ -import { showModal } from "@/components/modals"; import { createElementFromHtml } from "@/util/dom"; document.querySelector("#button-icon-legend").addEventListener("click", () => { + const template = document.querySelector("#template-icon-legend"); + const title = template.getAttribute("data-title"); const content = createElementFromHtml( - "
    " + - document.querySelector("#template-icon-legend").innerHTML + - "
    " + "
    " + template.innerHTML + "
    ", ); - showModal(content, { + dialog.modal(content, { maxWidth: "550px", + title: title, }); }); diff --git a/war/src/main/js/pages/manage-jenkins/index.js b/war/src/main/js/pages/manage-jenkins/index.js index 55861e2d6358a..43d780a948281 100644 --- a/war/src/main/js/pages/manage-jenkins/index.js +++ b/war/src/main/js/pages/manage-jenkins/index.js @@ -5,7 +5,7 @@ searchBarInput.suggestions = function () { .map((item) => ({ url: item.querySelector("a").href, icon: item.querySelector( - ".jenkins-section__item__icon svg, .jenkins-section__item__icon img" + ".jenkins-section__item__icon svg, .jenkins-section__item__icon img", ).outerHTML, label: item.querySelector("dt").textContent, })) diff --git a/war/src/main/js/pages/register/index.js b/war/src/main/js/pages/register/index.js new file mode 100644 index 0000000000000..01864a4379d36 --- /dev/null +++ b/war/src/main/js/pages/register/index.js @@ -0,0 +1,93 @@ +import { getI18n } from "@/util/i18n"; + +const passwordField = document.querySelector("#password1"); +const password2Field = document.querySelector("#password2"); +const showPasswordField = document.querySelector("#showPassword"); +const passwordStrengthWrapper = document.querySelector( + "#passwordStrengthWrapper", +); +const passwordStrengthIndicator = document.querySelector("#passwordStrength"); + +updatePasswordStrength(); + +passwordField.addEventListener("input", updatePasswordStrength); + +function updatePasswordStrength() { + if (passwordField.value.length === 0) { + passwordStrengthWrapper.hidden = true; + return; + } + + passwordStrengthWrapper.hidden = false; + const score = passwordScore(passwordField.value); + passwordStrengthIndicator.innerText = passwordStrength(score); + passwordStrengthIndicator.style.color = passwordStrengthColor(score); + password2Field.value = passwordField.value; +} + +// Toggle password visibility +showPasswordField.addEventListener("change", () => { + if (showPasswordField.checked) { + passwordField.type = "text"; + } else { + passwordField.type = "password"; + } +}); + +function passwordScore(password) { + let score = 0; + + if (!password) { + return score; + } + + // Award every unique letter until 5 repetitions + const letters = {}; + + for (let i = 0; i < password.length; i++) { + letters[password[i]] = (letters[password[i]] || 0) + 1; + score += 5.0 / letters[password[i]]; + } + + // Bonus points for mixing it up + const variations = { + digits: /\d/.test(password), + lower: /[a-z]/.test(password), + upper: /[A-Z]/.test(password), + nonWords: /\W/.test(password), + }; + + let variationCount = 0; + for (const check in variations) { + variationCount += variations[check] === true ? 1 : 0; + } + score += (variationCount - 1) * 10; + + return score; +} + +function passwordStrength(score) { + if (score > 80) { + return getI18n("strength-strong"); + } + if (score > 60) { + return getI18n("strength-moderate"); + } + if (score >= 30) { + return getI18n("strength-weak"); + } + return getI18n("strength-poor"); +} + +function passwordStrengthColor(score) { + if (score > 80) { + return "var(--green)"; + } + if (score > 60) { + return "var(--yellow)"; + } + if (score >= 30) { + return "var(--orange)"; + } + return "var(--error-color)"; +} diff --git a/war/src/main/js/plugin-manager-ui.js b/war/src/main/js/plugin-manager-ui.js index fb4c67d840018..7ef187deae958 100644 --- a/war/src/main/js/plugin-manager-ui.js +++ b/war/src/main/js/plugin-manager-ui.js @@ -40,13 +40,15 @@ function applyFilter(searchQuery) { clearOldResults(); var rows = pluginManagerAvailable({ plugins: plugins.filter( - (plugin) => selectedPlugins.indexOf(plugin.name) === -1 + (plugin) => selectedPlugins.indexOf(plugin.name) === -1, ), admin, }); tbody.insertAdjacentHTML("beforeend", rows); - } + + updateInstallButtonState(); + }, ); } @@ -68,4 +70,39 @@ document.addEventListener("DOMContentLoaded", function () { setTimeout(function () { layoutUpdateCallback.call(); }, 350); + + // Show update center error if element exists + const updateCenterError = document.querySelector("#update-center-error"); + if (updateCenterError) { + notificationBar.show( + updateCenterError.content.textContent, + notificationBar.ERROR, + ); + } }); + +function updateInstallButtonState() { + // Enable/disable the 'Install' button depending on if any plugins are checked + const anyCheckboxesSelected = () => { + return ( + document.querySelectorAll("input[type='checkbox']:checked").length > 0 + ); + }; + const installButton = document.querySelector("#button-install"); + const installAfterRestartButton = document.querySelector( + "#button-install-after-restart", + ); + if (!anyCheckboxesSelected()) { + installButton.disabled = true; + installAfterRestartButton.disabled = true; + } + const checkboxes = document.querySelectorAll("input[type='checkbox']"); + checkboxes.forEach((checkbox) => { + checkbox.addEventListener("click", () => { + setTimeout(() => { + installButton.disabled = !anyCheckboxesSelected(); + installAfterRestartButton.disabled = !anyCheckboxesSelected(); + }); + }); + }); +} diff --git a/war/src/main/js/pluginSetupWizardGui.js b/war/src/main/js/pluginSetupWizardGui.js index 5218a33def087..7d123e39876eb 100644 --- a/war/src/main/js/pluginSetupWizardGui.js +++ b/war/src/main/js/pluginSetupWizardGui.js @@ -122,7 +122,7 @@ var createPluginSetupWizard = function (appendTarget) { if (visibleDependencies[plugName]) { return options.fn(); } - } + }, ); // wrap calls with this method to handle generic errors returned by the plugin manager @@ -235,7 +235,7 @@ var createPluginSetupWizard = function (appendTarget) { onComplete(); } }, - { dataType: "html" } + { dataType: "html" }, ); }); } else { @@ -251,8 +251,8 @@ var createPluginSetupWizard = function (appendTarget) { baseUrl: jenkins.baseUrl, jenkinsVersion: getJenkinsVersion(), }, - data - ) + data, + ), ); if (panel === currentPanel) { // just replace id-marked elements @@ -300,7 +300,7 @@ var createPluginSetupWizard = function (appendTarget) { var $modalHeader = $container.find(".modal-header"); if ($modalHeader.length > 0 && $modalHeader.is(".closeable")) { $modalHeader.prepend( - '' + '', ); } @@ -310,7 +310,7 @@ var createPluginSetupWizard = function (appendTarget) { var $modalFooter = $container.find(".modal-footer"); if ($modalFooter.length === 0) { $modalFooter = $('').appendTo( - $container + $container, ); } $modalFooter.prepend( @@ -318,7 +318,7 @@ var createPluginSetupWizard = function (appendTarget) { translations.installWizard_jenkinsVersionTitle + " " + getJenkinsVersionFull() + - "" + "", ); } @@ -402,7 +402,7 @@ var createPluginSetupWizard = function (appendTarget) { { installStatus: "pending", }, - p + p, ); installingPlugins.push(plug); } @@ -418,14 +418,14 @@ var createPluginSetupWizard = function (appendTarget) { function () { return progressPanel(arguments); }, - { installingPlugins: [] } + { installingPlugins: [] }, ); pluginManager.installPlugins( pluginNames, handleGenericError(function () { showStatePanel(); - }) + }), ); }; @@ -526,7 +526,7 @@ var createPluginSetupWizard = function (appendTarget) { pluginManager.installStatus( handleGenericError(function (data) { showStatePanel(data.state); - }) + }), ); return; } @@ -577,7 +577,7 @@ var createPluginSetupWizard = function (appendTarget) { setPanel( progressPanel, { installingPlugins: installingPlugins }, - attachScrollEvent + attachScrollEvent, ); // call to the installStatus, update progress bar & plugin details; transition on complete @@ -663,7 +663,7 @@ var createPluginSetupWizard = function (appendTarget) { $txt.append($div); var $itemProgress = $( - '.selected-plugin[id="installing-' + idIfy(j.name) + '"]' + '.selected-plugin[id="installing-' + idIfy(j.name) + '"]', ); if ($itemProgress.length > 0 && !$itemProgress.is("." + state)) { $itemProgress.addClass(state); @@ -687,7 +687,7 @@ var createPluginSetupWizard = function (appendTarget) { $(".progress-bar").css({ width: "100%" }); showStatePanel(data.state); } - }) + }), ); }; @@ -714,7 +714,7 @@ var createPluginSetupWizard = function (appendTarget) { plug.allDependencies = getAllDependencies(plug.name); } oncomplete(); - }) + }), ); }; @@ -834,7 +834,7 @@ var createPluginSetupWizard = function (appendTarget) { ? xform : function (d) { return d; - } + }, ); return elements; }; @@ -859,7 +859,7 @@ var createPluginSetupWizard = function (appendTarget) { { scrollTop: pos, }, - 100 + 100, ); setTimeout(function () { // wait for css transitions to finish @@ -868,7 +868,7 @@ var createPluginSetupWizard = function (appendTarget) { { scrollTop: pos, }, - 50 + 50, ); }, 50); } @@ -895,7 +895,7 @@ var createPluginSetupWizard = function (appendTarget) { text.toLowerCase(), function (d) { return d.toLowerCase(); - } + }, ); if (localMatches.length > 0) { matches = matches.concat(localMatches); @@ -922,7 +922,7 @@ var createPluginSetupWizard = function (appendTarget) { function () { var val = $(this).val(); searchForPlugins(val, true); - } + }, ); // handle keyboard up/down navigation between items in @@ -989,7 +989,7 @@ var createPluginSetupWizard = function (appendTarget) { function () { var top = $pl.scrollTop() + $el.position().top; $pl.stop(true).scrollTop(top); - } + }, ); }; @@ -1023,7 +1023,7 @@ var createPluginSetupWizard = function (appendTarget) { if ($main.length > 0) { responseText = responseText.replace( /body([^>]*)[>](.|[\r\n])+[<][/]body/, - "body$1>" + $main.html() + "" + $main.html() + " 0) { responseText = responseText.replace( /body([^>]*)[>](.|[\r\n])+[<][/]body/, - "body$1>" + $main.html() + "" + $main.html() + " { const headerToScrollTo = document.getElementById( - item.querySelector(".task-link").dataset.sectionId + item.querySelector(".task-link").dataset.sectionId, ); const sectionTopPosition = diff --git a/war/src/main/js/section-to-tabs.js b/war/src/main/js/section-to-tabs.js index 56d2a191cefc7..6313cc227bf53 100644 --- a/war/src/main/js/section-to-tabs.js +++ b/war/src/main/js/section-to-tabs.js @@ -25,7 +25,8 @@ tabPanes.forEach((tabPane, index) => { tab.classList.add("active"); } - tab.addEventListener("click", function () { + tab.addEventListener("click", function (e) { + e.preventDefault(); document.querySelectorAll(".tab").forEach((tab) => { tab.classList.remove("active"); }); @@ -38,6 +39,7 @@ tabPanes.forEach((tabPane, index) => { }); const tabLink = document.createElement("a"); + tabLink.setAttribute("href", "#"); tabLink.innerText = tabPaneTitle.textContent; tab.append(tabLink); diff --git a/war/src/main/js/templates/welcomePanel.hbs b/war/src/main/js/templates/welcomePanel.hbs index f6b98a3b4ab9b..556001b932e07 100644 --- a/war/src/main/js/templates/welcomePanel.hbs +++ b/war/src/main/js/templates/welcomePanel.hbs @@ -2,7 +2,6 @@