The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    └── stale.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── .travis.yml
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Rakefile
├── bin
    └── dryrun
├── docs
    ├── css
    │   └── main.css
    ├── index.html
    ├── js
    │   ├── index.js
    │   └── vendor
    │   │   └── .keep
    └── res
    │   └── .keep
├── dryrun.gemspec
├── extras
    ├── gift.gif
    ├── logo.png
    ├── ss.gif
    ├── usage.gif
    ├── usage_v2.gif
    ├── usage_v3.gif
    └── usage_v4.gif
├── facelift.json
├── lib
    ├── dryrun.rb
    └── dryrun
    │   ├── android_project.rb
    │   ├── android_utils.rb
    │   ├── device.rb
    │   ├── dryrun_utils.rb
    │   ├── github.rb
    │   ├── gradle_adapter.rb
    │   ├── install_application_command.rb
    │   ├── manifest_parser.rb
    │   ├── test_application_command.rb
    │   └── version.rb
└── spec
    ├── dryrun_spec.rb
    ├── github_spec.rb
    └── spec_helper.rb


/.github/stale.yml:
--------------------------------------------------------------------------------
 1 | # Number of days of inactivity before an issue becomes stale
 2 | daysUntilStale: 30
 3 | # Number of days of inactivity before a stale issue is closed
 4 | daysUntilClose: 7
 5 | # Issues with these labels will never be considered stale
 6 | exemptLabels:
 7 |   - pinned
 8 |   - security
 9 | # Label to use when marking an issue as stale
10 | staleLabel: wontfix
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 |   This issue has been automatically marked as stale because it has not had
14 |   recent activity. It will be closed if no further activity occurs. Thank you
15 |   for your contributions.
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: false


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | /.bundle/
 2 | /.yardoc
 3 | /_yardoc/
 4 | /coverage/
 5 | /doc/
 6 | /pkg/
 7 | /spec/reports/
 8 | /tmp/
 9 | .idea/
10 | 


--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --require spec_helper
2 | --tty
3 | --color
4 | --format documentation
5 | --format html -o "tmp/rspec_result.html"
6 | 


--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
 1 | Style/Encoding:
 2 |   Enabled: false
 3 | 
 4 | Metrics/LineLength:
 5 |   Enabled: false
 6 | 
 7 | Metrics/MethodLength:
 8 |   Enabled: false
 9 | 
10 | Metrics/ClassLength:
11 |   Enabled: false
12 | 
13 | Metrics/PerceivedComplexity:
14 |   Enabled: false
15 | 
16 | Metrics/AbcSize:
17 |   Enabled: false
18 | 
19 | Metrics/CyclomaticComplexity:
20 |   Enabled: false
21 | 
22 | AllCops:
23 |   TargetRubyVersion: 2.0
24 | 
25 | Documentation:
26 |   Enabled: false
27 | 


--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | sudo: false
3 | rvm:
4 |   - 2.3.0
5 | 


--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | 
3 | # Specify your gem's dependencies in sinderella.gemspec
4 | gemspec
5 | 


--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
 1 | PATH
 2 |   remote: .
 3 |   specs:
 4 |     dryrun (1.3.2)
 5 |       bundler
 6 |       colorize
 7 |       highline
 8 |       oga
 9 |       rjb
10 | 
11 | GEM
12 |   remote: https://rubygems.org/
13 |   specs:
14 |     ansi (1.5.0)
15 |     ast (2.4.1)
16 |     byebug (11.1.3)
17 |     coderay (1.1.3)
18 |     colorize (0.8.1)
19 |     diff-lcs (1.4.4)
20 |     highline (2.0.3)
21 |     method_source (1.0.0)
22 |     oga (3.3)
23 |       ast
24 |       ruby-ll (~> 2.1)
25 |     pry (0.13.1)
26 |       coderay (~> 1.1)
27 |       method_source (~> 1.0)
28 |     pry-byebug (3.9.0)
29 |       byebug (~> 11.0)
30 |       pry (~> 0.13.0)
31 |     rake (13.0.1)
32 |     rjb (1.6.2)
33 |     rspec (3.9.0)
34 |       rspec-core (~> 3.9.0)
35 |       rspec-expectations (~> 3.9.0)
36 |       rspec-mocks (~> 3.9.0)
37 |     rspec-core (3.9.2)
38 |       rspec-support (~> 3.9.3)
39 |     rspec-expectations (3.9.2)
40 |       diff-lcs (>= 1.2.0, < 2.0)
41 |       rspec-support (~> 3.9.0)
42 |     rspec-mocks (3.9.1)
43 |       diff-lcs (>= 1.2.0, < 2.0)
44 |       rspec-support (~> 3.9.0)
45 |     rspec-support (3.9.3)
46 |     ruby-ll (2.1.2)
47 |       ansi
48 |       ast
49 | 
50 | PLATFORMS
51 |   ruby
52 | 
53 | DEPENDENCIES
54 |   dryrun!
55 |   pry-byebug
56 |   rake
57 |   rspec
58 | 
59 | BUNDLED WITH
60 |    2.1.4
61 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2015 César Ferreira
 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 all
13 | 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 THE
21 | SOFTWARE.
22 | 
23 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | <!--<p align="center">
 2 |   <a href="https://github.com/cesarferreira/dryrun" target="_blank">
 3 |     <img width="200"src="extras/gift.gif">
 4 |   </a>
 5 | </p>-->
 6 | <h1 align="center">dryrun</h1>
 7 | <p align="center"><strong>Try any android library</strong> hosted online <strong>directly</strong> from the <strong>command line</strong></p>
 8 | <p align="center">
 9 |   <a href="https://github.com/cesarferreira/dryrun"><img src="http://ruby-gem-downloads-badge.herokuapp.com/dryrun?type=total" alt="downloads"></a>
10 |   <a href="https://github.com/cesarferreira/dryrun"><img src="https://badge.fury.io/rb/dryrun.svg" alt="npm"></a>
11 |   <a href="http://androidweekly.net/issues/issue-200"><img src="https://img.shields.io/badge/Android%20Weekly-%23200-blue.svg" alt="Android Weekly"></a>
12 |   <a href="https://www.codacy.com/app/cesarferreira/dryrun?utm_source=github.com&utm_medium=referral&utm_content=cesarferreira/dryrun&utm_campaign=badger"><img src="https://api.codacy.com/project/badge/Grade/c9f73e75e72547008558b3e337acbff3" alt="Codacy Badge"></a>
13 | <a href="https://github.com/cesarferreira/dryrun/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed-raw/cesarferreira/dryrun.svg?color=%23FF69B4" alt="Closed"></a>
14 | 
15 | </p>
16 | 
17 | <p align="center">
18 |   <img src="extras/ss.gif" width="100%" />
19 | </p>
20 | 
21 | ## Install
22 | 
23 | ```sh
24 | gem install dryrun
25 | ```
26 | 
27 | ## Usage
28 | 
29 | ```bash
30 | dryrun https://github.com/cesarferreira/android-helloworld
31 | ```
32 | 
33 | Wait a few seconds and the app is now opened on your phone :smiley:
34 | 
35 | ```bash
36 | $ dryrun -h
37 | Usage: dryrun GIT_URL [OPTIONS]
38 | 
39 | Options
40 |     -m, --module MODULE_NAME         Custom module to run
41 |     -b, --branch BRANCH_NAME         Checkout custom branch to run
42 |     -f, --flavour FLAVOUR            Custom flavour (e.g. dev, qa, prod)
43 |     -p, --path PATH                  Custom path to android project
44 |     -t, --tag TAG                    Checkout tag/commit hash to clone (e.g. "v0.4.5", "6f7dd4b")
45 |     -c, --cleanup                    Clean the temporary folder before cloning the project
46 |     -w, --wipe                       Wipe the temporary dryrun folder
47 |     -h, --help                       Displays help
48 |     -v, --version                    Displays the version
49 |     -a, --android-test               Execute android tests
50 | ```
51 | 
52 | ## Alternative scenario (if you don't use `dryrun`)
53 | 
54 | 1. Find the github's repository url
55 | 2. Click the `download zip`
56 | 3. Extract the `zip file`
57 | 4. Open Android Studio
58 | 5. Import the project you just downloaded
59 | 6. Sync gradle
60 | 7. Run the project
61 | 8. Choose the device you want to run
62 | 9. Test all you want
63 | 10. Delete the `project folder` and the `zip file` when you don't want it anymore
64 | 
65 | ## Goodies
66 | 
67 | - Private repos can be tested too :smiley:
68 | ```
69 |   $ dryrun git@github.com:cesarferreira/android-helloworld.git
70 | ```
71 | - No need to cleanup after you test the library.
72 | - No need to wait for **Android Studio** to load.
73 | 
74 | 
75 | ## Notes
76 | 
77 | Be aware that `$ANDROID_SDK_ROOT` environment variable needs to be set. See more in [here](https://developer.android.com/studio/command-line/variables#set)
78 | 
79 | Additionally, on windows in order to use git commands, the following path should be on the environment variable
80 |   - ```...\Git\cmd ```
81 | 
82 | ## Created by
83 | [Cesar Ferreira](https://cesarferreira.com)
84 | 
85 | ## License
86 | MIT © [Cesar Ferreira](http://cesarferreira.com)
87 | 


--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler/gem_tasks'
2 | require 'rspec/core/rake_task'
3 | 
4 | task default: :test
5 | RSpec::Core::RakeTask.new(:test)
6 | 


--------------------------------------------------------------------------------
/bin/dryrun:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | 
3 | require 'bundler/setup'
4 | require 'dryrun'
5 | 
6 | Dryrun::MainApp.new(ARGV).call
7 | 


--------------------------------------------------------------------------------
/docs/css/main.css:
--------------------------------------------------------------------------------
 1 | div.notification.notification-producthunt {
 2 |   border-radius: 0 !important;
 3 |   background: #da552f;
 4 | }
 5 | 
 6 | p.install-text code {
 7 |   border-radius: 5px;
 8 |   padding: 0.75rem;
 9 | }
10 | 
11 | p.install-text code::before {
12 |   content: '$ ';
13 | }
14 | 
15 | p.install-text code:hover {
16 |   cursor: text;
17 | }
18 | 
19 | p.install-text code:hover span {
20 |   background: pink;
21 | }
22 | 
23 | .hero .hero-foot {
24 |   margin-bottom: 1rem;
25 | }
26 | 
27 | #madeWithBulma {
28 |   vertical-align: bottom;
29 | }
30 | 
31 | div.column.has-content-vcentered {
32 |   display: flex;
33 |   flex-direction: column;
34 |   justify-content: center;
35 | }
36 | 
37 | div.notification.copy-notification {
38 |   position: absolute;
39 |   top: 0;
40 |   right: 0;
41 |   z-index: 999;
42 | }
43 | 
44 | .makerlink {
45 |     font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
46 |     right: 0px;
47 |     bottom: 0px;
48 |     position: fixed;
49 |     z-index: 100;
50 |     border-top-left-radius: 5px;
51 |     color: rgb(111, 111, 111);
52 |     padding: 6px;
53 |     border-top: 1px solid rgb(239, 239, 239);
54 |     border-left: 1px solid rgb(239, 239, 239);
55 |     background: rgb(255, 255, 255);
56 |     text-decoration: none;
57 | }
58 | 
59 | .makerlink .makerlink__img {
60 |     width: 22px;
61 |     vertical-align: middle;
62 |     border-radius: 100%;
63 | }
64 | 
65 | .makerlink .makerlink__author {
66 |     vertical-align: middle;
67 |     display: inline;
68 |     font-weight: 500;
69 |     font-size: 14px;
70 |     margin: 0px 0px 0px 7px;
71 | }
72 | 
73 | h1 a {
74 |     color:inherit; 
75 |     text-decoration: none;
76 |  }


--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
 1 | <!-- Generated with: https://github.com/cesarferreira/facelift -->
 2 | <!DOCTYPE html>
 3 | <html>
 4 | <head>
 5 |   <meta charset="utf-8">
 6 |   <meta http-equiv="X-UA-Compatible" content="IE=edge">
 7 |   <meta name="viewport" content="width=device-width, initial-scale=1">
 8 |   <title>dryrun - ☁️ Try the demo project of any Android Library</title>
 9 |   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css" />
10 |   <link rel="stylesheet" href="./css/main.css" />
11 |   <!-- Twitter Meta -->
12 |   <meta name="twitter:card" content="summary" />
13 |   <meta name="twitter:title" content="dryrun" />
14 |   <meta name="twitter:url" content="https://github.com/cesarferreira/dryrun" />
15 |   <meta name="twitter:description" content="☁️ Try the demo project of any Android Library" />
16 |   <meta property="og:url" content="https://github.com/cesarferreira/dryrun" />
17 | 
18 |   <meta property="og:title" content="dryrun" />
19 |   <meta property="og:description" content="☁️ Try the demo project of any Android Library" />
20 | </head>
21 | <body>
22 |   <div class="hero is-fullheight">
23 |     <div class="hero-body">
24 |       <div class="container">
25 |         <div class="columns is-variable is-6">
26 |           <!-- Content Left -->
27 |           <div class="column is-5 has-content-vcentered">
28 |             <h1 class="title is-1"><a href="https://github.com/cesarferreira/dryrun">dryrun</a></h1>
29 |             <h2 class="subtitle">☁️ Try the demo project of any Android Library</h2>
30 |             <div class="call-to-action content">
31 |               <p class="install-text is-size-4">
32 |                 <code><span>gem install dryrun</span></code>
33 |               </p>
34 |               <div class="notification is-link is-hidden copy-notification">Copied to clipboard!</div>
35 |             </div>
36 | 
37 |             <div class="features content">
38 |               <strong>Features</strong>
39 |               <ul>
40 |                 <li>Try any android library hosted online directly from the command line</li>
41 |                 <li>Specify any custom branch to run</li>
42 |                 <li>Specify any flavour to run</li>
43 |                 <li>Specify any app module to run</li>
44 |                 <li>Checkout tag/commit hash to clone (e.g. "v0.4.5", "6f7dd4b")</li>
45 |               </ul>
46 |             </div>
47 |             <div class="features content">
48 |               <strong>Links</strong>
49 |               <ul>
50 |                 <li>GitHub: <a href='https://github.com/cesarferreira/dryrun'>https://github.com/cesarferreira/dryrun</a></li>
51 |                 <li>rubygems: <a href='https://rubygems.org/gems/dryrun/'>https://rubygems.org/gems/dryrun/</a></li>
52 |               </ul>
53 |             </div>
54 | 
55 |           </div>
56 |           <!-- Media Right -->
57 |           <div class="column is-7 has-content-vcentered">
58 |             <figure class="image is-4by2">
59 |               <img src="https://raw.githubusercontent.com/cesarferreira/dryrun/master/extras/ss.gif" />
60 |             </figure>
61 |           </div>
62 |         </div>
63 |       </div>
64 |     </div>
65 |   </div>
66 | 
67 |   <a target="_blank" rel="noopener" class="makerlink" href="http://cesarferreira.com">
68 |     <img class="makerlink__img" src="https://pbs.twimg.com/profile_images/884351017097322496/2mmpORsM_400x400.jpg" style="display: inline-block">
69 |     <p class="makerlink__author">by cesar ferreira</p>
70 |   </a>
71 |   <script async type="text/javascript" src="./js/index.js"></script>
72 | </body>
73 | </html>


--------------------------------------------------------------------------------
/docs/js/index.js:
--------------------------------------------------------------------------------
 1 | // `copyToClipboard()` courtesy @chalarangelo (Angelos Chalaris)
 2 | // refs: https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
 3 | const copyToClipboard = (str) => {
 4 |   const el = document.createElement('textarea');  // Create a <textarea> element
 5 |   el.value = str;                                 // Set its value to the string that you want copied
 6 |   el.setAttribute('readonly', '');                // Make it readonly to be tamper-proof
 7 |   el.style.position = 'absolute';
 8 |   el.style.left = '-9999px';                      // Move outside the screen to make it invisible
 9 |   document.body.appendChild(el);                  // Append the <textarea> element to the HTML document
10 |   const selected =
11 |     document.getSelection().rangeCount > 0        // Check if there is any content selected previously
12 |       ? document.getSelection().getRangeAt(0)     // Store selection if found
13 |       : false;                                    // Mark as false to know no selection existed before
14 |   el.select();                                    // Select the <textarea> content
15 |   document.execCommand('copy');                   // Copy - only works as a result of a user action (e.g. click events)
16 |   document.body.removeChild(el);                  // Remove the <textarea> element
17 |   if (selected) {                                 // If a selection existed before copying
18 |     document.getSelection().removeAllRanges();    // Unselect everything on the HTML document
19 |     document.getSelection().addRange(selected);   // Restore the original selection
20 |   }
21 | };
22 | 
23 | const showCopyNotification = () => {
24 |   const notification = document.querySelector('div.notification.copy-notification');
25 |   notification.classList.remove('is-hidden');
26 |   setTimeout(() => {
27 |     notification.classList.add('is-hidden');
28 |   }, 2000);
29 | };
30 | 
31 | const installTextCode = document.querySelector('p.install-text code');
32 | const installTextSpan = document.querySelector('p.install-text code span');
33 | 
34 | const clickableElements = [installTextCode, installTextSpan];
35 | 
36 | clickableElements.forEach((el) => {
37 |   const npmInstallText = installTextSpan.textContent; // 'npm i -g amo-cli'
38 |   el.addEventListener('click', () => {
39 |     copyToClipboard(npmInstallText);
40 |     showCopyNotification();
41 |   });
42 | });
43 | 


--------------------------------------------------------------------------------
/docs/js/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/docs/js/vendor/.keep


--------------------------------------------------------------------------------
/docs/res/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/docs/res/.keep


--------------------------------------------------------------------------------
/dryrun.gemspec:
--------------------------------------------------------------------------------
 1 | # coding: utf-8
 2 | require File.join([File.dirname(__FILE__), 'lib', 'dryrun', 'version.rb'])
 3 | 
 4 | # rake build    # Build dryrun-0.0.1.gem into the pkg directory
 5 | # rake install  # Build and install dryrun-0.0.1.gem into system gems
 6 | # rake release  # Create tag v0.0.1 and build and push dryrun-0.0.1.gem t...
 7 | # rake spec     # Run RSpec code examples
 8 | 
 9 | Gem::Specification.new do |s|
10 |   s.name          = 'dryrun'
11 |   s.version       = Dryrun::VERSION
12 |   s.authors       = ['cesar ferreira']
13 |   s.email         = ['cesar.manuel.ferreira@gmail.com']
14 | 
15 |   s.summary       = 'Tool to try any android library hosted online directly from the command line'
16 |   s.homepage      = 'http://cesarferreira.com'
17 |   s.license       = 'MIT'
18 |   s.platform      = Gem::Platform::RUBY
19 | 
20 |   s.files         = `git ls-files`.split("
21 | ")
22 |   s.bindir        = 'bin'
23 |   s.require_paths << 'lib'
24 |   s.executables   << 'dryrun'
25 | 
26 |   # s.required_ruby_version = '>= 2.0.0'
27 | 
28 |   s.add_development_dependency 'rake'
29 |   s.add_development_dependency 'pry-byebug'
30 |   s.add_development_dependency 'rspec'
31 | 
32 |   s.add_dependency 'bundler'
33 |   s.add_dependency 'colorize'
34 |   s.add_dependency 'oga'
35 |   s.add_dependency 'highline'
36 |   s.add_dependency 'rjb'
37 | end
38 | 


--------------------------------------------------------------------------------
/extras/gift.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/gift.gif


--------------------------------------------------------------------------------
/extras/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/logo.png


--------------------------------------------------------------------------------
/extras/ss.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/ss.gif


--------------------------------------------------------------------------------
/extras/usage.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/usage.gif


--------------------------------------------------------------------------------
/extras/usage_v2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/usage_v2.gif


--------------------------------------------------------------------------------
/extras/usage_v3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/usage_v3.gif


--------------------------------------------------------------------------------
/extras/usage_v4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesarferreira/dryrun/0ca622b596761cd171246e46b726cc838f179cb0/extras/usage_v4.gif


--------------------------------------------------------------------------------
/facelift.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "title": "dryrun",
 3 |     "subtitle": "☁️ Try the demo project of any Android Library",
 4 |     "installation": "gem install dryrun",
 5 |     "url": "https://github.com/cesarferreira/dryrun",
 6 |     "screenshot": "https://raw.githubusercontent.com/cesarferreira/dryrun/master/extras/ss.gif",
 7 |     "author": {
 8 |         "name": "cesar ferreira",
 9 |         "thumbnail": "https://pbs.twimg.com/profile_images/884351017097322496/2mmpORsM_400x400.jpg",
10 |         "homepage": "http://cesarferreira.com"
11 |     },
12 |     "highlights": [{
13 |             "title": "Features",
14 |             "items": [
15 |                 "Try any android library hosted online directly from the command line",
16 |                 "Specify any custom branch to run",
17 |                 "Specify any flavour to run",
18 |                 "Specify any app module to run",
19 |                 "Checkout tag/commit hash to clone (e.g. \"v0.4.5\", \"6f7dd4b\")"
20 |             ]
21 |         },
22 |         {
23 |             "title": "Links",
24 |             "items": [
25 |                 "GitHub: <a href='https://github.com/cesarferreira/dryrun'>https://github.com/cesarferreira/dryrun</a>",
26 |                 "rubygems: <a href='https://rubygems.org/gems/dryrun/'>https://rubygems.org/gems/dryrun/</a>"
27 |             ]
28 |         }
29 |     ]
30 | }


--------------------------------------------------------------------------------
/lib/dryrun.rb:
--------------------------------------------------------------------------------
  1 | require 'colorize'
  2 | require 'tmpdir'
  3 | require 'fileutils'
  4 | require 'dryrun/github'
  5 | require 'dryrun/version'
  6 | require 'dryrun/android_project'
  7 | require 'dryrun/install_application_command'
  8 | require 'dryrun/test_application_command'
  9 | require 'dryrun/device'
 10 | require 'highline/import'
 11 | require 'openssl'
 12 | require 'open3'
 13 | require 'optparse'
 14 | 
 15 | module Dryrun
 16 |   class MainApp
 17 |     def initialize(arguments)
 18 |       outdated_verification
 19 | 
 20 |       @url = %w(-h --help -v --version -w --wipe).include?(arguments.first) ? nil : arguments.shift
 21 | 
 22 |       # defaults
 23 |       @app_path = nil
 24 |       @custom_module = nil
 25 |       @flavour = ''
 26 |       @tag = nil
 27 |       @branch = 'master'
 28 |       @devices = []
 29 |       @cleanup = false
 30 |       @command = InstallApplicationCommand.new
 31 | 
 32 |       # Parse Options
 33 |       create_options_parser(arguments)
 34 |     end
 35 | 
 36 |     def create_options_parser(args)
 37 |       args.options do |opts|
 38 |         opts.banner = 'Usage: dryrun GIT_URL [OPTIONS]'
 39 |         opts.separator ''
 40 |         opts.separator 'Options'
 41 | 
 42 |         opts.on('-m MODULE_NAME', '--module MODULE_NAME', 'Custom module to run') do |custom_module|
 43 |           @custom_module = custom_module
 44 |         end
 45 | 
 46 |         opts.on('-b BRANCH_NAME', '--branch BRANCH_NAME', 'Checkout custom branch to run') do |branch|
 47 |           @branch = branch
 48 |         end
 49 | 
 50 |         opts.on('-f', '--flavour FLAVOUR', 'Custom flavour (e.g. dev, qa, prod)') do |flavour|
 51 |           @flavour = flavour.capitalize
 52 |         end
 53 | 
 54 |         opts.on('-p PATH', '--path PATH', 'Custom path to android project') do |app_path|
 55 |           @app_path = app_path
 56 |         end
 57 | 
 58 |         opts.on('-t TAG', '--tag TAG', 'Checkout tag/commit hash to clone (e.g. "v0.4.5", "6f7dd4b")') do |tag|
 59 |           @tag = tag
 60 |         end
 61 | 
 62 |         opts.on('-c', '--cleanup', 'Clean the temporary folder before cloning the project') do
 63 |           @cleanup = true
 64 |         end
 65 | 
 66 |         opts.on('-w', '--wipe', 'Wipe the temporary dryrun folder') do
 67 |           wipe_temporary_folder
 68 |         end
 69 | 
 70 |         opts.on('-h', '--help', 'Displays help') do
 71 |           puts opts.help
 72 |           exit
 73 |         end
 74 | 
 75 |         opts.on('-v', '--version', 'Displays the version') do
 76 |           puts Dryrun::VERSION
 77 |           exit
 78 |         end
 79 | 
 80 |         opts.on('-a', '--android-test', 'Execute android tests') do
 81 |           @command = TestApplicationCommand.new
 82 |         end
 83 | 
 84 |         opts.parse!
 85 |       end
 86 |     end
 87 | 
 88 |     def outdated_verification
 89 |       return if DryrunUtils.up_to_date
 90 | 
 91 |       input = nil
 92 | 
 93 |       begin
 94 |         input = ask "\n#{'Your Dryrun version is outdated, want to update?'.yellow} #{'[Y/n]:'.white}"
 95 |       end until %w(y n s).include?(input.downcase)
 96 | 
 97 |       DryrunUtils.execute('gem update dryrun') if input.casecmp('y') == 0
 98 |     end
 99 | 
100 |     def pick_device
101 |       @device = nil
102 | 
103 |       if !Gem.win_platform?
104 |         @sdk = `echo $ANDROID_SDK_ROOT`.delete("\n")
105 |       else
106 |         @sdk = `echo %ANDROID_SDK_ROOT%`.delete("\n")
107 |       end
108 | 
109 |       @sdk = 'adb' if @sdk.empty?
110 | 
111 |       $sdk = @sdk
112 | 
113 |       puts 'Searching for devices...'.yellow
114 | 
115 |       @devices = DryrunUtils.run_adb('devices')
116 | 
117 |       # if @devices.nil? || @devices.empty?
118 |       #   puts 'Killing adb, there might be an issue with it...'
119 |       #   DryrunUtils.run_adb('kill-server')
120 |       #   @devices = DryrunUtils.run_adb('devices')
121 |       # end
122 | 
123 |       puts 'No devices attached, but I\'ll run anyway' if @devices.empty?
124 | 
125 |       if @devices.size >= 2
126 |         puts 'Pick your device (1,2,3...):'
127 | 
128 |         @devices.each_with_index.map {|key, index| puts "#{index.to_s.green} -  #{key.name} \n"}
129 | 
130 |         input = gets.chomp
131 | 
132 |         @device = if input.match(/^\d+$/) && input.to_i <= (@devices.length - 1) && input.to_i >= 0
133 |                     @devices[input.to_i]
134 |                   else
135 |                     @devices.first
136 |                   end
137 |       else
138 |         @device = @devices.first
139 |       end
140 | 
141 |       $device = @device
142 |       puts "Picked #{@device.name.to_s.green}" unless @device.nil?
143 |     end
144 | 
145 |     def android_sdk_root_is_defined
146 |       @sdk = if !Gem.win_platform?
147 |                `echo $ANDROID_SDK_ROOT`.delete('\n')
148 |              else
149 |                `echo %ANDROID_SDK_ROOT%`.delete('\n')
150 |              end
151 |       !@sdk.empty?
152 |     end
153 | 
154 |     def wipe_temporary_folder
155 |       tmpdir = Dir.tmpdir + '/dryrun/'
156 |       puts 'Wiping ' + tmpdir.red
157 |       FileUtils.rm_rf tmpdir
158 |       puts 'Folder totally removed!'.green
159 |       exit 1
160 |     end
161 | 
162 |     def call
163 |       unless android_sdk_root_is_defined
164 |         puts "\nWARNING: your #{'$ANDROID_SDK_ROOT'.yellow} is not defined\n"
165 |         puts "\nhint: in your #{'~/.bashrc'.yellow} or #{'~/.bash_profile'.yellow}  add:\n  #{"export ANDROID_SDK_ROOT='/Users/cesarferreira/Library/Android/sdk/'".yellow}"
166 |         puts "\nNow type #{'source ~/.bashrc'.yellow}\n\n"
167 |         exit 1
168 |       end
169 | 
170 |       if @url.nil?
171 |         puts 'You need to insert a valid GIT URL/folder'
172 |         exit 1
173 |       end
174 | 
175 |       pick_device
176 | 
177 |       if DryrunUtils::is_folder? (@url)
178 |         repository_path = File.expand_path @url
179 |       else
180 | 
181 |         @url = @url.split('?').first
182 |         @url.chop! if @url.end_with? '/'
183 | 
184 |         github = Github.new(@url)
185 | 
186 |         unless github.valid?
187 |           puts "#{@url.red} is not a valid git @url"
188 |           exit 1
189 |         end
190 | 
191 |         # clone the repository
192 |         repository_path = github.clone(@branch, @tag, @cleanup)
193 | 
194 |       end
195 | 
196 |       android_project = AndroidProject.new(repository_path, @app_path, @custom_module, @flavour, @device)
197 | 
198 |       # is a valid android project?
199 |       unless android_project.valid?
200 |         puts "#{@url.red} is not a valid android project"
201 |         exit 1
202 |       end
203 | 
204 |       puts "Using custom app folder: #{@app_path.green}" if @app_path
205 |       puts "Using custom module: #{@custom_module.green}" if @custom_module
206 | 
207 |       # clean and install the apk
208 |       android_project.execute_command(@command)
209 | 
210 |       puts "\n> If you want to remove the app you just installed, execute:\n#{android_project.uninstall_command.yellow}\n\n"
211 |     end
212 |   end
213 | end
214 | 


--------------------------------------------------------------------------------
/lib/dryrun/android_project.rb:
--------------------------------------------------------------------------------
  1 | require 'oga'
  2 | require 'fileutils'
  3 | require 'tempfile'
  4 | require 'find'
  5 | require_relative 'dryrun_utils'
  6 | require_relative 'manifest_parser'
  7 | require_relative 'gradle_adapter'
  8 | 
  9 | module Dryrun
 10 |   class AndroidProject
 11 |     def initialize(path, custom_app_path, custom_module, flavour, device)
 12 |       @custom_app_path = custom_app_path
 13 |       @custom_module = custom_module
 14 |       @base_path = @custom_app_path ? File.join(path, @custom_app_path) : path
 15 |       @flavour = flavour
 16 |       @device = device
 17 |       @gradle_file_extension = gradle_file_extension
 18 |       @settings_gradle_path = settings_gradle_file
 19 |       @main_gradle_file = main_gradle_file
 20 | 
 21 |       check_custom_app_path
 22 | 
 23 |       @modules = find_modules
 24 |     end
 25 | 
 26 |     def gradle_file_extension
 27 |       gradle_file = File.join(@base_path, 'settings.gradle.kts')
 28 |       if (File.exist?(gradle_file))
 29 |         return ".gradle.kts"
 30 |       end
 31 |       ".gradle"
 32 |     end
 33 | 
 34 |     def check_custom_app_path
 35 |       return unless @custom_app_path
 36 | 
 37 |       full_custom_path = @base_path
 38 |       settings_path = settings_gradle_file(full_custom_path)
 39 |       main_gradle_path = main_gradle_file(full_custom_path)
 40 |       return unless valid?(main_gradle_path)
 41 | 
 42 |       @settings_gradle_path = settings_path
 43 |       @main_gradle_file = main_gradle_file
 44 | 
 45 |       @base_path = full_custom_path
 46 |     end
 47 | 
 48 |     def remove_local_properties
 49 |       Dir.chdir @base_path
 50 |       file_name = 'local.properties'
 51 | 
 52 |       File.delete(file_name) if File.exist?(file_name)
 53 | 
 54 |       DryrunUtils.execute("touch #{file_name}") unless Gem.win_platform?
 55 |     end
 56 | 
 57 |     def remove_application_id
 58 |       # Open temporary file
 59 |       tmp = Tempfile.new('extract')
 60 | 
 61 |       file = "#{@path_to_sample}/build#{@gradle_file_extension}"
 62 | 
 63 |       # Write good lines to temporary file
 64 |       File.open(file, 'r') do |f|
 65 |         f.each do |l|
 66 |           tmp << l unless l.include? 'applicationId'
 67 |         end
 68 |       end
 69 |       tmp.close
 70 | 
 71 |       # Move temp file to origin
 72 |       FileUtils.mv(tmp.path, file)
 73 |     end
 74 | 
 75 |     def settings_gradle_file(path = @base_path)
 76 |       File.join(path, "settings#{@gradle_file_extension}")
 77 |     end
 78 | 
 79 |     def main_gradle_file(path = @base_path)
 80 |       File.join(path, "build#{@gradle_file_extension}")
 81 |     end
 82 | 
 83 |     def valid?(main_gradle_file = @main_gradle_file)
 84 |       File.exist?(main_gradle_file) &&
 85 |           File.exist?(@settings_gradle_path)
 86 |     end
 87 | 
 88 |     def find_modules
 89 |       return [] unless valid?
 90 | 
 91 |       content = File.open(@settings_gradle_path, 'rb').read
 92 |       
 93 |       content = content.split(/\n/).delete_if { |x| !x.start_with?("include")}.join("\n")
 94 |       modules = content.scan(/'([^']*)'/) + content.scan(/\"([^"]*)\"/)
 95 |       
 96 |       modules.each {|replacement| replacement.first.tr!(':', '')}
 97 |     end
 98 | 
 99 |     def execute_command(command)
100 |       Dir.chdir @base_path
101 | 
102 |       path = sample_project
103 |       if path == false or !@launcher_activity
104 |         puts "Couldn't open or there isnt any sample project, sorry!".red
105 |         exit 1
106 |       end
107 | 
108 |       builder = create_builder
109 | 
110 |       remove_application_id
111 |       remove_local_properties
112 | 
113 |       command.run(builder, @package, @launcher_activity, @custom_module, @flavour, @device)
114 |     end
115 | 
116 |     def gradle_wrapped?
117 |       return false unless File.directory?('gradle/')
118 | 
119 |       File.exist?('gradle/wrapper/gradle-wrapper.properties') &&
120 |           File.exist?('gradle/wrapper/gradle-wrapper.jar')
121 |     end
122 | 
123 |     def sample_project
124 |       if @custom_module && @modules.any? {|m| m.first == "#{@custom_module}"}
125 |         @path_to_sample = File.join(@base_path, "#{@custom_module}")
126 |         return @path_to_sample if parse_manifest(@path_to_sample)
127 |       else
128 |         @modules.each do |child|
129 |           full_path = File.join(@base_path, child.first)
130 |           @path_to_sample = full_path
131 |           return full_path if parse_manifest(full_path)
132 |         end
133 |       end
134 |       false
135 |     end
136 | 
137 |     def uninstall_command
138 |       "adb uninstall \"#{@package}\""
139 |     end
140 | 
141 |     def uninstall_application
142 |       DryrunUtils.run_adb("shell pm uninstall #{@package}")
143 |     end
144 | 
145 |     def parse_manifest(path_to_sample)
146 |       manifest_file = get_manifest(path_to_sample)
147 | 
148 |       return false if manifest_file.nil?
149 | 
150 |       manifest_parser = ManifestParser.new(manifest_file)
151 |       @package = manifest_parser.package
152 |       @launcher_activity = manifest_parser.launcher_activity
153 |       manifest_file.close
154 |       @launcher_activity && @package
155 |     end
156 | 
157 |     def get_manifest(path_to_sample)
158 |       default_path = File.join(path_to_sample, 'src/main/AndroidManifest.xml')
159 | 
160 |       if File.exist?(default_path)
161 |         File.open(default_path)
162 |       else
163 |         puts path_to_sample
164 |         Find.find(path_to_sample) do |path|
165 |           return File.open(path) if path =~ /.*AndroidManifest.xml$/
166 |         end
167 |       end
168 |     end
169 | 
170 |     def create_builder
171 |       builder = 'gradle'
172 | 
173 |       if File.exist?('gradlew')
174 |         if !Gem.win_platform?
175 |           DryrunUtils.execute('chmod +x gradlew')
176 |         else
177 |           DryrunUtils.execute('icacls gradlew /T')
178 |         end
179 |         builder = './gradlew'
180 |       end
181 | 
182 |       # Generate the gradle/ folder
183 |       DryrunUtils.execute('gradle wrap') if File.exist?('gradlew') && !gradle_wrapped?
184 |       GradleAdapter.new(builder)
185 |     end
186 |   end
187 | end
188 | 


--------------------------------------------------------------------------------
/lib/dryrun/android_utils.rb:
--------------------------------------------------------------------------------
 1 | require_relative 'dryrun_utils'
 2 | 
 3 | module Dryrun
 4 |   class AndroidUtils
 5 | 
 6 |     def self.pretty_run(execute_line, package)
 7 |       puts "Installing #{package.green}...\n"
 8 |       puts "executing: #{execute_line.green}\n"
 9 | 
10 |       DryrunUtils.run_adb("shell #{execute_line}")
11 |     end
12 | 
13 |     def self.clear_app_data(package)
14 |       DryrunUtils.run_adb("shell pm clear #{package}")
15 |     end
16 |   end
17 | end
18 | 


--------------------------------------------------------------------------------
/lib/dryrun/device.rb:
--------------------------------------------------------------------------------
 1 | module Dryrun
 2 |   class Device
 3 |     attr_accessor :name, :id
 4 | 
 5 |     def initialize(name, id)
 6 |       @name = name
 7 |       @id = id
 8 |     end
 9 |   end
10 | end
11 | 


--------------------------------------------------------------------------------
/lib/dryrun/dryrun_utils.rb:
--------------------------------------------------------------------------------
 1 | require 'open-uri'
 2 | require 'dryrun/version'
 3 | require 'open3'
 4 | 
 5 | module Dryrun
 6 |   class DryrunUtils
 7 |     attr_accessor :sdk
 8 |     attr_accessor :device
 9 | 
10 |     def self.execute(command)
11 |       is_success = system command
12 |       unless is_success
13 |         puts "\n\n======================================================\n\n"
14 |         puts ' Something went wrong while executing this:'.red
15 |         puts "  $ #{command}\n".yellow
16 |         puts "======================================================\n\n"
17 |         exit 1
18 |       end
19 |     end
20 | 
21 |     def self.latest_version
22 |       url = 'https://raw.githubusercontent.com/cesarferreira/dryrun/master/lib/dryrun/version.rb'
23 |       page_string = nil
24 | 
25 |       if Gem.win_platform?
26 |         open(url, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) do |f|
27 |           page_string = f.read
28 |         end
29 |       else
30 |         URI.open(url) do |f|
31 |           page_string = f.read
32 |         end
33 |       end
34 | 
35 |       page_string[/#{Regexp.escape('\'')}(.*?)#{Regexp.escape('\'')}/m, 1]
36 |     end
37 | 
38 |     def self.up_to_date
39 |       latest = latest_version
40 |       latest.to_s <= Dryrun::VERSION.to_s
41 |     end
42 | 
43 |     def self.run_adb(args)
44 |       adb_arg = " -s #{$device.name} " unless $device.nil?
45 |       path = "#{$sdk} #{adb_arg} #{args} "
46 |       run(path)
47 |     end
48 | 
49 |     def self.is_folder? (path)
50 |       File.directory?(path)
51 |     end
52 | 
53 |     def self.run(path)
54 |       Open3.popen3(path) do |_stdin, stdout, _stderr|
55 |         devices = []
56 |         stdout.each do |line|
57 |           line = line.strip
58 |           if !line.empty? && line !~ /^List of devices/ && !line.start_with?('adb') && !line.start_with?('*')
59 |             parts = line.split
60 |             devices << Dryrun::Device.new(parts[0], parts[1])
61 |           end
62 |         end
63 |         devices
64 |       end
65 |     end
66 |   end
67 | end
68 | 


--------------------------------------------------------------------------------
/lib/dryrun/github.rb:
--------------------------------------------------------------------------------
 1 | require 'tmpdir'
 2 | require 'fileutils'
 3 | require 'uri'
 4 | require_relative 'dryrun_utils'
 5 | 
 6 | module Dryrun
 7 |   class Github
 8 |     def initialize(url)
 9 |       @base_url = sanitize_url(url)
10 |       @destination = destination
11 |     end
12 | 
13 |     def sanitize_url(url)
14 |       url = url.split('?').first
15 |       url.chop! if url.end_with? '/'
16 |       url
17 |     end
18 | 
19 |     def destination
20 |       unless @base_url.include? 'github.com'
21 |         return Digest::SHA256.hexdigest @base_url
22 |       end
23 | 
24 |       stripped_url = @base_url.gsub('.git', '')
25 |       stripped_url = stripped_url.gsub('.git', '')
26 |       stripped_url = stripped_url.gsub('git@github.com:', '')
27 |       stripped_url = stripped_url.gsub('https://github.com/', '')
28 |       stripped_url.gsub('http://github.com/', '')
29 |     end
30 | 
31 |     def valid?
32 |       starts_with_git = @base_url.split(//).first(4).join.eql? 'git@'
33 |       starts_with_http = @base_url.split(//).first(7).join.eql? 'http://'
34 |       starts_with_https = @base_url.split(//).first(8).join.eql? 'https://'
35 | 
36 |       (starts_with_git || starts_with_https || starts_with_http)
37 |     end
38 | 
39 |     def cloneable_url
40 |       starts_with_git = @base_url.split(//).first(4).join.eql? 'git@'
41 |       ends_with_git = @base_url.split(//).last(4).join.eql? '.git'
42 | 
43 |       # ends with git but doesnt start with git
44 |       return @base_url if ends_with_git && !starts_with_git
45 | 
46 |       # ends with git but doesnt start with git
47 |       return "#{@base_url}.git" if !ends_with_git && !starts_with_git
48 | 
49 |       @base_url
50 |     end
51 | 
52 |     ##
53 |     ## CLONE THE REPOSITORY
54 |     ##
55 |     def clone(branch, tag, cleanup)
56 |       cloneable = cloneable_url
57 | 
58 |       tmpdir = Dir.tmpdir + "/dryrun/#{@destination}"
59 | 
60 |       if cleanup
61 |         puts 'Wiping the folder: ' + tmpdir.green
62 |         FileUtils.rm_rf tmpdir
63 |         # FileUtils.mkdir_p tmpdir
64 |       end
65 | 
66 |       folder_exists = File.directory?(tmpdir)
67 | 
68 |       if folder_exists
69 |         Dir.chdir tmpdir
70 | 
71 |         is_git_repo = system('git rev-parse')
72 | 
73 |         if !is_git_repo
74 |           FileUtils.rm_rf(tmpdir)
75 |           DryrunUtils.execute("git clone --depth 1 #{cloneable} #{tmpdir}")
76 |           DryrunUtils.execute("git checkout #{branch}")
77 |         else
78 |           puts "Found project in #{tmpdir.green}..."
79 |           DryrunUtils.execute('git reset --hard HEAD')
80 |           DryrunUtils.execute('git fetch --all')
81 |           DryrunUtils.execute("git checkout #{branch}")
82 |           DryrunUtils.execute("git pull origin #{branch}")
83 |         end
84 |       else
85 |         DryrunUtils.execute("git clone --depth 1 #{cloneable} #{tmpdir}")
86 |       end
87 | 
88 |       if tag
89 |         Dir.chdir tmpdir
90 |         DryrunUtils.execute('git fetch --depth=10000')
91 |         DryrunUtils.execute("git checkout #{tag}")
92 |       end
93 | 
94 |       tmpdir
95 |     end
96 |   end
97 | end
98 | 


--------------------------------------------------------------------------------
/lib/dryrun/gradle_adapter.rb:
--------------------------------------------------------------------------------
 1 | require_relative 'dryrun_utils'
 2 | 
 3 | module Dryrun
 4 |   class GradleAdapter
 5 | 
 6 |     def initialize(builder)
 7 |       @builder = builder
 8 |     end
 9 | 
10 |     def clean
11 |       DryrunUtils.execute("#{@builder} clean")
12 |     end
13 | 
14 |     def run_android_tests(custom_module, flavour)
15 |       if custom_module
16 |         puts "#{@builder} :#{custom_module}:connected#{flavour}DebugAndroidTest"
17 |         DryrunUtils.execute("#{@builder} :#{custom_module}:connected#{flavour}DebugAndroidTest")
18 |       else
19 |         puts "#{@builder} connected#{flavour}DebugAndroidTest"
20 |         DryrunUtils.execute("#{@builder} connected#{flavour}DebugAndroidTest")
21 |       end
22 |     end
23 | 
24 |     def run_unit_tests(custom_module, flavour)
25 |       if custom_module
26 |         puts "#{@builder} :#{custom_module}:test#{flavour}DebugUnitTest"
27 |         DryrunUtils.execute("#{@builder} :#{custom_module}:test#{flavour}DebugUnitTest")
28 |       else
29 |         puts "#{@builder} test#{flavour}DebugUnitTest"
30 |         DryrunUtils.execute("#{@builder} test#{flavour}DebugUnitTest")
31 |       end
32 |     end
33 | 
34 |     def install(custom_module, flavour)
35 |       if custom_module
36 |         puts "#{@builder} :#{custom_module}:install#{flavour}Debug"
37 |         DryrunUtils.execute("#{@builder} :#{custom_module}:install#{flavour}Debug")
38 |       else
39 |         puts "#{@builder} install#{flavour}Debug"
40 |         DryrunUtils.execute("#{@builder} install#{flavour}Debug")
41 |       end
42 |     end
43 | 
44 | 
45 |     def assemble(custom_module, flavour)
46 |       if custom_module
47 |         puts "#{@builder} :#{custom_module}:assemble#{flavour}Debug"
48 |         DryrunUtils.execute("#{@builder} :#{custom_module}:assemble#{flavour}Debug")
49 |       else
50 |         puts "#{@builder} assemble#{flavour}Debug"
51 |         DryrunUtils.execute("#{@builder} assemble#{flavour}Debug")
52 |       end
53 |     end
54 |   end
55 | end
56 | 


--------------------------------------------------------------------------------
/lib/dryrun/install_application_command.rb:
--------------------------------------------------------------------------------
 1 | require_relative 'dryrun_utils'
 2 | require_relative 'android_utils'
 3 | 
 4 | module Dryrun
 5 |   class InstallApplicationCommand
 6 | 
 7 |     def run(builder, package, launcher_activity, custom_module, flavour, device)
 8 |       execute_line = get_execution_command_line(package, launcher_activity)
 9 |       builder.clean
10 | 
11 |       if device.nil?
12 |         puts 'No devices picked/available, proceeding with assemble instead'.green
13 |         builder.assemble(custom_module, flavour)
14 |       else
15 |         builder.install(custom_module, flavour)
16 |       end
17 | 
18 |       unless device.nil?
19 |         AndroidUtils.clear_app_data(package)
20 |         AndroidUtils.pretty_run(execute_line, package)
21 |       end
22 |     end
23 | 
24 |     def get_execution_command_line(package, launcher_activity)
25 |       "am start -n \"#{launcheable_activity(package, launcher_activity)}\" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER"
26 |     end
27 | 
28 |     def launcheable_activity(package, launcher_activity)
29 |       full_path_to_launcher = "#{package}#{launcher_activity.gsub(package, '')}"
30 |       "#{package}/#{full_path_to_launcher}"
31 |     end
32 |   end
33 | end
34 | 


--------------------------------------------------------------------------------
/lib/dryrun/manifest_parser.rb:
--------------------------------------------------------------------------------
 1 | require 'oga'
 2 | 
 3 | module Dryrun
 4 | 
 5 |   class ManifestParser
 6 | 
 7 |     attr_accessor :package, :launcher_activity
 8 | 
 9 |     def initialize(manifest_file)
10 |       doc = Oga.parse_xml(manifest_file)
11 | 
12 |       @package = get_package(doc)
13 |       @launcher_activity = get_launcher_activity(doc)
14 |     end
15 | 
16 |     def get_package(doc)
17 |       doc.xpath('//manifest').attr('package').first.value
18 |     end
19 | 
20 |     def get_launcher_activity(doc)
21 |       activities = doc.css('activity')
22 |       activities.each do |child|
23 |         intent_filter = child.css('intent-filter')
24 | 
25 |         if !intent_filter.nil? && !intent_filter.empty?
26 |           return child.attr('android:name').value
27 |         end
28 |       end
29 |       false
30 |     end
31 | 
32 |   end
33 | end
34 | 


--------------------------------------------------------------------------------
/lib/dryrun/test_application_command.rb:
--------------------------------------------------------------------------------
 1 | require_relative 'dryrun_utils'
 2 | require_relative 'android_utils'
 3 | 
 4 | module Dryrun
 5 |   class TestApplicationCommand
 6 | 
 7 |     def run(builder, package, launcher_activity, custom_module, flavour, device)
 8 |       execute_line = get_execution_command_line(package)
 9 |       builder.clean
10 | 
11 |       if device.nil?
12 |         puts 'No devices picked/available, proceeding with unit tests instead'.green
13 |         builder.run_unit_tests(custom_module, flavour)
14 |       else
15 |         builder.run_android_tests(custom_module, flavour)
16 |       end
17 | 
18 |       unless device.nil?
19 |         AndroidUtils.clear_app_data(package)
20 |         AndroidUtils.pretty_run(execute_line, package)
21 |       end
22 |     end
23 | 
24 |     def get_execution_command_line(package)
25 |       "adb shell am instrument -w #{package}"
26 |     end
27 |   end
28 | end
29 | 


--------------------------------------------------------------------------------
/lib/dryrun/version.rb:
--------------------------------------------------------------------------------
1 | module Dryrun
2 |   VERSION = '1.3.2'.freeze
3 | end
4 | 


--------------------------------------------------------------------------------
/spec/dryrun_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | 


--------------------------------------------------------------------------------
/spec/github_spec.rb:
--------------------------------------------------------------------------------
 1 | require 'spec_helper'
 2 | require 'dryrun/github'
 3 | 
 4 | describe '# Github' do
 5 | 
 6 |   context 'URL validity' do
 7 |     it 'URL should be valid' do
 8 |       url = 'https://github.com/cesarferreira/android-helloworld'
 9 |       github = Dryrun::Github.new(url)
10 |       expected = 'https://github.com/cesarferreira/android-helloworld.git'
11 |       expect(github.cloneable_url).to eq(expected)
12 |     end
13 | 
14 |     it 'URL that ends in .git should be valid' do
15 |       url = 'https://github.com/googlesamples/google-services.git'
16 |       github = Dryrun::Github.new(url)
17 |       expected = 'https://github.com/googlesamples/google-services.git'
18 |       expect(github.cloneable_url).to eq(expected)
19 |     end
20 | 
21 |     it 'SSH URL should be valid' do
22 |       url = 'git@github.com:cesarferreira/android-helloworld.git'
23 |       github = Dryrun::Github.new(url)
24 |       expected = 'git@github.com:cesarferreira/android-helloworld.git'
25 |       expect(github.cloneable_url).to eq(expected)
26 |     end
27 | 
28 |     it 'URL should not be valid' do
29 |       url = 'asdasdas'
30 |       github = Dryrun::Github.new(url)
31 |       expect(github.valid?).to be false
32 |     end
33 |   end
34 | 
35 |   context 'URL destination folders' do
36 |     it 'Given a regular url' do
37 |       url = 'https://github.com/cesarferreira/android-helloworld'
38 |       github = Dryrun::Github.new(url)
39 |       expected = 'cesarferreira/android-helloworld'
40 |       expect(github.destination).to eq(expected)
41 |     end
42 | 
43 |     it 'Given a URL that ends in .git' do
44 |       url = 'https://github.com/googlesamples/google-services.git'
45 |       github = Dryrun::Github.new(url)
46 |       expected = 'googlesamples/google-services'
47 |       expect(github.destination).to eq(expected)
48 |     end
49 | 
50 |     it 'Given a SSH URL' do
51 |       url = 'git@github.com:cesarferreira/android-helloworld.git'
52 |       github = Dryrun::Github.new(url)
53 |       expected = 'cesarferreira/android-helloworld'
54 |       expect(github.destination).to eq(expected)
55 |     end
56 | 
57 |     it 'Given a non Github URL' do
58 |       url = 'git@bitbucket.org:RyanBis/another-android-library.git'
59 |       github = Dryrun::Github.new(url)
60 |       expected = '2ef4153951350a0521cd8e02e4b629072dd515637610f0b48fe17a1a89a2c51a'
61 |       expect(github.destination).to eq(expected)
62 |     end
63 |   end
64 | end
65 | 


--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
 1 | require 'dryrun'
 2 | RSpec.configure do |config|
 3 |   # rspec-expectations config goes here. You can use an alternate
 4 |   # assertion/expectation library such as wrong or the stdlib/minitest
 5 |   # assertions if you prefer.
 6 |   config.expect_with :rspec do |expectations|
 7 |     # This option will default to `true` in RSpec 4. It makes the `description`
 8 |     # and `failure_message` of custom matchers include text for helper methods
 9 |     # defined using `chain`, e.g.:
10 |     #     be_bigger_than(2).and_smaller_than(4).description
11 |     #     # => "be bigger than 2 and smaller than 4"
12 |     # ...rather than:
13 |     #     # => "be bigger than 2"
14 |     expectations.include_chain_clauses_in_custom_matcher_descriptions = true
15 |   end
16 | 
17 |   # rspec-mocks config goes here. You can use an alternate test double
18 |   # library (such as bogus or mocha) by changing the `mock_with` option here.
19 |   config.mock_with :rspec do |mocks|
20 |     # Prevents you from mocking or stubbing a method that does not exist on
21 |     # a real object. This is generally recommended, and will default to
22 |     # `true` in RSpec 4.
23 |     mocks.verify_partial_doubles = true
24 |   end
25 | end
26 | 


--------------------------------------------------------------------------------