cavendish 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.circleci/config.yml +103 -0
- data/.circleci/setup-rubygems.sh +3 -0
- data/.editorconfig +24 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +496 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +143 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +82 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cavendish.gemspec +33 -0
- data/exe/cavendish +8 -0
- data/lib/cavendish.rb +13 -0
- data/lib/cavendish/assets/.circleci/config.yml +93 -0
- data/lib/cavendish/assets/.eslintrc.json +43 -0
- data/lib/cavendish/assets/.node-version +1 -0
- data/lib/cavendish/assets/App.jsx +12 -0
- data/lib/cavendish/assets/README.md.erb +59 -0
- data/lib/cavendish/assets/src/navigators/HomeNavigator.jsx +17 -0
- data/lib/cavendish/assets/src/screens/HomeScreen.jsx.erb +16 -0
- data/lib/cavendish/assets/src/screens/__specs__/HomeScreen.spec.js.erb +22 -0
- data/lib/cavendish/assets/src/utils/tailwindRn.js +7 -0
- data/lib/cavendish/assets/tailwind.config.js +8 -0
- data/lib/cavendish/cli.rb +53 -0
- data/lib/cavendish/commands/add_ci_config.rb +16 -0
- data/lib/cavendish/commands/add_eslint.rb +33 -0
- data/lib/cavendish/commands/add_react_navigation.rb +45 -0
- data/lib/cavendish/commands/add_readme.rb +15 -0
- data/lib/cavendish/commands/add_tailwind.rb +31 -0
- data/lib/cavendish/commands/add_testing.rb +81 -0
- data/lib/cavendish/commands/base.rb +9 -0
- data/lib/cavendish/commands/configure_git.rb +22 -0
- data/lib/cavendish/commands/create_expo_project.rb +20 -0
- data/lib/cavendish/config.rb +18 -0
- data/lib/cavendish/utils.rb +74 -0
- data/lib/cavendish/version.rb +5 -0
- metadata +260 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
{
|
2
|
+
"env": {
|
3
|
+
"es6": true,
|
4
|
+
"jest": true
|
5
|
+
},
|
6
|
+
"extends": "airbnb",
|
7
|
+
"globals": {
|
8
|
+
"Atomics": "readonly",
|
9
|
+
"SharedArrayBuffer": "readonly",
|
10
|
+
"jest": true
|
11
|
+
},
|
12
|
+
"parser": "babel-eslint",
|
13
|
+
"parserOptions": {
|
14
|
+
"ecmaFeatures": {
|
15
|
+
"jsx": true
|
16
|
+
},
|
17
|
+
"ecmaVersion": 2018,
|
18
|
+
"sourceType": "module"
|
19
|
+
},
|
20
|
+
"plugins": ["react"],
|
21
|
+
"rules": {
|
22
|
+
"no-console": 2,
|
23
|
+
"react/prop-types": ["error", { "ignore": ["route", "navigation"] }],
|
24
|
+
"react/jsx-first-prop-new-line": [1, "multiline"],
|
25
|
+
"react/jsx-max-props-per-line": [1, { "maximum": 1 }],
|
26
|
+
"react/jsx-one-expression-per-line": "off",
|
27
|
+
"global-require": "off",
|
28
|
+
"import/prefer-default-export": "off",
|
29
|
+
"import/no-extraneous-dependencies": [
|
30
|
+
"error",
|
31
|
+
{ "devDependencies": ["**/*.spec.js", "src/factories/**"] }
|
32
|
+
],
|
33
|
+
"react/jsx-filename-extension": [1, { "extensions": [".spec.js", ".jsx"] }],
|
34
|
+
"react/jsx-props-no-spreading": 0
|
35
|
+
},
|
36
|
+
"settings": {
|
37
|
+
"import/resolver": {
|
38
|
+
"alias": {
|
39
|
+
"extensions": [".js", ".jsx"]
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
14
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { NavigationContainer } from '@react-navigation/native';
|
3
|
+
|
4
|
+
import HomeNavigator from './src/navigators/HomeNavigator';
|
5
|
+
|
6
|
+
export default function App() {
|
7
|
+
return (
|
8
|
+
<NavigationContainer>
|
9
|
+
<HomeNavigator />
|
10
|
+
</NavigationContainer>
|
11
|
+
);
|
12
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# <%= @config.human_project_name %>
|
2
|
+
|
3
|
+
This is a React Native + Expo application, initially generated using [Cavendish](https://github.com/platanus/cavendish) by Platanus.
|
4
|
+
|
5
|
+
## Instalation and development
|
6
|
+
|
7
|
+
Assuming you've cloned the repo and that you have [Node](https://nodejs.org/en/) and [Yarn](https://yarnpkg.com/), the first thing you need to install is the Expo CLI:
|
8
|
+
|
9
|
+
```bash
|
10
|
+
yarn global add expo-cli@4.8.x
|
11
|
+
```
|
12
|
+
|
13
|
+
Then install the project dependencies in your local machine:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
yarn install
|
17
|
+
```
|
18
|
+
|
19
|
+
And you're ready to go! You can now run the project with `yarn start` and scan the QR shown in console with the [Expo Go App](https://expo.dev/client). Remember that your phone and laptop have to be connected to the same wi-fi network in order for this to work!
|
20
|
+
|
21
|
+
## Continuous Integration and deployment
|
22
|
+
|
23
|
+
The project has a setup to run tests and style guides in CircleCI. You can also run the test locally simulating the production environment using [CircleCI's method](https://circleci.com/docs/2.0/local-cli/).
|
24
|
+
|
25
|
+
The CI workflow also takes care of deploying and [publishing your application to Expo](https://docs.expo.io/workflow/publishing/). In order for this to work, you need to:
|
26
|
+
|
27
|
+
1. Create a new account in [Expo](https://expo.dev/)
|
28
|
+
1. [_Optional_] Create an [organization](https://docs.expo.io/accounts/account-types/#creating-new-organizations)
|
29
|
+
1. Create an [access token](https://docs.expo.io/accounts/programmatic-access/)
|
30
|
+
1. Configure the token as a [CircleCI environment variable](https://circleci.com/docs/2.0/env-vars/)
|
31
|
+
|
32
|
+
And you are done! Each time there is a commit in master, the pipeline will try to deploy the application.
|
33
|
+
|
34
|
+
If it succeeds, you will be able to scan and share the app QR code through `https://expo.io/@organization-or-user-name/<%= @config.project_name %>`.
|
35
|
+
|
36
|
+
## Style Guides
|
37
|
+
|
38
|
+
Style guides are enforced through a CircleCI [job](.circleci/config.yml) with [reviewdog](https://github.com/reviewdog/reviewdog) as a reporter, using per-project dependencies and style configurations.
|
39
|
+
|
40
|
+
Please note that this reviewdog implementation requires a GitHub user token to comment on pull requests. A token can be generated [here](https://github.com/settings/tokens), and it should have at least the `repo` option checked.
|
41
|
+
|
42
|
+
The included `config.yml` assumes your CircleCI organization has a context named `org-global` with the required token under the environment variable `REVIEWDOG_GITHUB_API_TOKEN`.
|
43
|
+
|
44
|
+
The project comes bundled with configuration files available in this repository. You can add or modify rules by editing the [`.eslintrc.json`](.eslintrc.json) file.
|
45
|
+
|
46
|
+
You can (and should) use linter integrations for your text editor of choice, using the project's configuration.
|
47
|
+
|
48
|
+
## Internal Dependencies
|
49
|
+
|
50
|
+
### Tailwind RN
|
51
|
+
We use the TailwindCSS adaptation for React Native: [`tailwind-rn`](https://github.com/vadimdemedes/tailwind-rn), in order to reduce the friction in mobile apps styling.
|
52
|
+
|
53
|
+
If you need to add custom styles, make sure you follow the instructions given in the package's README.
|
54
|
+
|
55
|
+
### React Navigation
|
56
|
+
We use [React Navigation](https://reactnavigation.org/)@<%= Cavendish::REACT_NAVIGATION_VERSION %> to handle the shown screens and navigation interactions of the application.
|
57
|
+
|
58
|
+
### Testing
|
59
|
+
We use [Jest](https://jestjs.io/) and [React Native Testing Library](https://testing-library.com/docs/react-native-testing-library/intro/) in order to test the components of this app.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { createStackNavigator } from '@react-navigation/stack';
|
3
|
+
|
4
|
+
import HomeScreen from '../screens/HomeScreen';
|
5
|
+
|
6
|
+
const Stack = createStackNavigator();
|
7
|
+
|
8
|
+
export default function HomeNavigator() {
|
9
|
+
return (
|
10
|
+
<Stack.Navigator>
|
11
|
+
<Stack.Screen
|
12
|
+
name="Home"
|
13
|
+
component={HomeScreen}
|
14
|
+
/>
|
15
|
+
</Stack.Navigator>
|
16
|
+
);
|
17
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { View, Text } from 'react-native';
|
3
|
+
|
4
|
+
import tailwind from '../utils/tailwindRn';
|
5
|
+
|
6
|
+
export default function HomeScreen() {
|
7
|
+
const [projectName] = useState('<%= @config.human_project_name %>');
|
8
|
+
|
9
|
+
return (
|
10
|
+
<View style={tailwind('p-4 bg-gray-900 flex-1 justify-center items-center')}>
|
11
|
+
<Text style={tailwind('text-white')}>
|
12
|
+
Hello {projectName}!
|
13
|
+
</Text>
|
14
|
+
</View>
|
15
|
+
);
|
16
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
<% if @config.use_enzyme? %>
|
3
|
+
import { shallow } from 'enzyme';
|
4
|
+
import HomeScreen from '../HomeScreen';
|
5
|
+
|
6
|
+
describe('HomeScreen specs', () => {
|
7
|
+
it('shows application name', () => {
|
8
|
+
const component = shallow(<HomeScreen />);
|
9
|
+
expect(component.contains('<%= @config.human_project_name %>')).toBe(true);
|
10
|
+
});
|
11
|
+
});
|
12
|
+
<% else %>
|
13
|
+
import { render } from '@testing-library/react-native';
|
14
|
+
import HomeScreen from '../HomeScreen';
|
15
|
+
|
16
|
+
describe('HomeScreen specs', () => {
|
17
|
+
it('shows application name', () => {
|
18
|
+
const component = render(<HomeScreen />);
|
19
|
+
expect(component.queryByText('Hello <%= @config.human_project_name %>!')).not.toBeNull();
|
20
|
+
});
|
21
|
+
});
|
22
|
+
<% end %>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Cavendish
|
2
|
+
class CLI
|
3
|
+
include Commander::Methods
|
4
|
+
|
5
|
+
def run
|
6
|
+
config = Cavendish::Config.new
|
7
|
+
define_program
|
8
|
+
define_create_command(config)
|
9
|
+
run!
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def define_program
|
15
|
+
program :name, 'Cavendish'
|
16
|
+
program :version, Cavendish::VERSION
|
17
|
+
program :description, 'React Native + Expo project generator for Platanus'
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_create_command(config)
|
21
|
+
command('create') do |c|
|
22
|
+
c.syntax = 'cavendish create'
|
23
|
+
c.description = 'Create a new React Native + Expo project'
|
24
|
+
c.action do |args|
|
25
|
+
setup_config(config, args)
|
26
|
+
create_command_steps.each { |command| command.for(config: config) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_command_steps
|
32
|
+
[
|
33
|
+
Cavendish::Commands::CreateExpoProject,
|
34
|
+
Cavendish::Commands::AddTailwind,
|
35
|
+
Cavendish::Commands::AddReactNavigation,
|
36
|
+
Cavendish::Commands::AddEslint,
|
37
|
+
Cavendish::Commands::AddTesting,
|
38
|
+
Cavendish::Commands::AddCiConfig,
|
39
|
+
Cavendish::Commands::AddReadme,
|
40
|
+
Cavendish::Commands::ConfigureGit
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup_config(config, args)
|
45
|
+
config.project_name = args.first
|
46
|
+
config.testing_library = choose(
|
47
|
+
'Which testing library would you like to use?',
|
48
|
+
'Enzyme (unit orientated library)',
|
49
|
+
'@testing-library/react-native (integration orientated library)'
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cavendish
|
2
|
+
module Commands
|
3
|
+
class AddCiConfig < Cavendish::Commands::Base
|
4
|
+
def perform
|
5
|
+
copy_ci_and_version_files
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def copy_ci_and_version_files
|
11
|
+
copy_file(".circleci/config.yml", ".circleci/config.yml")
|
12
|
+
copy_file(".node-version", ".node-version")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Cavendish
|
2
|
+
module Commands
|
3
|
+
class AddEslint < Cavendish::Commands::Base
|
4
|
+
def perform
|
5
|
+
copy_config_file
|
6
|
+
install_eslint_dependencies
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def copy_config_file
|
12
|
+
copy_file(".eslintrc.json", ".eslintrc.json")
|
13
|
+
end
|
14
|
+
|
15
|
+
def install_eslint_dependencies
|
16
|
+
run_in_project("yarn add -D #{eslint_dependencies.join(' ')}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def eslint_dependencies
|
20
|
+
%w[
|
21
|
+
babel-eslint
|
22
|
+
eslint
|
23
|
+
eslint-config-airbnb
|
24
|
+
eslint-import-resolver-alias
|
25
|
+
eslint-plugin-import
|
26
|
+
eslint-plugin-jsx-a11y
|
27
|
+
eslint-plugin-react
|
28
|
+
eslint-plugin-react-hooks
|
29
|
+
]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Cavendish
|
2
|
+
module Commands
|
3
|
+
class AddReactNavigation < Cavendish::Commands::Base
|
4
|
+
def perform
|
5
|
+
install_dependencies
|
6
|
+
add_example_navigator_and_screens
|
7
|
+
replace_app_entrypoint
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def install_dependencies
|
13
|
+
run_in_project("yarn add #{react_navigation_core_dependencies.join(' ')}")
|
14
|
+
run_in_project("expo install #{react_navigation_side_dependencies.join(' ')}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_example_navigator_and_screens
|
18
|
+
copy_template('src/screens/HomeScreen.jsx', 'src/screens/HomeScreen.jsx')
|
19
|
+
copy_file('src/navigators/HomeNavigator.jsx', 'src/navigators/HomeNavigator.jsx')
|
20
|
+
end
|
21
|
+
|
22
|
+
def replace_app_entrypoint
|
23
|
+
remove_in_project('App.js')
|
24
|
+
copy_file('App.jsx', 'App.jsx')
|
25
|
+
end
|
26
|
+
|
27
|
+
def react_navigation_core_dependencies
|
28
|
+
[
|
29
|
+
"@react-navigation/native@#{Cavendish::REACT_NAVIGATION_VERSION}",
|
30
|
+
"@react-navigation/stack@#{Cavendish::REACT_NAVIGATION_VERSION}"
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
def react_navigation_side_dependencies
|
35
|
+
%w[
|
36
|
+
react-native-gesture-handler
|
37
|
+
react-native-reanimated
|
38
|
+
react-native-screens
|
39
|
+
react-native-safe-area-context
|
40
|
+
@react-native-community/masked-view
|
41
|
+
]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Cavendish
|
2
|
+
module Commands
|
3
|
+
class AddTailwind < Cavendish::Commands::Base
|
4
|
+
def perform
|
5
|
+
install_tailwind_rn_dependencies
|
6
|
+
copy_tailwind_config_file
|
7
|
+
generate_tailwind_rn_styles_json
|
8
|
+
copy_tailwind_utils
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def install_tailwind_rn_dependencies
|
14
|
+
run_in_project('yarn add tailwind-rn')
|
15
|
+
run_in_project('yarn add -D tailwindcss')
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_tailwind_config_file
|
19
|
+
copy_file('tailwind.config.js', 'tailwind.config.js')
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate_tailwind_rn_styles_json
|
23
|
+
run_in_project('yarn run create-tailwind-rn')
|
24
|
+
end
|
25
|
+
|
26
|
+
def copy_tailwind_utils
|
27
|
+
copy_file('src/utils/tailwindRn.js', 'src/utils/tailwindRn.js')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Cavendish
|
2
|
+
module Commands
|
3
|
+
class AddTesting < Cavendish::Commands::Base
|
4
|
+
def perform
|
5
|
+
install_dependencies
|
6
|
+
add_config_to_package
|
7
|
+
@config.use_enzyme? ? add_enzyme_options : add_rn_testing_library_options
|
8
|
+
add_example_test_file
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def install_dependencies
|
14
|
+
run_in_project("yarn add -D #{jest_dependencies.join(' ')}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_config_to_package
|
18
|
+
inject_to_json_file('package.json', package_configuration)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_enzyme_options
|
22
|
+
run_in_project("yarn add -D #{enzyme_dependencies.join(' ')}")
|
23
|
+
inject_to_json_file('package.json', enzyme_configuration)
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_rn_testing_library_options
|
27
|
+
run_in_project("yarn add -D #{rn_testing_library_dependencies.join(' ')}")
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_example_test_file
|
31
|
+
copy_template(
|
32
|
+
'src/screens/__specs__/HomeScreen.spec.js',
|
33
|
+
'src/screens/__specs__/HomeScreen.spec.js'
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def jest_dependencies
|
38
|
+
%w[
|
39
|
+
jest
|
40
|
+
fishery
|
41
|
+
jest-expo
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
def rn_testing_library_dependencies
|
46
|
+
%w[
|
47
|
+
@testing-library/jest-dom
|
48
|
+
@testing-library/react-native
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
def enzyme_dependencies
|
53
|
+
%w[
|
54
|
+
enzyme
|
55
|
+
enzyme-adapter-react-16
|
56
|
+
jest-enzyme
|
57
|
+
jest-environment-enzyme
|
58
|
+
]
|
59
|
+
end
|
60
|
+
|
61
|
+
def package_configuration
|
62
|
+
{
|
63
|
+
scripts: { test: 'jest' },
|
64
|
+
jest: {
|
65
|
+
preset: 'jest-expo',
|
66
|
+
transform: { '^.+\\.[jt]sx?$': 'babel-jest' }
|
67
|
+
}
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def enzyme_configuration
|
72
|
+
{
|
73
|
+
jest: {
|
74
|
+
setupFilesAfterEnv: ['jest-enzyme'],
|
75
|
+
testEnvironment: 'enzyme'
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|