3 | Starts an Android emulator with given properties before a build, then shuts it down after.
4 |
5 |
--------------------------------------------------------------------------------
/src/main/webapp/help-failOnInstallFailure.html:
--------------------------------------------------------------------------------
1 | If the given APK fails to be installed (i.e. the Android package manager does not return "Success")
2 | and this option is enabled, then the build will be marked as failed.
--------------------------------------------------------------------------------
/src/main/webapp/help-emulatorNamed.html:
--------------------------------------------------------------------------------
1 | Starts an existing emulator — typically created using Android's AVD Manager tool, either
2 | by launching it from Eclipse, or using the android command line.
3 |
--------------------------------------------------------------------------------
/src/main/webapp/help-deviceLocale.html:
--------------------------------------------------------------------------------
1 | Must be a language and country pair that will exist on the emulator version being run.
2 | The values correspond to ISO 639-1 and ISO 3166 language and country codes, respectively.
3 |
--------------------------------------------------------------------------------
/src/main/webapp/help-failOnUninstallFailure.html:
--------------------------------------------------------------------------------
1 | If the given package ID fails to be uninstalled (i.e. the Android package manager does not return
2 | "Success") and this option is enabled, then the build will be marked as failed.
--------------------------------------------------------------------------------
/src/main/webapp/help-uninstallFirst.html:
--------------------------------------------------------------------------------
1 | If this option is checked, any existing instance of the given Android package
2 | will be removed from the device in question, before installation occurs.
3 |
4 | The device affected is chosen using the rules explained in the help section above.
5 |
6 |
--------------------------------------------------------------------------------
/src/test/resources/jenkins/plugin/android/emulator/sdk/cli/avdmanager_list_target.out:
--------------------------------------------------------------------------------
1 | Available Android targets:==============] 100% Fetch remote repository...
2 | ----------
3 | id: 1 or "android-21"
4 | Name: Android API 21
5 | Type: Platform
6 | API level: 21
7 | Revision: 2
8 |
--------------------------------------------------------------------------------
/src/main/webapp/help-deviceDefinition.html:
--------------------------------------------------------------------------------
1 | SDK Tools ≥ 25.3 only
2 | Defines the optional device definition to use for the Android Virtual Device. The available list can be retrieved via 'avdmanager list device'.
3 | If the SDK Tools < 25.3 are used, the value is ignored.
4 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/DefaultToolLocator.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk;
2 |
3 | public class DefaultToolLocator implements ToolLocator {
4 | @Override
5 | public String findInSdk(final boolean useLegacySdkStructure) {
6 | return ToolLocator.TOOLS_DIR;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/PlatformToolLocator.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk;
2 |
3 | public class PlatformToolLocator implements ToolLocator {
4 | @Override
5 | public String findInSdk(final boolean useLegacySdkStructure) {
6 | return ToolLocator.PLATFORM_TOOLS_DIR;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | tasks:
2 | - init: mvn clean verify
3 |
4 | vscode:
5 | extensions:
6 | - bierner.markdown-preview-github-styles
7 | - vscjava.vscode-java-pack
8 | - redhat.java
9 | - vscjava.vscode-java-debug
10 | - vscjava.vscode-java-dependency
11 | - vscjava.vscode-java-test
12 | - vscjava.vscode-maven
13 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/snapshot/SnapshotLoadBuilder/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/snapshot/SnapshotSaveBuilder/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/webapp/help-snapshotLoad.html:
--------------------------------------------------------------------------------
1 | Loads the named snapshot into an Android emulator.
2 |
3 | If an Android emulator was started automatically via the "Run an Android emulator during build"
4 | option above, that device will be used. Otherwise, it is assumed that there is an Android emulator
5 | running on port 5554 (the default).
6 |
7 |
--------------------------------------------------------------------------------
/src/main/webapp/help-snapshotSave.html:
--------------------------------------------------------------------------------
1 | Saves the current state of an Android emulator to the named snapshot.
2 |
3 | If an Android emulator was started automatically via the "Run an Android emulator during build"
4 | option above, that device will be used. Otherwise, it is assumed that there is an Android emulator
5 | running on port 5554 (the default).
6 |
2 | The emulator executable. Changing the default should not be necessary, but there are some bugs in the SDK
3 | which might prevent the default from working, see
4 | Issue 34233.
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-adbTimeout.html:
--------------------------------------------------------------------------------
1 | This determines how long the Android Emulator plugin should wait for ADB to become available before starting the Emulator.
2 |
3 | This is useful, for example, if starting the ADB takes some considerable time - for instance on the slow systems.
4 | By default the plugin waits for 60 seconds.
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: maven
4 | directory: "/"
5 | schedule:
6 | interval: weekly
7 | open-pull-requests-limit: 10
8 | target-branch: master
9 | reviewers:
10 | - orrc
11 | - nfalco79
12 | labels:
13 | - skip-changelog
14 | - package-ecosystem: github-actions
15 | directory: /
16 | schedule:
17 | interval: monthly
18 |
19 |
--------------------------------------------------------------------------------
/src/main/webapp/help-keepInWorkspace.html:
--------------------------------------------------------------------------------
1 | With this option enabled, all the Android emulators will be kept in a workspace-specific directory.
2 | This has a few implications:
3 |
4 |
5 |
Emulators for different jobs will be completely isolated
6 |
Workspaces will take up more space
7 |
You can easily clear out emulators & snapshots by deleting the workspace
8 |
9 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/monkey/MonkeyAction/summary.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ${it.summary}
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | /*
2 | See the documentation for more options:
3 | https://github.com/jenkins-infra/pipeline-library/
4 | */
5 | buildPlugin(
6 | useContainerAgent: false,
7 | forkCount: '1C', // Set to `false` if you need to use Docker for containerized tests
8 | configurations: [
9 | [platform: 'arm64linux', jdk: 21],
10 | [platform: 'windows', jdk: 17],
11 | [platform: 'linux', jdk: 25],
12 | ])
13 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/BuildNodeUnavailableException.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator;
2 |
3 | import java.io.IOException;
4 |
5 | public class BuildNodeUnavailableException extends IOException {
6 |
7 | public BuildNodeUnavailableException() {
8 | super(Messages.NODE_UNAVAILABLE_EXCEPTION());
9 | }
10 |
11 | private static final long serialVersionUID = 1L;
12 |
13 | }
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/SdkToolLocator.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk;
2 |
3 | public class SdkToolLocator implements ToolLocator {
4 | @Override
5 | public String findInSdk(final boolean useLegacySdkStructure) {
6 | if (!useLegacySdkStructure) {
7 | return ToolLocator.CMD_TOOLS_BIN_DIR;
8 | }
9 | return ToolLocator.TOOLS_BIN_DIR;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.mvn/extensions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | io.jenkins.tools.incrementals
4 | git-changelist-maven-extension
5 | 1.13
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/EmulatorToolLocator.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk;
2 |
3 | public class EmulatorToolLocator implements ToolLocator {
4 | @Override
5 | public String findInSdk(final boolean useLegacySdkStructure) {
6 | if (!useLegacySdkStructure) {
7 | return ToolLocator.EMULATOR_DIR;
8 | } else {
9 | return ToolLocator.TOOLS_DIR;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/SdkInstallationException.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator;
2 |
3 | public final class SdkInstallationException extends AndroidEmulatorException {
4 |
5 | public SdkInstallationException(String message) {
6 | super(message);
7 | }
8 |
9 | SdkInstallationException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 |
13 | private static final long serialVersionUID = 1L;
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-startupTimeout.html:
--------------------------------------------------------------------------------
1 | This determines how long the Android Emulator plugin should wait for the emulator to start at the beginning of a build.
2 |
3 | This is useful, for example, if starting the emulator takes some considerable time - for instance if you are unable to use hardware acceleration.
4 | By default the plugin waits for 360 seconds. This value is doubled to 720 seconds for first time boots without an initial snapshot.
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/monkey/MonkeyResult.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.monkey;
2 |
3 | enum MonkeyResult {
4 | /** Monkey test completed successfully */
5 | Success,
6 | /** Application crashed while under test */
7 | Crash,
8 | /** ANR occurred while under test */
9 | AppNotResponding,
10 | /** No monkey output was found to parse */
11 | NothingToParse,
12 | /** Monkey output was given, but outcome couldn't be determined */
13 | UnrecognisedFormat
14 | }
15 |
--------------------------------------------------------------------------------
/.github/workflows/cd.yaml:
--------------------------------------------------------------------------------
1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins
2 |
3 | name: cd
4 | on:
5 | workflow_dispatch:
6 | check_run:
7 | types:
8 | - completed
9 |
10 | permissions:
11 | checks: read
12 | contents: write
13 |
14 | jobs:
15 | maven-cd:
16 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1
17 | secrets:
18 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
19 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
20 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-startupDelay.html:
--------------------------------------------------------------------------------
1 | This determines how long the Android Emulator plugin should delay for, at the start of a build, before attempting to launch the emulator.
2 |
3 | This is useful, for example, if starting the emulator depends on other Build Environment plugins that need time to fully start up.
4 | e.g. If you find that starting a VNC server using the Xvnc plugin can take 30 seconds — due to slow hardware, or a large X startup script — you would enter 30 (or more) here.
5 |
6 |
--------------------------------------------------------------------------------
/src/main/webapp/help-installPackage.html:
--------------------------------------------------------------------------------
1 | Installs the given Android package (APK) file onto an Android emulator or device.
2 |
3 | If an Android emulator was started automatically via the "Run an Android emulator
4 | during build" option above, the APK will be installed onto that device.
5 |
6 |
7 | Otherwise, the APK will be installed onto an emulator or USB-attached Android device.
8 | If more than one emulator or device is present, this step will currently hang until
9 | only one emulator or device is available — this is the default Android SDK behaviour.
10 |
2 | If this option is selected, the Android emulator being run will be deleted when the build ends.
3 | This means permanantly erasing all of its files, snapshots and metadata from disk on the current
4 | build machine.
5 |
6 | This happens in all cases, regardless of:
7 |
8 |
why the build ended
9 |
what the build outcome is
10 |
whether the emulator has custom properties or not
11 |
whether the emulator was created at the start of the build
12 |
--------------------------------------------------------------------------------
/src/main/webapp/help-uninstallPackage.html:
--------------------------------------------------------------------------------
1 | Uninstalls the given Android package (APK) file from an Android emulator or device.
2 |
3 | If an Android emulator was started automatically via the "Run an Android emulator
4 | during build" option above, the APK will be uninstalled from that device.
5 |
6 |
7 | Otherwise, the APK will be uninstalled from an emulator or USB-attached Android device.
8 | If more than one emulator or device is present, this step will currently hang until
9 | only one emulator or device is available — this is the default Android SDK behaviour.
10 |
11 |
--------------------------------------------------------------------------------
/src/main/webapp/help-targetAbi.html:
--------------------------------------------------------------------------------
1 | Should be the name of the ABI / system image to be used, e.g "armeabi" or "x86".
2 | Additionally a tag can be specified via <Tag>/<ABI>, e.g "google_apis/x86_64".
3 | SDK Tools ≤ 25.2
4 | If empty the default ABI for the select platform will be used. You only need to define this field if you have
5 | more than one system image per Android platform installed.
6 | SDK Tools ≥ 25.3
7 | If AVD is created via this plugin, the value is required to run 'avdmanager create avd'.
8 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/monkey/BuildOutcome.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.monkey;
2 |
3 | import hudson.plugins.android_emulator.Messages;
4 |
5 | public enum BuildOutcome {
6 |
7 | UNSTABLE(Messages.BUILD_RESULT_UNSTABLE()),
8 | FAILURE(Messages.BUILD_RESULT_FAILURE()),
9 | IGNORE(Messages.BUILD_RESULT_IGNORE());
10 |
11 | private final String displayName;
12 |
13 | private BuildOutcome(String displayName) {
14 | this.displayName = displayName;
15 | }
16 |
17 | public String getDisplayName() {
18 | return displayName;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-avdName.html:
--------------------------------------------------------------------------------
1 |
2 | The names of existing Android emulator configurations (AVDs) can be seen by running the
3 | following command from the Android SDK: android list avd.
4 |
5 | The AVD must already exist at build time on the machine the build will be executed on —
6 | the emulator configuration will not be automatically created or copied from another machine.
7 |
8 | You can also do environment variable substitution for this setting, in the format:
9 | ${VARIABLE_NAME} or $VARIABLE_NAME.
10 |
11 |
--------------------------------------------------------------------------------
/src/main/webapp/help-osVersion.html:
--------------------------------------------------------------------------------
1 | Can be an OS version, target name or SDK add-on, e.g. "2.1" or "android-7".
2 | For example, to use the Google APIs add-on to get an Android 2.3 emulator with Google Maps support, enter "Google Inc.:Google APIs:9".
3 |
4 | The available targets in your installation of the Android SDK can be listed with the command: android list target
5 | — the values shown within double quotes can be entered here.
6 |
7 | While common values will be auto-completed when you start typing here, you are not bound to using these values, as shown by the "Google APIs" example.
8 |
2 | Select this option if you wish to automatically start an Android emulator of your choice before
3 | the build steps execute, with the emulator being stopped after building is complete.
4 |
5 | You can choose to start a pre-defined, existing Android emulator instance (also known as an
6 | Android Virtual Device, or AVD).
7 | Alternatively, the plugin can automatically create a new emulator on the build slave with
8 | properties you specify here.
9 |
10 | In any case, the "logcat" output will automatically be captured and archived.
11 |
12 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/cli/AdbShellCommand04To22.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk.cli;
2 |
3 | import hudson.plugins.android_emulator.constants.AndroidKeyEvent;
4 |
5 | /**
6 | * Extends {@code AdbShellCommandsCurrentBase} and simply overwrites the commands
7 | * which differ for devices running on API-level 4 to 22.
8 | */
9 | public class AdbShellCommand04To22 extends AdbShellCommandsCurrentBase implements AdbShellCommands {
10 |
11 | @Override
12 | public SdkCliCommand getDismissKeyguardCommand(String deviceSerial) {
13 | return getSendKeyEventCommand(deviceSerial, AndroidKeyEvent.KEYCODE_MENU);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-wipeData.html:
--------------------------------------------------------------------------------
1 |
2 | If this option is selected, the emulator will have its user data reset at start-up, as if the emulator was newly-created.
3 | Any modifications made to the system partition will remain untouched, as well as any SD cards and their contents that may exist.
4 | This is equivalent to running the Android emulator command with the -wipe-data option.
5 |
6 | Note: This option can add anywhere from 30 seconds to five minutes to the build startup time, depending on the build slave's CPU speed.
7 | Note: This option will be ignored if "Use emulator snapshots" is enabled.
8 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-showWindow.html:
--------------------------------------------------------------------------------
1 | If this option is selected, the Android emulator user interface will be displayed on screen during the build.
2 | Untick this option if you do not want the emulator to be visible while it runs.
3 |
4 | Disabling this is useful, for example, on Linux machines that do not have a graphical user interface.
5 | If you do require the emulator to be displayed on such machines, you can install and enable the Xvnc plugin.
6 | With Xvnc enabled for the build, you can keep this option selected and the emulator will be launched in a VNC session.
7 |
--------------------------------------------------------------------------------
/.github/workflows/jenkins-security-scan.yml:
--------------------------------------------------------------------------------
1 | name: Jenkins Security Scan
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | types: [ opened, synchronize, reopened ]
9 | workflow_dispatch:
10 |
11 | permissions:
12 | security-events: write
13 | contents: read
14 | actions: read
15 |
16 | jobs:
17 | security-scan:
18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2
19 | with:
20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate.
21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default.
22 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/cli/AdbShellCommand00To03.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk.cli;
2 |
3 | /**
4 | * Extends {@code AdbShellCommands04To22} and simply overwrites the commands
5 | * which differ for devices running on API-level 3 and below.
6 | */
7 | public class AdbShellCommand00To03 extends AdbShellCommand04To22 implements AdbShellCommands {
8 |
9 | @Override
10 | public SdkCliCommand getWaitForDeviceStartupCommand(final String deviceSerial) {
11 | return getAdbShellCommand(deviceSerial, true, "getprop dev.bootcomplete");
12 | }
13 |
14 | @Override
15 | public String getWaitForDeviceStartupExpectedAnswer() {
16 | return "1";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/cli/SdkToolsCommands00To16.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk.cli;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Extends {@code SdkToolsCommandsCurrentBase} and simply overwrites the commands
7 | * which differ for SDK with major version prior 17.
8 | */
9 | public class SdkToolsCommands00To16 extends SdkToolsCommands17To25_2 implements SdkToolsCommands {
10 |
11 | @Override
12 | public SdkCliCommand getSdkInstallAndUpdateCommand(final String proxySettings, final List components) {
13 | final SdkCliCommand cmd = super.getSdkInstallAndUpdateCommand(proxySettings, components);
14 | return new SdkCliCommand(cmd.getTool(), cmd.getArgs().replaceFirst("^update sdk -u -a", "update sdk -u -o"));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/webapp/help-createBuildFiles.html:
--------------------------------------------------------------------------------
1 | Note: This only works for projects using the deprecated Ant build system for Android.
2 |
3 | Creates or updates Ant build files for the Android apps, libraries and test projects in this job's
4 | workspace.
5 |
6 | This build step will search for Android projects in your workspace, ensure that the required
7 | platform(s) are installed, and then ensures that build files are in place by using the appropriate
8 | android update project command.
9 |
10 |
11 | Creating the build files for a test projects requires that the relative path to the respective app
12 | project is specified. This build step tries to do the right thing by selecting the app project which
13 | is nearest to the test project in the directory hierarchy.
14 |
15 |
--------------------------------------------------------------------------------
/src/main/webapp/help-publishMonkeyOutput.html:
--------------------------------------------------------------------------------
1 | Selecting this option will examine the output of the Android
2 | Application Exerciser
3 | Monkey tool and publish a summary to the build page.
4 | If it is determined that monkey crashed the application or a not-responding situation
5 | occurred, the build will be marked as unstable, unless another "Set build result" option is chosen.
6 |
7 | Unless a filename is entered below, the output will be read from a file called "monkey.txt"
8 | in the root of the build workspace.
9 |
10 | To run monkey automatically on an Android emulator or device and write the results to a
11 | file, select "Add build step" above and choose "Run Android monkey tester".
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/monkey/MonkeyRecorder/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ${%Optional: Name of a file within the workspace to read monkey output from. Defaults to "monkey.txt" in the root of the workspace}
7 |
8 |
9 |
10 | ${it.displayName}
11 | ${%Sets the result of the build to this value if monkey caused a crash or ANR}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main/webapp/help-sdCard.html:
--------------------------------------------------------------------------------
1 | Should be a numeric value followed by the suffix 'K' or 'M', for kilobytes or megabytes, respectively.
2 | e.g. "32M" or "10240K"
3 |
4 | For emulators that do not yet exist:
5 | If this field is left blank, no SD card will be created when the emulator is.
6 | If a value is set, an SD card of the given size will be associated with the newly-created emulator.
7 |
8 |
9 | For emulators that have been created by past builds:
10 | If this field is left blank, any existing SD card will remain; it will not be deleted.
11 | If a value is set, and the emulator does not have an SD card associated, one will be created.
12 | If a value is set, and the emulator already has an SD card defined, the existing SD card's contents or size will not be changed.
13 |
4 | Unless a filename is entered under the "Advanced…" section, the monkey results will
5 | be written to a file named "monkey.txt" in the root of the workspace.
6 | Selecting the "Publish Android monkey tester results" option below can examine this file
7 | at the end of the build and publish a summary on the build page.
8 |
9 |
10 | If an Android emulator was started automatically via the "Run an Android emulator
11 | during build" option above, monkey will be run on that device.
12 |
13 |
14 | Otherwise, the tool will be run on an emulator or USB-attached Android device.
15 | If more than one emulator or device is present, this step will currently hang until
16 | only one emulator or device is available — this is the default Android SDK behaviour.
17 |
18 |
--------------------------------------------------------------------------------
/src/main/webapp/help-installPrerequisites.html:
--------------------------------------------------------------------------------
1 | Note: This only works for projects using the deprecated Ant build system for Android.
2 | For Gradle projects, consider adding the Android SDK Manager plugin to your project.
4 |
5 | Installs any platforms required to build the Android apps in this job's workspace.
6 |
7 | In an Android app project, test project or library project built with Ant, the platform version to
8 | build against must be specified in either the project.properties or
9 | default.properties file, by setting the target parameter.
10 |
11 |
12 | This build step will search for these files in your workspace, determine which target platform(s)
13 | are required, and then ensure that they are installed. If the required platforms are already
14 | installed, no action is taken.
15 |
16 | Therefore it should always be safe to run this build step before any build steps which compile an
17 | Android project.
18 |
19 |
--------------------------------------------------------------------------------
/src/main/webapp/help-installSdk.html:
--------------------------------------------------------------------------------
1 | With this option enabled, the Android SDK will be automatically downloaded, installed and configured
2 | on any machine where builds occur with the "Run an Android emulator during build" option enabled.
3 |
4 | The SDK will be downloaded on-demand, the first time a job is built which requires it.
5 | The SDK will be installed to $JENKINS_HOME/tools/android-sdk on the build machine.
6 | If a working Android SDK is found on such a machine, the SDK will not be downloaded or installed.
7 |
8 |
9 | Similarly, any Android prerequisites required to create a certain emulator will be installed when
10 | Jenkins detects that they are required. For example, if a job is configured to use an emulator
11 | with Android 3.2, but this is not yet installed, it will be automatically downloaded and installed
12 | when that job is built. This requires that you have Android SDK Tools r14 or later installed.
13 |
14 | For each build, the path to the Android SDK being used is exposed via the ANDROID_HOME
15 | environment variable.
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/ToolLocator.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk;
2 |
3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
4 |
5 | public interface ToolLocator {
6 | public static final String BUILD_TOOLS_DIR = "build-tools";
7 | public static final String EMULATOR_DIR = "emulator";
8 | public static final String PLATFORM_TOOLS_DIR = "platform-tools";
9 | public static final String PLATFORMS_DIR = "platforms";
10 | public static final String TOOLS_DIR = "tools";
11 | public static final String TOOLS_BIN_DIR = "tools/bin";
12 | public static final String CMD_TOOLS_BIN_DIR = "cmdline-tools/bin";
13 |
14 | @SuppressFBWarnings("MS_MUTABLE_ARRAY")
15 | public static final String[] SDK_DIRECTORIES_LEGACY = {
16 | TOOLS_DIR
17 | };
18 |
19 | @SuppressFBWarnings("MS_MUTABLE_ARRAY")
20 | public static final String[] SDK_DIRECTORIES = {
21 | EMULATOR_DIR, PLATFORM_TOOLS_DIR, TOOLS_DIR, TOOLS_BIN_DIR
22 | };
23 |
24 | String findInSdk(final boolean useLegacySdkStructure);
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/AndroidEmulatorException.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator;
2 |
3 | abstract class AndroidEmulatorException extends Exception {
4 |
5 | protected AndroidEmulatorException(String message) {
6 | super(message);
7 | }
8 |
9 | protected AndroidEmulatorException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 |
13 | private static final long serialVersionUID = 1L;
14 |
15 | }
16 |
17 | final class EmulatorDiscoveryException extends AndroidEmulatorException {
18 |
19 | EmulatorDiscoveryException(String message) {
20 | super(message);
21 | }
22 |
23 | private static final long serialVersionUID = 1L;
24 |
25 | }
26 |
27 | final class EmulatorCreationException extends AndroidEmulatorException {
28 |
29 | EmulatorCreationException(String message) {
30 | super(message);
31 | }
32 |
33 | EmulatorCreationException(String message, Throwable cause) {
34 | super(message, cause);
35 | }
36 |
37 | private static final long serialVersionUID = 1L;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins.plugin.android.emulator.tools.AndroidSDKInstaller.json:
--------------------------------------------------------------------------------
1 | {
2 | "list": [
3 | {
4 | "id": "cmdline-tools:12.0",
5 | "url": "https://dl.google.com/android/repository/commandlinetools-{os}-11076708_latest.zip",
6 | "name": "Command-line Tools 12.0"
7 | },
8 | {
9 | "id": "cmdline-tools:4.0",
10 | "url": "https://dl.google.com/android/repository/commandlinetools-{os}-7302050_latest.zip",
11 | "name": "Command-line Tools 4.0"
12 | },
13 | {
14 | "id": "cmdline-tools:3.0",
15 | "url": "https://dl.google.com/android/repository/commandlinetools-{os}-6858069_latest.zip",
16 | "name": "Command-line Tools 3.0"
17 | },
18 | {
19 | "id": "cmdline-tools:2.1",
20 | "url": "https://dl.google.com/android/repository/commandlinetools-{os}-6609375_latest.zip",
21 | "name": "Command-line Tools 2.1"
22 | },
23 | {
24 | "id": "cmdline-tools:1.0",
25 | "url": "https://dl.google.com/android/repository/commandlinetools-{os}-6200805_latest.zip",
26 | "name": "Command-line Tools 1.0"
27 | }
28 | ]
29 | }
--------------------------------------------------------------------------------
/src/main/webapp/help-avdNameSuffix.html:
--------------------------------------------------------------------------------
1 | Should be empty or a custom suffix for the AVD name.
2 | e.g. "mySuffix" or "withPdf"
3 |
4 | If this field is left blank, no custom suffix will be added to the AVD name that
5 | this plugin generates when automatically creating an emulator.
6 | If a value is set, a suffix will be added to the AVD name, with any invalid characters
7 | replaced by a hyphen (as AVD names may only contain [a-z A-Z 0-9 . _ -]).
8 |
9 |
10 | This allows you to run multiple emulators with the same configuration in parallel on the
11 | same build machine.
12 | Normally, if you create two jobs with the same emulator configuration, only one of those
13 | jobs will run at a time — as the other job is using the emulator. But by setting a
14 | custom suffix one on or both jobs, the emulator names will differ for the two jobs, and
15 | Jenkins will consider them as two completely different emulators, allowing them to run in
16 | parallel.
17 |
18 | Note that this will cause more disk space to be used, as a new emulator will be created
19 | on disk for each unique suffix used.
20 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-useSnapshots.html:
--------------------------------------------------------------------------------
1 | Enabling snapshots allows the emulator to start up much faster, becoming ready for use in a matter of seconds.
2 |
3 | The first time an emulator is started with snapshots enabled, the plugin waits until the emulator has finished
4 | booting, unlocks the screen, and then saves the emulator state to disk.
5 | For subsequent builds, the emulator is started directly from this stored state. This means that Android has
6 | already finished booting, is sitting on the home screen, with the screen unlocked; i.e. ready for use.
7 |
8 | At the end of a build, the emulator state is not persisted to the snapshot file — subsequent jobs will
9 | always start from the same, clean state that was stored at the start of the first snapshot-enabled build.
10 |
11 | Should the emulator already have snapshots in place, these will be neither read nor overwritten —
12 | the plugin always writes its state to a separate snapshot file called "jenkins".
13 |
14 | Note: Using snapshots will consume around 150–200MB of disk space on the build slave, for each emulator.
15 |
--------------------------------------------------------------------------------
/src/test/java/jenkins/plugin/android/emulator/sdk/cli/AVDManagerCLIBuilderTest.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.cli;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 |
5 | import java.io.InputStream;
6 |
7 | import org.junit.jupiter.api.Test;
8 | import java.util.List;
9 |
10 | import jenkins.plugin.android.emulator.sdk.cli.Targets.TargetType;
11 |
12 | class AVDManagerCLIBuilderTest {
13 |
14 | @Test
15 | void test_list_parse() throws Exception {
16 | try (InputStream is = this.getClass().getResourceAsStream("avdmanager_list_target.out")) {
17 | List targets = new AVDManagerCLIBuilder.ListTargetParser().parse(is);
18 | assertThat(targets).hasSize(1);
19 | Targets target = targets.get(0);
20 | assertThat(target.getId()).isEqualTo("android-21");
21 | assertThat(target.getName()).isEqualTo("Android API 21");
22 | assertThat(target.getType()).isEqualTo(TargetType.platform);
23 | assertThat(target.getApiLevel()).isEqualTo(21);
24 | assertThat(target.getRevision()).isEqualTo(2);
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/NOTES:
--------------------------------------------------------------------------------
1 | - SDK installation should be on by default; option name and help file need to be updated
2 | - ABI support appeared in r13, i.e. using --abi with "android create avd"
3 | - Need to fix getSdkRootFromPath/isSdkToolsDirectory as they're trying to do an impossible check: that both adb and emulator are in the same directory... to test this, install an SDK without platform-tools and watch the misdetection occur...
4 | - Need to combine discoverAndroidHome and getAndroidSdk
5 | - Grab Semaphore when calling adb so that, after we know we've auto-installed some components, we can manually restart adb after all Semaphores have been released -- though this depends on Android bug 21923
6 | - Tools r16 will probably make "android.bat" become "android.exe" which will cause issues in our Tool class
7 | - Add timeouts to all ADB actions, including "logcat -c" etc.
8 | - Rewrite/split-up wiki page into more parts
9 | - Update/add screenshots to wiki
10 | >> STDERR (or whatever we do) isn't caught on Windows, but is on Linux...
11 | [android] Creating Android AVD: /home/hudson/.android/avd/hudson_en-NZ_160_WXGA_android-14.avd
12 | Error: 'WXGA' is not a valid skin name or size (NNNxMMM)
13 |
14 |
--------------------------------------------------------------------------------
/src/main/webapp/help-hardware.html:
--------------------------------------------------------------------------------
1 | Adding custom hardware properties allows you to override the default values for an AVD.
2 | For example, you can alter the amount of RAM available to each process (via the vm.heapSize
3 | property), or you can alter physical features of the emulated device, such as the presence of a keyboard.
4 |
5 | A list of common properties, along with their descriptions and default values can be found in the
6 | "Setting
7 | hardware emulation options" section of the Android Developers' site.
8 |
9 |
10 | To set a new hardware feature (or override a default value), enter the property name and the desired value.
11 | Generally, boolean properties should be either yes or no rather than true or false.
12 |
13 |
14 | Hardware properties configured here will be added to the appropriate AVD next time this job runs.
15 | However, removing hardware properties from the job configuration will not remove these properties from the AVD
16 | — the previously-added properties will remain.
17 |
2 | Enter the path — or an environment variable, in the format ${VARIABLE_NAME}
3 | — where an Android SDK
4 | installation can be found. If you want to create emulators on-the-fly, this SDK installation
5 | should have one or more platforms installed (check the "platforms" directory, or
6 | the Android SDK
7 | and AVD Manager).
8 |
9 | If nothing is entered here, the Android SDK tools (under the "tools"
10 | directory) will be presumed to be available on your PATH. Otherwise, this plugin
11 | will search for an SDK installation under the following environment variables on the build host:
12 |
13 |
14 |
ANDROID_SDK_ROOT
15 |
ANDROID_SDK_HOME
16 |
ANDROID_HOME
17 |
ANDROID_SDK
18 |
19 | Alternatively, select the option below to have the Android SDK installed automatically when it is needed.
20 |
21 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/InstallBuilder/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ${%Path to an Android package file, within the current workspace, to be installed}
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/cli/AdbShellCommands.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk.cli;
2 |
3 | import hudson.plugins.android_emulator.constants.AndroidKeyEvent;
4 |
5 | /**
6 | * Commands which are run via 'adb shell' command on a specified device
7 | */
8 | public interface AdbShellCommands {
9 | SdkCliCommand getListProcessesCommand(final String deviceSerial);
10 |
11 | SdkCliCommand getWaitForDeviceStartupCommand(final String deviceSerial);
12 | String getWaitForDeviceStartupExpectedAnswer();
13 |
14 | SdkCliCommand getClearMainLogCommand(final String deviceSerial);
15 |
16 | SdkCliCommand getSetLogCatFormatToTimeCommand(final String deviceSerial);
17 | SdkCliCommand getLogMessageCommand(final String deviceSerial, final String logMessage);
18 |
19 | SdkCliCommand getSendKeyEventCommand(final String deviceSerial, final AndroidKeyEvent keyEvent);
20 | SdkCliCommand getSendBackKeyEventCommand(final String deviceSerial);
21 |
22 | SdkCliCommand getDismissKeyguardCommand(final String deviceSerial);
23 |
24 | SdkCliCommand getMonkeyInputCommand(final String deviceSerial,
25 | final long seedValue, final int throttleMs,
26 | final String extraArgs, final int eventCount);
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/help-commandLineOptions.html:
--------------------------------------------------------------------------------
1 |
2 | The text entered here will be passed to the Android emulator executable at runtime.
3 | For a full list of available options, please run emulator -help, or consult the
4 | Android Emulator
5 | page on the Android Developers' site.
6 |
7 | Environment variable substitution can be used for these command line options, in the format:
8 | ${VARIABLE_NAME} or $VARIABLE_NAME.
9 |
10 | For example, if you want your emulator to have a larger-than-default /data partition,
11 | allowing you to install large APKs, then you could enter: -partition-size 128
12 |
13 | Options which cause the emulator to create files, for example the -tcpdump option,
14 | should be given an absolute filename, e.g. -tcpdump ${WORKSPACE}/network.cap
15 |
16 | Similarly, because arbitrary options can be combined here, you must make sure to add
17 | double quotes around any parameters which may contain spaces, e.g.:
18 | -netdelay gprs -tcpdump "/tmp/emulator captures/${JOB_NAME}_${BUILD_ID}.cap"
19 |
20 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/HardwareProperty/config.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2020, Nikolas Falco
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | key.title=Property
24 | value.title=Value
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/tools/AndroidSDKInstaller/config.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2016, Nikolas Falco
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | channel.title=Channel
24 | channel.description=Use a specific channel for this build tools to install or update packages
25 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/AndroidEmulator/global.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/main/webapp/help-emulatorCustom.html:
--------------------------------------------------------------------------------
1 |
2 | Values specified here will be used to generate an Android emulator on-the-fly, if one doesn't
3 | already exist with the given properties. Note that each emulator may consume anywhere from 30
4 | to 80MB of disk space on the build host.
5 |
6 | Each property will autocomplete to the standard Android SDK values, or you can provide custom
7 | values, e.g. if you have additional platforms defined or want to use a custom resolution.
8 |
9 |
10 | You can also do environment variable substitution for any of these properties, in the format:
11 | ${VARIABLE_NAME} or $VARIABLE_NAME.
12 |
13 |
14 | For example, if you have configured a
15 |
16 | matrix build to include a "density" axis with values "120 160 240", you
17 | could enter ${density} for the "Screen density" property below and the
18 | appropriate substitution would be made when each individual build is executed.
19 |
20 | Emulators are stored in the usual $HOME/.android/avd directory, named in the format:
21 | hudson_[locale]_[density]_[resolution]_[target].
22 | For example: hudson_en-GB_160_HVGA_android-7 for a British English, medium density, HVGA
23 | device running Android 2.1.
24 |
25 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/Messages.properties:
--------------------------------------------------------------------------------
1 | #
2 | # The MIT License (MIT)
3 | #
4 | # Copyright (c) 2020, Nikolas Falco
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in
14 | # all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | # THE SOFTWARE.
23 | AVDManagerStep.displayName=AVDManager Script
24 | SDKManagerStep.displayName=SDKManager Script
25 | EmulatorStep.displayName=QEMU Executable
26 | ADBStep.displayName=ADB Executable
27 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/home/HomeLocatorDescriptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.sdk.home;
25 |
26 | import hudson.model.Descriptor;
27 |
28 | public class HomeLocatorDescriptor extends Descriptor {
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/ADBStep/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/AVDManagerStep/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/EmulatorStep/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/SDKManagerStep/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/snapshot/SnapshotLoadBuilder.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.snapshot;
2 |
3 | import hudson.Functions;
4 | import hudson.model.Descriptor;
5 | import hudson.plugins.android_emulator.Messages;
6 | import hudson.tasks.Builder;
7 |
8 | import java.io.Serializable;
9 |
10 | import org.kohsuke.stapler.DataBoundConstructor;
11 |
12 | public class SnapshotLoadBuilder extends AbstractSnapshotBuilder {
13 |
14 | @DataBoundConstructor
15 | public SnapshotLoadBuilder(String name) {
16 | super(name);
17 | }
18 |
19 | @Override
20 | protected String getSnapshotAction() {
21 | return "load";
22 | }
23 |
24 | @Override
25 | protected String getLogMessage(String name, int port) {
26 | return Messages.LOADING_SNAPSHOT(name, port);
27 | }
28 |
29 | //@Extension
30 | public static class DescriptorImpl extends Descriptor implements Serializable {
31 |
32 | private static final long serialVersionUID = 1L;
33 |
34 | public DescriptorImpl() {
35 | super(SnapshotLoadBuilder.class);
36 | load();
37 | }
38 |
39 | @Override
40 | public String getHelpFile() {
41 | return Functions.getResourcePath() + "/plugin/android-emulator/help-snapshotLoad.html";
42 | }
43 |
44 | @Override
45 | public String getDisplayName() {
46 | return Messages.LOAD_EMULATOR_SNAPSHOT();
47 | }
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/snapshot/SnapshotSaveBuilder.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.snapshot;
2 |
3 | import hudson.Functions;
4 | import hudson.model.Descriptor;
5 | import hudson.plugins.android_emulator.Messages;
6 | import hudson.tasks.Builder;
7 |
8 | import java.io.Serializable;
9 |
10 | import org.kohsuke.stapler.DataBoundConstructor;
11 |
12 | public class SnapshotSaveBuilder extends AbstractSnapshotBuilder {
13 |
14 | @DataBoundConstructor
15 | public SnapshotSaveBuilder(String name) {
16 | super(name);
17 | }
18 |
19 | @Override
20 | protected String getSnapshotAction() {
21 | return "save";
22 | }
23 |
24 | @Override
25 | protected String getLogMessage(String name, int port) {
26 | return Messages.SAVING_SNAPSHOT(name, port);
27 | }
28 |
29 | //@Extension
30 | public static class DescriptorImpl extends Descriptor implements Serializable {
31 |
32 | private static final long serialVersionUID = 1L;
33 |
34 | public DescriptorImpl() {
35 | super(SnapshotSaveBuilder.class);
36 | load();
37 | }
38 |
39 | @Override
40 | public String getHelpFile() {
41 | return Functions.getResourcePath() + "/plugin/android-emulator/help-snapshotSave.html";
42 | }
43 |
44 | @Override
45 | public String getDisplayName() {
46 | return Messages.SAVE_EMULATOR_SNAPSHOT();
47 | }
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/AbstractCLIStep/config.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2020, Nikolas Falco
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | buildTools.title=Build Tools
24 | buildTools.description=The build tools installation where installed packages will be provided to the this emulator
25 | sdk.homeLocation=SDK Home location
26 | arguments.title=Command arguments
27 | quiet.title=Show output to console log
--------------------------------------------------------------------------------
/src/test/java/jenkins/plugin/android/emulator/sdk/cli/SDKManagerCLIBuilderTest.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.cli;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 |
5 | import java.io.InputStream;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import jenkins.plugin.android.emulator.sdk.cli.SDKPackages.SDKPackage;
10 |
11 | class SDKManagerCLIBuilderTest {
12 |
13 | @Test
14 | void test_list_parse() throws Exception {
15 | try (InputStream is = this.getClass().getResourceAsStream("sdkmanager_list.out")) {
16 | SDKPackages packages = new SDKManagerCLIBuilder.ListPackagesParser().parse(is);
17 | assertThat(packages.getAvailable()).isNotEmpty().hasSize(236).allMatch(p -> p.getId() != null, "Name is null");
18 | assertThat(packages.getInstalled()).isNotEmpty().hasSize(6).allMatch(p -> p.getId() != null, "Name is null");
19 | assertThat(packages.getUpdates()).isNotEmpty().hasSize(1).allMatch(p -> p.getId() != null, "Name is null");
20 | }
21 | }
22 |
23 | @Test
24 | void test_sort_packages() {
25 | SDKPackage p1 = new SDKPackage();
26 | p1.setId("test");
27 | p1.setVersion(new Version("1.0.0 rc1"));
28 |
29 | SDKPackage p2 = new SDKPackage();
30 | p2.setId("test");
31 | p2.setVersion(new Version("1.0.0"));
32 |
33 | SDKPackage p3 = new SDKPackage();
34 | p3.setId("notest");
35 | p3.setVersion(new Version("1.0.0 rc1"));
36 |
37 | assertThat(p1).isLessThan(p2).isGreaterThan(p3);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/pipeline/AbstractCLIStep.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.pipeline;
2 |
3 | import java.io.Serializable;
4 |
5 | import org.jenkinsci.plugins.workflow.steps.Step;
6 | import org.kohsuke.stapler.DataBoundSetter;
7 |
8 | import hudson.Util;
9 |
10 | import edu.umd.cs.findbugs.annotations.NonNull;
11 | import jenkins.plugin.android.emulator.sdk.home.HomeLocator;
12 |
13 | public abstract class AbstractCLIStep extends Step implements Serializable {
14 |
15 | private static final long serialVersionUID = 1L;
16 |
17 | protected final String emulatorTool;
18 | protected final HomeLocator homeLocationStrategy;
19 | protected final String arguments;
20 | protected boolean quiet = false;
21 |
22 | public AbstractCLIStep(@NonNull String emulatorTool, @NonNull HomeLocator homeLocationStrategy, @NonNull String arguments) {
23 | this.emulatorTool = Util.fixEmptyAndTrim(emulatorTool);
24 | this.homeLocationStrategy = homeLocationStrategy;
25 | this.arguments = Util.fixEmptyAndTrim(arguments);
26 | }
27 |
28 | public String getArguments() {
29 | return arguments;
30 | }
31 |
32 | public HomeLocator getHomeLocationStrategy() {
33 | return homeLocationStrategy;
34 | }
35 |
36 | public String getEmulatorTool() {
37 | return emulatorTool;
38 | }
39 |
40 | public boolean isQuiet() {
41 | return quiet;
42 | }
43 |
44 | @DataBoundSetter
45 | public void setQuiet(boolean quiet) {
46 | this.quiet = quiet;
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/tools/AndroidSDKInstaller/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/HardwareProperty/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/tools/DetectionFailedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.tools;
25 |
26 | import java.io.IOException;
27 |
28 | /**
29 | * Indicates the failure to detect the OS.
30 | */
31 | @SuppressWarnings("serial")
32 | public final class DetectionFailedException extends IOException {
33 | DetectionFailedException(String message) {
34 | super(message);
35 | }
36 |
37 | public DetectionFailedException(String message, Throwable cause) {
38 | super(message, cause);
39 | }
40 | }
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/AndroidEmulatorBuild/config.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2020, Nikolas Falco
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | buildTools.title=Build Tools
24 | buildTools.description=The build tools installation where installed packages will be provided to the this emulator
25 | osVersion.title=Android OS version
26 | screenDensity.title=Density
27 | screenResolution.title=Resolution
28 | sdk.homeLocation=SDK Home location
29 | avdName.title=Emulator Name
30 | deviceLocale.title=Devide Locale
31 | deviceDefinition.title=Device Definition
32 | sdCardSize.title=SD Card Size
33 | sdCardSize.description=Value is expressed in MB
34 | targetABI.title=Target ABI
35 | hardwareProperties.title=Hardware
36 | hardwareProperties.description=Add custom hardware properties for this device
37 | options.title=Common emulator options
38 | advanced.adbTimeout.title=ADB timeout
39 | advanced.adbTimeout.description=Wait this many seconds for ADB to be available
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/snapshot/AbstractSnapshotBuilder.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.snapshot;
2 |
3 | import static hudson.plugins.android_emulator.AndroidEmulator.log;
4 | import hudson.Launcher;
5 | import hudson.model.AbstractBuild;
6 | import hudson.model.BuildListener;
7 | import hudson.plugins.android_emulator.builder.AbstractBuilder;
8 | import hudson.plugins.android_emulator.util.Utils;
9 |
10 | import java.io.IOException;
11 | import java.io.PrintStream;
12 |
13 | import org.kohsuke.stapler.export.Exported;
14 |
15 | public abstract class AbstractSnapshotBuilder extends AbstractBuilder {
16 |
17 | private static final int DEFAULT_TIMEOUT_MS = 2 * 60 * 1000;
18 |
19 | /** Name of the snapshot involved. */
20 | @Exported
21 | public final String name;
22 |
23 | protected AbstractSnapshotBuilder(String name) {
24 | this.name = name;
25 | }
26 |
27 | @Override
28 | public boolean perform(AbstractBuild, ?> build, Launcher launcher, BuildListener listener)
29 | throws InterruptedException, IOException {
30 | final PrintStream logger = listener.getLogger();
31 |
32 | // Expand snapshot name
33 | final String snapshotName = Utils.expandVariables(build, listener, name);
34 |
35 | // Get AVD port
36 | final int port = getDeviceTelnetPort(build, listener);
37 |
38 | // Send telnet command: "avd snapshot $action $name"
39 | log(logger, getLogMessage(snapshotName, port));
40 | String command = String.format("avd snapshot %s %s", getSnapshotAction(), snapshotName);
41 | return Utils.sendEmulatorCommand(launcher, logger, port, command, getCommandTimeout());
42 | }
43 |
44 | /* Retrieves the time in which the snapshot command should complete, in milliseconds. */
45 | protected int getCommandTimeout() {
46 | return DEFAULT_TIMEOUT_MS;
47 | }
48 |
49 | /* Retrieves the snapshot action to execute (i.e. "load" or "save"). */
50 | protected abstract String getSnapshotAction();
51 |
52 | /* Retrieves the log message to print when performing the snapshot action. */
53 | protected abstract String getLogMessage(String snapshotName, int avdPort);
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/cli/SdkToolsCommands.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk.cli;
2 |
3 | import hudson.plugins.android_emulator.sdk.Tool;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * CLI commands using the SDK tools.
9 | */
10 | public interface SdkToolsCommands {
11 |
12 | SdkCliCommand getSdkInstallAndUpdateCommand(final String proxySettings, final List components);
13 | SdkCliCommand getListSdkComponentsCommand();
14 | SdkCliCommand getListExistingTargetsCommand();
15 | SdkCliCommand getListSystemImagesCommand();
16 | boolean isImageForPlatformAndABIInstalled(final String listSystemImagesOutput,
17 | final String platform, final String abi);
18 | SdkCliCommand getCreatedAvdCommand(final String avdName, final boolean supportsSnapshots,
19 | final String sdCardSize, final String screenResolutionSkinName, final String deviceDefinition,
20 | final String androidTarget, final String systemImagePackagePath, final String tag);
21 |
22 | SdkCliCommand getAdbInstallPackageCommand(final String deviceIdentifier, final String packageFileName);
23 | SdkCliCommand getAdbUninstallPackageCommand(final String deviceIdentifier, final String packageId);
24 |
25 | /**
26 | * Creates the command ({@code Tool} and arguments to created a sdcard-images.
27 | *
28 | * @param absolutePathToSdCard The absolute path where the images should be created
29 | * @param requestedSdCardSize The requested size of the sdcard-image in bytes (may be suffixed with 'K', 'M', 'G')
30 | * @return a {@code SdkCommand} which holds the command to use and the arguments
31 | */
32 | SdkCliCommand getCreateSdkCardCommand(final String absolutePathToSdCard, final String requestedSdCardSize);
33 |
34 | SdkCliCommand getEmulatorListSnapshotsCommand(final String avdName, final Tool executable);
35 |
36 | SdkCliCommand getAdbStartServerCommand();
37 | SdkCliCommand getAdbKillServerCommand();
38 |
39 | @Deprecated
40 | SdkCliCommand getUpdateProjectCommand(final String projectPath);
41 | @Deprecated
42 | SdkCliCommand getUpdateTestProjectCommand(final String projectPath, final String testMainClass);
43 | @Deprecated
44 | SdkCliCommand getUpdateLibProjectCommand(final String projectPath);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/util/ValidationResult.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.util;
2 |
3 | import hudson.util.FormValidation;
4 |
5 | import java.io.Serializable;
6 |
7 | public class ValidationResult implements Serializable {
8 |
9 | public static enum Type {
10 | OK,
11 | WARNING,
12 | ERROR
13 | }
14 |
15 | private final Type type;
16 | private final String message;
17 | private final boolean hasMarkup;
18 |
19 | public ValidationResult(Type type, String message) {
20 | this(type, message, false);
21 | }
22 |
23 | public ValidationResult(Type type, String message, boolean hasMarkup) {
24 | this.type = type;
25 | this.message = message;
26 | this.hasMarkup = hasMarkup;
27 | }
28 |
29 | public static ValidationResult ok() {
30 | return new ValidationResult(Type.OK, null);
31 | }
32 |
33 | public static ValidationResult warning(String message) {
34 | return new ValidationResult(Type.WARNING, message);
35 | }
36 |
37 | public static ValidationResult error(String message) {
38 | return new ValidationResult(Type.ERROR, message);
39 | }
40 |
41 | public static ValidationResult errorWithMarkup(String message) {
42 | return new ValidationResult(Type.ERROR, message, true);
43 | }
44 |
45 | public FormValidation getFormValidation() {
46 | switch (type) {
47 | case WARNING:
48 | return FormValidation.warning(message);
49 | case ERROR:
50 | if (hasMarkup) {
51 | return FormValidation.errorWithMarkup(message);
52 | } else {
53 | return FormValidation.error(message);
54 | }
55 | case OK:
56 | default:
57 | return FormValidation.ok();
58 | }
59 | }
60 |
61 | public boolean isFatal() {
62 | return type == Type.ERROR;
63 | }
64 |
65 | public Type getType() {
66 | return type;
67 | }
68 |
69 | public String getMessage() {
70 | return message;
71 | }
72 |
73 | @Override
74 | public String toString() {
75 | return "ValidationResult[type="+ type +", message="+ message +"]";
76 | }
77 |
78 | private static final long serialVersionUID = 1L;
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/ReceiveEmulatorPortTask.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 | import java.net.ServerSocket;
8 | import java.net.Socket;
9 |
10 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11 | import jenkins.security.MasterToSlaveCallable;
12 |
13 | /**
14 | * Task that will wait, up to a certain timeout, for an inbound connection from the emulator,
15 | * informing us on which port it is running.
16 | */
17 | public final class ReceiveEmulatorPortTask
18 | extends MasterToSlaveCallable {
19 |
20 | private static final long serialVersionUID = 1L;
21 |
22 | private final int port;
23 | private final int timeout;
24 |
25 | /**
26 | * @param port The local TCP port to listen on.
27 | * @param timeout How many milliseconds to wait for an emulator connection before giving up.
28 | */
29 | public ReceiveEmulatorPortTask(int port, int timeout) {
30 | this.port = port;
31 | this.timeout = timeout;
32 | }
33 |
34 | @SuppressFBWarnings("DM_DEFAULT_ENCODING")
35 | public Integer call() throws InterruptedException {
36 | // TODO: Find a better way to allow the build to be interrupted.
37 | // ServerSocket#accept() blocks and cannot be interrupted, which means that any
38 | // attempts to stop the build will fail. The best we can do here is to set the
39 | // SO_TIMEOUT, so at least if an emulator fails to start, we won't wait here forever
40 | try (ServerSocket socket = new ServerSocket(port)) {
41 | socket.setSoTimeout(timeout);
42 |
43 | // Wait for the emulator to connect to us
44 | Socket completed = socket.accept();
45 |
46 | // Parse and return the port number the emulator sent us
47 | try (InputStream is = completed.getInputStream()) {
48 | BufferedReader reader = new BufferedReader(new InputStreamReader(is));
49 | return Integer.parseInt(reader.readLine());
50 | } catch (NumberFormatException ignore) {
51 | }
52 | } catch (IOException ignore) {
53 | }
54 |
55 | // Timed out
56 | return -1;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/sdk/pipeline/AbstractCLIStep/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/home/PerJobHomeLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.sdk.home;
25 |
26 | import org.jenkinsci.Symbol;
27 | import org.kohsuke.stapler.DataBoundConstructor;
28 |
29 | import hudson.Extension;
30 |
31 | import edu.umd.cs.findbugs.annotations.NonNull;
32 | import hudson.FilePath;
33 | import jenkins.plugin.android.emulator.Messages;
34 |
35 | /**
36 | * Relocates the default SDK Home to the workspace folder. This allow clean
37 | * unused packages when the job is gone.
38 | */
39 | public class PerJobHomeLocator extends HomeLocator {
40 |
41 | private static final long serialVersionUID = 1L;
42 |
43 | @DataBoundConstructor
44 | public PerJobHomeLocator() {
45 | // default constructor
46 | }
47 |
48 | @Override
49 | public FilePath locate(@NonNull FilePath workspace) {
50 | return workspace;
51 | }
52 |
53 | @Extension
54 | @Symbol("workspace")
55 | public static class DescriptorImpl extends HomeLocatorDescriptor {
56 | @Override
57 | public String getDisplayName() {
58 | return Messages.JobHomeLocationLocator_displayName();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/Messages.properties:
--------------------------------------------------------------------------------
1 | # The MIT License
2 | #
3 | # Copyright (c) 2020, Nikolas Falco
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | required=Required
24 | nodeNotAvailable=Cannot get installation for node, since it count be not online
25 | noInstallationFound=No installation {0} found. Please define one in manager Jenkins.
26 | noExecutableFound=Couldn''t find executable "{0}"
27 | Platform.unknown=Unknown OS name: {0}
28 | SystemTools.failureOnProperties=Error getting system properties on remote Node
29 | SystemTools.unsupported32bitArchitecture=NodeJS does not have a 32bit package available for the current node
30 | AndroidSDKInstallation.displayName=Android Build Tool
31 | AndroidSDKInstaller.displayName=Install from dl.google.com/android/repository
32 | AndroidEmulatorBuild.displayName=Run an Android emulator during build
33 | AndroidEmulatorBuild.wrongDensity=Expected a pair integer greater than 0
34 | AndroidEmulatorBuild.defaultLocale=Locale will default to ''{0}'' if not specified
35 | AndroidEmulatorBuild.wrongLocale=Locale is incorrect
36 | AndroidEmulatorBuild.sdCardTooSmall=SD card size must be at least 9 MB
37 | JobHomeLocationLocator.displayName=Local to the workspace
38 | ExecutorHomeLocationLocator.displayName=Local to the executor
39 | DefaultHomeLocationLocator.displayName=Default (~/.android or %HOME%\\.android)
40 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/cli/AVDevice.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.cli;
2 |
3 | import java.util.Objects;
4 |
5 | public class AVDevice {
6 |
7 | private String name;
8 | private String path;
9 | private String sdCard;
10 | private String target;
11 | private String os;
12 | private String abi;
13 | private String error;
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | public void setName(String name) {
20 | this.name = name;
21 | }
22 |
23 | public String getPath() {
24 | return path;
25 | }
26 |
27 | public void setPath(String path) {
28 | this.path = path;
29 | }
30 |
31 | public String getError() {
32 | return error;
33 | }
34 |
35 | public void setError(String error) {
36 | this.error = error;
37 | }
38 |
39 | public String getSDCard() {
40 | return sdCard;
41 | }
42 |
43 | public void setSDCard(String sdcard) {
44 | this.sdCard = sdcard;
45 | }
46 |
47 | public String getTarget() {
48 | return target;
49 | }
50 |
51 | public void setTarget(String target) {
52 | this.target = target;
53 | }
54 |
55 | public String getAndroidOS() {
56 | return os;
57 | }
58 |
59 | public void setAndroidOS(String os) {
60 | this.os = os;
61 | }
62 |
63 | public String getABI() {
64 | return abi;
65 | }
66 |
67 | public void setABI(String abi) {
68 | this.abi = abi;
69 | }
70 |
71 | @Override
72 | public int hashCode() {
73 | return Objects.hash(error, name, path, sdCard, target, abi, os);
74 | }
75 |
76 | @Override
77 | public boolean equals(Object obj) {
78 | if (this == obj) {
79 | return true;
80 | }
81 | if (obj == null) {
82 | return false;
83 | }
84 | if (getClass() != obj.getClass()) {
85 | return false;
86 | }
87 | AVDevice other = (AVDevice) obj;
88 | return Objects.equals(error, other.error) && Objects.equals(name, other.name) //
89 | && Objects.equals(path, other.path) && Objects.equals(sdCard, other.sdCard) //
90 | && Objects.equals(target, other.target) && Objects.equals(abi, other.abi) //
91 | && Objects.equals(os, other.os);
92 | }
93 |
94 | public boolean hasError() {
95 | return error == null;
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/pipeline/AbstractCLIStepExecution.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.pipeline;
2 |
3 | import org.jenkinsci.plugins.workflow.steps.StepContext;
4 | import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution;
5 |
6 | import hudson.AbortException;
7 | import hudson.EnvVars;
8 | import hudson.FilePath;
9 | import hudson.model.Computer;
10 | import hudson.model.Node;
11 | import hudson.model.TaskListener;
12 | import jenkins.plugin.android.emulator.AndroidSDKUtil;
13 | import jenkins.plugin.android.emulator.sdk.home.HomeLocator;
14 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation;
15 |
16 | abstract class AbstractCLIStepExecution extends SynchronousNonBlockingStepExecution {
17 | private static final long serialVersionUID = 1L;
18 |
19 | private final String emulatorTool;
20 | private final HomeLocator homeLocationStrategy;
21 |
22 | protected AbstractCLIStepExecution(String emulatorTool, HomeLocator homeLocationStrategy, StepContext context) {
23 | super(context);
24 | this.emulatorTool = emulatorTool;
25 | this.homeLocationStrategy = homeLocationStrategy;
26 | }
27 |
28 | @Override
29 | protected Void run() throws Exception {
30 | FilePath workspace = getContext().get(FilePath.class);
31 | workspace.mkdirs();
32 |
33 | AndroidSDKInstallation sdk = AndroidSDKUtil.getAndroidSDK(emulatorTool);
34 | if (sdk == null) {
35 | throw new AbortException(jenkins.plugin.android.emulator.Messages.noInstallationFound(emulatorTool));
36 | }
37 |
38 | Computer computer = workspace.toComputer();
39 | if (computer == null) {
40 | throw new AbortException(jenkins.plugin.android.emulator.Messages.nodeNotAvailable());
41 | }
42 | Node node = computer.getNode();
43 | if (node == null) {
44 | throw new AbortException(jenkins.plugin.android.emulator.Messages.nodeNotAvailable());
45 | }
46 |
47 | TaskListener listener = getContext().get(TaskListener.class);
48 | EnvVars env = getContext().get(EnvVars.class);
49 | sdk = sdk.forNode(node, listener);
50 | sdk = sdk.forEnvironment(env);
51 |
52 | sdk.buildEnvVars(env);
53 |
54 | // configure home location
55 | FilePath homeLocation = homeLocationStrategy.locate(workspace);
56 | HomeLocator.buildEnvVars(homeLocation, env);
57 |
58 | return doRun(sdk, listener, env);
59 | }
60 |
61 | protected abstract Void doRun(AndroidSDKInstallation sdk, TaskListener listener, EnvVars env) throws Exception;
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/home/DefaultHomeLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.sdk.home;
25 |
26 | import java.io.IOException;
27 |
28 | import org.jenkinsci.Symbol;
29 | import org.kohsuke.stapler.DataBoundConstructor;
30 |
31 | import hudson.Extension;
32 |
33 | import edu.umd.cs.findbugs.annotations.NonNull;
34 | import hudson.FilePath;
35 | import jenkins.model.Jenkins;
36 | import jenkins.plugin.android.emulator.Messages;
37 |
38 | /**
39 | * Uses NPM's default global cache, which is actually {@code ~/.android} on Unix
40 | * system or {@code %HOME%\.android} on Windows system.
41 | */
42 | public class DefaultHomeLocator extends HomeLocator {
43 |
44 | private static final long serialVersionUID = 3368523530762397938L;
45 |
46 | @DataBoundConstructor
47 | public DefaultHomeLocator() {
48 | // default constructor
49 | }
50 |
51 | @Override
52 | public FilePath locate(@NonNull FilePath workspace) {
53 | try {
54 | return FilePath.getHomeDirectory(workspace.getChannel());
55 | } catch (InterruptedException | IOException e) {
56 | return Jenkins.get().getRootPath();
57 | }
58 | }
59 |
60 | @Extension
61 | @Symbol("home")
62 | public static class DescriptorImpl extends HomeLocatorDescriptor {
63 | @Override
64 | public String getDisplayName() {
65 | return Messages.DefaultHomeLocationLocator_displayName();
66 | }
67 | }
68 |
69 | }
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/AndroidSDKConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator;
25 |
26 | public final class AndroidSDKConstants {
27 |
28 | private AndroidSDKConstants() {
29 | // default constructor
30 | }
31 |
32 | public static final String ANDROID_CACHE = ".android";
33 | public static final String DDMS_CONFIG = "ddms.cfg";
34 | public static final String LOCAL_REPO_CONFIG = "repositories.cfg";
35 |
36 | public static final String ENV_ADB_TRACE = "ADB_TRACE";
37 | public static final String ENV_ADB_LOCAL_TRANSPORT_MAX_PORT = "ADB_LOCAL_TRANSPORT_MAX_PORT";
38 | /**
39 | * Sets the path to the directory that contains all AVD-specific files,
40 | * which mostly consist of very large disk images.
41 | *
42 | * The default location is $ANDROID_EMULATOR_HOME/avd/. You might want to
43 | * specify a new location if the default location is low on disk space.
44 | */
45 | public static final String ENV_ANDROID_AVD_HOME = "ANDROID_AVD_HOME";
46 | /**
47 | * Sets the path to the user-specific emulator configuration directory.
48 | *
49 | * The default location is $ANDROID_SDK_HOME/.android/.
50 | */
51 | public static final String ENV_ANDROID_EMULATOR_HOME = "ANDROID_EMULATOR_HOME";
52 |
53 | /**
54 | * The Android Debug Bridge (adb) server default TCP port.
55 | */
56 | public static final int ADB_DEFAULT_SERVER_PORT = 5037;
57 | public static final int ADB_CONNECT_TIMEOUT = 60;
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/HardwareProperty.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator;
25 |
26 | import org.apache.commons.lang3.StringUtils;
27 | import org.jenkinsci.Symbol;
28 | import org.kohsuke.stapler.DataBoundConstructor;
29 | import org.kohsuke.stapler.QueryParameter;
30 |
31 | import hudson.Extension;
32 | import hudson.Util;
33 | import hudson.model.AbstractDescribableImpl;
34 | import hudson.model.Descriptor;
35 | import hudson.util.FormValidation;
36 |
37 | public class HardwareProperty extends AbstractDescribableImpl {
38 |
39 | private final String key;
40 | private final String value;
41 |
42 | @DataBoundConstructor
43 | public HardwareProperty(String key, String value) {
44 | this.key = Util.fixEmptyAndTrim(key);
45 | this.value = Util.fixEmptyAndTrim(value);
46 | }
47 |
48 | public String getKey() {
49 | return key;
50 | }
51 |
52 | public String getValue() {
53 | return value;
54 | }
55 |
56 | @Symbol("hwProperty")
57 | @Extension
58 | public static final class DescriptorImpl extends Descriptor {
59 | @Override
60 | public String getDisplayName() {
61 | return "Property";
62 | }
63 |
64 | public FormValidation doCheckKey(@QueryParameter String key) {
65 | if (StringUtils.isBlank(key)) {
66 | return FormValidation.error(Messages.required());
67 | }
68 | return FormValidation.ok();
69 | }
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/android_emulator/monkey/MonkeyBuilder/config.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ${%Zero or more Android package IDs to monkey around with. If not specified, all installed packages will be used. Multiple packages can be separated by a comma}
7 |
8 |
9 |
10 |
11 | ${%Number of events the monkey should perform. If not specified, no events will be generated}
12 |
13 |
14 |
15 |
16 | ${%In milliseconds. If 0 or not specified, events are generated as rapidly as possible}
17 |
18 |
19 |
20 |
21 |
22 | ${%Name of a file within the workspace to write monkey output to. Defaults to "monkey.txt" in the root of the workspace}
23 |
24 |
25 |
26 |
27 | ${%Seed value for the pseudo-random number generator. Enter a number, "timestamp", or "random". If 0 or not specified, a timestamp-based value will be used}
28 |
29 |
30 |
31 |
32 | ${%Zero or more intent categories for the monkey to visit. If not specified, activities with "android.intent.category.LAUNCHER" or "android.intent.category.MONKEY" will be used. Multiple categories can be separated by a comma}
33 |
34 |
35 |
36 |
37 | ${%A list of optional command line parameters to pass to monkey. e.g. "--ignore-native-crashes --pct-trackball 0"}
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/ScreenDensity.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator;
2 |
3 | import java.io.Serializable;
4 |
5 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
6 | import hudson.Util;
7 |
8 | @SuppressWarnings("serial")
9 | public class ScreenDensity implements Serializable {
10 |
11 | public static final ScreenDensity LOW = new ScreenDensity(120, "ldpi");
12 | public static final ScreenDensity MEDIUM = new ScreenDensity(160, "mdpi");
13 | public static final ScreenDensity TV_720P = new ScreenDensity(213, "tvdpi");
14 | public static final ScreenDensity HIGH = new ScreenDensity(240, "hdpi");
15 | public static final ScreenDensity EXTRA_HIGH = new ScreenDensity(320, "xhdpi");
16 | public static final ScreenDensity EXTRA_HIGH_400 = new ScreenDensity(400);
17 | public static final ScreenDensity EXTRA_HIGH_420 = new ScreenDensity(420);
18 | public static final ScreenDensity EXTRA_EXTRA_HIGH = new ScreenDensity(480, "xxhdpi");
19 | public static final ScreenDensity EXTRA_EXTRA_HIGH_560 = new ScreenDensity(560);
20 | public static final ScreenDensity EXTRA_EXTRA_EXTRA_HIGH = new ScreenDensity(640, "xxxhdpi");
21 | private static final ScreenDensity[] PRESETS = new ScreenDensity[] { LOW, MEDIUM, TV_720P, HIGH,
22 | EXTRA_HIGH, EXTRA_HIGH_400, EXTRA_HIGH_420, EXTRA_EXTRA_HIGH, EXTRA_EXTRA_HIGH_560,
23 | EXTRA_EXTRA_EXTRA_HIGH };
24 |
25 | public static ScreenDensity[] values() {
26 | return PRESETS;
27 | }
28 |
29 | public static ScreenDensity valueOf(String density) {
30 | if (Util.fixEmptyAndTrim(density) == null) {
31 | return null;
32 | } else {
33 | density = density.toLowerCase();
34 | }
35 |
36 | for (ScreenDensity preset : PRESETS) {
37 | if (density.equals(preset.alias) || density.equals(preset.toString())) {
38 | return preset;
39 | }
40 | }
41 |
42 | // Return custom value, if things look valid
43 | try {
44 | int dpi = Integer.parseInt(density);
45 | return new ScreenDensity(dpi);
46 | } catch (NumberFormatException ex) {
47 | return null;
48 | }
49 | }
50 |
51 | private final int dpi;
52 | private final String alias;
53 |
54 | private ScreenDensity(int dpi, String alias) {
55 | this.dpi = dpi;
56 | this.alias = alias;
57 | }
58 |
59 | private ScreenDensity(int density) {
60 | this(density, null);
61 | }
62 |
63 | public boolean isCustomDensity() {
64 | return alias == null;
65 | }
66 |
67 | public int getDpi() {
68 | return dpi;
69 | }
70 |
71 | @Override
72 | public String toString() {
73 | return Integer.toString(dpi);
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/AndroidSDKUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator;
25 |
26 | import edu.umd.cs.findbugs.annotations.Nullable;
27 |
28 | import jenkins.model.Jenkins;
29 |
30 | import edu.umd.cs.findbugs.annotations.NonNull;
31 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation;
32 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation.DescriptorImpl;
33 |
34 | public final class AndroidSDKUtil {
35 | private AndroidSDKUtil() {
36 | // default constructor
37 | }
38 |
39 | /**
40 | * Gets the AndroidSDK to use.
41 | *
42 | * @param name the name of AndroidSDK installation
43 | * @return a AndroidSDK installation for the given name if exists,
44 | * {@code null} otherwise.
45 | */
46 | @Nullable
47 | public static AndroidSDKInstallation getAndroidSDK(@Nullable String name) {
48 | if (name != null) {
49 | for (AndroidSDKInstallation installation : getInstallations()) {
50 | if (name.equals(installation.getName()))
51 | return installation;
52 | }
53 | }
54 | return null;
55 | }
56 |
57 | /**
58 | * Get all AndroidSDK installation defined in Jenkins.
59 | *
60 | * @return an array of AndroidSDK tool installation
61 | */
62 | @NonNull
63 | public static AndroidSDKInstallation[] getInstallations() {
64 | DescriptorImpl descriptor = (DescriptorImpl) Jenkins.get().getDescriptorOrDie(AndroidSDKInstallation.class);
65 | return descriptor.getInstallations();
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/pipeline/ADBStep.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.pipeline;
2 |
3 | import java.util.Set;
4 |
5 | import org.jenkinsci.plugins.workflow.steps.StepContext;
6 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
7 | import org.jenkinsci.plugins.workflow.steps.StepExecution;
8 | import org.kohsuke.stapler.DataBoundConstructor;
9 |
10 | import com.google.common.collect.ImmutableSet;
11 |
12 | import edu.umd.cs.findbugs.annotations.NonNull;
13 |
14 | import hudson.EnvVars;
15 | import hudson.Extension;
16 | import hudson.FilePath;
17 | import hudson.Launcher;
18 | import hudson.model.TaskListener;
19 | import jenkins.plugin.android.emulator.sdk.cli.ADBCLIBuilder;
20 | import jenkins.plugin.android.emulator.sdk.cli.CLICommand;
21 | import jenkins.plugin.android.emulator.sdk.home.HomeLocator;
22 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation;
23 |
24 | public class ADBStep extends AbstractCLIStep {
25 | private class ADBStepExecution extends AbstractCLIStepExecution {
26 | private static final long serialVersionUID = 1L;
27 |
28 | protected ADBStepExecution(StepContext context) {
29 | super(emulatorTool, homeLocationStrategy, context);
30 | }
31 |
32 | @Override
33 | protected Void doRun(AndroidSDKInstallation sdk, TaskListener listener, EnvVars env) throws Exception {
34 | FilePath adb = sdk.getToolLocator().getADB(getContext().get(Launcher.class));
35 |
36 | String[] argumentsExp = env.expand(arguments.replaceAll("[\t\r\n]+", " ")).split("\\s+");
37 | CLICommand cli = ADBCLIBuilder.with(adb) //
38 | .arguments(argumentsExp) //
39 | .withEnv(env);
40 | return quiet ? cli.execute() : cli.execute(listener);
41 | }
42 |
43 | }
44 |
45 | private static final long serialVersionUID = -1557453962312014910L;
46 |
47 | @DataBoundConstructor
48 | public ADBStep(@NonNull String emulatorTool, @NonNull HomeLocator homeLocationStrategy, @NonNull String arguments) {
49 | super(emulatorTool, homeLocationStrategy, arguments);
50 | }
51 |
52 | @Override
53 | public StepExecution start(StepContext context) throws Exception {
54 | return new ADBStepExecution(context);
55 | }
56 |
57 | @Extension
58 | public static class DescriptorImpl extends StepDescriptor {
59 | @Override
60 | public String getFunctionName() {
61 | return "adb";
62 | }
63 |
64 | @Override
65 | public String getDisplayName() {
66 | return Messages.ADBStep_displayName();
67 | }
68 |
69 | @Override
70 | public Set extends Class>> getRequiredContext() {
71 | return ImmutableSet.of(FilePath.class, TaskListener.class, Launcher.class, EnvVars.class);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/pipeline/AVDManagerStep.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.pipeline;
2 |
3 | import java.util.Set;
4 |
5 | import org.jenkinsci.plugins.workflow.steps.StepContext;
6 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
7 | import org.jenkinsci.plugins.workflow.steps.StepExecution;
8 | import org.kohsuke.stapler.DataBoundConstructor;
9 |
10 | import com.google.common.collect.ImmutableSet;
11 |
12 | import edu.umd.cs.findbugs.annotations.NonNull;
13 |
14 | import hudson.EnvVars;
15 | import hudson.Extension;
16 | import hudson.FilePath;
17 | import hudson.Launcher;
18 | import hudson.model.TaskListener;
19 | import jenkins.plugin.android.emulator.sdk.cli.AVDManagerCLIBuilder;
20 | import jenkins.plugin.android.emulator.sdk.cli.CLICommand;
21 | import jenkins.plugin.android.emulator.sdk.home.HomeLocator;
22 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation;
23 |
24 | public class AVDManagerStep extends AbstractCLIStep {
25 | private class AVDManagerStepExecution extends AbstractCLIStepExecution {
26 | private static final long serialVersionUID = 1L;
27 |
28 | protected AVDManagerStepExecution(StepContext context) {
29 | super(emulatorTool, homeLocationStrategy, context);
30 | }
31 |
32 | @Override
33 | protected Void doRun(AndroidSDKInstallation sdk, TaskListener listener, EnvVars env) throws Exception {
34 | FilePath avdManager = sdk.getToolLocator().getAVDManager(getContext().get(Launcher.class));
35 |
36 | String[] argumentsExp = env.expand(arguments.replaceAll("[\t\r\n]+", " ")).split("\\s+");
37 | CLICommand cli = AVDManagerCLIBuilder.with(avdManager) //
38 | .arguments(argumentsExp) //
39 | .withEnv(env);
40 | return quiet ? cli.execute() : cli.execute(listener);
41 | }
42 |
43 | }
44 |
45 | private static final long serialVersionUID = -9142762434729619710L;
46 |
47 | @DataBoundConstructor
48 | public AVDManagerStep(@NonNull String emulatorTool, @NonNull HomeLocator homeLocationStrategy, @NonNull String arguments) {
49 | super(emulatorTool, homeLocationStrategy, arguments);
50 | }
51 |
52 | @Override
53 | public StepExecution start(StepContext context) throws Exception {
54 | return new AVDManagerStepExecution(context);
55 | }
56 |
57 | @Extension
58 | public static class DescriptorImpl extends StepDescriptor {
59 | @Override
60 | public String getFunctionName() {
61 | return "avdmanager";
62 | }
63 |
64 | @Override
65 | public String getDisplayName() {
66 | return Messages.AVDManagerStep_displayName();
67 | }
68 |
69 | @Override
70 | public Set extends Class>> getRequiredContext() {
71 | return ImmutableSet.of(FilePath.class, TaskListener.class, Launcher.class, EnvVars.class);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/monkey/MonkeyAction.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.monkey;
2 |
3 | import hudson.model.Action;
4 | import hudson.plugins.android_emulator.Messages;
5 |
6 | import org.apache.commons.lang3.builder.HashCodeBuilder;
7 | import org.kohsuke.stapler.export.Exported;
8 |
9 | public class MonkeyAction implements Action {
10 |
11 | private final MonkeyResult result;
12 | private final int eventCount;
13 | private final int totalEventCount;
14 |
15 | public MonkeyAction(MonkeyResult outcome) {
16 | this(outcome, 0, 0);
17 | }
18 |
19 | public MonkeyAction(MonkeyResult outcome, int eventsCompleted, int configuredEvents) {
20 | this.result = outcome;
21 | this.eventCount = eventsCompleted;
22 | this.totalEventCount = configuredEvents;
23 | }
24 |
25 | @Exported
26 | public String getResultIcon() {
27 | if (result == MonkeyResult.Success) {
28 | return "monkey-happy_48x48.png";
29 | }
30 | return "monkey-sad_48x48.png";
31 | }
32 |
33 | @Exported
34 | public String getSummary() {
35 | String description;
36 | switch (result) {
37 | case Success:
38 | description = Messages.MONKEY_RESULT_SUCCESS(eventCount);
39 | break;
40 | case Crash:
41 | description = Messages.MONKEY_RESULT_CRASH(eventCount, totalEventCount);
42 | break;
43 | case AppNotResponding:
44 | description = Messages.MONKEY_RESULT_ANR(eventCount, totalEventCount);
45 | break;
46 | case UnrecognisedFormat:
47 | description = Messages.MONKEY_RESULT_UNRECOGNISED();
48 | break;
49 | case NothingToParse:
50 | default:
51 | description = Messages.MONKEY_RESULT_NONE();
52 | break;
53 | }
54 | return Messages.MONKEY_RESULT(description);
55 | }
56 |
57 | public String getDisplayName() {
58 | return null;
59 | }
60 |
61 | public String getIconFileName() {
62 | return null;
63 | }
64 |
65 | public String getUrlName() {
66 | return null;
67 | }
68 |
69 | @Override
70 | public boolean equals(Object that) {
71 | if (this == that) {
72 | return true;
73 | }
74 | if (!(that instanceof MonkeyAction)) {
75 | return false;
76 | }
77 |
78 | MonkeyAction other = (MonkeyAction) that;
79 | return result == other.result
80 | && eventCount == other.eventCount
81 | && totalEventCount == other.totalEventCount;
82 | }
83 |
84 | @Override
85 | public int hashCode() {
86 | return new HashCodeBuilder()
87 | .append(result)
88 | .append(eventCount)
89 | .append(totalEventCount)
90 | .toHashCode();
91 | }
92 |
93 | @Override
94 | public String toString() {
95 | return String.format("%s:%d,%d", result, eventCount, totalEventCount);
96 | }
97 |
98 | }
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/pipeline/EmulatorStep.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.pipeline;
2 |
3 | import java.util.Set;
4 |
5 | import org.jenkinsci.plugins.workflow.steps.StepContext;
6 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
7 | import org.jenkinsci.plugins.workflow.steps.StepExecution;
8 | import org.kohsuke.stapler.DataBoundConstructor;
9 |
10 | import com.google.common.collect.ImmutableSet;
11 |
12 | import edu.umd.cs.findbugs.annotations.NonNull;
13 |
14 | import hudson.EnvVars;
15 | import hudson.Extension;
16 | import hudson.FilePath;
17 | import hudson.Launcher;
18 | import hudson.model.TaskListener;
19 | import jenkins.model.Jenkins;
20 | import jenkins.plugin.android.emulator.sdk.cli.CLICommand;
21 | import jenkins.plugin.android.emulator.sdk.cli.EmulatorCLIBuilder;
22 | import jenkins.plugin.android.emulator.sdk.home.HomeLocator;
23 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation;
24 |
25 | public class EmulatorStep extends AbstractCLIStep {
26 | private class EmulatorStepExecution extends AbstractCLIStepExecution {
27 | private static final long serialVersionUID = 1L;
28 |
29 | protected EmulatorStepExecution(StepContext context) {
30 | super(emulatorTool, homeLocationStrategy, context);
31 | }
32 |
33 | @Override
34 | protected Void doRun(AndroidSDKInstallation sdk, TaskListener listener, EnvVars env) throws Exception {
35 | FilePath emulator = sdk.getToolLocator().getEmulator(getContext().get(Launcher.class));
36 |
37 | String[] argumentsExp = env.expand(arguments.replaceAll("[\t\r\n]+", " ")).split("\\s+");
38 | CLICommand cli = EmulatorCLIBuilder.with(emulator) //
39 | .proxy(Jenkins.get().proxy) //
40 | .arguments(argumentsExp) //
41 | .withEnv(env);
42 | return quiet ? cli.execute() : cli.execute(listener);
43 | }
44 |
45 | }
46 |
47 | private static final long serialVersionUID = -1557453962312014910L;
48 |
49 | @DataBoundConstructor
50 | public EmulatorStep(@NonNull String emulatorTool, @NonNull HomeLocator homeLocationStrategy, @NonNull String arguments) {
51 | super(emulatorTool, homeLocationStrategy, arguments);
52 | }
53 |
54 | @Override
55 | public StepExecution start(StepContext context) throws Exception {
56 | return new EmulatorStepExecution(context);
57 | }
58 |
59 | @Extension
60 | public static class DescriptorImpl extends StepDescriptor {
61 | @Override
62 | public String getFunctionName() {
63 | return "emulator";
64 | }
65 |
66 | @Override
67 | public String getDisplayName() {
68 | return Messages.EmulatorStep_displayName();
69 | }
70 |
71 | @Override
72 | public Set extends Class>> getRequiredContext() {
73 | return ImmutableSet.of(FilePath.class, TaskListener.class, Launcher.class, EnvVars.class);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/cli/Targets.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.sdk.cli;
25 |
26 | import java.util.Objects;
27 |
28 | public class Targets {
29 |
30 | public enum TargetType {
31 | platform;
32 | }
33 |
34 | private String id;
35 | private String name;
36 | private TargetType type;
37 | private int apiLevel = -1;
38 | private int revision = -1;
39 |
40 | public String getId() {
41 | return id;
42 | }
43 |
44 | public void setId(String id) {
45 | this.id = id;
46 | }
47 |
48 | public String getName() {
49 | return name;
50 | }
51 |
52 | public void setName(String name) {
53 | this.name = name;
54 | }
55 |
56 | public TargetType getType() {
57 | return type;
58 | }
59 |
60 | public void setType(TargetType type) {
61 | this.type = type;
62 | }
63 |
64 | public int getApiLevel() {
65 | return apiLevel;
66 | }
67 |
68 | public void setAPILevel(int apiLevel) {
69 | this.apiLevel = apiLevel;
70 | }
71 |
72 | public int getRevision() {
73 | return revision;
74 | }
75 |
76 | public void setRevision(int revision) {
77 | this.revision = revision;
78 | }
79 |
80 | @Override
81 | public int hashCode() {
82 | return Objects.hash(id, revision);
83 | }
84 |
85 | @Override
86 | public boolean equals(Object obj) {
87 | if (this == obj) {
88 | return true;
89 | }
90 | if (obj == null) {
91 | return false;
92 | }
93 | if (getClass() != obj.getClass()) {
94 | return false;
95 | }
96 | Targets other = (Targets) obj;
97 | return Objects.equals(id, other.id) && revision == other.revision;
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/android_emulator/sdk/cli/SdkCliCommandFactory.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk.cli;
2 |
3 | import hudson.plugins.android_emulator.sdk.AndroidSdk;
4 | import hudson.plugins.android_emulator.util.Utils;
5 |
6 | /**
7 | * This helper class is used to retrieve the correct implementation
8 | * of the {@code adb shell} and the Android SDK tools commands for
9 | * the given device API level respective for the SDK version.
10 | */
11 | public final class SdkCliCommandFactory {
12 |
13 | // empty private constructor to avoid instantiation and sub-classing
14 | private SdkCliCommandFactory() {}
15 |
16 | /**
17 | * Retrieve the correct {@code AdbShellCommands} for the given API-Level of the
18 | * device where the commands should run.
19 | *
20 | * @param deviceAPILevel Android API-Level for the target device
21 | * @return an object of an class implementing the {@code AdbShellCommands} interface to retrieve
22 | * the correct {@code adb shell} commands for the given API-level
23 | */
24 | public static AdbShellCommands getAdbShellCommandForAPILevel(final int deviceAPILevel) {
25 | if (deviceAPILevel < 4) {
26 | return new AdbShellCommand00To03();
27 | } else if (deviceAPILevel < 23) {
28 | return new AdbShellCommand04To22();
29 | } else {
30 | return new AdbShellCommandsCurrentBase();
31 | }
32 | }
33 |
34 | /**
35 | * Retrieve the correct {@code SdkCommands} for the given Android SDK.
36 | *
37 | * @param androidSdk SDK tools to extract the current version and retrieve the correct commands
38 | * @return an object of an class implementing the {@code SdkToolsCommands} interface to retrieve
39 | * the correct tools commands for the given SDK
40 | */
41 | public static SdkToolsCommands getCommandsForSdk(final AndroidSdk androidSdk) {
42 | if (androidSdk != null && androidSdk.hasCommandLineTools()) {
43 | return new SdkToolsCommandsCurrentBase();
44 | }
45 |
46 | // if no androidSdk is given, simply assume the latest commands
47 | final String sdkToolsVersion = (androidSdk != null) ? androidSdk.getSdkToolsVersion() : String.valueOf(Integer.MAX_VALUE);
48 | return SdkCliCommandFactory.getCommandsForSdk(sdkToolsVersion);
49 | }
50 |
51 | /**
52 | * Retrieve the correct {@code SdkCommands} for the given SDK Tools major version.
53 | *
54 | * @param sdkToolsVersion SDK Tools version, to retrieve the correct commands
55 | * @return an object of an class implementing the {@code SdkToolsCommands} interface to retrieve
56 | * the correct tools commands for the given SDK version
57 | */
58 | public static SdkToolsCommands getCommandsForSdk(final String sdkToolsVersion) {
59 | if (Utils.isVersionOlderThan(sdkToolsVersion, "17")) {
60 | return new SdkToolsCommands00To16();
61 | } else if (Utils.isVersionOlderThan(sdkToolsVersion, "25.3")) {
62 | return new SdkToolsCommands17To25_2();
63 | } else {
64 | return new SdkToolsCommandsCurrentBase();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/home/PerExecutorHomeLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.sdk.home;
25 |
26 | import org.jenkinsci.Symbol;
27 | import org.kohsuke.stapler.DataBoundConstructor;
28 |
29 | import hudson.Extension;
30 |
31 | import edu.umd.cs.findbugs.annotations.NonNull;
32 | import hudson.FilePath;
33 | import hudson.model.Computer;
34 | import hudson.model.Executor;
35 | import hudson.model.Node;
36 | import jenkins.plugin.android.emulator.Messages;
37 |
38 | /**
39 | * Relocates the default SDk home to a folder specific for the executor in the
40 | * node home folder {@code ~/android_$executorNumber/.android}.
41 | */
42 | public class PerExecutorHomeLocator extends HomeLocator {
43 |
44 | private static final long serialVersionUID = 5353670448852887996L;
45 |
46 | @DataBoundConstructor
47 | public PerExecutorHomeLocator() {
48 | // default constructor
49 | }
50 |
51 | @Override
52 | public FilePath locate(@NonNull FilePath workspace) {
53 | final Computer computer = workspace.toComputer();
54 | if (computer == null) {
55 | throw new IllegalStateException(Messages.nodeNotAvailable());
56 | }
57 | final Node node = computer.getNode();
58 | if (node == null) {
59 | throw new IllegalStateException(Messages.nodeNotAvailable());
60 | }
61 | final FilePath rootPath = node.getRootPath();
62 | final Executor executor = Executor.currentExecutor();
63 | if (rootPath == null || executor == null) {
64 | return null;
65 | }
66 | return rootPath.child("android_" + executor.getNumber());
67 | }
68 |
69 | @Extension
70 | @Symbol("executor")
71 | public static class DescriptorImpl extends HomeLocatorDescriptor {
72 | @Override
73 | public String getDisplayName() {
74 | return Messages.ExecutorHomeLocationLocator_displayName();
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/pipeline/SDKManagerStep.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.pipeline;
2 |
3 | import java.util.Set;
4 |
5 | import org.jenkinsci.plugins.workflow.steps.StepContext;
6 | import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
7 | import org.jenkinsci.plugins.workflow.steps.StepExecution;
8 | import org.kohsuke.stapler.DataBoundConstructor;
9 |
10 | import com.google.common.collect.ImmutableSet;
11 |
12 | import edu.umd.cs.findbugs.annotations.NonNull;
13 |
14 | import hudson.EnvVars;
15 | import hudson.Extension;
16 | import hudson.FilePath;
17 | import hudson.Launcher;
18 | import hudson.model.TaskListener;
19 | import hudson.plugins.android_emulator.Constants;
20 | import jenkins.model.Jenkins;
21 | import jenkins.plugin.android.emulator.sdk.cli.CLICommand;
22 | import jenkins.plugin.android.emulator.sdk.cli.SDKManagerCLIBuilder;
23 | import jenkins.plugin.android.emulator.sdk.home.HomeLocator;
24 | import jenkins.plugin.android.emulator.tools.AndroidSDKInstallation;
25 |
26 | public class SDKManagerStep extends AbstractCLIStep {
27 | private class SDKManagerStepExecution extends AbstractCLIStepExecution {
28 | private static final long serialVersionUID = 1L;
29 |
30 | protected SDKManagerStepExecution(StepContext context) {
31 | super(emulatorTool, homeLocationStrategy, context);
32 | }
33 |
34 | @Override
35 | protected Void doRun(AndroidSDKInstallation sdk, TaskListener listener, EnvVars env) throws Exception {
36 | FilePath sdkManager = sdk.getToolLocator().getSDKManager(getContext().get(Launcher.class));
37 |
38 | String[] argumentsExp = env.expand(arguments.replaceAll("[\t\r\n]+", " ")).split("\\s+");
39 | CLICommand cli = SDKManagerCLIBuilder.with(sdkManager) //
40 | .proxy(Jenkins.get().proxy) //
41 | .sdkRoot(env.get(Constants.ENV_VAR_ANDROID_SDK_ROOT)) //
42 | .arguments(argumentsExp) //
43 | .withEnv(env);
44 | return quiet ? cli.execute() : cli.execute(listener);
45 | }
46 |
47 | }
48 |
49 | private static final long serialVersionUID = -1557453962312014910L;
50 |
51 | @DataBoundConstructor
52 | public SDKManagerStep(@NonNull String emulatorTool, @NonNull HomeLocator homeLocationStrategy, @NonNull String arguments) {
53 | super(emulatorTool, homeLocationStrategy, arguments);
54 | }
55 |
56 | @Override
57 | public StepExecution start(StepContext context) throws Exception {
58 | return new SDKManagerStepExecution(context);
59 | }
60 |
61 | @Extension
62 | public static class DescriptorImpl extends StepDescriptor {
63 | @Override
64 | public String getFunctionName() {
65 | return "sdkmanager";
66 | }
67 |
68 | @Override
69 | public String getDisplayName() {
70 | return Messages.AVDManagerStep_displayName();
71 | }
72 |
73 | @Override
74 | public Set extends Class>> getRequiredContext() {
75 | return ImmutableSet.of(FilePath.class, TaskListener.class, Launcher.class, EnvVars.class);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/android_emulator/sdk/AndroidSdkTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.android_emulator.sdk;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.io.IOException;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertEquals;
8 | import static org.junit.jupiter.api.Assertions.assertFalse;
9 | import static org.junit.jupiter.api.Assertions.assertTrue;
10 |
11 | class AndroidSdkTest {
12 |
13 | @Test
14 | void testGetSdkToolsMajorVersion() {
15 | assertEquals(0, createSdkWithTools(null).getSdkToolsMajorVersion());
16 | assertEquals(20, createSdkWithTools("20").getSdkToolsMajorVersion());
17 | assertEquals(20, createSdkWithTools("20.0").getSdkToolsMajorVersion());
18 | assertEquals(20, createSdkWithTools("20.0.1").getSdkToolsMajorVersion());
19 | assertEquals(21, createSdkWithTools("21 rc3").getSdkToolsMajorVersion());
20 | assertEquals(22, createSdkWithTools("22.6").getSdkToolsMajorVersion());
21 | }
22 |
23 | @Test
24 | void testEmulatorEngineV2Support() {
25 | assertEqualsHelperEmulatorEngineV2Support(null, false, false);
26 | assertEqualsHelperEmulatorEngineV2Support("24", false, false);
27 | assertEqualsHelperEmulatorEngineV2Support("24.1.1", false, false);
28 | assertEqualsHelperEmulatorEngineV2Support("24.4", false, false);
29 | assertEqualsHelperEmulatorEngineV2Support("25", true, false);
30 | assertEqualsHelperEmulatorEngineV2Support("25.2.1", true, false);
31 | assertEqualsHelperEmulatorEngineV2Support("25.3", true, false);
32 | assertEqualsHelperEmulatorEngineV2Support("26", true, true);
33 | assertEqualsHelperEmulatorEngineV2Support("26.1.1", true, true);
34 | assertEqualsHelperEmulatorEngineV2Support("27", true, true);
35 | }
36 |
37 | @Test
38 | void testUseLegacySdkStructure() {
39 | assertFalse(createSdkWithTools(null).useLegacySdkStructure());
40 | assertTrue(createSdkWithTools("24").useLegacySdkStructure());
41 | assertTrue(createSdkWithTools("24.1.1").useLegacySdkStructure());
42 | assertTrue(createSdkWithTools("24.4").useLegacySdkStructure());
43 | assertTrue(createSdkWithTools("25").useLegacySdkStructure());
44 | assertTrue(createSdkWithTools("25.2.1").useLegacySdkStructure());
45 | assertFalse(createSdkWithTools("25.3").useLegacySdkStructure());
46 | assertFalse(createSdkWithTools("26").useLegacySdkStructure());
47 | assertFalse(createSdkWithTools("26.1.1").useLegacySdkStructure());
48 | assertFalse(createSdkWithTools("27").useLegacySdkStructure());
49 | }
50 |
51 | private void assertEqualsHelperEmulatorEngineV2Support(final String sdkToolsVersion,
52 | final boolean expectedSupportV2Result, final boolean expectedSupportV2FullResult) {
53 |
54 | final AndroidSdk androidSdk = createSdkWithTools(sdkToolsVersion);
55 | assertEquals(expectedSupportV2Result, androidSdk.supportsEmulatorV2());
56 | assertEquals(expectedSupportV2FullResult, androidSdk.supportsEmulatorV2Full());
57 | }
58 |
59 | private static AndroidSdk createSdkWithTools(String version) {
60 | AndroidSdk sdk = null;
61 | try {
62 | sdk = new AndroidSdk(null, null);
63 | sdk.setSdkToolsVersion(version);
64 | } catch (IOException e) {
65 | e.printStackTrace();
66 | }
67 | return sdk;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/home/HomeLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.sdk.home;
25 |
26 | import java.io.IOException;
27 | import java.io.Serializable;
28 |
29 | import edu.umd.cs.findbugs.annotations.CheckForNull;
30 |
31 | import hudson.AbortException;
32 |
33 | import edu.umd.cs.findbugs.annotations.NonNull;
34 | import hudson.EnvVars;
35 | import hudson.ExtensionPoint;
36 | import hudson.FilePath;
37 | import hudson.model.AbstractDescribableImpl;
38 | import hudson.model.Computer;
39 | import hudson.plugins.android_emulator.Constants;
40 | import jenkins.plugin.android.emulator.AndroidSDKConstants;
41 |
42 | /**
43 | * Strategy pattern that decides the location of the SDK home location for a
44 | * build.
45 | */
46 | public abstract class HomeLocator extends AbstractDescribableImpl implements ExtensionPoint, Serializable {
47 |
48 | private static final long serialVersionUID = 1L;
49 |
50 | /**
51 | * Called during the build on the master to determine the location of the
52 | * local SDK home location.
53 | *
54 | * @param workspace the workspace file path locator
55 | * @return null to let SDK build tool uses its default location. Otherwise
56 | * this must be located on the same node as described by this path.
57 | */
58 | public abstract FilePath locate(@NonNull FilePath workspace);
59 |
60 | @Override
61 | public HomeLocatorDescriptor getDescriptor() {
62 | return (HomeLocatorDescriptor) super.getDescriptor();
63 | }
64 |
65 | public static void buildEnvVars(@NonNull FilePath homeLocation, @CheckForNull EnvVars env) throws IOException, InterruptedException {
66 | if (env == null) {
67 | env = new EnvVars();
68 | }
69 | env.put(Constants.ENV_VAR_ANDROID_SDK_HOME, homeLocation.getRemote());
70 |
71 | FilePath emulatorLocation = homeLocation.child(AndroidSDKConstants.ANDROID_CACHE);
72 | env.put(AndroidSDKConstants.ENV_ANDROID_EMULATOR_HOME, emulatorLocation.getRemote());
73 |
74 | FilePath avdPath = emulatorLocation.child("avd");
75 | avdPath.mkdirs(); // ensure that this folder exists
76 | env.put(AndroidSDKConstants.ENV_ANDROID_AVD_HOME, avdPath.getRemote());
77 | }
78 | }
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/sdk/cli/SDKPackages.java:
--------------------------------------------------------------------------------
1 | package jenkins.plugin.android.emulator.sdk.cli;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import java.util.Objects;
6 |
7 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
8 |
9 | public class SDKPackages {
10 | public static class SDKPackage implements Comparable {
11 | private String id;
12 | private Version version;
13 | private Version available;
14 | private String description;
15 | private String location;
16 |
17 | public String getId() {
18 | return id;
19 | }
20 |
21 | public void setId(String id) {
22 | this.id = id;
23 | }
24 |
25 | public Version getVersion() {
26 | return version;
27 | }
28 |
29 | public void setVersion(Version version) {
30 | this.version = version;
31 | }
32 |
33 | public String getDescription() {
34 | return description;
35 | }
36 |
37 | public void setDescription(String description) {
38 | this.description = description;
39 | }
40 |
41 | public String getLocation() {
42 | return location;
43 | }
44 |
45 | public void setLocation(String location) {
46 | this.location = location;
47 | }
48 |
49 | public Version getAvailable() {
50 | return available;
51 | }
52 |
53 | public void setAvailable(Version available) {
54 | this.available = available;
55 | }
56 |
57 | @Override
58 | public int compareTo(SDKPackage o) {
59 | if (o == null) {
60 | return 1;
61 | }
62 | int result = id.compareTo(o.getId());
63 | if (result == 0) {
64 | result = version.compareTo(o.getVersion());
65 | }
66 | return result;
67 | }
68 |
69 | @Override
70 | public int hashCode() {
71 | return Objects.hash(id, version);
72 | }
73 |
74 | @Override
75 | public boolean equals(Object obj) {
76 | if (this == obj) {
77 | return true;
78 | }
79 | if (obj == null) {
80 | return false;
81 | }
82 | if (getClass() != obj.getClass())
83 | return false;
84 | SDKPackage other = (SDKPackage) obj;
85 | return Objects.equals(id, other.id) && Objects.equals(version, other.version);
86 | }
87 |
88 | @Override
89 | public String toString() {
90 | return id;
91 | }
92 | }
93 |
94 | private List available = new LinkedList<>();
95 | private List updates = new LinkedList<>();
96 | private List installed = new LinkedList<>();
97 |
98 | public List getAvailable() {
99 | return available;
100 | }
101 |
102 | public void setAvailable(List available) {
103 | this.available = available;
104 | }
105 |
106 | public List getUpdates() {
107 | return updates;
108 | }
109 |
110 | public void setUpdates(List updates) {
111 | this.updates = updates;
112 | }
113 |
114 | public List getInstalled() {
115 | return installed;
116 | }
117 |
118 | public void setInstalled(List installed) {
119 | this.installed = installed;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/resources/jenkins/plugin/android/emulator/AndroidEmulatorBuild/config.jelly:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/main/java/jenkins/plugin/android/emulator/tools/Platform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright (c) 2020, Nikolas Falco
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | package jenkins.plugin.android.emulator.tools;
25 |
26 | import java.io.IOException;
27 | import java.util.Locale;
28 | import java.util.Map;
29 |
30 | import hudson.model.Computer;
31 | import hudson.model.Node;
32 | import jenkins.plugin.android.emulator.Messages;
33 |
34 | /**
35 | * Supported platform.
36 | */
37 | public enum Platform {
38 | LINUX("", "bin"), WINDOWS(".bat", "bin"), OSX(".sh", "bin");
39 |
40 | /**
41 | * Choose the extension file name suitable to run cli commands.
42 | */
43 | public final String extension;
44 | /**
45 | * Choose the folder path suitable bin folder of the bundle.
46 | */
47 | public final String binFolder;
48 |
49 | Platform(String extension, String binFolder) {
50 | this.extension = extension;
51 | this.binFolder = binFolder;
52 | }
53 |
54 | public boolean is(String line) {
55 | return line.contains(name());
56 | }
57 |
58 | /**
59 | * Determines the platform of the given node.
60 | *
61 | * @param node
62 | * the computer node
63 | * @return a platform value that represent the given node
64 | * @throws DetectionFailedException
65 | * when the current platform node is not supported.
66 | */
67 | public static Platform of(Node node) throws DetectionFailedException {
68 | try {
69 | Computer computer = node.toComputer();
70 | if (computer == null) {
71 | throw new DetectionFailedException(Messages.nodeNotAvailable());
72 | }
73 | return detect(computer.getSystemProperties());
74 | } catch (IOException | InterruptedException e) {
75 | throw new DetectionFailedException(Messages.SystemTools_failureOnProperties(), e);
76 | }
77 | }
78 |
79 | public static Platform current() throws DetectionFailedException {
80 | return detect(System.getProperties());
81 | }
82 |
83 | private static Platform detect(Map