├── .github ├── .codecov.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── config.yml ├── dependabot.yml ├── images │ ├── cgapp_create.gif │ ├── cgapp_create.jpg │ ├── cgapp_deploy.gif │ ├── cgapp_deploy.jpg │ ├── cgapp_logo.png │ ├── cgapp_logo.svg │ ├── cgapp_logo.webp │ ├── cgapp_logo@2x.png │ ├── gh-cover-v2.png │ └── logo-preview.jpg └── workflows │ └── golang.yml ├── .gitignore ├── .goreleaser.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── cgapp │ └── main.go ├── create.go ├── deploy.go └── root.go ├── go.mod ├── go.sum └── pkg ├── cgapp ├── exec.go ├── exec_test.go ├── files.go ├── files_test.go ├── git.go ├── git_test.go ├── utils.go └── utils_test.go └── registry ├── defaults.go ├── misc ├── .editorconfig ├── .gitattributes ├── .gitignore └── Makefile ├── roles ├── backend │ └── tasks │ │ └── main.yml ├── docker │ └── tasks │ │ └── main.yml ├── nginx │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── default-http.conf.j2 │ │ ├── default-https.conf.j2 │ │ └── nginx.conf.j2 ├── postgres │ └── tasks │ │ └── main.yml ├── redis │ └── tasks │ │ └── main.yml └── traefik │ ├── tasks │ └── main.yml │ └── templates │ └── traefik.yml.j2 └── templates ├── hosts.ini.tmpl └── playbook.yml.tmpl /.github/.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: 80% 6 | threshold: 1% 7 | 8 | comment: 9 | # Impact Codecov analysis, see: https://docs.codecov.com/docs/impact-analysis 10 | layout: "reach,diff,flags,tree,betaprofiling" 11 | show_critical_paths: true 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug, help wanted 6 | assignees: koddr 7 | --- 8 | 9 | 10 | 11 | **Required check list:** 12 | 13 | - [ ] I didn't find in the repository's issues section a similar bug. 14 | - [ ] I understand, this is an Open Source and not-for-profit product. 15 | - [ ] This is not about a third-party project, framework, or technology. 16 | 17 | **My environment:** 18 | 19 | - OS (`uname -a`): 20 | - Go (`go version`): 21 | 22 | **Describe the bug:** 23 | _A clear and concise description of what the bug is._ 24 | 25 | ... 26 | 27 | **Steps to reproduce the behavior:** 28 | 29 | 1. ... 30 | 2. ... 31 | 3. ... 32 | 33 | **Expected behavior:** 34 | _A clear and concise description of what you expected to happen._ 35 | 36 | ... 37 | 38 | **Screenshots:** 39 | _If applicable, add screenshots to help explain your problem._ 40 | 41 | ... 42 | 43 | **Additional context:** 44 | _Any other context about the issue here._ 45 | 46 | ... 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: GitHub Community Support 5 | url: https://github.com/orgs/community/discussions 6 | about: Please ask and answer questions here. 7 | - name: GitHub Security Bug Bounty 8 | url: https://bounty.github.com/ 9 | about: Please report security vulnerabilities here. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: koddr 7 | --- 8 | 9 | 10 | 11 | **Required check list:** 12 | 13 | - [ ] I didn't find in the repository's issues section a similar bug. 14 | - [ ] I understand, this is an Open Source and not-for-profit product. 15 | - [ ] This is not about a third-party project, framework, or technology. 16 | 17 | **Is your feature request related to a problem? Please describe.** 18 | _A clear and concise description of what the issue is._ 19 | 20 | ... 21 | 22 | **Describe the solution you'd like:** 23 | _A clear and concise description of what you want to happen._ 24 | 25 | ... 26 | 27 | **Describe alternatives you've considered:** 28 | _A clear and concise description of any alternative solutions._ 29 | 30 | ... 31 | 32 | **Screenshots:** 33 | _If applicable, add screenshots to help explain your feature._ 34 | 35 | ... 36 | 37 | **Additional context:** 38 | _Any other context or screenshots about the feature request here._ 39 | 40 | ... 41 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | # Comment to be posted to on first time issues 2 | newIssueWelcomeComment: > 3 | Hey! 👋 Thanks for opening your first issue here! Be sure to follow the issue template. 4 | 5 | # Comment to be posted to on PRs from first time contributors in your repository 6 | newPRWelcomeComment: > 7 | Yep! ✌️ Thanks for creating this pull request! Please check out our contributing guidelines. 8 | 9 | # Comment to be posted to on pull requests merged by a first time user 10 | firstPRMergeComment: > 11 | Wow! 🎉 Congratulations on merging your first pull request! We are proud of you. 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: gomod 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | time: "06:00" 9 | open-pull-requests-limit: 10 10 | -------------------------------------------------------------------------------- /.github/images/cgapp_create.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_create.gif -------------------------------------------------------------------------------- /.github/images/cgapp_create.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_create.jpg -------------------------------------------------------------------------------- /.github/images/cgapp_deploy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_deploy.gif -------------------------------------------------------------------------------- /.github/images/cgapp_deploy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_deploy.jpg -------------------------------------------------------------------------------- /.github/images/cgapp_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_logo.png -------------------------------------------------------------------------------- /.github/images/cgapp_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/images/cgapp_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_logo.webp -------------------------------------------------------------------------------- /.github/images/cgapp_logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/cgapp_logo@2x.png -------------------------------------------------------------------------------- /.github/images/gh-cover-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/gh-cover-v2.png -------------------------------------------------------------------------------- /.github/images/logo-preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/create-go-app/cli/e61a8c5d38e397d21486e1719ffa42d6fe9ab594/.github/images/logo-preview.jpg -------------------------------------------------------------------------------- /.github/workflows/golang.yml: -------------------------------------------------------------------------------- 1 | name: Golang workflow 2 | 3 | on: 4 | push: 5 | paths: [ '**.go' ] 6 | pull_request: 7 | paths: [ '**.go' ] 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | go: [ 'stable' ] 14 | os: [ 'ubuntu-latest' ] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: actions/setup-go@v4 19 | with: 20 | go-version: ${{ matrix.go }} 21 | 22 | # - name: Run "google/wire" for dependency injection 23 | # run: go run github.com/google/wire/cmd/wire@latest 24 | 25 | - name: Run "securego/gosec" for security checks 26 | run: go run github.com/securego/gosec/v2/cmd/gosec@latest -quiet ./... 27 | 28 | - name: Run "go-critic/go-critic" for code linting 29 | run: go run github.com/go-critic/go-critic/cmd/gocritic@latest check -enableAll ./... 30 | 31 | # - name: Run Go test with coverage report 32 | # run: go test -race -coverprofile=coverage.out -covermode=atomic 33 | # 34 | # - name: Upload coverage report to Codecov 35 | # uses: codecov/codecov-action@v3 36 | # with: 37 | # token: ${{ secrets.CODECOV_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test dir and binary, built with `go test -c` 9 | tests/ 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Go workspace file 16 | go.work 17 | 18 | # macOS files 19 | .DS_Store 20 | 21 | # IDE config directories (remove the comment below to include it) 22 | .idea/ 23 | .vscode/ 24 | 25 | # Dependency directories (remove the comment below to include it) 26 | vendor/ 27 | 28 | # Binary directories 29 | bin/ 30 | 31 | # GoReleaser directories 32 | dist/ 33 | 34 | # Go generate files 35 | *_gen.go 36 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | project_name: cgapp 4 | report_sizes: true 5 | 6 | env_files: 7 | github_token: ~/.github_token 8 | 9 | before: 10 | hooks: 11 | - go mod download 12 | - go mod tidy 13 | # - go run github.com/google/wire/cmd/wire@latest 14 | - go run github.com/securego/gosec/v2/cmd/gosec@latest -quiet ./... 15 | - go run github.com/go-critic/go-critic/cmd/gocritic@latest check -enableAll ./... 16 | - go run github.com/google/osv-scanner/cmd/osv-scanner@latest -r . 17 | - go test -race ./... 18 | 19 | builds: 20 | - id: default 21 | main: ./cmd/cgapp/main.go 22 | env: [CGO_ENABLED=0] 23 | goos: [linux, windows, darwin] 24 | goarch: [amd64, arm64] 25 | 26 | upx: 27 | - ids: [default] 28 | enabled: true 29 | compress: best 30 | lzma: true 31 | brute: true 32 | goos: [linux, windows] # skip darwin (macOS 13.x Ventura is not support now) 33 | goarch: [amd64, arm64] 34 | 35 | release: 36 | ids: [default] 37 | draft: true 38 | replace_existing_draft: true 39 | target_commitish: "{{ .Commit }}" 40 | # discussion_category_name: General 41 | prerelease: auto 42 | mode: replace 43 | header: | 44 | ## ⚙️ The `{{ .Tag }}` release 45 | footer: | 46 | ## Install or update 47 | 48 | For native Go installation (any platforms): 49 | 50 | ```console 51 | go install github.com/create-go-app/cli/v4/cmd/cgapp@latest 52 | ``` 53 | 54 | For [Homebrew][brew_url] users (GNU/Linux, macOS): 55 | 56 | ```console 57 | # Tap a new formula: 58 | brew tap create-go-app/tap 59 | 60 | # Installation: 61 | brew install create-go-app/tap/cli 62 | 63 | # Upgrade to the latest: 64 | brew upgrade create-go-app/tap/cli 65 | ``` 66 | 67 | > 💡 Note: See the [`Wiki page`][wiki_url] to understand the project structure and get general recommendations. 68 | 69 | ## Your help to improve project 70 | 71 | I'd be truly grateful for help with: 72 | 73 | - Creating tests (and/or benchmarks) for code. 74 | - Improving existing functions, structs, or tests. 75 | - Feature requests with interesting functions that would be good to add. 76 | 77 | Your PRs & issues are welcome! Thanks 😉 78 | 79 | [brew_url]: https://brew.sh 80 | [wiki_url]: https://github.com/create-go-app/cli/wiki 81 | disable: false 82 | skip_upload: false 83 | 84 | brews: 85 | - repository: 86 | owner: create-go-app 87 | name: homebrew-tap 88 | branch: main 89 | token: "{{ .Env.GITHUB_TOKEN }}" 90 | pull_request: 91 | enabled: true 92 | git: 93 | url: "git@github.com:create-go-app/homebrew-tap.git" 94 | private_key: "{{ .Env.PRIVATE_KEY_PATH }}" 95 | commit_author: 96 | name: Vic Shóstak 97 | email: koddr.me@gmail.com 98 | commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}" 99 | directory: Formula 100 | caveats: | 101 | After install (or update) cgapp, let's create a new project via interactive console UI in current folder: 102 | 103 | $ cgapp create 104 | 105 | Next, open the generated Ansible inventory file (called hosts.ini) and fill in the variables according to your server configuration. 106 | 107 | And you're ready to automatically deploy this project: 108 | 109 | $ cgapp deploy 110 | 111 | That's all you need to know to start! 🎉 112 | homepage: "https://github.com/create-go-app/cli" 113 | description: | 114 | Create a new production-ready project with backend (Golang), frontend (JavaScript, TypeScript) and deploy automation (Ansible, Docker) by running one CLI command. 115 | Focus on writing code and thinking of business-logic! The CLI will take care of the rest. 116 | license: Apache 2.0 117 | skip_upload: false 118 | dependencies: 119 | - name: git 120 | - name: npm 121 | 122 | dockers: 123 | - id: "{{ .ProjectName }}" 124 | ids: [default] 125 | image_templates: 126 | - "koddr/{{ .ProjectName }}:latest" 127 | - "koddr/{{ .ProjectName }}:{{ .Tag }}" 128 | - "koddr/{{ .ProjectName }}:v{{ .Major }}" 129 | - "koddr/{{ .ProjectName }}:v{{ .Major }}.{{ .Minor }}" 130 | build_flag_templates: 131 | - "--pull" 132 | - "--label=org.opencontainers.image.created={{ .Date }}" 133 | - "--label=org.opencontainers.image.title={{ .ProjectName }}" 134 | - "--label=org.opencontainers.image.revision={{ .FullCommit }}" 135 | - "--label=org.opencontainers.image.version={{ .Version }}" 136 | - "--platform=linux/amd64" 137 | skip_push: false 138 | push_flags: 139 | - --tls-verify=false 140 | 141 | nfpms: 142 | - maintainer: Vic Shóstak 143 | description: | 144 | Create a new production-ready project with backend (Golang), frontend (JavaScript, TypeScript) and deploy automation (Ansible, Docker) by running one CLI command. 145 | Focus on writing code and thinking of business-logic! The CLI will take care of the rest. 146 | homepage: "https://github.com/create-go-app/cli" 147 | license: Apache 2.0 148 | formats: [deb, rpm, apk, archlinux] 149 | dependencies: [git, npm] 150 | 151 | archives: 152 | - format_overrides: 153 | - goos: windows 154 | format: zip 155 | files: [LICENSE, README.md] 156 | 157 | checksum: 158 | name_template: "checksums.txt" 159 | 160 | changelog: 161 | # use: github 162 | sort: asc 163 | abbrev: -1 164 | filters: 165 | exclude: ["^*.md", "^*.ya?ml"] 166 | groups: 167 | - title: Features 168 | regexp: ^.*?(F|f)eature.*?$ 169 | order: 0 170 | - title: Bug fixes 171 | regexp: ^.*?((B|b)ug)|((F|f)ix).*?$ 172 | order: 1 173 | - title: Improvements 174 | regexp: ^.*?(I|i)mprove.*?$ 175 | order: 2 176 | - title: Updates 177 | regexp: ^.*?(U|u)pdate.*?$ 178 | order: 3 179 | - title: Security issues 180 | regexp: ^.*?(S|s)ecurity.*?$ 181 | order: 4 182 | - title: Delete unused or stale 183 | regexp: ^.*?((D|d)elete)|((U|u)nused)|((S|s)tale).*?$ 184 | order: 5 185 | - title: Others 186 | order: 999 187 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | COPY cgapp / 3 | ENTRYPOINT ["/cgapp"] 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2024 Vic Shóstak and Create Go App Contributors 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean security critic test install build release build-and-push-images delete-tag update-pkg-cache 2 | 3 | clean: 4 | rm -rf ./tmp ./tests 5 | 6 | security: 7 | go run github.com/securego/gosec/v2/cmd/gosec@latest -quiet ./... 8 | 9 | critic: 10 | go run github.com/go-critic/go-critic/cmd/gocritic@latest check -enableAll ./... 11 | 12 | test: clean security critic 13 | mkdir ./tests 14 | go test -coverprofile=./tests/coverage.out ./... 15 | go tool cover -func=./tests/coverage.out 16 | rm -rf ./tests 17 | 18 | install: test 19 | CGO_ENABLED=0 go build -ldflags="-s -w" -o $(GOPATH)/bin/cgapp ./cmd/cgapp/main.go 20 | 21 | build: test 22 | goreleaser --snapshot 23 | 24 | release: test 25 | git tag -a v$(VERSION) -m "$(VERSION)" 26 | goreleaser --snapshot 27 | 28 | build-and-push-images: test 29 | docker build -t docker.io/koddr/cgapp:latest . 30 | docker push docker.io/koddr/cgapp:latest 31 | docker build -t docker.io/koddr/cgapp:$(VERSION) . 32 | docker push docker.io/koddr/cgapp:$(VERSION) 33 | docker image rm docker.io/koddr/cgapp:$(VERSION) 34 | 35 | update-pkg-cache: 36 | curl -i https://proxy.golang.org/github.com/create-go-app/cli/v4/@v/v$(VERSION).info 37 | 38 | delete-tag: 39 | git tag --delete v$(VERSION) 40 | docker image rm docker.io/koddr/cgapp:latest 41 | docker image rm docker.io/koddr/cgapp:$(VERSION) 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | [![Create Go App][repo_logo_img]][repo_url] 4 | 5 | # Create Go App CLI 6 | 7 | [![Go version][go_version_img]][go_dev_url] 8 | [![Go report][go_report_img]][go_report_url] 9 | [![Code coverage][go_code_coverage_img]][repo_url]
10 | [![Wiki][repo_wiki_img]][repo_wiki_url] 11 | [![License][repo_license_img]][repo_license_url] 12 | 13 | Create a new production-ready project with **backend** (Golang), 14 | **frontend** (JavaScript, TypeScript) and **deploy automation** (Ansible, Docker) by running only one command. Focus on **writing your code** and **thinking of the business-logic**! The CLI will take care of the rest. 15 | 16 |
17 | 18 | ## ⚡️ Quick start 19 | 20 | First, [download][go_download_url] and install **Go**. Version `1.21` or 21 | higher is required. 22 | 23 | > 👆 You can also use **Create Go App CLI** via other Go 24 | > versions: [`1.16`][repo_v2_url], [`1.17`][repo_v3_url]. 25 | 26 | Installation is done by using the [`go install`][go_install_url] command: 27 | 28 | ```bash 29 | go install github.com/create-go-app/cli/v4/cmd/cgapp@latest 30 | ``` 31 | 32 | Or see the repository's [Release page][repo_releases_url], if you want to 33 | download a ready-made `deb`, `rpm`, `apk` or `Arch Linux` package. 34 | 35 | Also, GNU/Linux and macOS users available way to install via 36 | [Homebrew][brew_url]: 37 | 38 | ```bash 39 | # Tap a new formula: 40 | brew tap create-go-app/tap 41 | 42 | # Installation: 43 | brew install create-go-app/tap/cgapp 44 | ``` 45 | 46 | Let's create a new project via **interactive console UI** (or **CUI** for 47 | short) in current folder: 48 | 49 | ```bash 50 | cgapp create 51 | ``` 52 | 53 | Next, open the generated Ansible inventory file (called `hosts.ini`) and 54 | fill in the variables according to your server configuration. And you're 55 | ready to **automatically deploy** this project: 56 | 57 | ```bash 58 | cgapp deploy 59 | ``` 60 | 61 | That's all you need to know to start! 🎉 62 | 63 | ### 🐳 Docker-way to quick start 64 | 65 | If you don't want to install Create Go App CLI to your system, you feel free 66 | to using our official [Docker image][docker_url] and run CLI from isolated 67 | container: 68 | 69 | ```bash 70 | docker run --rm -it -v ${PWD}:${PWD} -w ${PWD} koddr/cgapp:latest [COMMAND] 71 | ``` 72 | 73 | > 🔔 Please note: the `deploy` command is currently **unavailable** in this 74 | > image. 75 | 76 | ## 📖 Project Wiki 77 | 78 | The best way to better explore all the features of the **Create Go App CLI** 79 | is to read the project [Wiki][repo_wiki_url] and take part in 80 | [Discussions][repo_discussions_url] and/or [Issues][repo_issues_url]. 81 | 82 | Yes, the most frequently asked questions (FAQ) are also 83 | [here][repo_wiki_faq_url]. 84 | 85 | ## ⚙️ Commands & Options 86 | 87 | ### `create` 88 | 89 | CLI command for create a new project with the interactive console UI. 90 | 91 | ```bash 92 | cgapp create [OPTION] 93 | ``` 94 | 95 | | Option | Description | Type | Default | Required? | 96 | | ------ | -------------------------------------------------------- | ------ | ------- | --------- | 97 | | `-t` | Enables to define custom backend and frontend templates. | `bool` | `false` | No | 98 | 99 | ![cgapp_create][cgapp_create_gif] 100 | 101 | - 📺 Full demo video: https://recordit.co/OQAwkZBrjN 102 | - 📖 Docs: https://github.com/create-go-app/cli/wiki/Command-create 103 | 104 | ### `deploy` 105 | 106 | CLI command for deploy Docker containers with your project via Ansible to 107 | the remote server. 108 | 109 | > 🔔 Make sure that you have [Python 3.8+][python_url] and 110 | > [Ansible 2.9+][ansible_url] installed on your computer. 111 | 112 | ```bash 113 | cgapp deploy [OPTION] 114 | ``` 115 | 116 | | Option | Description | Type | Default | Required? | 117 | | ------ | ------------------------------------------------------------------------------------------------------ | ------ | ------- | --------- | 118 | | `-k` | Prompt you to provide the remote user sudo password (_a standard Ansible `--ask-become-pass` option_). | `bool` | `false` | No | 119 | 120 | ![cgapp_deploy][cgapp_deploy_gif] 121 | 122 | - 📺 Full demo video: https://recordit.co/ishTf0Au1x 123 | - 📖 Docs: https://github.com/create-go-app/cli/wiki/Command-deploy 124 | 125 | ## 📝 Production-ready project templates 126 | 127 | ### Backend 128 | 129 | - Backend template with Golang built-in [net/http][net_http_url] package: 130 | - [`net/http`][cgapp_net-http-template_url] — simple REST API with CRUD 131 | and JWT auth. 132 | - Backend template with [Fiber][fiber_url]: 133 | - [`fiber`][cgapp_fiber-template_url] — complex REST API with CRUD, JWT auth 134 | with renew token, DB and cache. 135 | - Backend template with [go-chi][chi_url]: 136 | - [`chi`][cgapp_chi-template_url] — a basic application with health check. 137 | 138 | ### Frontend 139 | 140 | Frontend part will be generated using awesome tool [Vite.js][vitejs_url] 141 | under the hood. 142 | 143 | So, you'll always get the latest version of React, Preact, Vue, Svelte, 144 | Solid, Lit, Qwik, or pure JavaScript/TypeScript templates for your project. 145 | 146 | | Name | Description | JavaScript | Typescript | 147 | | --------------------------------- | -------------------------------- | ----------- | -------------- | 148 | | Pure | A pure JavaScript/Typescript app | `vanilla` | `vanilla-ts` | 149 | | [React][react_url] | A common React app | `react` | `react-ts` | 150 | | [React (with SWC)][react_swc_url] | A React app with SWC | `react-swc` | `react-swc-ts` | 151 | | [Preact][preact_url] | A common Preact app | `preact` | `preact-ts` | 152 | | [Vue.js][vuejs_url] | A common Vue.js app | `vue` | `vue-ts` | 153 | | [Svelte][svelte_url] | A common Svelte app | `svelte` | `svelte-ts` | 154 | | [Solid][solid_url] | A common Solid app | `solid` | `solid-ts` | 155 | | [Lit][lit_url] | A common Lit app | `lit` | `lit-ts` | 156 | | [Qwik][qwik_url] | A common Qwik app | `qwik` | `qwik-ts` | 157 | 158 | The `Next.js` and `Nuxt` frontend parts will be generated using the latest 159 | `create-next-app` and `nuxi` utilities. 160 | 161 | | Name | Description | JavaScript | Typescript | 162 | | -------------------------- | ---------------------- | ---------- | ----------- | 163 | | [Next.js][nextjs_url] | A common Next.js app | `next` | `next-ts` | 164 | | [Nuxt][nuxt_url] | A common Nuxt v3 app | - | `nuxt` | 165 | | [Sveltekit][sveltekit_url] | A common Sveltekit app | - | `sveltekit` | 166 | 167 | > ❗️ Please make sure that you have `npm` version `7` or higher installed to 168 | > create the frontend part of the project correctly. If you run the 169 | > `cgapp -create` command using our [Docker image][docker_url], `npm` of the 170 | > correct version is **already** included. 171 | 172 | ## 🚚 Pre-configured Ansible roles 173 | 174 | ### Web/Proxy server 175 | 176 | - Roles for run Docker container with [Traefik Proxy][traefik_url]: 177 | - `traefik` — configured Traefik container with a simple ACME challenge 178 | via CA server. 179 | - `traefik-acme-dns` — configured Traefik container with a complex ACME 180 | challenge via DNS provider. 181 | - Roles for run Docker container with [Nginx][nginx_url]: 182 | - `nginx` — pure Nginx container with "the best practice" configuration. 183 | 184 | > ✌️ Since Create Go App CLI `v2.0.0`, we're recommended to use **Traefik 185 | > Proxy** as default proxy server for your projects. The main reason: this 186 | > proxy provides _automatic_ SSL certificates from Let's Encrypt out of the 187 | > box. Also, Traefik was built on the Docker ecosystem and has a _really 188 | > good-looking_ and _useful_ Web UI. 189 | 190 | ### Database 191 | 192 | - Roles for run Docker container with [PostgreSQL][postgresql_url]: 193 | - `postgres` — configured PostgreSQL container with apply migrations for 194 | backend. 195 | 196 | ### Cache (key-value storage) 197 | 198 | - Roles for run Docker container with [Redis][redis_url]: 199 | - `redis` — configured Redis container for backend. 200 | 201 | ## ⭐️ Project assistance 202 | 203 | If you want to say **thank you** or/and support active development of 204 | `Create Go App CLI`: 205 | 206 | - Add a [GitHub Star][repo_url] to the project. 207 | - Write interesting articles about project on [Dev.to][dev_to_url], or 208 | personal blog. 209 | - Leave a review on our [ProductHunt][cgapp_product-hunt_url] page. 210 | 211 | ## ❗️ Support the author 212 | 213 | You can support the author on [Boosty][boosty_url], both on a _permanent_ and on a _one-time_ basis. 214 | 215 | All proceeds from this way will go to **support** my OSS projects and will energize me to **create** new products and articles for the community. 216 | 217 | support me on Boosty 218 | 219 | ## 🏆 A win-win cooperation 220 | 221 | And now, I invite you to participate in this project! Let's work **together** to 222 | create the **most useful** tool for developers on the web today. 223 | 224 | - [Issues][repo_issues_url]: ask questions and submit your features. 225 | - [Pull requests][repo_pull_request_url]: send your improvements to the current. 226 | 227 | Together, we can make this project **better** every day! 😘 228 | 229 | ## 🔥 Other projects from the author 230 | 231 | gowebly project 232 | 233 | ## ⚠️ License 234 | 235 | [`Create Go App CLI`][repo_url] is free and open-source software licensed under 236 | the [Apache 2.0 License][repo_license_url]. Official [logo][repo_logo_url] was 237 | created by [Vic Shóstak][author] and distributed under 238 | [Creative Commons][repo_cc_url] license (CC BY-SA 4.0 International). 239 | 240 | 241 | 242 | [go_download_url]: https://golang.org/dl/ 243 | [go_install_url]: https://golang.org/cmd/go/#hdr-Compile_and_install_packages_and_dependencies 244 | [go_version_img]: https://img.shields.io/badge/Go-1.21+-00ADD8?style=for-the-badge&logo=go 245 | [go_report_img]: https://img.shields.io/badge/Go_report-A+-success?style=for-the-badge&logo=none 246 | [go_report_url]: https://goreportcard.com/report/github.com/create-go-app/cli 247 | [go_code_coverage_img]: https://img.shields.io/badge/code_coverage-88%25-success?style=for-the-badge&logo=none 248 | [go_dev_url]: https://pkg.go.dev/github.com/create-go-app/cli/v4 249 | 250 | 251 | 252 | [repo_url]: https://github.com/create-go-app/cli 253 | [repo_logo_url]: https://github.com/create-go-app/cli/wiki/Logo 254 | [repo_logo_img]: https://github.com/create-go-app/cli/assets/11155743/95024afc-5e3b-4d6f-8c9c-5daaa51d080d 255 | [repo_license_url]: https://github.com/create-go-app/cli/blob/main/LICENSE 256 | [repo_license_img]: https://img.shields.io/badge/license-Apache_2.0-red?style=for-the-badge&logo=none 257 | [repo_cc_url]: https://creativecommons.org/licenses/by-sa/4.0/ 258 | [repo_v2_url]: https://github.com/create-go-app/cli/tree/v2 259 | [repo_v3_url]: https://github.com/create-go-app/cli/tree/v3 260 | [repo_issues_url]: https://github.com/create-go-app/cli/issues 261 | [repo_pull_request_url]: https://github.com/create-go-app/cli/pulls 262 | [repo_discussions_url]: https://github.com/create-go-app/cli/discussions 263 | [repo_releases_url]: https://github.com/create-go-app/cli/releases 264 | [repo_wiki_url]: https://github.com/create-go-app/cli/wiki 265 | [repo_wiki_img]: https://img.shields.io/badge/docs-wiki_page-blue?style=for-the-badge&logo=none 266 | [repo_wiki_faq_url]: https://github.com/create-go-app/cli/wiki/FAQ 267 | 268 | 269 | 270 | [cgapp_deploy_gif]: https://user-images.githubusercontent.com/11155743/116796941-3c421e00-aae9-11eb-9575-d72550814d7a.gif 271 | [cgapp_create_gif]: https://user-images.githubusercontent.com/11155743/116796937-38160080-aae9-11eb-8e21-fb1be2750aa4.gif 272 | [cgapp_product-hunt_url]: https://www.producthunt.com/posts/create-go-app?utm_source=badge-review&utm_medium=badge&utm_souce=badge-create-go-app#discussion-body 273 | [cgapp_product-hunt_img]: https://api.producthunt.com/widgets/embed-image/v1/review.svg?post_id=316086&theme=light 274 | [cgapp_chi-template_url]: https://github.com/create-go-app/chi-go-template 275 | [cgapp_fiber-template_url]: https://github.com/create-go-app/fiber-go-template 276 | [cgapp_net-http-template_url]: https://github.com/create-go-app/net_http-go-template 277 | 278 | 279 | 280 | [author]: https://github.com/koddr 281 | [author_do_ref_url]: https://m.do.co/c/b41859fa9b6e 282 | 283 | 284 | 285 | [twitter_url]: https://twitter.com/intent/tweet?text=Wow%21%20%F0%9F%8E%89%20Create%20a%20new%20production-ready%20project%20with%20backend%20%28Golang%29%2C%20frontend%20%28JavaScript%2C%20TypeScript%29%0Aand%20deploy%20automation%20%28Ansible%2C%20Docker%29%20by%20running%20one%20CLI%20command%20%F0%9F%91%89%20https%3A%2F%2Fgithub.com%2Fcreate-go-app%2Fcli 286 | [dev_to_url]: https://dev.to/ 287 | [redis_url]: https://redis.io/ 288 | [postgresql_url]: https://postgresql.org/ 289 | [nginx_url]: https://nginx.org/ 290 | [traefik_url]: https://traefik.io/traefik/ 291 | [vitejs_url]: https://vitejs.dev/ 292 | [vuejs_url]: https://vuejs.org/ 293 | [react_url]: https://reactjs.org/ 294 | [preact_url]: https://preactjs.com/ 295 | [nextjs_url]: https://nextjs.org/ 296 | [nuxt_url]: https://v3.nuxtjs.org/ 297 | [sveltekit_url]: https://kit.svelte.dev/ 298 | [svelte_url]: https://svelte.dev/ 299 | [lit_url]: https://lit.dev/ 300 | [chi_url]: https://github.com/go-chi/chi 301 | [fiber_url]: https://github.com/gofiber/fiber 302 | [net_http_url]: https://golang.org/pkg/net/http/ 303 | [docker_url]: https://hub.docker.com/r/koddr/cgapp 304 | [python_url]: https://www.python.org/downloads/ 305 | [ansible_url]: https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible-on-specific-operating-systems 306 | [brew_url]: https://brew.sh/ 307 | [qwik_url]: https://github.com/BuilderIO/qwik 308 | [solid_url]: https://github.com/solidjs/solid 309 | [react_swc_url]: https://swc.rs/ 310 | 311 | 312 | 313 | [gowebly_url]: https://github.com/gowebly/gowebly 314 | [gowebly_img_url]: https://github.com/gowebly/.github/blob/a8ae889ed2c5baefcd307ad4505161f98f75669f/images/gowebly-banner-logo.png 315 | [boosty_url]: https://boosty.to/koddr 316 | -------------------------------------------------------------------------------- /cmd/cgapp/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package main includes call for the Create Go App CLI. 3 | 4 | Create a new production-ready project with backend (Golang), 5 | frontend (JavaScript, TypeScript) and deploy automation 6 | (Ansible, Docker) by running one CLI command. 7 | 8 | Focus on writing your code and thinking of the business logic! 9 | The Create Go App CLI will take care of the rest. 10 | 11 | A helpful documentation and next steps -> https://github.com/create-go-app/cli 12 | 13 | # Copyright 2023 Vic Shóstak and Create Go App Contributors 14 | 15 | Licensed under the Apache License, Version 2.0 (the "License"); 16 | you may not use this file except in compliance with the License. 17 | You may obtain a copy of the License at 18 | 19 | http://www.apache.org/licenses/LICENSE-2.0 20 | 21 | Unless required by applicable law or agreed to in writing, software 22 | distributed under the License is distributed on an "AS IS" BASIS, 23 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | See the License for the specific language governing permissions and 25 | limitations under the License. 26 | */ 27 | package main 28 | 29 | import "github.com/create-go-app/cli/v4/cmd" 30 | 31 | func main() { 32 | cmd.Execute() 33 | } 34 | -------------------------------------------------------------------------------- /cmd/create.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cmd 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | "time" 11 | 12 | "github.com/AlecAivazis/survey/v2" 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/create-go-app/cli/v4/pkg/cgapp" 16 | "github.com/create-go-app/cli/v4/pkg/registry" 17 | ) 18 | 19 | func init() { 20 | rootCmd.AddCommand(createCmd) 21 | createCmd.Flags().BoolVarP( 22 | &useCustomTemplate, 23 | "template", "t", false, 24 | "enables to use custom backend and frontend templates", 25 | ) 26 | } 27 | 28 | // createCmd represents the `create` command. 29 | var createCmd = &cobra.Command{ 30 | Use: "create", 31 | Aliases: []string{"new"}, 32 | Short: "Create a new project via interactive UI", 33 | Long: "\nCreate a new project via interactive UI.", 34 | RunE: runCreateCmd, 35 | } 36 | 37 | // runCreateCmd represents runner for the `create` command. 38 | func runCreateCmd(cmd *cobra.Command, args []string) error { 39 | // Start message. 40 | cgapp.ShowMessage( 41 | "", 42 | fmt.Sprintf( 43 | "Create a new project via Create Go App CLI v%v...", 44 | registry.CLIVersion, 45 | ), 46 | true, true, 47 | ) 48 | 49 | // Start survey. 50 | if useCustomTemplate { 51 | // Custom survey. 52 | if err := survey.Ask( 53 | registry.CustomCreateQuestions, 54 | &customCreateAnswers, 55 | survey.WithIcons(surveyIconsConfig), 56 | ); err != nil { 57 | return cgapp.ShowError(err.Error()) 58 | } 59 | 60 | // Define variables for better display. 61 | backend = customCreateAnswers.Backend 62 | frontend = customCreateAnswers.Frontend 63 | proxy = customCreateAnswers.Proxy 64 | } else { 65 | // Default survey. 66 | if err := survey.Ask( 67 | registry.CreateQuestions, 68 | &createAnswers, 69 | survey.WithIcons(surveyIconsConfig), 70 | ); err != nil { 71 | return cgapp.ShowError(err.Error()) 72 | } 73 | 74 | // Define variables for better display. 75 | backend = fmt.Sprintf( 76 | "github.com/create-go-app/%v-go-template", 77 | strings.ReplaceAll(createAnswers.Backend, "/", "_"), 78 | ) 79 | frontend = createAnswers.Frontend 80 | proxy = createAnswers.Proxy 81 | } 82 | 83 | // Catch the cancel action (hit "n" in the last question). 84 | if (!createAnswers.AgreeCreation && !useCustomTemplate) || (!customCreateAnswers.AgreeCreation && useCustomTemplate) { 85 | cgapp.ShowMessage( 86 | "", 87 | "Oh no! You said \"no\", so I won't create anything. Hope to see you soon!", 88 | true, true, 89 | ) 90 | return nil 91 | } 92 | 93 | // Start timer. 94 | startTimer := time.Now() 95 | 96 | /* 97 | The project's backend part creation. 98 | */ 99 | 100 | // Clone backend files from git repository. 101 | if err := cgapp.GitClone("backend", backend); err != nil { 102 | return cgapp.ShowError(err.Error()) 103 | } 104 | 105 | // Show success report. 106 | cgapp.ShowMessage( 107 | "success", 108 | fmt.Sprintf("Backend was created with template `%v`!", backend), 109 | true, false, 110 | ) 111 | 112 | /* 113 | The project's frontend part creation. 114 | */ 115 | 116 | if frontend != "none" { 117 | // Checking, if you use custom templates. 118 | if useCustomTemplate { 119 | // Clone frontend files from git repository. 120 | if err := cgapp.GitClone("frontend", frontend); err != nil { 121 | return cgapp.ShowError(err.Error()) 122 | } 123 | } else { 124 | switch frontend { 125 | case "next": 126 | // Create a default frontend template with Next.js (React). 127 | if err := cgapp.ExecCommand( 128 | "npx", 129 | []string{ 130 | "create-next-app@latest", "frontend", 131 | "--javascript", 132 | "--eslint", 133 | "--app", 134 | "--tailwind", "false", 135 | "--src-dir", "false", 136 | "--import-alias", "false", 137 | }, true, 138 | ); err != nil { 139 | return err 140 | } 141 | case "next-ts": 142 | // Create a default frontend template with Next.js (React, Typescript). 143 | if err := cgapp.ExecCommand( 144 | "npx", 145 | []string{ 146 | "create-next-app@latest", "frontend", 147 | "--typescript", 148 | "--eslint", 149 | "--app", 150 | "--tailwind", "false", 151 | "--src-dir", "false", 152 | "--import-alias", "false", 153 | }, true, 154 | ); err != nil { 155 | return err 156 | } 157 | case "nuxt": 158 | // Create a default frontend template with Nuxt v3 (Vue.js v3, Typescript). 159 | if err := cgapp.ExecCommand( 160 | "npx", 161 | []string{ 162 | "nuxi@latest", "init", "frontend", 163 | }, true, 164 | ); err != nil { 165 | return err 166 | } 167 | case "sveltekit": 168 | // Create a default frontend template with Sveltekit (Svelte, Typescript). 169 | if err := cgapp.ExecCommand( 170 | "npm", 171 | []string{ 172 | "create", "@svelte-add/kit@latest", "frontend", 173 | "--", 174 | "--with", "typescript+eslint+prettier", 175 | }, true, 176 | ); err != nil { 177 | return err 178 | } 179 | default: 180 | // Create a default frontend template from Vite (Pure JS/TS, React, Preact, Vue, Svelte, Lit). 181 | if err := cgapp.ExecCommand( 182 | "npm", 183 | []string{ 184 | "create", "vite@latest", "frontend", 185 | "--", 186 | "--template", 187 | frontend, 188 | }, true, 189 | ); err != nil { 190 | return err 191 | } 192 | } 193 | } 194 | 195 | // Show success report. 196 | cgapp.ShowMessage( 197 | "success", 198 | fmt.Sprintf("Frontend was created with template `%v`!", frontend), 199 | false, false, 200 | ) 201 | } 202 | 203 | /* 204 | The project's webserver part creation. 205 | */ 206 | 207 | // Copy Ansible playbook, inventory and roles from embedded file system. 208 | if err := cgapp.CopyFromEmbeddedFS( 209 | &cgapp.EmbeddedFileSystem{ 210 | Name: registry.EmbedTemplates, 211 | RootFolder: "templates", 212 | SkipDir: true, 213 | }, 214 | ); err != nil { 215 | return cgapp.ShowError(err.Error()) 216 | } 217 | 218 | // Set template variables for Ansible playbook and inventory files. 219 | inventory = registry.AnsibleInventoryVariables[proxy].List 220 | playbook = registry.AnsiblePlaybookVariables[proxy].List 221 | 222 | // Generate Ansible inventory file. 223 | if err := cgapp.GenerateFileFromTemplate("hosts.ini.tmpl", inventory); err != nil { 224 | return cgapp.ShowError(err.Error()) 225 | } 226 | 227 | // Generate Ansible playbook file. 228 | if err := cgapp.GenerateFileFromTemplate("playbook.yml.tmpl", playbook); err != nil { 229 | return cgapp.ShowError(err.Error()) 230 | } 231 | 232 | // Show success report. 233 | if proxy != "none" { 234 | cgapp.ShowMessage( 235 | "success", 236 | fmt.Sprintf("Web/Proxy server configuration for `%v` was created!", proxy), 237 | false, false, 238 | ) 239 | } 240 | 241 | /* 242 | The project's Ansible roles part creation. 243 | */ 244 | 245 | // Copy Ansible roles from embedded file system. 246 | if err := cgapp.CopyFromEmbeddedFS( 247 | &cgapp.EmbeddedFileSystem{ 248 | Name: registry.EmbedRoles, 249 | RootFolder: "roles", 250 | SkipDir: false, 251 | }, 252 | ); err != nil { 253 | return cgapp.ShowError(err.Error()) 254 | } 255 | 256 | // Show success report. 257 | cgapp.ShowMessage( 258 | "success", 259 | "Ansible inventory, playbook and roles for deploying your project was created!", 260 | false, false, 261 | ) 262 | 263 | /* 264 | The project's misc files part creation. 265 | */ 266 | 267 | // Copy from embedded file system. 268 | if err := cgapp.CopyFromEmbeddedFS( 269 | &cgapp.EmbeddedFileSystem{ 270 | Name: registry.EmbedMiscFiles, 271 | RootFolder: "misc", 272 | SkipDir: true, 273 | }, 274 | ); err != nil { 275 | return cgapp.ShowError(err.Error()) 276 | } 277 | 278 | /* 279 | Cleanup project. 280 | */ 281 | 282 | // Set unused proxy roles. 283 | switch proxy { 284 | case "traefik", "traefik-acme-dns": 285 | proxyList = []string{"nginx"} 286 | case "nginx": 287 | proxyList = []string{"traefik"} 288 | default: 289 | proxyList = []string{"traefik", "nginx"} 290 | } 291 | 292 | // Delete unused roles, backend and frontend files. 293 | cgapp.RemoveFolders("roles", proxyList) 294 | cgapp.RemoveFolders("backend", []string{".git", ".github"}) 295 | cgapp.RemoveFolders("frontend", []string{".git", ".github"}) 296 | 297 | // Stop timer. 298 | stopTimer := cgapp.CalculateDurationTime(startTimer) 299 | cgapp.ShowMessage( 300 | "info", 301 | fmt.Sprintf("Completed in %v seconds!", stopTimer), 302 | true, true, 303 | ) 304 | 305 | // Ending messages. 306 | cgapp.ShowMessage( 307 | "", 308 | "* Please put credentials into the Ansible inventory file (`hosts.ini`) before you start deploying a project!", 309 | false, false, 310 | ) 311 | if !useCustomTemplate && frontend != "none" { 312 | cgapp.ShowMessage( 313 | "", 314 | fmt.Sprintf("* Visit https://vitejs.dev/guide/ for more info about using the `%v` frontend template!", frontend), 315 | false, false, 316 | ) 317 | } 318 | cgapp.ShowMessage( 319 | "", 320 | "* A helpful documentation and next steps with your project is here https://github.com/create-go-app/cli/wiki", 321 | false, true, 322 | ) 323 | cgapp.ShowMessage( 324 | "", 325 | "Have a happy new project! :)", 326 | false, true, 327 | ) 328 | 329 | return nil 330 | } 331 | -------------------------------------------------------------------------------- /cmd/deploy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cmd 6 | 7 | import ( 8 | "fmt" 9 | "time" 10 | 11 | "github.com/spf13/cobra" 12 | 13 | "github.com/create-go-app/cli/v4/pkg/cgapp" 14 | "github.com/create-go-app/cli/v4/pkg/registry" 15 | ) 16 | 17 | func init() { 18 | rootCmd.AddCommand(deployCmd) 19 | deployCmd.Flags().BoolVarP( 20 | &askBecomePass, 21 | "ask-become-pass", "k", false, 22 | "prompt you to provide the remote user sudo password (standard Ansible `--ask-become-pass` option)", 23 | ) 24 | } 25 | 26 | // deployCmd represents the `deploy` command. 27 | var deployCmd = &cobra.Command{ 28 | Use: "deploy", 29 | Aliases: []string{"push"}, 30 | Short: "Deploy your project to the remote server via Ansible", 31 | Long: "\nDeploy your project to the remote server by Ansible playbooks and roles.", 32 | RunE: runDeployCmd, 33 | } 34 | 35 | // runDeployCmd represents runner for the `deploy` command. 36 | func runDeployCmd(cmd *cobra.Command, args []string) error { 37 | // Start message. 38 | cgapp.ShowMessage( 39 | "", 40 | fmt.Sprintf("Deploying project via Create Go App CLI v%v...", registry.CLIVersion), 41 | true, true, 42 | ) 43 | 44 | // Set Ansible playbook and inventory files. 45 | if askBecomePass { 46 | // With entering password. 47 | options = []string{"playbook.yml", "-i", "hosts.ini", "-K"} 48 | } else { 49 | // Without entering password. 50 | options = []string{"playbook.yml", "-i", "hosts.ini"} 51 | } 52 | 53 | // Create config files for your project. 54 | cgapp.ShowMessage( 55 | "info", 56 | "Ansible playbook for deploy your project is running. Please wait for completion!", 57 | false, false, 58 | ) 59 | 60 | // Start timer. 61 | startTimer := time.Now() 62 | 63 | // Run execution for Ansible playbook. 64 | if err := cgapp.ExecCommand("ansible-playbook", options, false); err != nil { 65 | return cgapp.ShowError(err.Error()) 66 | } 67 | 68 | // Stop timer. 69 | stopTimer := cgapp.CalculateDurationTime(startTimer) 70 | cgapp.ShowMessage( 71 | "info", 72 | fmt.Sprintf("Completed in %v seconds!", stopTimer), 73 | false, true, 74 | ) 75 | 76 | // Ending message. 77 | cgapp.ShowMessage( 78 | "", 79 | "Have a great project launch! :)", 80 | false, true, 81 | ) 82 | 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cmd 6 | 7 | import ( 8 | "github.com/AlecAivazis/survey/v2" 9 | "github.com/spf13/cobra" 10 | 11 | "github.com/create-go-app/cli/v4/pkg/cgapp" 12 | "github.com/create-go-app/cli/v4/pkg/registry" 13 | ) 14 | 15 | var ( 16 | backend, frontend, proxy string // define project variables 17 | inventory, playbook map[string]interface{} // define template variables 18 | options, proxyList []string // define options, proxy list 19 | useCustomTemplate bool // define custom templates 20 | askBecomePass bool // install Ansible roles, ask become pass 21 | createAnswers, customCreateAnswers registry.CreateAnswers // define answers variable for `create` command 22 | 23 | // Config for survey icons and colors. 24 | // See: https://github.com/mgutz/ansi#style-format 25 | surveyIconsConfig = func(icons *survey.IconSet) { 26 | icons.Question.Format = "cyan" 27 | icons.Question.Text = "[?]" 28 | icons.Help.Format = "blue" 29 | icons.Help.Text = "Help ->" 30 | icons.Error.Format = "yellow" 31 | icons.Error.Text = "Note ->" 32 | } 33 | ) 34 | 35 | // rootCmd represents the base command when called without any subcommands. 36 | var rootCmd = &cobra.Command{ 37 | Use: "cgapp", 38 | Version: registry.CLIVersion, 39 | Short: "A powerful CLI for the Create Go App project", 40 | Long: ` 41 | A powerful CLI for the Create Go App project. 42 | 43 | Create a new production-ready project with backend (Golang), 44 | frontend (JavaScript, TypeScript) and deploy automation 45 | (Ansible, Docker) by running one CLI command. 46 | 47 | -> Focus on writing code and thinking of business logic! 48 | <- The Create Go App CLI will take care of the rest. 49 | 50 | A helpful documentation and next steps -> https://github.com/create-go-app/cli/wiki`, 51 | } 52 | 53 | func init() { 54 | rootCmd.SetOut(cgapp.Stdout) 55 | rootCmd.SetErr(cgapp.Stderr) 56 | } 57 | 58 | // Execute adds all child commands to the root command and sets flags appropriately. 59 | // This is called by main.main(). It only needs to happen once to the rootCmd. 60 | func Execute() { 61 | _ = rootCmd.Execute() 62 | } 63 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/create-go-app/cli/v4 2 | 3 | go 1.21 4 | toolchain go1.24.1 5 | 6 | require ( 7 | github.com/AlecAivazis/survey/v2 v2.3.7 8 | github.com/go-git/go-git/v5 v5.16.0 9 | github.com/mattn/go-colorable v0.1.14 10 | github.com/spf13/cobra v1.9.1 11 | ) 12 | 13 | require ( 14 | dario.cat/mergo v1.0.1 // indirect 15 | github.com/Microsoft/go-winio v0.6.2 // indirect 16 | github.com/ProtonMail/go-crypto v1.1.6 // indirect 17 | github.com/cloudflare/circl v1.6.1 // indirect 18 | github.com/cyphar/filepath-securejoin v0.4.1 // indirect 19 | github.com/emirpasic/gods v1.18.1 // indirect 20 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 21 | github.com/go-git/go-billy/v5 v5.6.2 // indirect 22 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 23 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 24 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 25 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect 26 | github.com/kevinburke/ssh_config v1.2.0 // indirect 27 | github.com/mattn/go-isatty v0.0.20 // indirect 28 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect 29 | github.com/pjbgf/sha1cd v0.3.2 // indirect 30 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect 31 | github.com/skeema/knownhosts v1.3.1 // indirect 32 | github.com/spf13/pflag v1.0.6 // indirect 33 | github.com/xanzy/ssh-agent v0.3.3 // indirect 34 | golang.org/x/crypto v0.37.0 // indirect 35 | golang.org/x/net v0.39.0 // indirect 36 | golang.org/x/sys v0.32.0 // indirect 37 | golang.org/x/term v0.31.0 // indirect 38 | golang.org/x/text v0.24.0 // indirect 39 | gopkg.in/warnings.v0 v0.1.2 // indirect 40 | ) 41 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 2 | dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 3 | github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= 4 | github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= 5 | github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 6 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 7 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 8 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= 9 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= 10 | github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= 11 | github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= 12 | github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 13 | github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 14 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 15 | github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 16 | github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= 17 | github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 18 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 19 | github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= 20 | github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 21 | github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= 22 | github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 23 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 24 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 25 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 26 | github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= 27 | github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= 28 | github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 29 | github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 30 | github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= 31 | github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= 32 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= 33 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= 34 | github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= 35 | github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= 36 | github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= 37 | github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= 38 | github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ= 39 | github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= 40 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 41 | github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 42 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 43 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 44 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= 45 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= 46 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 47 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 48 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 49 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 50 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 51 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 52 | github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= 53 | github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 54 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 55 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 56 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 57 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 58 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 59 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 60 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 61 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 62 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 63 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 64 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 65 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 66 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 67 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 68 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= 69 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 70 | github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 71 | github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 72 | github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= 73 | github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= 74 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 75 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 76 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 77 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 78 | github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 79 | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 80 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 81 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= 82 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 83 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 84 | github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= 85 | github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= 86 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= 87 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= 88 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 89 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 90 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 91 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 92 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 93 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 94 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 95 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 96 | github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= 97 | github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 98 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 99 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 100 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 101 | golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 102 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 103 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 104 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= 105 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 106 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 107 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 108 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 109 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 110 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 111 | golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= 112 | golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= 113 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 114 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 115 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 116 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 117 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 118 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 119 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 120 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 121 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 122 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 123 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 124 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 125 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 126 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 127 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 128 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 129 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 130 | golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= 131 | golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= 132 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 133 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 134 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 135 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 136 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 137 | golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= 138 | golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 139 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 140 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 141 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 142 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 143 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 144 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 145 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 146 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 147 | gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 148 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 149 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 150 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 151 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 152 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 153 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 154 | -------------------------------------------------------------------------------- /pkg/cgapp/exec.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cgapp 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "fmt" 11 | "os/exec" 12 | ) 13 | 14 | // ExecCommand function to execute a given command. 15 | func ExecCommand(command string, options []string, silentMode bool) error { 16 | // Checking for nil. 17 | if command == "" || options == nil { 18 | return fmt.Errorf("no command to execute") 19 | } 20 | 21 | // Create buffer for stderr. 22 | stderr := &bytes.Buffer{} 23 | 24 | // Collect command line. 25 | cmd := exec.Command(command, options...) // #nosec G204 26 | 27 | // Set buffer for stderr from cmd. 28 | cmd.Stderr = stderr 29 | 30 | // Create a new reader. 31 | cmdReader, errStdoutPipe := cmd.StdoutPipe() 32 | if errStdoutPipe != nil { 33 | return ShowError(errStdoutPipe.Error()) 34 | } 35 | 36 | // Start executing command. 37 | if errStart := cmd.Start(); errStart != nil { 38 | return ShowError(errStart.Error()) 39 | } 40 | 41 | // Create a new scanner and run goroutine func with output, if not in silent mode. 42 | if !silentMode { 43 | scanner := bufio.NewScanner(cmdReader) 44 | go func() { 45 | for scanner.Scan() { 46 | ShowMessage("", scanner.Text(), false, false) 47 | } 48 | }() 49 | } 50 | 51 | // Wait for executing command. 52 | if errWait := cmd.Wait(); errWait != nil { 53 | return ShowError(errWait.Error()) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/cgapp/exec_test.go: -------------------------------------------------------------------------------- 1 | package cgapp 2 | 3 | import "testing" 4 | 5 | func TestExecCommand(t *testing.T) { 6 | type args struct { 7 | command string 8 | options []string 9 | silentMode bool 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | wantErr bool 15 | }{ 16 | { 17 | "successfully executing command", 18 | args{ 19 | command: "echo", 20 | options: []string{"ping"}, 21 | silentMode: false, 22 | }, 23 | false, 24 | }, 25 | { 26 | "successfully executing command with silent mode", 27 | args{ 28 | command: "echo", 29 | options: []string{"ping"}, 30 | silentMode: true, 31 | }, 32 | false, 33 | }, 34 | { 35 | "failed executing command", 36 | args{}, 37 | true, 38 | }, 39 | } 40 | for _, tt := range tests { 41 | t.Run(tt.name, func(t *testing.T) { 42 | if err := ExecCommand(tt.args.command, tt.args.options, tt.args.silentMode); (err != nil) != tt.wantErr { 43 | t.Errorf("ExecCommand() error = %v, wantErr %v", err, tt.wantErr) 44 | } 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/cgapp/files.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cgapp 6 | 7 | import ( 8 | "embed" 9 | "fmt" 10 | "io/fs" 11 | "os" 12 | "path/filepath" 13 | "strings" 14 | "text/template" 15 | ) 16 | 17 | // EmbeddedFileSystem struct contains embedded file system fields. 18 | type EmbeddedFileSystem struct { 19 | Name embed.FS 20 | RootFolder string 21 | SkipDir bool 22 | } 23 | 24 | // CopyFromEmbeddedFS function for copy files from embedded file system. 25 | func CopyFromEmbeddedFS(efs *EmbeddedFileSystem) error { 26 | // Return copied folders and files. 27 | if err := fs.WalkDir(efs.Name, efs.RootFolder, func(path string, entry fs.DirEntry, err error) error { 28 | // Checking embed path. 29 | if err != nil { 30 | return ShowError( 31 | fmt.Sprintf("Can't copy files from embedded path `%v`!", efs.RootFolder), 32 | ) 33 | } 34 | 35 | // Checking, if embedded file is a folder. 36 | if entry.IsDir() && !efs.SkipDir { 37 | // Create folders structure from embedded. 38 | if err := MakeFolder(path); err != nil { 39 | return err 40 | } 41 | } 42 | 43 | // Checking, if embedded file is not a folder. 44 | if !entry.IsDir() { 45 | // Set file data. 46 | fileData, errReadFile := fs.ReadFile(efs.Name, path) 47 | if errReadFile != nil { 48 | return errReadFile 49 | } 50 | 51 | // Path to file, if skipped folders. 52 | if efs.SkipDir { 53 | path = entry.Name() 54 | } 55 | 56 | // Create file from embedded. 57 | if errMakeFile := MakeFile(path, fileData); errMakeFile != nil { 58 | return errMakeFile 59 | } 60 | } 61 | 62 | return nil 63 | }); err != nil { 64 | return err 65 | } 66 | 67 | return nil 68 | } 69 | 70 | // GenerateFileFromTemplate func to generate files from templates. 71 | func GenerateFileFromTemplate(fileName string, variables map[string]interface{}) error { 72 | // Checking file name. 73 | if fileName == "" { 74 | return ShowError( 75 | fmt.Sprintf("Not correct or empty file name (given: `%s`)!", fileName), 76 | ) 77 | } 78 | 79 | // Clean file name. 80 | cleanFileName := filepath.Clean(fileName) 81 | 82 | // Parse template. 83 | tmpl, errParseFiles := template.ParseFiles(cleanFileName) 84 | if errParseFiles != nil { 85 | return ShowError(errParseFiles.Error()) 86 | } 87 | 88 | // Create a new file with template data. 89 | file, errCreate := os.Create(cleanFileName) 90 | if errCreate != nil { 91 | return ShowError(errCreate.Error()) 92 | } 93 | 94 | // Execute template with variables. 95 | if errExecute := tmpl.Execute(file, variables); errExecute != nil { 96 | return ShowError(errExecute.Error()) 97 | } 98 | _ = file.Close() 99 | 100 | // Rename output file. 101 | newFileName := strings.ReplaceAll(cleanFileName, ".tmpl", "") 102 | if errRename := os.Rename(cleanFileName, newFileName); errRename != nil { 103 | return ShowError(errRename.Error()) 104 | } 105 | 106 | return nil 107 | } 108 | 109 | // MakeFile function for single file create. 110 | func MakeFile(fileName string, fileData []byte) error { 111 | // Write to created file. 112 | if err := os.WriteFile(fileName, fileData, 0o600); err != nil { 113 | return err 114 | } 115 | 116 | return nil 117 | } 118 | 119 | // MakeFolder function for create folder. 120 | func MakeFolder(folderName string) error { 121 | // Check if folder exists, fail if it does. 122 | if err := os.Mkdir(folderName, 0o750); err != nil { 123 | return err 124 | } 125 | 126 | return nil 127 | } 128 | 129 | // RemoveFolders function for massively remove folders. 130 | func RemoveFolders(rootFolder string, foldersToRemove []string) { 131 | for _, folder := range foldersToRemove { 132 | _ = os.RemoveAll(filepath.Join(rootFolder, folder)) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /pkg/cgapp/files_test.go: -------------------------------------------------------------------------------- 1 | package cgapp 2 | 3 | import ( 4 | "io/fs" 5 | "os" 6 | "testing" 7 | 8 | "github.com/create-go-app/cli/v4/pkg/registry" 9 | ) 10 | 11 | func TestMakeFile(t *testing.T) { 12 | 13 | fileData, err := fs.ReadFile(registry.EmbedMiscFiles, "misc/Makefile") 14 | if err != nil { 15 | t.Error() 16 | } 17 | 18 | type args struct { 19 | rootFolder string 20 | file string 21 | data []byte 22 | } 23 | tests := []struct { 24 | name string 25 | args args 26 | wantErr bool 27 | }{ 28 | { 29 | "successfully created files", 30 | args{ 31 | rootFolder: "Makefile", 32 | file: "Makefile", 33 | data: fileData, 34 | }, 35 | false, 36 | }, 37 | { 38 | "failed created files", 39 | args{ 40 | rootFolder: "", 41 | file: "", 42 | data: fileData, 43 | }, 44 | true, 45 | }, 46 | } 47 | 48 | for _, tt := range tests { 49 | t.Run(tt.name, func(t *testing.T) { 50 | if err := MakeFile(tt.args.rootFolder, tt.args.data); (err != nil) != tt.wantErr { 51 | t.Errorf("MakeFile() error = %v, wantErr %v", err, tt.wantErr) 52 | } 53 | }) 54 | 55 | // Clean 56 | err := os.RemoveAll("Makefile") 57 | if err != nil { 58 | return 59 | } 60 | } 61 | } 62 | 63 | func TestMakeFolder(t *testing.T) { 64 | type args struct { 65 | folderName string 66 | } 67 | tests := []struct { 68 | name string 69 | args args 70 | wantErr bool 71 | }{ 72 | { 73 | "successfully created folder", 74 | args{ 75 | folderName: "../../tmp", 76 | }, 77 | false, 78 | }, 79 | { 80 | "failed, folder is exists", 81 | args{ 82 | folderName: "", 83 | }, 84 | true, 85 | }, 86 | { 87 | "failed, folder is exists", 88 | args{ 89 | folderName: "cgapp-project", 90 | }, 91 | true, 92 | }, 93 | } 94 | 95 | _ = os.Mkdir("cgapp-project", 0o750) 96 | 97 | for _, tt := range tests { 98 | t.Run(tt.name, func(t *testing.T) { 99 | if err := MakeFolder(tt.args.folderName); (err != nil) != tt.wantErr { 100 | t.Errorf("MakeFolder() error = %v, wantErr %v", err, tt.wantErr) 101 | } 102 | }) 103 | 104 | // Clean 105 | err := os.RemoveAll(tt.args.folderName) 106 | if err != nil { 107 | return 108 | } 109 | } 110 | } 111 | 112 | func TestRemoveFolders(t *testing.T) { 113 | type args struct { 114 | rootFolder string 115 | foldersToRemove []string 116 | } 117 | tests := []struct { 118 | name string 119 | args args 120 | }{ 121 | { 122 | "successfully removed", 123 | args{ 124 | rootFolder: "../../tmp", 125 | foldersToRemove: []string{"folder-1"}, 126 | }, 127 | }, 128 | } 129 | 130 | _ = os.MkdirAll("../../tmp/folder-1", 0o750) 131 | 132 | for _, tt := range tests { 133 | t.Run(tt.name, func(t *testing.T) { 134 | RemoveFolders(tt.args.rootFolder, tt.args.foldersToRemove) 135 | }) 136 | } 137 | } 138 | 139 | func TestCopyFromEmbeddedFS(t *testing.T) { 140 | type args struct { 141 | efs *EmbeddedFileSystem 142 | } 143 | tests := []struct { 144 | name string 145 | args args 146 | wantErr bool 147 | }{ 148 | { 149 | "successfully copy from embedded fs", 150 | args{ 151 | efs: &EmbeddedFileSystem{ 152 | Name: registry.EmbedTemplates, 153 | RootFolder: "templates", 154 | SkipDir: false, 155 | }, 156 | }, 157 | false, 158 | }, 159 | { 160 | "successfully copy from embedded fs with skip dirs", 161 | args{ 162 | efs: &EmbeddedFileSystem{ 163 | Name: registry.EmbedTemplates, 164 | RootFolder: "templates", 165 | SkipDir: true, 166 | }, 167 | }, 168 | false, 169 | }, 170 | { 171 | "fail to copy from embedded fs", 172 | args{ 173 | efs: &EmbeddedFileSystem{ 174 | Name: registry.EmbedTemplates, 175 | RootFolder: "does-not-exist", 176 | SkipDir: false, 177 | }, 178 | }, 179 | true, 180 | }, 181 | { 182 | "fail (no args)", 183 | args{ 184 | efs: &EmbeddedFileSystem{}, 185 | }, 186 | true, 187 | }, 188 | } 189 | for _, tt := range tests { 190 | t.Run(tt.name, func(t *testing.T) { 191 | if err := CopyFromEmbeddedFS(tt.args.efs); (err != nil) != tt.wantErr { 192 | t.Errorf("CopyFromEmbeddedFS() error = %v, wantErr %v", err, tt.wantErr) 193 | } 194 | }) 195 | 196 | // Clean 197 | _ = os.Remove("hosts.ini.tmpl") 198 | _ = os.Remove("playbook.yml.tmpl") 199 | _ = os.RemoveAll(tt.args.efs.RootFolder) 200 | } 201 | } 202 | 203 | func TestGenerateFileFromTemplate(t *testing.T) { 204 | type args struct { 205 | fileName string 206 | variables map[string]interface{} 207 | } 208 | tests := []struct { 209 | name string 210 | args args 211 | wantErr bool 212 | }{ 213 | { 214 | "successfully generate file", 215 | args{ 216 | fileName: "../../tmp/test.txt", 217 | variables: map[string]interface{}{}, 218 | }, 219 | false, 220 | }, 221 | { 222 | "failed to generate file", 223 | args{}, 224 | true, 225 | }, 226 | } 227 | 228 | _ = os.Mkdir("../../tmp", 0o750) 229 | _, _ = os.Create("../../tmp/test.txt") 230 | 231 | for _, tt := range tests { 232 | t.Run(tt.name, func(t *testing.T) { 233 | if err := GenerateFileFromTemplate(tt.args.fileName, tt.args.variables); (err != nil) != tt.wantErr { 234 | t.Errorf("GenerateFileFromTemplate() error = %v, wantErr %v", err, tt.wantErr) 235 | } 236 | }) 237 | 238 | // Clean 239 | _ = os.RemoveAll("../../tmp") 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /pkg/cgapp/git.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cgapp 6 | 7 | import ( 8 | "fmt" 9 | "net/url" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | 14 | "github.com/go-git/go-git/v5" 15 | ) 16 | 17 | // GitClone function for `git clone` defined project template. 18 | func GitClone(templateType, templateURL string) error { 19 | // Checking for nil. 20 | if templateType == "" || templateURL == "" { 21 | return fmt.Errorf("project template not found") 22 | } 23 | 24 | // Get current directory. 25 | currentDir, _ := os.Getwd() 26 | 27 | // Set project folder. 28 | folder := filepath.Join(currentDir, templateType) 29 | 30 | // Clone project template. 31 | _, errPlainClone := git.PlainClone( 32 | folder, 33 | false, 34 | &git.CloneOptions{ 35 | URL: getAbsoluteURL(templateURL), 36 | }, 37 | ) 38 | if errPlainClone != nil { 39 | return ShowError( 40 | fmt.Sprintf("Repository `%v` was not cloned!", templateURL), 41 | ) 42 | } 43 | 44 | // Cleanup project. 45 | RemoveFolders(folder, []string{".git", ".github"}) 46 | 47 | return nil 48 | } 49 | 50 | // getAbsolutURL func for help define correct HTTP protocol. 51 | func getAbsoluteURL(templateURL string) string { 52 | templateURL = strings.TrimSpace(templateURL) 53 | u, _ := url.Parse(templateURL) 54 | 55 | if u.Scheme == "" { 56 | u.Scheme = "https" 57 | } 58 | 59 | return u.String() 60 | } 61 | -------------------------------------------------------------------------------- /pkg/cgapp/git_test.go: -------------------------------------------------------------------------------- 1 | package cgapp 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func TestGitClone(t *testing.T) { 9 | type args struct { 10 | rootFolder string 11 | templateName string 12 | } 13 | tests := []struct { 14 | name string 15 | args args 16 | wantErr bool 17 | }{ 18 | { 19 | "successfully cloned project", 20 | args{ 21 | rootFolder: "../../tmp/test", 22 | templateName: "github.com/koddr/koddr", 23 | }, 24 | false, 25 | }, 26 | { 27 | "failed clone project (empty template)", 28 | args{ 29 | rootFolder: "../../tmp/test", 30 | templateName: "", 31 | }, 32 | true, 33 | }, 34 | { 35 | "failed clone project", 36 | args{ 37 | rootFolder: "../../tmp/test", 38 | templateName: "404.404/404/404", 39 | }, 40 | true, 41 | }, 42 | { 43 | "failed clone project (empty args)", 44 | args{}, 45 | true, 46 | }, 47 | } 48 | for _, tt := range tests { 49 | t.Run(tt.name, func(t *testing.T) { 50 | if err := GitClone(tt.args.rootFolder, tt.args.templateName); (err != nil) != tt.wantErr { 51 | t.Errorf("GitClone() error = %v, wantErr %v", err, tt.wantErr) 52 | } 53 | }) 54 | 55 | // Clean 56 | err := os.RemoveAll("../../tmp") 57 | if err != nil { 58 | return 59 | } 60 | } 61 | } 62 | 63 | func Test_getAbsoluteURL(t *testing.T) { 64 | type args struct { 65 | templateURL string 66 | } 67 | tests := []struct { 68 | name string 69 | args args 70 | want string 71 | }{ 72 | { 73 | "successfully get absolute url from url with scheme", 74 | args{ 75 | templateURL: "https://github.com/create-go-app/net_http-go-template", 76 | }, 77 | "https://github.com/create-go-app/net_http-go-template", 78 | }, 79 | { 80 | "successfully get absolute url from url without scheme", 81 | args{ 82 | templateURL: "github.com/create-go-app/net_http-go-template", 83 | }, 84 | "https://github.com/create-go-app/net_http-go-template", 85 | }, 86 | { 87 | "successfully get absolute url from url starting space", 88 | args{ 89 | templateURL: " github.com/create-go-app/net_http-go-template", 90 | }, 91 | "https://github.com/create-go-app/net_http-go-template", 92 | }, 93 | } 94 | 95 | for _, tt := range tests { 96 | t.Run(tt.name, func(t *testing.T) { 97 | if got := getAbsoluteURL(tt.args.templateURL); got != tt.want { 98 | t.Errorf("getAbsoluteURL() = %v, want %v", got, tt.want) 99 | } 100 | }) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /pkg/cgapp/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package cgapp 6 | 7 | import ( 8 | "fmt" 9 | "time" 10 | 11 | "github.com/mattn/go-colorable" 12 | ) 13 | 14 | var ( 15 | Stdout = colorable.NewColorableStdout() // add a colorable std out 16 | Stderr = colorable.NewColorableStderr() // add a colorable std err 17 | ) 18 | 19 | // ShowMessage function for showing output messages. 20 | func ShowMessage(level, text string, startWithNewLine, endWithNewLine bool) { 21 | // Define variables. 22 | var startLine, endLine string 23 | 24 | if startWithNewLine { 25 | startLine = "\n" // set a new line 26 | } 27 | 28 | if endWithNewLine { 29 | endLine = "\n" // set a new line 30 | } 31 | 32 | // Formatting message. 33 | message := fmt.Sprintf("%s %s %s %s", startLine, colorizeLevel(level), text, endLine) 34 | 35 | // Return output. 36 | _, err := fmt.Fprintln(Stdout, message) 37 | if err != nil { 38 | return 39 | } 40 | } 41 | 42 | // ShowError function for send error message to output. 43 | func ShowError(text string) error { 44 | return fmt.Errorf("%s%s", colorizeLevel("error"), text) 45 | } 46 | 47 | // CalculateDurationTime func to calculate duration time. 48 | func CalculateDurationTime(startTimer time.Time) string { 49 | return fmt.Sprintf("%.0f", time.Since(startTimer).Seconds()) 50 | } 51 | 52 | // colorizeLevel function for send (colored or common) message to output. 53 | func colorizeLevel(level string) string { 54 | // Define variables. 55 | var ( 56 | red = "\033[0;31m" 57 | green = "\033[0;32m" 58 | yellow = "\033[1;33m" 59 | noColor = "\033[0m" 60 | color, icon string 61 | ) 62 | 63 | // Switch color. 64 | switch level { 65 | case "success": 66 | color = green 67 | icon = "[OK]" 68 | case "error": 69 | color = red 70 | icon = "[ERROR]" 71 | case "info": 72 | color = yellow 73 | icon = "[INFO]" 74 | default: 75 | color = noColor 76 | } 77 | 78 | // Send common or colored caption. 79 | return fmt.Sprintf("%s%s%s", color, icon, noColor) 80 | } 81 | -------------------------------------------------------------------------------- /pkg/cgapp/utils_test.go: -------------------------------------------------------------------------------- 1 | package cgapp 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func Test_colorizeLevel(t *testing.T) { 9 | type args struct { 10 | level string 11 | } 12 | tests := []struct { 13 | name string 14 | args args 15 | }{ 16 | { 17 | "successfully send message", 18 | args{level: ""}, 19 | }, 20 | { 21 | "successfully send success message", 22 | args{level: "success"}, 23 | }, 24 | { 25 | "successfully send error message", 26 | args{level: "error"}, 27 | }, 28 | { 29 | "successfully send info message", 30 | args{level: "info"}, 31 | }, 32 | } 33 | for _, tt := range tests { 34 | t.Run(tt.name, func(t *testing.T) { 35 | _ = colorizeLevel(tt.args.level) 36 | }) 37 | } 38 | } 39 | 40 | func TestShowMessage(t *testing.T) { 41 | type args struct { 42 | level string 43 | text string 44 | startWithNewLine bool 45 | endWithNewLine bool 46 | } 47 | tests := []struct { 48 | name string 49 | args args 50 | }{ 51 | { 52 | "successfully send message without args", 53 | args{}, 54 | }, 55 | { 56 | "successfully send message with args", 57 | args{"success", "Test", true, true}, 58 | }, 59 | } 60 | for _, tt := range tests { 61 | t.Run(tt.name, func(t *testing.T) { 62 | ShowMessage(tt.args.level, tt.args.text, tt.args.startWithNewLine, tt.args.endWithNewLine) 63 | }) 64 | } 65 | } 66 | 67 | func TestCalculateDurationTime(t *testing.T) { 68 | type args struct { 69 | startTimer time.Time 70 | } 71 | tests := []struct { 72 | name string 73 | args args 74 | want string 75 | }{ 76 | { 77 | "successfully", 78 | args{ 79 | startTimer: time.Now(), 80 | }, 81 | "0", 82 | }, 83 | } 84 | for _, tt := range tests { 85 | t.Run(tt.name, func(t *testing.T) { 86 | if got := CalculateDurationTime(tt.args.startTimer); got != tt.want { 87 | t.Errorf("CalculateDurationTime() = %v, want %v", got, tt.want) 88 | } 89 | }) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /pkg/registry/defaults.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Vic Shóstak and Create Go App Contributors. All rights reserved. 2 | // Use of this source code is governed by Apache 2.0 license 3 | // that can be found in the LICENSE file. 4 | 5 | package registry 6 | 7 | import ( 8 | "embed" 9 | 10 | "github.com/AlecAivazis/survey/v2" 11 | ) 12 | 13 | // CLIVersion version of Create Go App CLI. 14 | const CLIVersion string = "4.1.0" 15 | 16 | // Variables struct for Ansible variables (inventory, hosts). 17 | type Variables struct { 18 | List map[string]interface{} 19 | } 20 | 21 | // CreateAnswers struct for a survey's answers for `create` command. 22 | type CreateAnswers struct { 23 | Backend string 24 | Frontend string 25 | Proxy string 26 | AgreeCreation bool `survey:"agree"` 27 | } 28 | 29 | var ( 30 | // EmbedMiscFiles misc files and configs. 31 | //go:embed misc/* 32 | EmbedMiscFiles embed.FS 33 | 34 | // EmbedRoles Ansible roles. 35 | //go:embed roles/* 36 | EmbedRoles embed.FS 37 | 38 | // EmbedTemplates template files. 39 | //go:embed templates/* 40 | EmbedTemplates embed.FS 41 | 42 | // CreateQuestions survey's questions for `create` command. 43 | CreateQuestions = []*survey.Question{ 44 | { 45 | Name: "backend", 46 | Prompt: &survey.Select{ 47 | Message: "Choose a backend framework:", 48 | Options: []string{ 49 | "net/http", 50 | "fiber", 51 | "chi", 52 | }, 53 | Default: "fiber", 54 | PageSize: 3, 55 | }, 56 | Validate: survey.Required, 57 | }, 58 | { 59 | Name: "frontend", 60 | Prompt: &survey.Select{ 61 | Message: "Choose a frontend framework/library:", 62 | Help: "Option with a `*-ts` tail will create a TypeScript template.", 63 | Options: []string{ 64 | "none", 65 | "vanilla", 66 | "vanilla-ts", 67 | "react", 68 | "react-ts", 69 | "react-swc", 70 | "react-swc-ts", 71 | "preact", 72 | "preact-ts", 73 | "next", 74 | "next-ts", 75 | "nuxt", 76 | "vue", 77 | "vue-ts", 78 | "sveltekit", 79 | "svelte", 80 | "svelte-ts", 81 | "solid", 82 | "solid-ts", 83 | "lit", 84 | "lit-ts", 85 | "qwik", 86 | "qwik-ts", 87 | }, 88 | Default: "none", 89 | PageSize: 21, 90 | }, 91 | }, 92 | { 93 | Name: "proxy", 94 | Prompt: &survey.Select{ 95 | Message: "Choose a web/proxy server:", 96 | Options: []string{ 97 | "none", 98 | "traefik", 99 | "traefik-acme-dns", 100 | "nginx", 101 | }, 102 | Default: "none", 103 | PageSize: 4, 104 | }, 105 | }, 106 | { 107 | Name: "agree", 108 | Prompt: &survey.Confirm{ 109 | Message: "If everything is okay, can I create this project for you? ;)", 110 | Default: true, 111 | }, 112 | }, 113 | } 114 | 115 | // CustomCreateQuestions survey's questions for `create -c` command. 116 | CustomCreateQuestions = []*survey.Question{ 117 | { 118 | Name: "backend", 119 | Prompt: &survey.Input{ 120 | Message: "Enter URL to the custom backend repository:", 121 | }, 122 | Validate: survey.Required, 123 | }, 124 | { 125 | Name: "frontend", 126 | Prompt: &survey.Input{ 127 | Message: "Enter URL to the custom frontend repository:", 128 | Default: "none", 129 | }, 130 | }, 131 | { 132 | Name: "proxy", 133 | Prompt: &survey.Select{ 134 | Message: "Choose a web/proxy server:", 135 | Options: []string{ 136 | "none", 137 | "traefik", 138 | "traefik-acme-dns", 139 | "nginx", 140 | }, 141 | Default: "none", 142 | PageSize: 4, 143 | }, 144 | }, 145 | { 146 | Name: "agree", 147 | Prompt: &survey.Confirm{ 148 | Message: "If everything is okay, can I create this project for you? ;)", 149 | Default: true, 150 | }, 151 | }, 152 | } 153 | 154 | // AnsibleInventoryVariables list of variables for inventory. 155 | AnsibleInventoryVariables = map[string]*Variables{ 156 | "none": { 157 | List: map[string]interface{}{ 158 | "Proxy": "none", 159 | }, 160 | }, 161 | "traefik": { 162 | List: map[string]interface{}{ 163 | "Proxy": "traefik", 164 | "Wildcard": false, 165 | }, 166 | }, 167 | "traefik-acme-dns": { 168 | List: map[string]interface{}{ 169 | "Proxy": "traefik", 170 | "Wildcard": true, 171 | }, 172 | }, 173 | "nginx": { 174 | List: map[string]interface{}{ 175 | "Proxy": "nginx", 176 | }, 177 | }, 178 | } 179 | 180 | // AnsiblePlaybookVariables list of variables for playbook. 181 | AnsiblePlaybookVariables = map[string]*Variables{ 182 | "none": { 183 | List: map[string]interface{}{ 184 | "Proxy": "none", 185 | }, 186 | }, 187 | "traefik": { 188 | List: map[string]interface{}{ 189 | "Proxy": "traefik", 190 | }, 191 | }, 192 | "traefik-acme-dns": { 193 | List: map[string]interface{}{ 194 | "Proxy": "traefik", 195 | }, 196 | }, 197 | "nginx": { 198 | List: map[string]interface{}{ 199 | "Proxy": "nginx", 200 | }, 201 | }, 202 | } 203 | ) 204 | -------------------------------------------------------------------------------- /pkg/registry/misc/.editorconfig: -------------------------------------------------------------------------------- 1 | # A default .editorconfig for Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [{go.mod,go.sum,*.go}] 15 | indent_style = tab 16 | indent_size = 4 17 | 18 | [{Dockerfile,Makefile,*.yml,*.yaml}] 19 | indent_style = tab 20 | indent_size = 2 21 | -------------------------------------------------------------------------------- /pkg/registry/misc/.gitattributes: -------------------------------------------------------------------------------- 1 | # A default .gitattributes for Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | go.sum merge=union 6 | *.go text eol=lf 7 | -------------------------------------------------------------------------------- /pkg/registry/misc/.gitignore: -------------------------------------------------------------------------------- 1 | # A default .gitignore for Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | # macOS 6 | **/.DS_store 7 | 8 | # Go builds 9 | **/app/ 10 | **/build/ 11 | 12 | # Temporary files 13 | tmp/ 14 | 15 | # Node.js dependencies 16 | **/node_modules/ 17 | 18 | # Files 19 | hosts.ini 20 | *.out 21 | -------------------------------------------------------------------------------- /pkg/registry/misc/Makefile: -------------------------------------------------------------------------------- 1 | # A default Makefile for Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | .PHONY: test run build 6 | 7 | FRONTEND_PATH = $(PWD)/frontend 8 | BACKEND_PATH = $(PWD)/backend 9 | 10 | test: 11 | @if [ -d "$(FRONTEND_PATH)" ]; then cd $(FRONTEND_PATH) && npm run test; fi 12 | @if [ -d "$(BACKEND_PATH)" ]; then cd $(BACKEND_PATH) && go test ./...; fi 13 | 14 | run: test 15 | @if [ -d "$(FRONTEND_PATH)" ]; then cd $(FRONTEND_PATH) && npm run dev; fi 16 | @if [ -d "$(BACKEND_PATH)" ]; then cd $(BACKEND_PATH) && $(MAKE) run; fi 17 | 18 | build: test 19 | @if [ -d "$(FRONTEND_PATH)" ]; then cd $(FRONTEND_PATH) && npm run build; fi 20 | @if [ -d "$(BACKEND_PATH)" ]; then cd $(BACKEND_PATH) && $(MAKE) build; fi 21 | -------------------------------------------------------------------------------- /pkg/registry/roles/backend/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Ansible role for deploy a backend of the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Delete backend files. 8 | # 9 | - name: Delete previous backend files 10 | file: 11 | state: absent 12 | path: "{{ server_dir }}/backend" 13 | 14 | # 15 | # Copy `./backend` folder to the remote server. 16 | # 17 | - name: Copy a new backend files 18 | synchronize: 19 | src: ./backend 20 | dest: "{{ server_dir }}" 21 | rsync_opts: 22 | - "--exclude=.git,.github,build,*.md" 23 | 24 | # 25 | # Build backend Docker container. 26 | # 27 | - name: Build Docker image for backend 28 | community.docker.docker_image: 29 | name: cgapp_backend # name of the backend image 30 | build: 31 | path: "{{ server_dir }}/backend" # folder with Dockerfile 32 | pull: yes 33 | source: build 34 | 35 | # 36 | # Run backend container (for Traefik Proxy). 37 | # 38 | - name: Run Docker container with backend (for Traefik Proxy) 39 | community.docker.docker_container: 40 | name: cgapp-backend # name of the backend container 41 | image: cgapp_backend:latest 42 | restart_policy: unless-stopped 43 | recreate: true 44 | networks: 45 | - name: "{{ docker_network }}" 46 | ports: 47 | - "{{ backend_port }}:{{ backend_port }}" 48 | labels: 49 | traefik.enable: "true" 50 | traefik.http.routers.backend.rule: "Host(`{{ project_domain }}`)" 51 | traefik.http.routers.backend.entrypoints: "websecure" 52 | when: traefik_version is defined 53 | 54 | # 55 | # Run backend container (for Nginx). 56 | # 57 | - name: Run Docker container with backend (for Nginx) 58 | community.docker.docker_container: 59 | name: cgapp-backend # name of the backend container 60 | image: cgapp_backend:latest 61 | restart_policy: unless-stopped 62 | recreate: true 63 | networks: 64 | - name: "{{ docker_network }}" 65 | ports: 66 | - "{{ backend_port }}:{{ backend_port }}" 67 | when: nginx_version is defined 68 | -------------------------------------------------------------------------------- /pkg/registry/roles/docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Ansible role for deploy the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Make `apt update`. 8 | # 9 | - name: Update system packages cache 10 | apt: 11 | update_cache: yes 12 | cache_valid_time: 3600 13 | 14 | # 15 | # Make `apt upgrade`. 16 | # 17 | - name: Update all system packages to their latest versions 18 | apt: 19 | name: "*" 20 | state: latest 21 | 22 | # 23 | # Install `python3-pip` package for working with Docker from Ansible on the remote host. 24 | # 25 | - name: Install python3-pip package 26 | apt: 27 | pkg: 28 | - python3-pip 29 | 30 | # 31 | # Install `docker` package for Python 3 from pip3. 32 | # 33 | - name: Add the Python 3 client for Docker 34 | pip: 35 | name: docker 36 | 37 | # 38 | # Create a new system group for Docker. 39 | # 40 | - name: Create a new Docker group 41 | group: 42 | name: "{{ server_group }}" 43 | 44 | # 45 | # Create a new system user for Docker. 46 | # 47 | - name: Add the default user to the Docker group 48 | user: 49 | name: "{{ server_user }}" 50 | group: "{{ server_group }}" 51 | 52 | # 53 | # Create a new Docker network for connect all project elements into one network. 54 | # 55 | - name: Create a new Docker network 56 | community.docker.docker_network: 57 | name: "{{ docker_network }}" 58 | 59 | # 60 | # Create folder for project files. 61 | # 62 | - name: Create folder for project files 63 | file: 64 | state: directory 65 | path: "{{ server_dir }}" 66 | owner: "{{ server_user }}" 67 | group: "{{ server_group }}" 68 | -------------------------------------------------------------------------------- /pkg/registry/roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Ansible role for deploy the Nginx for the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Delete webserver files. 8 | # 9 | - name: Delete previous webserver files 10 | file: 11 | state: absent 12 | path: "{{ server_dir }}/webserver" 13 | 14 | # 15 | # Create folder for Nginx. 16 | # 17 | - name: Ensures Nginx dir exists 18 | file: 19 | state: directory 20 | path: "{{ server_dir }}/webserver" 21 | owner: "{{ server_user }}" 22 | group: "{{ server_group }}" 23 | 24 | # 25 | # Create Nginx config. 26 | # 27 | - name: Adding nginx.conf file 28 | template: 29 | src: nginx.conf.j2 30 | dest: "{{ server_dir }}/webserver/nginx.conf" 31 | mode: 0600 32 | 33 | # 34 | # Create default server config. 35 | # 36 | - name: Adding default.conf file 37 | template: 38 | src: "{{ 'default-https.conf.j2' if nginx_use_only_https == 'yes' else 'default-http.conf.j2' }}" 39 | dest: "{{ server_dir }}/webserver/default.conf" 40 | mode: 0600 41 | 42 | # 43 | # Run official Nginx Docker container (for HTTP only) with specified version. 44 | # 45 | - name: Run Nginx container (for HTTP) 46 | community.docker.docker_container: 47 | name: cgapp-nginx 48 | image: "nginx:{{ nginx_version }}" 49 | restart_policy: unless-stopped 50 | recreate: true 51 | networks: 52 | - name: "{{ docker_network }}" 53 | ports: 54 | - "80:80" 55 | volumes: 56 | - "{{ server_dir }}/webserver/nginx.conf:/etc/nginx/nginx.conf:ro" 57 | - "{{ server_dir }}/webserver/default.conf:/etc/nginx/conf.d/default.conf" 58 | when: nginx_use_only_https == 'no' 59 | 60 | # 61 | # Run official Nginx Docker container (for HTTPS only) with specified version. 62 | # 63 | - name: Run Nginx container (for HTTPS only) 64 | community.docker.docker_container: 65 | name: cgapp-nginx 66 | image: "nginx:{{ nginx_version }}" 67 | restart_policy: unless-stopped 68 | recreate: true 69 | networks: 70 | - name: "{{ docker_network }}" 71 | ports: 72 | - "80:80" 73 | - "443:443" 74 | volumes: 75 | - "{{ server_dir }}/webserver/nginx.conf:/etc/nginx/nginx.conf:ro" 76 | - "{{ server_dir }}/webserver/default.conf:/etc/nginx/conf.d/default.conf" 77 | when: nginx_use_only_https == 'yes' 78 | -------------------------------------------------------------------------------- /pkg/registry/roles/nginx/templates/default-http.conf.j2: -------------------------------------------------------------------------------- 1 | # 2 | # Default server config without SSL certificate: 3 | # 4 | 5 | {% if nginx_redirect_to_non_www %} 6 | # WWW redirects 7 | server { 8 | listen 80 default_server; 9 | listen [::]:80 default_server; 10 | server_name www.{{ project_domain }}; 11 | return 301 https://{{ project_domain }}$request_uri; 12 | } 13 | {% endif %} 14 | 15 | # Main server 16 | server { 17 | listen 80; 18 | listen [::]:80; 19 | {% if nginx_redirect_to_non_www %} 20 | server_name {{ project_domain }}; 21 | {% else %} 22 | server_name {{ project_domain }} www.{{ project_domain }}; 23 | {% endif %} 24 | location / { 25 | resolver 127.0.0.11; 26 | proxy_pass http://cgapp-backend:{{ backend_port }}/; 27 | proxy_set_header Host $host; 28 | proxy_set_header X-Real-IP $remote_addr; 29 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 30 | proxy_set_header X-Forwarded-Proto $scheme; 31 | proxy_redirect off; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pkg/registry/roles/nginx/templates/default-https.conf.j2: -------------------------------------------------------------------------------- 1 | # 2 | # Default server config with SSL certificate (Let's Encrypt): 3 | # 4 | 5 | # HTTP redirects 6 | server { 7 | listen 80 default_server; 8 | listen [::]:80 default_server; 9 | server_name {{ project_domain }} www.{{ project_domain }}; 10 | return 301 https://{{ project_domain }}$request_uri; 11 | } 12 | 13 | # WWW redirects 14 | server { 15 | listen 443 ssl http2; 16 | listen [::]:443 ssl http2; 17 | {% if nginx_redirect_to_non_www %} 18 | server_name www.{{ project_domain }}; 19 | return 301 https://{{ project_domain }}$request_uri; 20 | {% else %} 21 | server_name {{ project_domain }}; 22 | return 301 https://www.{{ project_domain }}$request_uri; 23 | {% endif %} 24 | } 25 | 26 | # Main server 27 | server { 28 | listen 443 ssl http2; 29 | listen [::]:443 ssl http2; 30 | {% if nginx_redirect_to_non_www %} 31 | server_name {{ project_domain }}; 32 | {% else %} 33 | server_name {{ project_domain }} www.{{ project_domain }}; 34 | {% endif %} 35 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 36 | ssl_certificate /etc/letsencrypt/live/{{ project_domain }}/fullchain.pem; 37 | ssl_certificate_key /etc/letsencrypt/live/{{ project_domain }}/privkey.pem; 38 | ssl_trusted_certificate /etc/letsencrypt/live/{{ project_domain }}/chain.pem; 39 | location / { 40 | resolver 127.0.0.11; 41 | proxy_pass http://cgapp-backend:{{ backend_port }}/; 42 | proxy_set_header Host $host; 43 | proxy_set_header X-Real-IP $remote_addr; 44 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 45 | proxy_set_header X-Forwarded-Proto $scheme; 46 | proxy_redirect off; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/registry/roles/nginx/templates/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | # 2 | # Nginx config 3 | # 4 | 5 | worker_processes auto; 6 | 7 | events { 8 | use epoll; 9 | multi_accept on; 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | charset utf-8; 15 | sendfile on; 16 | tcp_nopush on; 17 | tcp_nodelay on; 18 | server_tokens off; 19 | log_not_found off; 20 | 21 | # Bucket size for server names hash 22 | server_names_hash_bucket_size 64; 23 | 24 | # MIME 25 | include /etc/nginx/mime.types; 26 | default_type application/octet-stream; 27 | 28 | # Logging 29 | error_log /var/log/nginx/error.log crit; 30 | access_log off; 31 | 32 | # Timeouts 33 | send_timeout 2; 34 | keepalive_timeout 30; 35 | keepalive_requests 100; 36 | client_body_timeout 10; 37 | reset_timedout_connection on; 38 | 39 | # Max body size 40 | client_max_body_size 4m; 41 | 42 | # Cache 43 | open_file_cache max=200000 inactive=20s; 44 | open_file_cache_valid 30s; 45 | open_file_cache_errors on; 46 | open_file_cache_min_uses 2; 47 | 48 | # Gzip 49 | gzip on; 50 | gzip_vary on; 51 | gzip_disable "msie6"; 52 | gzip_proxied any; 53 | gzip_comp_level 6; 54 | 55 | # File types for compress via gzip 56 | gzip_types text/plain text/css application/json application/x-javascript text/xml 57 | application/xml application/xml+rss text/javascript application/javascript 58 | image/svg+xml image/gif image/png image/jpeg image/x-icon image/webp; 59 | 60 | # SSL 61 | ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; 62 | ssl_stapling on; 63 | ssl_protocols TLSv1.2 TLSv1.3; 64 | ssl_session_cache shared:le_nginx_SSL:1m; 65 | ssl_stapling_verify on; 66 | ssl_session_timeout 1d; 67 | ssl_session_tickets off; 68 | ssl_prefer_server_ciphers off; 69 | 70 | # Security headers 71 | add_header X-Frame-Options "SAMEORIGIN" always; 72 | add_header Referrer-Policy "no-referrer-when-downgrade" always; 73 | add_header X-XSS-Protection "1; mode=block" always; 74 | add_header X-Content-Type-Options "nosniff" always; 75 | add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; 76 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; 77 | 78 | # Load configs 79 | include /usr/share/nginx/modules/*.conf; 80 | include /etc/nginx/conf.d/*.conf; 81 | include /etc/nginx/sites-enabled/*; 82 | } -------------------------------------------------------------------------------- /pkg/registry/roles/postgres/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Ansible role for deploy the PostgreSQL for the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Create folder for PostgreSQL database. 8 | # 9 | - name: Ensures PostgreSQL dir exists 10 | file: 11 | state: directory 12 | path: "{{ server_dir }}/database" 13 | owner: "{{ server_user }}" 14 | group: "{{ server_group }}" 15 | 16 | # 17 | # Run official PostgreSQL Docker container with specified version. 18 | # 19 | - name: Run PostgreSQL container 20 | community.docker.docker_container: 21 | name: "{{ postgres_container_name }}" 22 | image: "postgres:{{ postgres_version }}" 23 | restart_policy: unless-stopped 24 | recreate: true 25 | networks: 26 | - name: "{{ docker_network }}" 27 | ports: 28 | - "{{ postgres_port }}:{{ postgres_port }}" 29 | env: 30 | POSTGRES_USER: "{{ postgres_user }}" 31 | POSTGRES_PASSWORD: "{{ postgres_password }}" 32 | POSTGRES_DB: "{{ postgres_db }}" 33 | volumes: 34 | - "{{ server_dir }}/database/data/:/var/lib/postgresql/data" 35 | 36 | # 37 | # Make DB migration. 38 | # 39 | - name: Make DB migration 40 | community.docker.docker_container: 41 | name: cgapp-db-migration 42 | image: "migrate/migrate" 43 | recreate: true 44 | networks: 45 | - name: "{{ docker_network }}" 46 | command: 47 | [ 48 | "-path", 49 | "/migrations", 50 | "-database", 51 | "postgres://{{ postgres_user }}:{{ postgres_password }}@{{ postgres_container_name }}:{{ postgres_port }}/{{ postgres_db }}?sslmode={{ postgres_ssl_mode }}", 52 | "up", 53 | "{{ migrate_number }}", 54 | ] 55 | volumes: 56 | - "{{ server_dir }}/backend/platform/migrations/:/migrations" 57 | -------------------------------------------------------------------------------- /pkg/registry/roles/redis/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Ansible role for deploy the Redis for the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Create folder for Redis cache. 8 | # 9 | - name: Ensures Redis dir exists 10 | file: 11 | state: directory 12 | path: "{{ server_dir }}/cache" 13 | owner: "{{ server_user }}" 14 | group: "{{ server_group }}" 15 | 16 | # 17 | # Run official Redis Docker container with specified version. 18 | # 19 | - name: Run Redis container 20 | community.docker.docker_container: 21 | name: "{{ redis_container_name }}" 22 | image: "redis:{{ redis_version }}" 23 | restart_policy: unless-stopped 24 | recreate: true 25 | networks: 26 | - name: "{{ docker_network }}" 27 | ports: 28 | - "{{ redis_port }}:{{ redis_port }}" 29 | volumes: 30 | - "{{ server_dir }}/cache/data/:/data" 31 | -------------------------------------------------------------------------------- /pkg/registry/roles/traefik/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Ansible role for deploy the Traefik Proxy for the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Delete webserver files. 8 | # 9 | - name: Delete previous webserver files 10 | file: 11 | state: absent 12 | path: "{{ server_dir }}/webserver" 13 | 14 | # 15 | # Create folder for Traefik. 16 | # 17 | - name: Ensures Traefik dir exists 18 | file: 19 | state: directory 20 | path: "{{ server_dir }}/webserver" 21 | owner: "{{ server_user }}" 22 | group: "{{ server_group }}" 23 | 24 | # 25 | # Create file for ACME challenge. 26 | # 27 | - name: Ensures acme.json file exists 28 | file: 29 | state: touch 30 | path: "{{ server_dir }}/webserver/acme.json" 31 | mode: 0600 32 | 33 | # 34 | # Create Traefik config. 35 | # 36 | - name: Adding traefik.yml file 37 | template: 38 | src: traefik.yml.j2 39 | dest: "{{ server_dir }}/webserver/traefik.yml" 40 | mode: 0600 41 | 42 | # 43 | # Create Traefik log file. 44 | # 45 | - name: Ensures traefik.log file exists 46 | file: 47 | state: touch 48 | path: "{{ server_dir }}/webserver/traefik.log" 49 | mode: 0600 50 | 51 | # 52 | # Run official Traefik Docker container 53 | # WITHOUT dashboard (Traefik Web UI) and specified version. 54 | # 55 | - name: Run Traefik container without dashboard (Traefik Web UI) 56 | community.docker.docker_container: 57 | name: cgapp-traefik 58 | image: "traefik:{{ traefik_version }}" 59 | restart_policy: unless-stopped 60 | recreate: true 61 | networks: 62 | - name: "{{ docker_network }}" 63 | ports: 64 | - "80:80" 65 | - "443:443" 66 | volumes: 67 | - "/var/run/docker.sock:/var/run/docker.sock" 68 | - "{{ server_dir }}/webserver/traefik.yml:/etc/traefik/traefik.yml:ro" 69 | - "{{ server_dir }}/webserver/acme.json:/acme.json:rw" 70 | - "{{ server_dir }}/webserver/traefik.log:/traefik.log:rw" 71 | # 72 | # Don't forget to set environment variables, if your choose DNS way to getting SSL cert. 73 | # See: https://doc.traefik.io/traefik/https/acme/#providers 74 | # 75 | # env: 76 | # # For example, auth token for DigitalOcean DNS provider: 77 | # DO_AUTH_TOKEN: "{{ do_auth_token }}" 78 | # 79 | when: (traefik_dashboard_url is not defined) or (traefik_dashboard_url|length == 0) 80 | 81 | # 82 | # Run official Traefik Docker container 83 | # WITH dashboard (Traefik Web UI) and specified version. 84 | # 85 | - name: Run Traefik container with dashboard (Traefik Web UI) 86 | community.docker.docker_container: 87 | name: cgapp-traefik 88 | image: "traefik:{{ traefik_version }}" 89 | restart_policy: unless-stopped 90 | recreate: true 91 | networks: 92 | - name: "{{ docker_network }}" 93 | ports: 94 | - "80:80" 95 | - "443:443" 96 | volumes: 97 | - "/var/run/docker.sock:/var/run/docker.sock" 98 | - "{{ server_dir }}/webserver/traefik.yml:/etc/traefik/traefik.yml:ro" 99 | - "{{ server_dir }}/webserver/acme.json:/acme.json:rw" 100 | - "{{ server_dir }}/webserver/traefik.log:/traefik.log:rw" 101 | labels: 102 | traefik.enable: "true" 103 | traefik.http.routers.traefik.rule: "Host(`{{ traefik_dashboard_url }}`)" 104 | traefik.http.routers.traefik.entrypoints: "websecure" 105 | traefik.http.routers.traefik.service: "api@internal" 106 | traefik.http.routers.traefik.middlewares: "auth" 107 | traefik.http.middlewares.auth.basicauth.users: "{{ traefik_dashboard_user }}:{{ traefik_dashboard_password }}" 108 | # 109 | # Don't forget to set environment variables, if your choose DNS way to getting SSL cert. 110 | # See: https://doc.traefik.io/traefik/https/acme/#providers 111 | # 112 | # env: 113 | # # For example, auth token for DigitalOcean DNS provider: 114 | # DO_AUTH_TOKEN: "{{ do_auth_token }}" 115 | # 116 | when: (traefik_dashboard_url is defined) or (traefik_dashboard_url|length > 0) 117 | -------------------------------------------------------------------------------- /pkg/registry/roles/traefik/templates/traefik.yml.j2: -------------------------------------------------------------------------------- 1 | global: 2 | checkNewVersion: false 3 | sendAnonymousUsage: false 4 | 5 | log: 6 | level: "{{ traefik_log_level }}" 7 | format: "{{ traefik_log_format }}" 8 | filePath: traefik.log 9 | {% if traefik_dashboard_url|length > 0 %} 10 | api: 11 | dashboard: true 12 | {% endif %} 13 | entryPoints: 14 | web: 15 | address: :80 16 | http: 17 | redirections: 18 | entryPoint: 19 | to: websecure 20 | scheme: https 21 | websecure: 22 | address: :443 23 | http: 24 | tls: 25 | certResolver: le 26 | domains: 27 | - main: "{{ project_domain }}" 28 | {% if acme_dns_provider %} 29 | sans: 30 | - "*.{{ project_domain }}" 31 | {% endif %} 32 | 33 | certificatesResolvers: 34 | le: 35 | acme: 36 | email: "{{ acme_email }}" 37 | storage: acme.json 38 | {% if acme_dns_provider %} 39 | dnsChallenge: 40 | provider: "{{ acme_dns_provider }}" 41 | delayBeforeCheck: 5 42 | resolvers: 43 | - 1.1.1.1:53 44 | - 8.8.8.8:53 45 | {% else %} 46 | caServer: https://acme-{% if acme_staging == 'yes' %}staging-{% endif %}v02.api.letsencrypt.org/directory 47 | {% endif %} 48 | 49 | providers: 50 | docker: 51 | network: "{{ docker_network }}" 52 | exposedByDefault: false 53 | -------------------------------------------------------------------------------- /pkg/registry/templates/hosts.ini.tmpl: -------------------------------------------------------------------------------- 1 | # Ansible inventory for deploy the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | [cgapp_project] 6 | 127.0.0.1 # CHANGE THIS TO YOUR REMOTE SERVER IP! 7 | 8 | [cgapp_project:vars] 9 | # 10 | # Ansible default variables to start playbook: 11 | # 12 | 13 | # Set remote sudo username 14 | ansible_user=root 15 | # Ask become password for remote sudo user 16 | ansible_become=yes 17 | # Set connection type to remote server (usually, 'ssh') 18 | ansible_connection=ssh 19 | # Set Python 3 default path 20 | ansible_python_interpreter=/usr/bin/python3 21 | 22 | # 23 | # Remote server configuration: 24 | # 25 | 26 | # Set directory on your remote server for store project files 27 | server_dir=/var/www/cgapp 28 | # Set user (owner of files/folders) name 29 | server_user=root 30 | # Set group name 31 | server_group=docker 32 | 33 | # 34 | # Project configuration: 35 | # 36 | 37 | # Set your project domain 38 | project_domain=example.com 39 | 40 | # 41 | # Docker configuration: 42 | # 43 | 44 | # Set Docker network name 45 | docker_network=cgapp_network 46 | 47 | # 48 | # Backend configuration: 49 | # 50 | 51 | # Set backend port number, 52 | # MUST BE MATCH to the port that is listed in your `./backend/.env` file! 53 | backend_port=5000 54 | 55 | # 56 | # PostgreSQL configuration (backend DB): 57 | # 58 | 59 | # Set PostgreSQL container name 60 | # MUST BE MATCH to the port that is listed in your `./backend/.env` file! 61 | postgres_container_name=cgapp-postgres 62 | # Set PostgreSQL version (for example, 13.2) 63 | postgres_version=latest 64 | # Set PostgreSQL port number, 65 | # MUST BE MATCH to the port that is listed in your `./backend/.env` file! 66 | postgres_port=5432 67 | # Set PostgreSQL user name, 68 | # MUST BE MATCH to the user name that is listed in your `./backend/.env` file! 69 | postgres_user=postgres 70 | # Set PostgreSQL password, 71 | # MUST BE MATCH to the password that is listed in your `./backend/.env` file! 72 | postgres_password=password 73 | # Set PostgreSQL DB name, 74 | # MUST BE MATCH to the DB name that is listed in your `./backend/.env` file! 75 | postgres_db=postgres 76 | # Set PostgreSQL SSL mode state ('enabled' or 'disabled'), 77 | # MUST BE MATCH to the SSL mode state that is listed in your `./backend/.env` file! 78 | postgres_ssl_mode=disable 79 | 80 | # 81 | # Go-Migrate configuration (DB migrations): 82 | # 83 | 84 | # Set migration number, 85 | # if you WANT to migrate all of your migrations, just leave it blank, 86 | # for only initial migration set it to '1' 87 | migrate_number=1 88 | 89 | # 90 | # Redis configuration (backend cache): 91 | # 92 | 93 | # Set Redis container name 94 | # MUST BE MATCH to the port that is listed in your `./backend/.env` file! 95 | redis_container_name=cgapp-redis 96 | # Set Redis version (for example, 6.2) 97 | redis_version=latest 98 | # Set Redis port number, 99 | # MUST BE MATCH to the port that is listed in your `./backend/.env` file! 100 | redis_port=6379 101 | 102 | {{ if eq .Proxy "traefik" }}# 103 | # Traefik Proxy configuration: 104 | # 105 | 106 | # Set Traefik version (for example, v2.4) 107 | traefik_version=latest 108 | # Set log level in capital letters (DEBUG, PANIC, FATAL, ERROR, WARN, INFO) 109 | traefik_log_level=ERROR 110 | # Set log format between json and common 111 | traefik_log_format=json 112 | # Set URL for Traefik admin dashboard, 113 | # if you DO NOT NEED dashboard (Web UI), just leave it blank 114 | traefik_dashboard_url=cp.example.com 115 | # Set username for Traefik admin dashboard, 116 | # DO NOT FORGET to set this setting, if `traefik_dashboard_url` variable IS NOT empty! 117 | traefik_dashboard_user=admin 118 | # Set hashed password for Traefik admin dashboard, 119 | # DO NOT FORGET to set this setting, if `traefik_dashboard_url` variable IS NOT empty! 120 | # See: https://doc.traefik.io/traefik/middlewares/basicauth/#users 121 | traefik_dashboard_password=admin:$$apr1$$WpxRpfMZ$$TMTfGB37C9xAHiPIDiFiB1 122 | 123 | # 124 | # ACME configuration (Let's Encrypt): 125 | # 126 | 127 | # Set your email address for SSL cert 128 | acme_email=mail@example.com 129 | {{ if .Wildcard }} 130 | # You choose a DNS way to getting SSL cert, 131 | # DO NOT FORGET to set this variable here as well as in `./roles/traefik/tasks/main.yml` file! 132 | 133 | # Set DNS provider 134 | # See: https://doc.traefik.io/traefik/https/acme/#providers 135 | acme_dns_provider=digitalocean 136 | # Set environment variable(s) for a DNS provider, 137 | # for example, auth token for DigitalOcean 138 | do_auth_token=XXXXXXXXXXX 139 | {{ else }}# Change to 'no' for getting a real SSL cert 140 | acme_staging=yes{{ end }} 141 | {{ else if eq .Proxy "nginx" }}# 142 | # Nginx configuration: 143 | # 144 | 145 | # Set Nginx version (for example, 1.20-alpine) 146 | nginx_version=alpine 147 | # Set redirect from HTTP to HTTPS for default server 148 | nginx_use_only_https=yes 149 | # Set redirect from WWW to non-WWW domain for default server 150 | nginx_redirect_to_non_www=yes{{ end }} 151 | -------------------------------------------------------------------------------- /pkg/registry/templates/playbook.yml.tmpl: -------------------------------------------------------------------------------- 1 | # Ansible playbook for deploy the Create Go App project. 2 | # Author: Vic Shóstak (https://github.com/koddr) 3 | # For more information, please visit https://github.com/create-go-app/cli 4 | 5 | --- 6 | # 7 | # Playbook for deploy. 8 | # 9 | - name: Deploy the Create Go App project 10 | hosts: cgapp_project 11 | 12 | # 13 | # List of all roles. 14 | # 15 | roles: 16 | - { role: docker, tags: [docker] } 17 | - { role: backend, tags: [backend] } 18 | - { role: redis, tags: [redis] } 19 | - { role: postgres, tags: [postgres] } 20 | {{ if ne .Proxy "none" }} - { role: {{.Proxy}}, tags: [{{.Proxy}}] }{{ end }} 21 | --------------------------------------------------------------------------------