Przeglądaj źródła

SONAR17527 Add new mainBranch param to projects/create

tags/9.8.0.63668
Léo Geoffroy 1 rok temu
rodzic
commit
93f44f077c

+ 18
- 3
server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java Wyświetl plik

@@ -28,6 +28,7 @@ import javax.annotation.Nullable;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.i18n.I18n;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
@@ -38,6 +39,8 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.portfolio.PortfolioDto;
import org.sonar.db.portfolio.PortfolioDto.SelectionMode;
import org.sonar.db.project.ProjectDto;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.property.PropertyDto;
import org.sonar.server.es.ProjectIndexer.Cause;
import org.sonar.server.es.ProjectIndexers;
import org.sonar.server.favorite.FavoriteUpdater;
@@ -63,10 +66,11 @@ public class ComponentUpdater {
private final FavoriteUpdater favoriteUpdater;
private final ProjectIndexers projectIndexers;
private final UuidFactory uuidFactory;
private final PropertiesDao propertiesDao;

public ComponentUpdater(DbClient dbClient, I18n i18n, System2 system2,
PermissionTemplateService permissionTemplateService, FavoriteUpdater favoriteUpdater,
ProjectIndexers projectIndexers, UuidFactory uuidFactory) {
ProjectIndexers projectIndexers, UuidFactory uuidFactory, PropertiesDao propertiesDao) {
this.dbClient = dbClient;
this.i18n = i18n;
this.system2 = system2;
@@ -74,6 +78,7 @@ public class ComponentUpdater {
this.favoriteUpdater = favoriteUpdater;
this.projectIndexers = projectIndexers;
this.uuidFactory = uuidFactory;
this.propertiesDao = propertiesDao;
}

/**
@@ -83,7 +88,11 @@ public class ComponentUpdater {
* - Index component in es indexes
*/
public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin) {
ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, c -> {
return create(dbSession, newComponent, userUuid, userLogin, null);
}

public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin, @Nullable String mainBranchName) {
ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, mainBranchName, c -> {
});
commitAndIndex(dbSession, componentDto);
return componentDto;
@@ -205,10 +214,16 @@ public class ComponentUpdater {
}

private void createMainBranch(DbSession session, String componentUuid, @Nullable String mainBranch) {

String branchKey = Optional.ofNullable(mainBranch)
.or(() -> Optional.ofNullable(propertiesDao.selectGlobalProperty(session, CorePropertyDefinitions.SONAR_PROJECTCREATION_MAINBRANCHNAME))
.map(PropertyDto::getValue))
.orElse(BranchDto.DEFAULT_MAIN_BRANCH_NAME);

BranchDto branch = new BranchDto()
.setBranchType(BranchType.BRANCH)
.setUuid(componentUuid)
.setKey(Optional.ofNullable(mainBranch).orElse(BranchDto.DEFAULT_MAIN_BRANCH_NAME))
.setKey(branchKey)
.setMergeBranchUuid(null)
.setExcludeFromPurge(true)
.setProjectUuid(componentUuid);

+ 29
- 6
server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/CreateAction.java Wyświetl plik

@@ -44,6 +44,7 @@ import static org.sonar.server.component.NewComponent.newComponentBuilder;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_MAIN_BRANCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
@@ -74,6 +75,7 @@ public class CreateAction implements ProjectsWsAction {
.setHandler(this);

action.setChangelog(
new Change("9.8", "Field 'mainBranch' added to the request"),
new Change("7.1", "The 'visibility' parameter is public"));

action.createParam(PARAM_PROJECT)
@@ -87,6 +89,12 @@ public class CreateAction implements ProjectsWsAction {
.setRequired(true)
.setExampleValue("SonarQube");

action.createParam(PARAM_MAIN_BRANCH)
.setDescription("Key of the main branch of the project. If not provided, the default main branch key will be used.")
.setRequired(false)
.setSince("9.8")
.setExampleValue("develop");

action.createParam(PARAM_VISIBILITY)
.setDescription("Whether the created project should be visible to everyone, or only specific user/groups.<br/>" +
"If no visibility is specified, the default project visibility will be used.")
@@ -109,13 +117,14 @@ public class CreateAction implements ProjectsWsAction {
boolean changeToPrivate = visibility == null ? projectDefaultVisibility.get(dbSession).isPrivate() : "private".equals(visibility);

ComponentDto componentDto = componentUpdater.create(dbSession, newComponentBuilder()
.setKey(request.getProjectKey())
.setName(request.getName())
.setPrivate(changeToPrivate)
.setQualifier(PROJECT)
.build(),
.setKey(request.getProjectKey())
.setName(request.getName())
.setPrivate(changeToPrivate)
.setQualifier(PROJECT)
.build(),
userSession.isLoggedIn() ? userSession.getUuid() : null,
userSession.isLoggedIn() ? userSession.getLogin() : null);
userSession.isLoggedIn() ? userSession.getLogin() : null,
request.getMainBranchKey());
return toCreateResponse(componentDto);
}
}
@@ -125,6 +134,7 @@ public class CreateAction implements ProjectsWsAction {
.setProjectKey(request.mandatoryParam(PARAM_PROJECT))
.setName(abbreviate(request.mandatoryParam(PARAM_NAME), MAX_COMPONENT_NAME_LENGTH))
.setVisibility(request.param(PARAM_VISIBILITY))
.setMainBranchKey(request.param(PARAM_MAIN_BRANCH))
.build();
}

@@ -141,6 +151,7 @@ public class CreateAction implements ProjectsWsAction {
static class CreateRequest {
private final String projectKey;
private final String name;
private final String mainBranchKey;
@CheckForNull
private final String visibility;

@@ -148,6 +159,7 @@ public class CreateAction implements ProjectsWsAction {
this.projectKey = builder.projectKey;
this.name = builder.name;
this.visibility = builder.visibility;
this.mainBranchKey = builder.mainBranchKey;
}

public String getProjectKey() {
@@ -163,6 +175,10 @@ public class CreateAction implements ProjectsWsAction {
return visibility;
}

public String getMainBranchKey() {
return mainBranchKey;
}

public static Builder builder() {
return new Builder();
}
@@ -171,6 +187,8 @@ public class CreateAction implements ProjectsWsAction {
static class Builder {
private String projectKey;
private String name;
private String mainBranchKey;

@CheckForNull
private String visibility;

@@ -194,6 +212,11 @@ public class CreateAction implements ProjectsWsAction {
return this;
}

public Builder setMainBranchKey(@Nullable String mainBranchKey) {
this.mainBranchKey = mainBranchKey;
return this;
}

public CreateRequest build() {
requireNonNull(projectKey);
requireNonNull(name);

+ 4
- 3
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java Wyświetl plik

@@ -80,7 +80,8 @@ public class ImportAzureProjectActionTest {
private final AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(),
new SequenceUuidFactory(), db.getDbClient().propertiesDao());

private final Encryption encryption = mock(Encryption.class);
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
@@ -109,7 +110,7 @@ public class ImportAzureProjectActionTest {
GsonAzureRepo repo = getGsonAzureRepo();
when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
"project-name", "repo-name"))
.thenReturn(repo);
.thenReturn(repo);

Projects.CreateWsResponse response = ws.newRequest()
.setParam("almSetting", almSetting.getKey())
@@ -154,7 +155,7 @@ public class ImportAzureProjectActionTest {
GsonAzureRepo repo = getEmptyGsonAzureRepo();
when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
"project-name", "repo-name"))
.thenReturn(repo);
.thenReturn(repo);

Projects.CreateWsResponse response = ws.newRequest()
.setParam("almSetting", almSetting.getKey())

+ 2
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionTest.java Wyświetl plik

@@ -82,7 +82,8 @@ public class ImportBitbucketCloudRepoActionTest {
private final BitbucketCloudRestClient bitbucketCloudRestClient = mock(BitbucketCloudRestClient.class);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());

private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);

+ 2
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionTest.java Wyświetl plik

@@ -87,7 +87,8 @@ public class ImportBitbucketServerProjectActionTest {
private final BitbucketServerRestClient bitbucketServerRestClient = mock(BitbucketServerRestClient.class);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());

private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);

+ 2
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionTest.java Wyświetl plik

@@ -75,7 +75,8 @@ public class ImportGithubProjectActionTest {
public DbTester db = DbTester.create(system2);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE,
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());

private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);

+ 2
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/gitlab/ImportGitLabProjectActionTest.java Wyświetl plik

@@ -72,7 +72,8 @@ public class ImportGitLabProjectActionTest {
public DbTester db = DbTester.create(system2);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE,
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());

private final GitlabHttpClient gitlabHttpClient = mock(GitlabHttpClient.class);
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);

+ 5
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/queue/ReportSubmitterTest.java Wyświetl plik

@@ -39,6 +39,7 @@ import org.sonar.db.DbTester;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.GlobalPermission;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.TestProjectIndexers;
@@ -87,8 +88,11 @@ public class ReportSubmitterTest {
private final CeQueue queue = mock(CeQueueImpl.class);
private final TestProjectIndexers projectIndexers = new TestProjectIndexers();
private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);

private final PropertiesDao propertiesDao = mock(PropertiesDao.class);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService,
new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory());
new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory(), propertiesDao);
private final BranchSupport ossEditionBranchSupport = new BranchSupport(null);

private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport,

+ 37
- 2
server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java Wyświetl plik

@@ -19,12 +19,14 @@
*/
package org.sonar.server.component;

import java.util.Map;
import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
@@ -65,11 +67,10 @@ public class ComponentUpdaterTest {

private final TestProjectIndexers projectIndexers = new TestProjectIndexers();
private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);

private final ComponentUpdater underTest = new ComponentUpdater(db.getDbClient(), i18n, system2,
permissionTemplateService,
new FavoriteUpdater(db.getDbClient()),
projectIndexers, new SequenceUuidFactory());
projectIndexers, new SequenceUuidFactory(), db.getDbClient().propertiesDao());

@Test
public void persist_and_index_when_creating_project() {
@@ -105,6 +106,40 @@ public class ComponentUpdaterTest {
assertThat(branch.get().getProjectUuid()).isEqualTo(returned.uuid());
}

@Test
public void create_project_with_main_branch_global_property(){
String globalBranchName = "main-branch-global";
db.getDbClient().propertiesDao().saveGlobalProperties(Map.of(CorePropertyDefinitions.SONAR_PROJECTCREATION_MAINBRANCHNAME, globalBranchName));
NewComponent project = NewComponent.newComponentBuilder()
.setKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
.setPrivate(true)
.build();

ComponentDto returned = underTest.create(db.getSession(), project, null, null, null);

Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.branchUuid());
assertThat(branch).get().extracting(BranchDto::getBranchKey).isEqualTo(globalBranchName);

}

@Test
public void create_project_with_main_branch_param(){
String customBranchName = "main-branch-custom";
db.getDbClient().propertiesDao().saveGlobalProperties(Map.of(CorePropertyDefinitions.SONAR_PROJECTCREATION_MAINBRANCHNAME, customBranchName));
NewComponent project = NewComponent.newComponentBuilder()
.setKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
.setPrivate(true)
.build();

ComponentDto returned = underTest.create(db.getSession(), project, null, null, customBranchName);

Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.branchUuid());
assertThat(branch).get().extracting(BranchDto::getBranchKey).isEqualTo(customBranchName);

}

@Test
public void persist_private_flag_true_when_creating_project() {
NewComponent project = NewComponent.newComponentBuilder()

+ 18
- 7
server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/CreateActionTest.java Wyświetl plik

@@ -29,6 +29,7 @@ import org.sonar.api.utils.System2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentUpdater;
@@ -59,6 +60,7 @@ import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.WsRequest.Method.POST;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_MAIN_BRANCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
@@ -67,6 +69,7 @@ public class CreateActionTest {

private static final String DEFAULT_PROJECT_KEY = "project-key";
private static final String DEFAULT_PROJECT_NAME = "project-name";
private static final String MAIN_BRANCH = "main-branch";

private final System2 system2 = System2.INSTANCE;

@@ -83,7 +86,8 @@ public class CreateActionTest {
private final WsActionTester ws = new WsActionTester(
new CreateAction(
db.getDbClient(), userSession,
new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory()),
new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()), projectIndexers,
new SequenceUuidFactory(), db.getDbClient().propertiesDao()),
projectDefaultVisibility));

@Before
@@ -98,14 +102,20 @@ public class CreateActionTest {
CreateWsResponse response = call(CreateRequest.builder()
.setProjectKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
.setMainBranchKey(MAIN_BRANCH)
.build());

assertThat(response.getProject())
.extracting(Project::getKey, Project::getName, Project::getQualifier, Project::getVisibility)
.containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "public");
assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get())
ComponentDto component = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
assertThat(component)
.extracting(ComponentDto::getKey, ComponentDto::name, ComponentDto::qualifier, ComponentDto::scope, ComponentDto::isPrivate, ComponentDto::getMainBranchProjectUuid)
.containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "PRJ", false, null);

assertThat(db.getDbClient().branchDao().selectByUuid(db.getSession(), component.branchUuid()).get())
.extracting(BranchDto::getKey)
.isEqualTo(MAIN_BRANCH);
}

@Test
@@ -235,7 +245,7 @@ public class CreateActionTest {
public void fail_when_missing_project_parameter() {
userSession.addPermission(PROVISION_PROJECTS);

assertThatThrownBy(() -> call(null, DEFAULT_PROJECT_NAME))
assertThatThrownBy(() -> call(null, DEFAULT_PROJECT_NAME, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("The 'project' parameter is missing");
}
@@ -244,7 +254,7 @@ public class CreateActionTest {
public void fail_when_missing_name_parameter() {
userSession.addPermission(PROVISION_PROJECTS);

assertThatThrownBy(() -> call(DEFAULT_PROJECT_KEY, null))
assertThatThrownBy(() -> call(DEFAULT_PROJECT_KEY, null, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("The 'name' parameter is missing");
}
@@ -281,7 +291,7 @@ public class CreateActionTest {
assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder(
PARAM_VISIBILITY,
PARAM_NAME,
PARAM_PROJECT);
PARAM_PROJECT, PARAM_MAIN_BRANCH);

WebService.Param visibilityParam = definition.param(PARAM_VISIBILITY);
assertThat(visibilityParam.description()).isNotEmpty();
@@ -335,14 +345,15 @@ public class CreateActionTest {
}

private CreateWsResponse call(CreateRequest request) {
return call(request.getProjectKey(), request.getName());
return call(request.getProjectKey(), request.getName(), request.getMainBranchKey());
}

private CreateWsResponse call(@Nullable String projectKey, @Nullable String projectName) {
private CreateWsResponse call(@Nullable String projectKey, @Nullable String projectName, @Nullable String mainBranch) {
TestRequest httpRequest = ws.newRequest()
.setMethod(POST.name());
ofNullable(projectKey).ifPresent(key -> httpRequest.setParam("project", key));
ofNullable(projectName).ifPresent(name -> httpRequest.setParam("name", name));
ofNullable(mainBranch).ifPresent(name -> httpRequest.setParam("mainBranch", mainBranch));
return httpRequest.executeProtobuf(CreateWsResponse.class);
}


+ 1
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java Wyświetl plik

@@ -33,6 +33,7 @@ public class ProjectsWsParameters {
public static final String PARAM_PROJECT = "project";
public static final String PARAM_PROJECT_ID = "projectId";
public static final String PARAM_NAME = "name";
public static final String PARAM_MAIN_BRANCH = "mainBranch";
public static final String PARAM_BRANCH = "branch";
public static final String PARAM_QUALIFIERS = "qualifiers";
public static final String PARAM_FROM = "from";

Ładowanie…
Anuluj
Zapisz