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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
<properties>
<changelist>999999-SNAPSHOT</changelist>
<spotbugs.skip>true</spotbugs.skip>
<jenkins.version>2.547</jenkins.version>
<!-- using version with garbage data fix for better stability -->
<jenkins.version>2.548-rc37921.fdf986d6fc46</jenkins.version>
<selenium.version>4.40.0</selenium.version>
<!-- aligned with selenium -->
<guava.version>33.5.0-jre</guava.version>
Expand Down Expand Up @@ -500,6 +501,10 @@ and
</systemPropertyVariables>
<!-- SUREFIRE-1588 workaround; too late for systemProperties: -->
<argLine>-Djdk.net.URLClassPath.disableClassPathURLCheck=true</argLine>
<environmentVariables>
<!-- Use local version of the plugin over the released one ATH would otherwise use -->
<LOCAL_JARS>target/credentials.hpi</LOCAL_JARS>
</environmentVariables>
Comment on lines +504 to +507
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be reverted before merge

Suggested change
<environmentVariables>
<!-- Use local version of the plugin over the released one ATH would otherwise use -->
<LOCAL_JARS>target/credentials.hpi</LOCAL_JARS>
</environmentVariables>

</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -773,6 +778,12 @@ and
<version>${jenkins.version}</version>
<type>war</type>
</artifactItem>
<artifactItem>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials</artifactId>
<version>1578.v4ea_f41d464ed</version>
<type>hpi</type>
</artifactItem>
Comment on lines +781 to +786
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be reverted before merge

Suggested change
<artifactItem>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials</artifactId>
<version>1578.v4ea_f41d464ed</version>
<type>hpi</type>
</artifactItem>

</artifactItems>
<outputDirectory>${project.build.directory}</outputDirectory>
<stripVersion>true</stripVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.jenkinsci.test.acceptance.plugins.credentials.UserPwdCredential;
import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshPrivateKeyCredential;
import org.jenkinsci.test.acceptance.po.Jenkins;
import org.junit.AssumptionViolatedException;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
Expand Down Expand Up @@ -107,19 +106,13 @@ private boolean enterCredentials(WithCredentials wp) {
* @param sshKeyPath path to the ssh key
*/
private void addSshUsernamePrivateKeyCredentials(String username, String sshKeyPath, String id) {
try {
CredentialsPage cp = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
cp.open();
SshPrivateKeyCredential sc = cp.add(SshPrivateKeyCredential.class);
sc.username.set(username);
sc.selectEnterDirectly()
.privateKey
.set(resource(sshKeyPath).asText());
maybeSetId(sc, id);
cp.create();
} catch (Exception ex) {
throw new AssumptionViolatedException("@WithCredentials requires credentials@2.0.7.", ex);
}
CredentialsPage cp = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
cp.open();
SshPrivateKeyCredential sc = cp.add(SshPrivateKeyCredential.class);
sc.username.set(username);
sc.selectEnterDirectly().privateKey.set(resource(sshKeyPath).asText());
maybeSetId(sc, id);
cp.create();
}

/**
Expand All @@ -128,17 +121,13 @@ private void addSshUsernamePrivateKeyCredentials(String username, String sshKeyP
* @param password password
*/
private void addUsernamePasswordCredentials(String username, String password, String id) {
try {
CredentialsPage c = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
c.open();
final UserPwdCredential upc = c.add(UserPwdCredential.class);
upc.username.set(username);
upc.password.set(password);
maybeSetId(upc, id);
c.create();
} catch (Exception ex) {
throw new AssumptionViolatedException("@WithCredentials requires credentials@2.0.7.", ex);
}
CredentialsPage c = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
c.open();
final UserPwdCredential upc = c.add(UserPwdCredential.class);
upc.username.set(username);
upc.password.set(password);
maybeSetId(upc, id);
c.create();
}

private void maybeSetId(BaseStandardCredentials creds, String id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ protected <T extends BaseStandardCredentials> T createCredentials(
SshPrivateKeyCredential castedCred = (SshPrivateKeyCredential) cred;
castedCred.description.set(CRED_DSCR);
if (scope != null) {
waitFor(by.option(scope));
castedCred.scope.select(scope);
}
castedCred.username.set(CRED_USER);
Expand All @@ -126,8 +127,7 @@ private void navigateToCreateCredentials() {
tryCredentialsClick();
waitFor(by.href("/user/" + CREATED_USER + "/credentials/store/user")).click();
waitFor(by.href("domain/_")).click();
waitFor(by.href("newCredentials")).click();
waitFor(by.name("_.id"));
waitFor(by.button("Add Credentials")).click();
}

private void tryCredentialsClick() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ protected Credential(PageArea area, String relativePath) {
*/
public void add() {
WebElement dialog = find(by.id("credentials-dialog-form"));
WebElement we = find(submitButton());
WebElement we = find(by.id("cr-dialog-submit"));
we.click();
// wait for the form to be removed from the UI
waitFor(driver).until(ExpectedConditions.invisibilityOf(dialog));
// the notification bar can place itslef over other elements
// the notification bar can place itself over other elements
// so wait for it to be added and then disappear
waitFor(waitFor(By.id("notification-bar"))).until(bar -> !bar.isDisplayed());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.Folder;
import org.jenkinsci.test.acceptance.po.Jenkins;
import org.jenkinsci.test.acceptance.selenium.Scroller;
import org.openqa.selenium.UnhandledAlertException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class CredentialsPage extends ConfigurablePageObject {
public final Control addButton = control(by.xpath("//select[contains(@class, 'setting-input dropdownList')] | "
Expand All @@ -22,26 +25,41 @@ public class CredentialsPage extends ConfigurablePageObject {
* Create a new Credential
*/
public CredentialsPage(Jenkins j, String domainName) {
super(j, j.url("credentials/store/system/domain/" + domainName + "/newCredentials"));
super(j, j.url("credentials/store/system/domain/" + domainName));
}

/**
* Create a new Credential scoped to a Folder
*/
public CredentialsPage(Folder f, String domainName) {
super(f, f.url("credentials/store/folder/domain/" + domainName + "/newCredentials"));
super(f, f.url("credentials/store/folder/domain/" + domainName));
}

/**
* Create a new personal Credential
*/
public CredentialsPage(Jenkins j, String domainName, String userName) {
super(j, j.url(String.format("user/%s/credentials/store/user/domain/%s/newCredentials", userName, domainName)));
super(j, j.url(String.format("user/%s/credentials/store/user/domain/%s", userName, domainName)));
}

public <T extends Credential> T add(Class<T> type) {
addButton.selectDropdownMenuAlt(type);
String path = find(by.name("credentials")).getAttribute("path");
WebElement radio = findCaption(type, caption -> {
for (WebElement webElement : all(by.css(".jenkins-choice-list__item__label"))) {
if (webElement.getText().equals(caption)) {
webElement.click();
return webElement.findElement(by.xpath("./../input"));
}
}
return null;
});

String path = radio.getAttribute("path");

WebElement nextButton = find(by.id("cr-dialog-next"));
nextButton.click();
waitFor(by.id("cr-dialog-submit"));
new Scroller(driver).disableStickyElements();

return newInstance(type, this, path);
}

Expand All @@ -56,8 +74,15 @@ public void setConfigUrl(String url) throws MalformedURLException {
}

public void create() {
find(by.name("Submit")).click();
assertThat(driver, not(hasContent("This page expects a form submission")));
find(by.id("cr-dialog-submit")).click();
try {
assertThat(driver, not(hasContent("This page expects a form submission")));
} catch (UnhandledAlertException e) {
// TODO seems to occur on at least up to 2.541.1 but doesn't occur on 2.547
// can't see what the alert is, selenium goes too fast and if you pause it there's no issue
sleep(100);
assertThat(driver, not(hasContent("This page expects a form submission")));
}
}

public void delete() {
Expand All @@ -72,9 +97,10 @@ public void delete() {
@Override
public WebDriver open() {
WebDriver wd = super.open();
// wait for default form fields to be present to avoid possible race
// condition when changing credentials type too fast (happens rarely)
waitFor(by.name("_.id"));

clickButton("Add Credentials");
// Selenium will execute the next step before the options have loaded if we don't wait for them
waitFor(by.css(".jenkins-choice-list__item__label"));
return wd;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@Describable("Secret file")
public class FileCredentials extends BaseStandardCredentials {

public Control file = control("file");
public Control file = control(by.name("file"));

public FileCredentials(PageObject context, String path) {
super(context, path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@Describable("Secret text")
public class StringCredentials extends BaseStandardCredentials {

public Control secret = control("secret");
public Control secret = control(by.name("_.secret"));

public StringCredentials(PageObject context, String path) {
super(context, path);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.jenkinsci.test.acceptance.plugins.ssh_credentials;

import org.jenkinsci.test.acceptance.plugins.credentials.BaseStandardCredentials;
import org.jenkinsci.test.acceptance.plugins.credentials.Credential;
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.PageObject;

Expand All @@ -16,19 +15,4 @@ public class SshCredentialDialog extends BaseStandardCredentials {
public SshCredentialDialog(PageObject context, String path) {
super(context, path);
}

/**
* Selects the credential type and bind the controls to the page area.
*/
public <T extends Credential> T select(Class<T> type) {

findCaption(type, new Resolver() {
@Override
protected void resolve(String caption) {
kind.select(caption);
}
});

return newInstance(type, getPage(), getPath());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

import edu.umd.cs.findbugs.annotations.CheckForNull;
import java.time.Duration;
import org.jenkinsci.test.acceptance.plugins.credentials.Credential;
import org.jenkinsci.test.acceptance.plugins.credentials.UserPwdCredential;
import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshCredentialDialog;
import org.jenkinsci.test.acceptance.plugins.ssh_credentials.SshPrivateKeyCredential;
import org.jenkinsci.test.acceptance.po.ComputerLauncher;
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.Describable;
import org.jenkinsci.test.acceptance.po.PageObject;
import org.jenkinsci.test.acceptance.selenium.Scroller;
import org.jenkinsci.test.acceptance.selenium.UselessFileDetectorReplacement;
import org.openqa.selenium.WebElement;

/**
* @author Kohsuke Kawaguchi
Expand All @@ -32,14 +34,31 @@ public SshSlaveLauncher(PageObject context, String path) {
super(context, path);
}

public SshCredentialDialog addCredential() {
public <T extends Credential> T addCredential(Class<T> type) {
find(by.button("Add")).click();

find(by.css(".jenkins-dropdown"))
.findElement(by.button("Jenkins Credentials Provider"))
.click();
find(by.css(".jenkins-dropdown")).findElement(by.button("Global")).click();

return new SshCredentialDialog(getPage(), "/credentials");
// Selenium will execute the next step before the options have loaded if we don't wait for them
waitFor(by.css(".jenkins-choice-list__item__label"));

WebElement radio = findCaption(type, caption -> {
for (WebElement webElement : all(by.css(".jenkins-choice-list__item__label"))) {
if (webElement.getText().equals(caption)) {
webElement.click();
return webElement.findElement(by.xpath("./../input"));
}
}
return null;
});

String path = radio.getAttribute("path");

WebElement nextButton = find(by.id("cr-dialog-next"));
nextButton.click();
waitFor(by.id("cr-dialog-submit"));
new Scroller(driver).disableStickyElements();
return newInstance(type, getPage(), path);
}

public void setJavaPath(String jvmPath) {
Expand All @@ -55,6 +74,8 @@ public SshSlaveLauncher port(int port) {
}

private void ensureAdvancedOpen() {
new Scroller(driver).disableStickyElements();

control("advanced-button").click();
}

Expand All @@ -66,8 +87,7 @@ private void ensureAdvancedOpen() {
* @return the SshSlaveLauncher to be configured
*/
public SshSlaveLauncher pwdCredentials(String username, String password) {
final SshCredentialDialog dia = this.addCredential();
final UserPwdCredential cred = dia.select(UserPwdCredential.class);
final UserPwdCredential cred = this.addCredential(UserPwdCredential.class);
cred.username.set(username);
cred.password.set(password);
// credentials are identified by their id. Set username as id so it can be found by it
Expand All @@ -86,8 +106,7 @@ public SshSlaveLauncher pwdCredentials(String username, String password) {
* @return the SshSlaveLauncher to be configured
*/
public SshSlaveLauncher pwdCredentials(String username, String password, String id) {
final SshCredentialDialog dia = this.addCredential();
final UserPwdCredential cred = dia.select(UserPwdCredential.class);
final UserPwdCredential cred = this.addCredential(UserPwdCredential.class);
cred.username.set(username);
cred.password.set(password);
// credentials are identified by their id.
Expand All @@ -105,8 +124,7 @@ public SshSlaveLauncher pwdCredentials(String username, String password, String
* @return the SshSlaveLauncher to be configured
*/
public SshSlaveLauncher keyCredentials(String username, String key, @CheckForNull String passphrase) {
final SshCredentialDialog dia = this.addCredential();
final SshPrivateKeyCredential cred = dia.select(SshPrivateKeyCredential.class);
final SshPrivateKeyCredential cred = this.addCredential(SshPrivateKeyCredential.class);
cred.username.set(username);
if (passphrase != null) {
cred.passphrase.set(passphrase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ const bottomAppBar = document.getElementById("bottom-sticker");
// https://github.com/jenkinsci/jenkins/commit/6481e78d20a0c689859058da5a029489e8b5072c introduced a shadow on a different div!?
const bottomShadow = document.querySelector(".jenkins-bottom-app-bar__shadow")

document.querySelectorAll(".bottom-sticker-inner")
.forEach(element => {
// there can be multiple bottom stickers (e.g. in a dialog) but there's no class on the actual element
const bottomSticker = element.parentNode
if (bottomSticker) {
bottomSticker.style.position = "relative";
}
})

document.querySelectorAll(".jenkins-bottom-app-bar__shadow")
.forEach(element => {
element.style.position = "initial";
})

if (header) {
header.style.position = "relative";
}
Expand Down
1 change: 1 addition & 0 deletions src/test/java/plugins/CredentialsBindingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public void testTextBinding() {
CredentialsPage mc = new CredentialsPage(jenkins, ManagedCredentials.DEFAULT_DOMAIN);
mc.open();
StringCredentials cred = mc.add(StringCredentials.class);
cred.scope.waitFor(by.option("GLOBAL"));
cred.scope.select("GLOBAL");
cred.secret.set(SECRET_TEXT);
mc.create();
Expand Down
Loading